mindoodb-app-sdk 0.0.14 → 0.0.16
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 +251 -12
- package/dist/index.d.ts +97 -4
- package/dist/index.js +177 -12
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +101 -9
- package/dist/{types-B1iKRIuy.d.ts → types-D0vtIHBf.d.ts} +60 -9
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -319,22 +319,56 @@ const window = await db.documents.list({
|
|
|
319
319
|
// Read
|
|
320
320
|
const doc = await db.documents.get(docId);
|
|
321
321
|
|
|
322
|
-
// Create (optionally
|
|
322
|
+
// Create (MindooDB generates a UUID7 id; optionally use a named document key)
|
|
323
323
|
const created = await db.documents.create({
|
|
324
324
|
set: { title: "Meeting notes", content: "..." },
|
|
325
325
|
decryptionKeyId: "team-key", // omit to use "default"
|
|
326
326
|
});
|
|
327
327
|
|
|
328
|
-
//
|
|
328
|
+
// Create with a caller-provided id (e.g. a known well-known document the app
|
|
329
|
+
// always loads on launch, or migrating an id from another system).
|
|
330
|
+
const settings = await db.documents.create({
|
|
331
|
+
id: "AppSettings",
|
|
332
|
+
set: { theme: "dark" },
|
|
333
|
+
});
|
|
334
|
+
// Subsequent calls with the same id return the existing document and DO NOT
|
|
335
|
+
// overwrite `set`, so `documents.create({ id })` is safe to call on every app
|
|
336
|
+
// launch as a "create-if-missing" primitive. Custom ids must match
|
|
337
|
+
// /^[A-Za-z][A-Za-z0-9_]*$/ (first char must be a letter, subsequent chars
|
|
338
|
+
// may be letters, digits, or `_`). Documents created with the same custom id
|
|
339
|
+
// on different replicas merge correctly when synced.
|
|
340
|
+
|
|
341
|
+
// Update top-level fields
|
|
329
342
|
const updated = await db.documents.update(docId, {
|
|
330
343
|
set: { title: "Updated title" },
|
|
331
344
|
unset: ["legacyField"],
|
|
332
345
|
});
|
|
333
346
|
|
|
347
|
+
// Update with a granular text patch (see "Collaborative text editing" below).
|
|
348
|
+
// `baseHeads` is the document version this edit was authored against; Haven
|
|
349
|
+
// merges these splices with any concurrent changes since `baseHeads`.
|
|
350
|
+
const merged = await db.documents.update(docId, {
|
|
351
|
+
text: [
|
|
352
|
+
{
|
|
353
|
+
path: ["body"],
|
|
354
|
+
baseHeads: doc!.heads,
|
|
355
|
+
edits: [
|
|
356
|
+
{ index: 0, deleteCount: 0, insert: "Hello, " },
|
|
357
|
+
{ index: 12, deleteCount: 5, insert: "team" },
|
|
358
|
+
],
|
|
359
|
+
},
|
|
360
|
+
],
|
|
361
|
+
});
|
|
362
|
+
|
|
334
363
|
// Delete
|
|
335
364
|
await db.documents.delete(docId);
|
|
365
|
+
|
|
366
|
+
// Undelete (resurrect a deleted document)
|
|
367
|
+
await db.documents.undelete(docId);
|
|
336
368
|
```
|
|
337
369
|
|
|
370
|
+
Every `MindooDBAppDocument` snapshot also exposes a `heads?: string[]` field. Those heads identify the document's current Automerge version and are the value you pass to `baseHeads` when issuing the next text patch. After Haven applies and merges your patch, the returned document carries the new `heads` you should use for the following edit cycle.
|
|
371
|
+
|
|
338
372
|
`documents.list()` is backed by Haven's internal changefeed, not by a positional offset. The query object supports:
|
|
339
373
|
|
|
340
374
|
| Field | Meaning |
|
|
@@ -349,24 +383,187 @@ await db.documents.delete(docId);
|
|
|
349
383
|
|
|
350
384
|
`nextCursor` is the latest checkpoint reached by the page. Persist it after each successful call when you are building your own index or sync loop. If there were no changes after the supplied cursor, `nextCursor` is `null`.
|
|
351
385
|
|
|
352
|
-
`documents.update()` accepts
|
|
386
|
+
`documents.update()` accepts three independent operations on the same call:
|
|
387
|
+
|
|
388
|
+
- `set` -- assign top-level fields (shallow JSON merge).
|
|
389
|
+
- `unset` -- remove top-level fields entirely.
|
|
390
|
+
- `text` -- one or more **granular text patches** applied to specific JSON paths. Each patch carries the `baseHeads` version it was authored against and is merged on the Haven side with any concurrent changes that arrived since. This is the recommended way to edit collaborative text fields like a markdown body. See [Collaborative text editing](#collaborative-text-editing) below.
|
|
391
|
+
|
|
392
|
+
Prefer sending small, intentional field-level changes instead of rewriting whole documents when only a few fields changed. This keeps MindooDB change tracking more meaningful and helps Automerge produce cleaner merge results.
|
|
353
393
|
|
|
354
394
|
When Haven can resolve the signing identity from the tenant directory, list items may also include `identityLabel` and `publicKeyFingerprint` for the latest visible change. Apps can use this to show who last touched a document without loading the full revision history first.
|
|
355
395
|
|
|
356
396
|
### Document history
|
|
357
397
|
|
|
358
|
-
When the `history` capability is granted, you can walk the
|
|
398
|
+
When the `history` capability is granted, you can walk the document revision list and load historical snapshots. Prefer `revisionId` for follow-up reads: it is a stable, DAG-backed identifier for the exact document revision, while timestamps are mainly useful for display and backwards-compatible point-in-time lookups.
|
|
359
399
|
|
|
360
400
|
```ts
|
|
361
401
|
// List all revisions
|
|
362
402
|
const history = await db.documents.listHistory(docId);
|
|
363
|
-
// Each entry:
|
|
403
|
+
// Each entry:
|
|
404
|
+
// {
|
|
405
|
+
// revisionId,
|
|
406
|
+
// timestamp,
|
|
407
|
+
// heads?,
|
|
408
|
+
// publicKey,
|
|
409
|
+
// identityLabel?,
|
|
410
|
+
// isDeleted,
|
|
411
|
+
// isCurrent,
|
|
412
|
+
// summary?
|
|
413
|
+
// }
|
|
414
|
+
|
|
415
|
+
// Load the document state at an exact DAG revision
|
|
416
|
+
const snapshot = await db.documents.getAtRevision(docId, history[0]!.revisionId);
|
|
417
|
+
// {
|
|
418
|
+
// id,
|
|
419
|
+
// revisionId,
|
|
420
|
+
// timestamp,
|
|
421
|
+
// heads?,
|
|
422
|
+
// state: "exists" | "deleted" | "missing",
|
|
423
|
+
// data,
|
|
424
|
+
// attachments?,
|
|
425
|
+
// attachmentSnapshotRevisionId?
|
|
426
|
+
// }
|
|
427
|
+
|
|
428
|
+
// Timestamp lookup is still available when all you have is a timestamp.
|
|
429
|
+
const pointInTime = await db.documents.getAtTimestamp(docId, history[0]!.timestamp);
|
|
430
|
+
```
|
|
364
431
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
432
|
+
Historical snapshots include the document data payload as it existed at that revision. When the snapshot has attachments, `attachments` reflects the historical `_attachments` array for that same revision, including the attachment reference that Haven needs to stop at the correct historical `lastChunkId`.
|
|
433
|
+
|
|
434
|
+
### Collaborative text editing
|
|
435
|
+
|
|
436
|
+
MindooDB stores collaborative text fields as Automerge text CRDTs internally, but apps never touch Automerge directly -- the SDK bridge is JSON-only. Instead, your app describes text changes as **granular splice operations** against a known document version, and Haven applies and merges them on its side.
|
|
437
|
+
|
|
438
|
+
Two layers are available:
|
|
439
|
+
|
|
440
|
+
- **Low level**: raw text patches via `documents.update({ text: [...] })`.
|
|
441
|
+
- **High level**: `createMindooDBTextBuffer(...)` -- a small editor-friendly helper that tracks local edits and flushes them as one patch.
|
|
442
|
+
|
|
443
|
+
The end-to-end flow is the same in both cases:
|
|
444
|
+
|
|
445
|
+
```
|
|
446
|
+
┌────────────────────────────────────────────────────┐
|
|
447
|
+
edit ───► │ App buffer (local string + pending splices) │ ──► flush
|
|
448
|
+
└─────────────────────────┬──────────────────────────┘
|
|
449
|
+
│ documents.update({
|
|
450
|
+
│ text: [{ path, baseHeads, edits }]
|
|
451
|
+
│ })
|
|
452
|
+
▼
|
|
453
|
+
┌────────────────────────────────────────────────────┐
|
|
454
|
+
│ Haven applies edits at `baseHeads` and merges with │
|
|
455
|
+
│ concurrent changes via Automerge │
|
|
456
|
+
└─────────────────────────┬──────────────────────────┘
|
|
457
|
+
│ canonical merged document
|
|
458
|
+
▼
|
|
459
|
+
┌────────────────────────────────────────────────────┐
|
|
460
|
+
│ App reconciles its editor with the canonical text │
|
|
461
|
+
└────────────────────────────────────────────────────┘
|
|
368
462
|
```
|
|
369
463
|
|
|
464
|
+
#### Text patch shape
|
|
465
|
+
|
|
466
|
+
```ts
|
|
467
|
+
interface MindooDBAppTextEdit {
|
|
468
|
+
index: number; // 0-based position in the current string at baseHeads
|
|
469
|
+
deleteCount: number; // number of characters to remove at `index`
|
|
470
|
+
insert?: string; // text to insert at `index` after deletion
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
interface MindooDBAppTextPatch {
|
|
474
|
+
path: Array<string | number>; // path inside `document.data`, e.g. ["body"]
|
|
475
|
+
baseHeads?: string[]; // document version the edits were authored against
|
|
476
|
+
edits: MindooDBAppTextEdit[]; // applied in order
|
|
477
|
+
}
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
Each edit is a JavaScript-style `splice(index, deleteCount, insert)`. Multiple patches in a single `update()` call are applied atomically.
|
|
481
|
+
|
|
482
|
+
#### Low-level: `documents.update({ text: [...] })`
|
|
483
|
+
|
|
484
|
+
If your editor already exposes raw text operations (e.g. ProseMirror or CodeMirror transactions), forward them directly:
|
|
485
|
+
|
|
486
|
+
```ts
|
|
487
|
+
const doc = await db.documents.get(docId);
|
|
488
|
+
|
|
489
|
+
// User typed "Hello, " at the beginning of the body.
|
|
490
|
+
const result = await db.documents.update(docId, {
|
|
491
|
+
text: [{
|
|
492
|
+
path: ["body"],
|
|
493
|
+
baseHeads: doc!.heads,
|
|
494
|
+
edits: [{ index: 0, deleteCount: 0, insert: "Hello, " }],
|
|
495
|
+
}],
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
// `result.data.body` -- canonical merged text
|
|
499
|
+
// `result.heads` -- new heads to use as `baseHeads` next time
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
When two app instances send patches concurrently against the same `baseHeads`, Haven merges both via Automerge and returns the canonical text. If the merged result differs from what your editor currently displays, replace the editor content with `result.data[path]`.
|
|
503
|
+
|
|
504
|
+
#### High-level: `createMindooDBTextBuffer`
|
|
505
|
+
|
|
506
|
+
For WYSIWYG editors that emit a full markdown / plain-text string after each transaction (Milkdown, TinyMCE, etc.), the SDK ships a small buffer helper that does the splice diffing and flush bookkeeping for you:
|
|
507
|
+
|
|
508
|
+
```ts
|
|
509
|
+
import { createMindooDBTextBuffer } from "mindoodb-app-sdk";
|
|
510
|
+
|
|
511
|
+
const doc = await db.documents.get(docId);
|
|
512
|
+
const buffer = createMindooDBTextBuffer({
|
|
513
|
+
database: db,
|
|
514
|
+
document: doc!,
|
|
515
|
+
path: ["body"], // string field inside `document.data`
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
editor.value = buffer.value;
|
|
519
|
+
|
|
520
|
+
// Editor reports a new full markdown value -- the buffer turns it into one splice.
|
|
521
|
+
editor.on("update", (next: string) => {
|
|
522
|
+
buffer.replaceText(next);
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
// On save (e.g. Cmd+S), flush all pending edits to Haven.
|
|
526
|
+
async function save() {
|
|
527
|
+
const result = await buffer.flush();
|
|
528
|
+
if (result.reconciled) {
|
|
529
|
+
// Haven merged in concurrent changes; show the canonical merged text.
|
|
530
|
+
editor.value = result.value;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Re-read the document without saving (e.g. a Refresh button).
|
|
535
|
+
async function refresh() {
|
|
536
|
+
const fresh = await db.documents.get(docId);
|
|
537
|
+
if (fresh && buffer.reconcile(fresh)) {
|
|
538
|
+
editor.value = buffer.value;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
Buffer API at a glance:
|
|
544
|
+
|
|
545
|
+
| Member | Description |
|
|
546
|
+
|---|---|
|
|
547
|
+
| `value` / `toString()` | Current local text value |
|
|
548
|
+
| `dirty` / `pendingCount` | Whether/how many local splices are buffered |
|
|
549
|
+
| `splice(index, deleteCount, insert?)` | Record an exact text operation |
|
|
550
|
+
| `replaceText(next)` | Diff `value` against `next` and record one minimal splice |
|
|
551
|
+
| `reconcile(document)` | Adopt a fresh document snapshot, drop pending edits |
|
|
552
|
+
| `flush()` | Send pending edits to Haven; resolves to `{ document, value, reconciled }` |
|
|
553
|
+
|
|
554
|
+
`flush()` always sends the original `baseHeads` captured when the buffer was created (or last reconciled), so two windows editing the same document at the same heads will both produce a clean merge -- they will not overwrite each other.
|
|
555
|
+
|
|
556
|
+
#### Concurrent-edit walkthrough
|
|
557
|
+
|
|
558
|
+
1. Window A and window B both `documents.get(docId)` and create a buffer at the same `baseHeads`.
|
|
559
|
+
2. Window A inserts text at the top, window B deletes a paragraph in the middle.
|
|
560
|
+
3. Window A calls `buffer.flush()` first. Haven applies its patch, advances the document heads, and returns the canonical text to A.
|
|
561
|
+
4. Window B calls `buffer.flush()` next. Haven still applies B's patch causally at B's original `baseHeads`, then merges with A's already-stored change. B's `result.reconciled` is `true` and `result.value` contains both A's and B's edits.
|
|
562
|
+
|
|
563
|
+
#### End-to-end sample
|
|
564
|
+
|
|
565
|
+
The [`mindoodb-app-teamedit`](https://github.com/klehmann/mindoodb-app-teamedit) sample wires `MindooDBTextBuffer` to a Milkdown markdown editor with Save / Refresh / preview pane, and is the recommended starting point for building your own collaborative text app.
|
|
566
|
+
|
|
370
567
|
### Incremental sync
|
|
371
568
|
|
|
372
569
|
The changefeed-backed `documents.list()` API is also the right primitive for app-side indexes, search, and other derived caches.
|
|
@@ -457,6 +654,26 @@ await writer.close();
|
|
|
457
654
|
await db.attachments.remove(docId, "old-file.txt");
|
|
458
655
|
```
|
|
459
656
|
|
|
657
|
+
For historical reads, pass the same `revisionId` you received from `documents.listHistory()` or from a `MindooDBAppHistoricalDocument`. This tells Haven to resolve the attachment from that revision's document payload instead of the latest document state:
|
|
658
|
+
|
|
659
|
+
```ts
|
|
660
|
+
const history = await db.documents.listHistory(docId);
|
|
661
|
+
const revisionId = history[0]!.revisionId;
|
|
662
|
+
const historical = await db.documents.getAtRevision(docId, revisionId);
|
|
663
|
+
|
|
664
|
+
const historicalFiles = await db.attachments.list(docId, {
|
|
665
|
+
revisionId,
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
const historicalReader = await db.attachments.openReadStream(
|
|
669
|
+
docId,
|
|
670
|
+
historicalFiles[0]!.fileName,
|
|
671
|
+
{ revisionId },
|
|
672
|
+
);
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
Use `revisionId` instead of `timestamp` whenever possible. Attachment blobs can grow over time by appending chunks and changing the attachment's `lastChunkId` in newer document revisions; `revisionId` ensures Haven reads from the historical attachment reference and does not accidentally include chunks added later.
|
|
676
|
+
|
|
460
677
|
### Attachment previews
|
|
461
678
|
|
|
462
679
|
Haven includes a **built-in file viewer** that your app can open for common attachment formats. This is one of the most powerful SDK features -- it works with both online and offline data, and media formats support streaming playback with skip/seek.
|
|
@@ -485,10 +702,12 @@ You can also preview attachments from a **historical document snapshot**:
|
|
|
485
702
|
|
|
486
703
|
```ts
|
|
487
704
|
await db.attachments.openPreview(docId, "report.pdf", {
|
|
488
|
-
|
|
705
|
+
revisionId: historyEntry.revisionId,
|
|
489
706
|
});
|
|
490
707
|
```
|
|
491
708
|
|
|
709
|
+
`timestamp` is still accepted in attachment options for compatibility, but `revisionId` is the preferred identifier because it targets an exact DAG revision.
|
|
710
|
+
|
|
492
711
|
**Check preview support locally** before showing a preview button:
|
|
493
712
|
|
|
494
713
|
```ts
|
|
@@ -729,23 +948,42 @@ Connect options: `launchId?`, `targetOrigin?`, `connectTimeoutMs?`.
|
|
|
729
948
|
| `create(input)` | `Promise<MindooDBAppDocument>` |
|
|
730
949
|
| `update(docId, patch)` | `Promise<MindooDBAppDocument>` |
|
|
731
950
|
| `delete(docId)` | `Promise<{ ok: true }>` |
|
|
951
|
+
| `undelete(docId)` | `Promise<{ ok: true }>` |
|
|
732
952
|
| `listHistory(docId)` | `Promise<MindooDBAppDocumentHistoryEntry[]>` |
|
|
733
953
|
| `getAtTimestamp(docId, timestamp)` | `Promise<MindooDBAppHistoricalDocument>` |
|
|
954
|
+
| `getAtRevision(docId, revisionId)` | `Promise<MindooDBAppHistoricalDocument>` |
|
|
734
955
|
|
|
735
956
|
`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.
|
|
736
957
|
|
|
737
|
-
For `
|
|
958
|
+
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.
|
|
959
|
+
|
|
960
|
+
`delete(docId)` writes a lifecycle tombstone; it does not erase the document body from the append-only history. Use `undelete(docId)` to make the latest document state live again. If you want to record a deletion reason, first call `update(docId, { set: { intendedDeletionReason: "..." } })`, then call `delete(docId)`.
|
|
961
|
+
|
|
962
|
+
For `update(docId, patch)`, use `MindooDBAppUpdateDocumentInput`:
|
|
963
|
+
|
|
964
|
+
```ts
|
|
965
|
+
interface MindooDBAppUpdateDocumentInput {
|
|
966
|
+
set?: Record<string, unknown>; // shallow assign top-level fields
|
|
967
|
+
unset?: string[]; // remove top-level fields entirely
|
|
968
|
+
text?: MindooDBAppTextPatch[]; // granular collaborative text edits
|
|
969
|
+
}
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
`set` and `unset` apply to top-level fields only. `text` patches operate on string fields at any JSON path inside `document.data` and are merged on the Haven side using the document's Automerge heads. See [Collaborative text editing](#collaborative-text-editing).
|
|
738
973
|
|
|
739
974
|
### MindooDBAppAttachmentApi
|
|
740
975
|
|
|
741
976
|
| Method | Returns |
|
|
742
977
|
|---|---|
|
|
743
|
-
| `list(docId)` | `Promise<MindooDBAppAttachmentInfo[]>` |
|
|
978
|
+
| `list(docId, options?)` | `Promise<MindooDBAppAttachmentInfo[]>` |
|
|
744
979
|
| `remove(docId, attachmentName)` | `Promise<{ ok: true }>` |
|
|
745
|
-
| `openReadStream(docId, attachmentName)` | `Promise<MindooDBAppReadableAttachmentStream>` |
|
|
980
|
+
| `openReadStream(docId, attachmentName, options?)` | `Promise<MindooDBAppReadableAttachmentStream>` |
|
|
746
981
|
| `openWriteStream(docId, attachmentName, contentType?)` | `Promise<MindooDBAppWritableAttachmentStream>` |
|
|
982
|
+
| `preparePreviewSession(docId, attachmentName, options?)` | `Promise<MindooDBAppAttachmentPreviewSession>` |
|
|
747
983
|
| `openPreview(docId, attachmentName, options?)` | `Promise<{ ok: true }>` |
|
|
748
984
|
|
|
985
|
+
`options` accepts `{ timestamp?: number; revisionId?: string }` for read-only historical attachment access. Mutation methods (`openWriteStream`, `remove`) always target the current document.
|
|
986
|
+
|
|
749
987
|
### MindooDBAppViewNavigator
|
|
750
988
|
|
|
751
989
|
| Method | Returns |
|
|
@@ -792,6 +1030,7 @@ For `update(docId, patch)`, use `{ set?: Record<string, unknown>; unset?: string
|
|
|
792
1030
|
| Function | Description |
|
|
793
1031
|
|---|---|
|
|
794
1032
|
| `createMindooDBAppBridge()` | Create the bridge object used to connect to Haven |
|
|
1033
|
+
| `createMindooDBTextBuffer(options)` | Create an editor-friendly buffer for granular collaborative text edits on a document field |
|
|
795
1034
|
| `canPreviewAttachment(fileName, mimeType)` | Check if Haven can preview a file (returns mode or `null`) |
|
|
796
1035
|
| `createViewLanguage<T>()` | Create a typed expression builder for view definitions |
|
|
797
1036
|
| `abbreviateCanonicalName(value)` | Convert a canonical Notes-style name like `cn=Jane/ou=Dev/o=Mindoo` to `Jane/Dev/Mindoo` |
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { M as MindooDBAppAttachmentPreviewMode, a as MindooDBAppBridge } from './types-
|
|
2
|
-
export {
|
|
1
|
+
import { M as MindooDBAppAttachmentPreviewMode, a as MindooDBAppBridge, b as MindooDBAppDatabase, c as MindooDBAppDocument } from './types-D0vtIHBf.js';
|
|
2
|
+
export { d as MindooDBAppAttachmentApi, e as MindooDBAppAttachmentChunk, f as MindooDBAppAttachmentInfo, g as MindooDBAppAttachmentPreviewOptions, h as MindooDBAppAttachmentPreviewSession, i as MindooDBAppBridgeConnectMessage, j as MindooDBAppBridgeConnectOptions, k as MindooDBAppBridgeConnectedMessage, l as MindooDBAppBridgeErrorPayload, m as MindooDBAppBridgeHandshakeErrorMessage, n as MindooDBAppBridgePortMessage, o as MindooDBAppBridgeRpcError, p as MindooDBAppBridgeRpcMessage, q as MindooDBAppBridgeRpcRequest, r as MindooDBAppBridgeRpcSuccess, s as MindooDBAppBridgeStreamAbortRequest, t as MindooDBAppBridgeStreamAck, u as MindooDBAppBridgeStreamCloseRequest, v as MindooDBAppBridgeStreamError, w as MindooDBAppBridgeStreamMessage, x as MindooDBAppBridgeStreamOpenResult, y as MindooDBAppBridgeStreamReadRequest, z as MindooDBAppBridgeStreamWriteRequest, A as MindooDBAppBridgeThemeChangedMessage, B as MindooDBAppBridgeUiPreferencesChangedMessage, C as MindooDBAppBridgeViewportChangedMessage, D as MindooDBAppCapability, E as MindooDBAppConfiguredViewCategorizationStyle, F as MindooDBAppConfiguredViewColumn, G as MindooDBAppConfiguredViewColumnRole, H as MindooDBAppConfiguredViewExpressionMode, I as MindooDBAppConfiguredViewFieldExpression, J as MindooDBAppConfiguredViewFilterDefinition, K as MindooDBAppConfiguredViewFilterMode, L as MindooDBAppConfiguredViewFilterRule, N as MindooDBAppConfiguredViewFormulaExpression, O as MindooDBAppConfiguredViewFormulaFilterDefinition, P as MindooDBAppConfiguredViewPreviewMode, Q as MindooDBAppConfiguredViewRuleFilterDefinition, R as MindooDBAppConfiguredViewRuleMatchMode, S as MindooDBAppConfiguredViewRuleOperator, T as MindooDBAppConfiguredViewValueExpression, U as MindooDBAppCreateDocumentInput, V as MindooDBAppCreateViewInput, W as MindooDBAppCreateViewNavigatorInput, X as MindooDBAppDatabaseInfo, Y as MindooDBAppDocumentApi, Z as MindooDBAppDocumentHeadCursorResult, _ as MindooDBAppDocumentHistoryEntry, $ as MindooDBAppDocumentListQuery, a0 as MindooDBAppDocumentListResult, a1 as MindooDBAppDocumentRevisionId, a2 as MindooDBAppDocumentSummary, a3 as MindooDBAppHistoricalDocument, a4 as MindooDBAppHistoryQuery, a5 as MindooDBAppHostTheme, a6 as MindooDBAppLaunchContext, a7 as MindooDBAppMenuAnchor, a8 as MindooDBAppMenuApi, a9 as MindooDBAppMenuCommandItem, aa as MindooDBAppMenuDismissReason, ab as MindooDBAppMenuDismissedResult, ac as MindooDBAppMenuItem, ad as MindooDBAppMenuKind, ae as MindooDBAppMenuPlacement, af as MindooDBAppMenuPointAnchor, ag as MindooDBAppMenuRect, ah as MindooDBAppMenuRectAnchor, ai as MindooDBAppMenuSelectionResult, aj as MindooDBAppMenuSeparatorItem, ak as MindooDBAppReadableAttachmentStream, al as MindooDBAppResolvedViewDefinition, am as MindooDBAppResolvedViewSource, an as MindooDBAppRuntime, ao as MindooDBAppScopedDocId, ap as MindooDBAppScopedDocumentSummary, aq as MindooDBAppSession, ar as MindooDBAppShowMenuInput, as as MindooDBAppShowMenuResult, at as MindooDBAppTextEdit, au as MindooDBAppTextPatch, av as MindooDBAppThemeMode, aw as MindooDBAppUiPreferences, ax as MindooDBAppUpdateDocumentInput, ay as MindooDBAppViewCursorDocumentListResult, az as MindooDBAppViewCursorResult, aA as MindooDBAppViewEntry, aB as MindooDBAppViewEntryKind, aC as MindooDBAppViewNavigator, aD as MindooDBAppViewNavigatorExpansionState, aE as MindooDBAppViewNavigatorOpenOptions, aF as MindooDBAppViewNavigatorPageOptions, aG as MindooDBAppViewNavigatorPageResult, aH as MindooDBAppViewNavigatorRangeQuery, aI as MindooDBAppViewNavigatorSelectionState, aJ as MindooDBAppViewport, aK as MindooDBAppWritableAttachmentStream } from './types-D0vtIHBf.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
|
/**
|
|
@@ -32,9 +32,102 @@ declare function expandAbbreviatedName(value: string): string;
|
|
|
32
32
|
* Creates the browser-side bridge entry point used by MindooDB apps.
|
|
33
33
|
*
|
|
34
34
|
* The returned object performs the initial postMessage handshake with the
|
|
35
|
-
*
|
|
35
|
+
* Haven host and exposes a session with document, view, and attachment
|
|
36
36
|
* APIs over a dedicated `MessagePort`.
|
|
37
37
|
*/
|
|
38
38
|
declare function createMindooDBAppBridge(): MindooDBAppBridge;
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Options used to create a text buffer for one string field in a MindooDB
|
|
42
|
+
* document.
|
|
43
|
+
*
|
|
44
|
+
* The buffer keeps a local editable string and records text operations that can
|
|
45
|
+
* later be flushed over the JSON bridge. `path` points to the string inside
|
|
46
|
+
* `document.data`, for example `["body"]` for a markdown body field.
|
|
47
|
+
*/
|
|
48
|
+
interface CreateMindooDBTextBufferOptions {
|
|
49
|
+
/** Open database handle used when `flush()` sends the buffered text patch. */
|
|
50
|
+
database: MindooDBAppDatabase;
|
|
51
|
+
/** Document snapshot the local editor state is based on. */
|
|
52
|
+
document: MindooDBAppDocument;
|
|
53
|
+
/** Path to the string field inside `document.data`. */
|
|
54
|
+
path: Array<string | number>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Result returned after flushing pending text edits.
|
|
58
|
+
*/
|
|
59
|
+
interface MindooDBTextBufferFlushResult {
|
|
60
|
+
/** Updated document returned by Haven after applying and reconciling edits. */
|
|
61
|
+
document: MindooDBAppDocument;
|
|
62
|
+
/** Canonical text value at the configured path after the flush. */
|
|
63
|
+
value: string;
|
|
64
|
+
/**
|
|
65
|
+
* `true` when the canonical value returned by Haven differs from the local
|
|
66
|
+
* value that was flushed. This usually means concurrent edits from another
|
|
67
|
+
* app instance or sync source were merged during save and the editor should
|
|
68
|
+
* replace its visible content with `value`.
|
|
69
|
+
*/
|
|
70
|
+
reconciled: boolean;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Local text editing buffer for SDK apps.
|
|
74
|
+
*
|
|
75
|
+
* `MindooDBTextBuffer` is intentionally not an Automerge document. It is a
|
|
76
|
+
* small app-side helper that behaves like a mutable string, keeps track of
|
|
77
|
+
* local text edits, and flushes those edits as JSON-safe operations to Haven.
|
|
78
|
+
* Haven then applies the operations against the real Automerge document using
|
|
79
|
+
* the document heads captured when this buffer was created or last reconciled.
|
|
80
|
+
*
|
|
81
|
+
* Use `splice()` when your editor can report exact text operations. Use
|
|
82
|
+
* `replaceText()` for WYSIWYG or markdown editors that expose only the full
|
|
83
|
+
* current text value; the buffer computes a minimal single-splice diff.
|
|
84
|
+
*/
|
|
85
|
+
declare class MindooDBTextBuffer {
|
|
86
|
+
private readonly options;
|
|
87
|
+
private valueInternal;
|
|
88
|
+
private heads;
|
|
89
|
+
private pendingEdits;
|
|
90
|
+
constructor(options: CreateMindooDBTextBufferOptions);
|
|
91
|
+
get value(): string;
|
|
92
|
+
/** Whether there are local edits that have not been flushed yet. */
|
|
93
|
+
get dirty(): boolean;
|
|
94
|
+
/** Number of pending text operations currently buffered. */
|
|
95
|
+
get pendingCount(): number;
|
|
96
|
+
/** Return the current local text value. */
|
|
97
|
+
toString(): string;
|
|
98
|
+
/**
|
|
99
|
+
* Apply an exact local text splice and queue it for the next flush.
|
|
100
|
+
*
|
|
101
|
+
* Offsets use JavaScript string indexing. The delete count is clamped to the
|
|
102
|
+
* remaining local text length so callers can safely delete to the end.
|
|
103
|
+
*/
|
|
104
|
+
splice(index: number, deleteCount: number, insert?: string): void;
|
|
105
|
+
/**
|
|
106
|
+
* Replace the current local text value and queue the change as one splice.
|
|
107
|
+
*
|
|
108
|
+
* This is useful for editors such as Milkdown that can produce the full
|
|
109
|
+
* markdown string after each transaction but do not expose raw text splices.
|
|
110
|
+
*/
|
|
111
|
+
replaceText(nextValue: string): void;
|
|
112
|
+
/**
|
|
113
|
+
* Replace local state from a fresh document snapshot and clear pending edits.
|
|
114
|
+
*
|
|
115
|
+
* Returns whether the text value changed. Use this after an external refresh
|
|
116
|
+
* or after receiving a document update through another app-level mechanism.
|
|
117
|
+
*/
|
|
118
|
+
reconcile(document: MindooDBAppDocument): boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Flush pending edits to Haven using `documents.update({ text: ... })`.
|
|
121
|
+
*
|
|
122
|
+
* The request includes the document heads this buffer is based on, allowing
|
|
123
|
+
* Haven to apply the text operations at the original causal version and merge
|
|
124
|
+
* them with any concurrent document changes. After a successful flush the
|
|
125
|
+
* buffer adopts the returned canonical value and heads, and clears the
|
|
126
|
+
* pending edit queue.
|
|
127
|
+
*/
|
|
128
|
+
flush(): Promise<MindooDBTextBufferFlushResult>;
|
|
129
|
+
}
|
|
130
|
+
/** Create a local text buffer for one string field in a document. */
|
|
131
|
+
declare function createMindooDBTextBuffer(options: CreateMindooDBTextBufferOptions): MindooDBTextBuffer;
|
|
132
|
+
|
|
133
|
+
export { type CreateMindooDBTextBufferOptions, MindooDBAppAttachmentPreviewMode, MindooDBAppBridge, MindooDBAppDatabase, MindooDBAppDocument, MindooDBTextBuffer, type MindooDBTextBufferFlushResult, abbreviateCanonicalName, canPreviewAttachment, createMindooDBAppBridge, createMindooDBTextBuffer, expandAbbreviatedName };
|
package/dist/index.js
CHANGED
|
@@ -281,7 +281,7 @@ function resolveTargetWindow() {
|
|
|
281
281
|
if (window.opener) {
|
|
282
282
|
return window.opener;
|
|
283
283
|
}
|
|
284
|
-
throw new Error("Could not find a MindooDB
|
|
284
|
+
throw new Error("Could not find a MindooDB Haven host window.");
|
|
285
285
|
}
|
|
286
286
|
function waitForConnectedPort(options, launchId) {
|
|
287
287
|
const targetWindow = resolveTargetWindow();
|
|
@@ -298,16 +298,25 @@ function waitForConnectedPort(options, launchId) {
|
|
|
298
298
|
};
|
|
299
299
|
const handleMessage = (event) => {
|
|
300
300
|
const payload = event.data;
|
|
301
|
-
if (!payload || payload.protocol !== PROTOCOL2
|
|
301
|
+
if (!payload || payload.protocol !== PROTOCOL2) {
|
|
302
302
|
return;
|
|
303
303
|
}
|
|
304
|
-
|
|
305
|
-
|
|
304
|
+
if (payload.type === "mindoodb-app:connected") {
|
|
305
|
+
cleanup();
|
|
306
|
+
resolve(channel.port1);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (payload.type === "mindoodb-app:error") {
|
|
310
|
+
cleanup();
|
|
311
|
+
channel.port1.close();
|
|
312
|
+
const message2 = typeof payload.error === "string" && payload.error.trim() ? payload.error : "MindooDB Haven bridge connection failed.";
|
|
313
|
+
reject(new Error(message2));
|
|
314
|
+
}
|
|
306
315
|
};
|
|
307
316
|
timeoutId = window.setTimeout(() => {
|
|
308
317
|
cleanup();
|
|
309
318
|
channel.port1.close();
|
|
310
|
-
reject(new Error(`Timed out while connecting to the MindooDB
|
|
319
|
+
reject(new Error(`Timed out while connecting to the MindooDB Haven bridge for launch ${launchId}.`));
|
|
311
320
|
}, timeoutMs);
|
|
312
321
|
channel.port1.addEventListener("message", handleMessage);
|
|
313
322
|
channel.port1.start();
|
|
@@ -665,6 +674,10 @@ var MindooDBAppDatabaseImpl = class {
|
|
|
665
674
|
databaseId: this.databaseId,
|
|
666
675
|
docId
|
|
667
676
|
}),
|
|
677
|
+
undelete: async (docId) => await this.rpc.call("documents.undelete", {
|
|
678
|
+
databaseId: this.databaseId,
|
|
679
|
+
docId
|
|
680
|
+
}),
|
|
668
681
|
listHistory: async (docId) => await this.rpc.call("documents.history.list", {
|
|
669
682
|
databaseId: this.databaseId,
|
|
670
683
|
docId
|
|
@@ -673,23 +686,32 @@ var MindooDBAppDatabaseImpl = class {
|
|
|
673
686
|
databaseId: this.databaseId,
|
|
674
687
|
docId,
|
|
675
688
|
timestamp
|
|
689
|
+
}),
|
|
690
|
+
getAtRevision: async (docId, revisionId) => await this.rpc.call("documents.history.getAtRevision", {
|
|
691
|
+
databaseId: this.databaseId,
|
|
692
|
+
docId,
|
|
693
|
+
revisionId
|
|
676
694
|
})
|
|
677
695
|
};
|
|
678
696
|
this.attachments = {
|
|
679
|
-
list: async (docId) => await this.rpc.call("attachments.list", {
|
|
697
|
+
list: async (docId, options) => await this.rpc.call("attachments.list", {
|
|
680
698
|
databaseId: this.databaseId,
|
|
681
|
-
docId
|
|
699
|
+
docId,
|
|
700
|
+
timestamp: options?.timestamp,
|
|
701
|
+
revisionId: options?.revisionId
|
|
682
702
|
}),
|
|
683
703
|
remove: async (docId, attachmentName) => await this.rpc.call("attachments.remove", {
|
|
684
704
|
databaseId: this.databaseId,
|
|
685
705
|
docId,
|
|
686
706
|
attachmentName
|
|
687
707
|
}),
|
|
688
|
-
openReadStream: async (docId, attachmentName) => {
|
|
708
|
+
openReadStream: async (docId, attachmentName, options) => {
|
|
689
709
|
const result = await this.rpc.call("attachments.openReadStream", {
|
|
690
710
|
databaseId: this.databaseId,
|
|
691
711
|
docId,
|
|
692
|
-
attachmentName
|
|
712
|
+
attachmentName,
|
|
713
|
+
timestamp: options?.timestamp,
|
|
714
|
+
revisionId: options?.revisionId
|
|
693
715
|
});
|
|
694
716
|
return new MindooDBAppReadableAttachmentStreamImpl(this.rpc, result.streamId);
|
|
695
717
|
},
|
|
@@ -706,13 +728,15 @@ var MindooDBAppDatabaseImpl = class {
|
|
|
706
728
|
databaseId: this.databaseId,
|
|
707
729
|
docId,
|
|
708
730
|
attachmentName,
|
|
709
|
-
timestamp: options?.timestamp
|
|
731
|
+
timestamp: options?.timestamp,
|
|
732
|
+
revisionId: options?.revisionId
|
|
710
733
|
}),
|
|
711
734
|
openPreview: async (docId, attachmentName, options) => await this.rpc.call("attachments.openPreview", {
|
|
712
735
|
databaseId: this.databaseId,
|
|
713
736
|
docId,
|
|
714
737
|
attachmentName,
|
|
715
|
-
timestamp: options?.timestamp
|
|
738
|
+
timestamp: options?.timestamp,
|
|
739
|
+
revisionId: options?.revisionId
|
|
716
740
|
})
|
|
717
741
|
};
|
|
718
742
|
}
|
|
@@ -736,7 +760,7 @@ var MindooDBAppSessionImpl = class {
|
|
|
736
760
|
};
|
|
737
761
|
}
|
|
738
762
|
menus;
|
|
739
|
-
/** Returns the launch context provided by the
|
|
763
|
+
/** Returns the launch context provided by the Haven host. */
|
|
740
764
|
async getLaunchContext() {
|
|
741
765
|
return await this.rpc.call("session.getLaunchContext", {});
|
|
742
766
|
}
|
|
@@ -817,6 +841,145 @@ function createMindooDBAppBridge() {
|
|
|
817
841
|
};
|
|
818
842
|
}
|
|
819
843
|
|
|
844
|
+
// src/textBuffer.ts
|
|
845
|
+
var MindooDBTextBuffer = class {
|
|
846
|
+
constructor(options) {
|
|
847
|
+
this.options = options;
|
|
848
|
+
this.valueInternal = readTextAtPath(options.document.data, options.path);
|
|
849
|
+
this.heads = options.document.heads ? [...options.document.heads] : [];
|
|
850
|
+
}
|
|
851
|
+
valueInternal;
|
|
852
|
+
heads;
|
|
853
|
+
pendingEdits = [];
|
|
854
|
+
get value() {
|
|
855
|
+
return this.valueInternal;
|
|
856
|
+
}
|
|
857
|
+
/** Whether there are local edits that have not been flushed yet. */
|
|
858
|
+
get dirty() {
|
|
859
|
+
return this.pendingEdits.length > 0;
|
|
860
|
+
}
|
|
861
|
+
/** Number of pending text operations currently buffered. */
|
|
862
|
+
get pendingCount() {
|
|
863
|
+
return this.pendingEdits.length;
|
|
864
|
+
}
|
|
865
|
+
/** Return the current local text value. */
|
|
866
|
+
toString() {
|
|
867
|
+
return this.valueInternal;
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* Apply an exact local text splice and queue it for the next flush.
|
|
871
|
+
*
|
|
872
|
+
* Offsets use JavaScript string indexing. The delete count is clamped to the
|
|
873
|
+
* remaining local text length so callers can safely delete to the end.
|
|
874
|
+
*/
|
|
875
|
+
splice(index, deleteCount, insert = "") {
|
|
876
|
+
if (!Number.isInteger(index) || index < 0 || index > this.valueInternal.length) {
|
|
877
|
+
throw new RangeError("Text splice index is out of range");
|
|
878
|
+
}
|
|
879
|
+
if (!Number.isInteger(deleteCount) || deleteCount < 0) {
|
|
880
|
+
throw new RangeError("Text splice deleteCount must be a non-negative integer");
|
|
881
|
+
}
|
|
882
|
+
const clampedDeleteCount = Math.min(deleteCount, this.valueInternal.length - index);
|
|
883
|
+
this.valueInternal = this.valueInternal.slice(0, index) + insert + this.valueInternal.slice(index + clampedDeleteCount);
|
|
884
|
+
this.pendingEdits.push({ index, deleteCount: clampedDeleteCount, insert });
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Replace the current local text value and queue the change as one splice.
|
|
888
|
+
*
|
|
889
|
+
* This is useful for editors such as Milkdown that can produce the full
|
|
890
|
+
* markdown string after each transaction but do not expose raw text splices.
|
|
891
|
+
*/
|
|
892
|
+
replaceText(nextValue) {
|
|
893
|
+
if (nextValue === this.valueInternal) {
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
896
|
+
const edit = computeSingleSplice(this.valueInternal, nextValue);
|
|
897
|
+
this.splice(edit.index, edit.deleteCount, edit.insert ?? "");
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* Replace local state from a fresh document snapshot and clear pending edits.
|
|
901
|
+
*
|
|
902
|
+
* Returns whether the text value changed. Use this after an external refresh
|
|
903
|
+
* or after receiving a document update through another app-level mechanism.
|
|
904
|
+
*/
|
|
905
|
+
reconcile(document) {
|
|
906
|
+
const nextValue = readTextAtPath(document.data, this.options.path);
|
|
907
|
+
const changed = nextValue !== this.valueInternal;
|
|
908
|
+
this.valueInternal = nextValue;
|
|
909
|
+
this.heads = document.heads ? [...document.heads] : [];
|
|
910
|
+
this.pendingEdits = [];
|
|
911
|
+
return changed;
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* Flush pending edits to Haven using `documents.update({ text: ... })`.
|
|
915
|
+
*
|
|
916
|
+
* The request includes the document heads this buffer is based on, allowing
|
|
917
|
+
* Haven to apply the text operations at the original causal version and merge
|
|
918
|
+
* them with any concurrent document changes. After a successful flush the
|
|
919
|
+
* buffer adopts the returned canonical value and heads, and clears the
|
|
920
|
+
* pending edit queue.
|
|
921
|
+
*/
|
|
922
|
+
async flush() {
|
|
923
|
+
if (this.pendingEdits.length === 0) {
|
|
924
|
+
return {
|
|
925
|
+
document: this.options.document,
|
|
926
|
+
value: this.valueInternal,
|
|
927
|
+
reconciled: false
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
const localValueAtFlush = this.valueInternal;
|
|
931
|
+
const document = await this.options.database.documents.update(this.options.document.id, {
|
|
932
|
+
text: [{
|
|
933
|
+
path: this.options.path,
|
|
934
|
+
baseHeads: this.heads,
|
|
935
|
+
edits: this.pendingEdits.map((edit) => ({ ...edit }))
|
|
936
|
+
}]
|
|
937
|
+
});
|
|
938
|
+
const nextValue = readTextAtPath(document.data, this.options.path);
|
|
939
|
+
const reconciled = nextValue !== localValueAtFlush;
|
|
940
|
+
this.valueInternal = nextValue;
|
|
941
|
+
this.heads = document.heads ? [...document.heads] : [];
|
|
942
|
+
this.pendingEdits = [];
|
|
943
|
+
return {
|
|
944
|
+
document,
|
|
945
|
+
value: this.valueInternal,
|
|
946
|
+
reconciled
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
};
|
|
950
|
+
function createMindooDBTextBuffer(options) {
|
|
951
|
+
return new MindooDBTextBuffer(options);
|
|
952
|
+
}
|
|
953
|
+
function readTextAtPath(data, path) {
|
|
954
|
+
let value = data;
|
|
955
|
+
for (const segment of path) {
|
|
956
|
+
if (value == null || typeof value !== "object") {
|
|
957
|
+
return "";
|
|
958
|
+
}
|
|
959
|
+
value = value[segment];
|
|
960
|
+
}
|
|
961
|
+
return typeof value === "string" ? value : "";
|
|
962
|
+
}
|
|
963
|
+
function computeSingleSplice(previous, next) {
|
|
964
|
+
let prefixLength = 0;
|
|
965
|
+
const maxPrefix = Math.min(previous.length, next.length);
|
|
966
|
+
while (prefixLength < maxPrefix && previous[prefixLength] === next[prefixLength]) {
|
|
967
|
+
prefixLength += 1;
|
|
968
|
+
}
|
|
969
|
+
let suffixLength = 0;
|
|
970
|
+
const previousRemaining = previous.length - prefixLength;
|
|
971
|
+
const nextRemaining = next.length - prefixLength;
|
|
972
|
+
const maxSuffix = Math.min(previousRemaining, nextRemaining);
|
|
973
|
+
while (suffixLength < maxSuffix && previous[previous.length - 1 - suffixLength] === next[next.length - 1 - suffixLength]) {
|
|
974
|
+
suffixLength += 1;
|
|
975
|
+
}
|
|
976
|
+
return {
|
|
977
|
+
index: prefixLength,
|
|
978
|
+
deleteCount: previous.length - prefixLength - suffixLength,
|
|
979
|
+
insert: next.slice(prefixLength, next.length - suffixLength)
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
|
|
820
983
|
// src/viewLanguage.ts
|
|
821
984
|
import {
|
|
822
985
|
createViewLanguage,
|
|
@@ -825,9 +988,11 @@ import {
|
|
|
825
988
|
mindooDBViewLanguageHelpersByName
|
|
826
989
|
} from "mindoodb-view-language";
|
|
827
990
|
export {
|
|
991
|
+
MindooDBTextBuffer,
|
|
828
992
|
abbreviateCanonicalName,
|
|
829
993
|
canPreviewAttachment,
|
|
830
994
|
createMindooDBAppBridge,
|
|
995
|
+
createMindooDBTextBuffer,
|
|
831
996
|
createViewLanguage,
|
|
832
997
|
expandAbbreviatedName
|
|
833
998
|
};
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a6 as MindooDBAppLaunchContext, X as MindooDBAppDatabaseInfo, Y as MindooDBAppDocumentApi, W as MindooDBAppCreateViewNavigatorInput, aC as MindooDBAppViewNavigator, aE as MindooDBAppViewNavigatorOpenOptions, d as MindooDBAppAttachmentApi, a as MindooDBAppBridge, aq as MindooDBAppSession, q as MindooDBAppBridgeRpcRequest, a5 as MindooDBAppHostTheme, aJ as MindooDBAppViewport, aw as MindooDBAppUiPreferences, n as MindooDBAppBridgePortMessage } from '../types-D0vtIHBf.js';
|
|
2
2
|
import 'mindoodb-view-language';
|
|
3
3
|
|
|
4
4
|
type MaybePromise<T> = T | Promise<T>;
|
package/dist/testing/index.js
CHANGED
|
@@ -20,8 +20,37 @@ function applyDocumentUpdatePatch(current, patch) {
|
|
|
20
20
|
for (const key of patch.unset ?? []) {
|
|
21
21
|
Reflect.deleteProperty(next, key);
|
|
22
22
|
}
|
|
23
|
+
for (const textPatch of patch.text ?? []) {
|
|
24
|
+
applyMockTextPatch(next, textPatch.path, textPatch.edits);
|
|
25
|
+
}
|
|
23
26
|
return next;
|
|
24
27
|
}
|
|
28
|
+
function applyMockTextPatch(target, path, edits) {
|
|
29
|
+
if (path.length === 0) {
|
|
30
|
+
throw new Error("Text patch path must contain at least one segment");
|
|
31
|
+
}
|
|
32
|
+
let parent = target;
|
|
33
|
+
for (let index = 0; index < path.length - 1; index += 1) {
|
|
34
|
+
const segment = path[index];
|
|
35
|
+
const nextSegment = path[index + 1];
|
|
36
|
+
if (parent[segment] == null) {
|
|
37
|
+
parent[segment] = typeof nextSegment === "number" ? [] : {};
|
|
38
|
+
}
|
|
39
|
+
parent = parent[segment];
|
|
40
|
+
}
|
|
41
|
+
const leaf = path[path.length - 1];
|
|
42
|
+
let value = parent[leaf];
|
|
43
|
+
if (value == null) {
|
|
44
|
+
value = "";
|
|
45
|
+
}
|
|
46
|
+
if (typeof value !== "string") {
|
|
47
|
+
throw new Error(`Cannot apply text patch to non-string value at ${path.map(String).join(".")}`);
|
|
48
|
+
}
|
|
49
|
+
for (const edit of edits) {
|
|
50
|
+
value = value.slice(0, edit.index) + (edit.insert ?? "") + value.slice(edit.index + edit.deleteCount);
|
|
51
|
+
}
|
|
52
|
+
parent[leaf] = value;
|
|
53
|
+
}
|
|
25
54
|
function mergeLaunchContext(current, patch) {
|
|
26
55
|
if (!patch) {
|
|
27
56
|
return {
|
|
@@ -393,6 +422,7 @@ function createDefaultViewNavigator() {
|
|
|
393
422
|
}
|
|
394
423
|
function createDatabaseHandle(definition) {
|
|
395
424
|
let createCounter = 0;
|
|
425
|
+
let changeCounter = 0;
|
|
396
426
|
const defaultViewFactory = async () => createDefaultViewNavigator();
|
|
397
427
|
const storedDocuments = /* @__PURE__ */ new Map();
|
|
398
428
|
const defaultDocuments = {
|
|
@@ -438,16 +468,42 @@ function createDatabaseHandle(definition) {
|
|
|
438
468
|
return {
|
|
439
469
|
id: document.id,
|
|
440
470
|
data: structuredClone(document.data),
|
|
471
|
+
heads: document.heads ? [...document.heads] : void 0,
|
|
441
472
|
attachments: document.attachments ? structuredClone(document.attachments) : [],
|
|
442
473
|
updatedAt: document.updatedAt
|
|
443
474
|
};
|
|
444
475
|
},
|
|
445
476
|
async create(input) {
|
|
446
|
-
|
|
477
|
+
const callerId = typeof input.id === "string" && input.id.length > 0 ? input.id : null;
|
|
478
|
+
if (callerId) {
|
|
479
|
+
const existing = storedDocuments.get(callerId);
|
|
480
|
+
if (existing) {
|
|
481
|
+
if (existing.isDeleted) {
|
|
482
|
+
existing.isDeleted = false;
|
|
483
|
+
existing.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
484
|
+
existing.heads = [`mock-head-${++changeCounter}`];
|
|
485
|
+
}
|
|
486
|
+
return {
|
|
487
|
+
id: existing.id,
|
|
488
|
+
data: structuredClone(existing.data),
|
|
489
|
+
heads: existing.heads ? [...existing.heads] : void 0,
|
|
490
|
+
attachments: existing.attachments ? structuredClone(existing.attachments) : [],
|
|
491
|
+
updatedAt: existing.updatedAt
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
let id;
|
|
496
|
+
if (callerId) {
|
|
497
|
+
id = callerId;
|
|
498
|
+
} else {
|
|
499
|
+
createCounter += 1;
|
|
500
|
+
id = `doc-${createCounter}`;
|
|
501
|
+
}
|
|
447
502
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
448
503
|
const created = {
|
|
449
|
-
id
|
|
504
|
+
id,
|
|
450
505
|
data: { ...input.set },
|
|
506
|
+
heads: [`mock-head-${++changeCounter}`],
|
|
451
507
|
attachments: [],
|
|
452
508
|
updatedAt: createdAt
|
|
453
509
|
};
|
|
@@ -467,6 +523,7 @@ function createDatabaseHandle(definition) {
|
|
|
467
523
|
const updated = {
|
|
468
524
|
id: docId,
|
|
469
525
|
data: applyDocumentUpdatePatch(existing?.data ?? {}, patch),
|
|
526
|
+
heads: [`mock-head-${++changeCounter}`],
|
|
470
527
|
attachments: existing?.attachments ? structuredClone(existing.attachments) : [],
|
|
471
528
|
updatedAt
|
|
472
529
|
};
|
|
@@ -489,6 +546,18 @@ function createDatabaseHandle(definition) {
|
|
|
489
546
|
}
|
|
490
547
|
return { ok: true };
|
|
491
548
|
},
|
|
549
|
+
async undelete(_docId) {
|
|
550
|
+
const existing = storedDocuments.get(_docId);
|
|
551
|
+
if (existing) {
|
|
552
|
+
storedDocuments.set(_docId, {
|
|
553
|
+
...existing,
|
|
554
|
+
isDeleted: false,
|
|
555
|
+
heads: [`mock-head-${++changeCounter}`],
|
|
556
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
return { ok: true };
|
|
560
|
+
},
|
|
492
561
|
async listHistory(_docId) {
|
|
493
562
|
return [];
|
|
494
563
|
},
|
|
@@ -497,7 +566,19 @@ function createDatabaseHandle(definition) {
|
|
|
497
566
|
id: docId,
|
|
498
567
|
timestamp,
|
|
499
568
|
state: "missing",
|
|
500
|
-
data: null
|
|
569
|
+
data: null,
|
|
570
|
+
attachments: []
|
|
571
|
+
};
|
|
572
|
+
},
|
|
573
|
+
async getAtRevision(docId, revisionId) {
|
|
574
|
+
return {
|
|
575
|
+
id: docId,
|
|
576
|
+
revisionId,
|
|
577
|
+
timestamp: Date.now(),
|
|
578
|
+
heads: [],
|
|
579
|
+
state: "missing",
|
|
580
|
+
data: null,
|
|
581
|
+
attachments: []
|
|
501
582
|
};
|
|
502
583
|
}
|
|
503
584
|
};
|
|
@@ -510,13 +591,13 @@ function createDatabaseHandle(definition) {
|
|
|
510
591
|
}
|
|
511
592
|
};
|
|
512
593
|
const defaultAttachments = {
|
|
513
|
-
async list(_docId) {
|
|
594
|
+
async list(_docId, _options) {
|
|
514
595
|
return [];
|
|
515
596
|
},
|
|
516
597
|
async remove(_docId, _attachmentName) {
|
|
517
598
|
return { ok: true };
|
|
518
599
|
},
|
|
519
|
-
async openReadStream(_docId, _attachmentName) {
|
|
600
|
+
async openReadStream(_docId, _attachmentName, _options) {
|
|
520
601
|
return createDefaultReadableAttachmentStream();
|
|
521
602
|
},
|
|
522
603
|
async openWriteStream(_docId, _attachmentName, _contentType) {
|
|
@@ -931,6 +1012,8 @@ function createFakeBridgeHost(options = {}) {
|
|
|
931
1012
|
);
|
|
932
1013
|
case "documents.delete":
|
|
933
1014
|
return await state.getDatabase(String(params.databaseId)).documents.delete(String(params.docId));
|
|
1015
|
+
case "documents.undelete":
|
|
1016
|
+
return await state.getDatabase(String(params.databaseId)).documents.undelete(String(params.docId));
|
|
934
1017
|
case "documents.history.list":
|
|
935
1018
|
return await state.getDatabase(String(params.databaseId)).documents.listHistory(String(params.docId));
|
|
936
1019
|
case "documents.history.getAtTimestamp":
|
|
@@ -938,8 +1021,16 @@ function createFakeBridgeHost(options = {}) {
|
|
|
938
1021
|
String(params.docId),
|
|
939
1022
|
Number(params.timestamp)
|
|
940
1023
|
);
|
|
1024
|
+
case "documents.history.getAtRevision":
|
|
1025
|
+
return await state.getDatabase(String(params.databaseId)).documents.getAtRevision(
|
|
1026
|
+
String(params.docId),
|
|
1027
|
+
String(params.revisionId)
|
|
1028
|
+
);
|
|
941
1029
|
case "attachments.list":
|
|
942
|
-
return await state.getDatabase(String(params.databaseId)).attachments.list(
|
|
1030
|
+
return await state.getDatabase(String(params.databaseId)).attachments.list(
|
|
1031
|
+
String(params.docId),
|
|
1032
|
+
typeof params.revisionId === "string" ? { revisionId: params.revisionId } : typeof params.timestamp === "number" ? { timestamp: params.timestamp } : void 0
|
|
1033
|
+
);
|
|
943
1034
|
case "attachments.remove":
|
|
944
1035
|
return await state.getDatabase(String(params.databaseId)).attachments.remove(
|
|
945
1036
|
String(params.docId),
|
|
@@ -948,7 +1039,8 @@ function createFakeBridgeHost(options = {}) {
|
|
|
948
1039
|
case "attachments.openReadStream": {
|
|
949
1040
|
const stream = await state.getDatabase(String(params.databaseId)).attachments.openReadStream(
|
|
950
1041
|
String(params.docId),
|
|
951
|
-
String(params.attachmentName)
|
|
1042
|
+
String(params.attachmentName),
|
|
1043
|
+
typeof params.revisionId === "string" ? { revisionId: params.revisionId } : typeof params.timestamp === "number" ? { timestamp: params.timestamp } : void 0
|
|
952
1044
|
);
|
|
953
1045
|
const streamId = `read-${streamCounter += 1}`;
|
|
954
1046
|
readStreams.set(streamId, stream);
|
|
@@ -968,13 +1060,13 @@ function createFakeBridgeHost(options = {}) {
|
|
|
968
1060
|
return await state.getDatabase(String(params.databaseId)).attachments.openPreview(
|
|
969
1061
|
String(params.docId),
|
|
970
1062
|
String(params.attachmentName),
|
|
971
|
-
typeof params.timestamp === "number" ? { timestamp: params.timestamp } : void 0
|
|
1063
|
+
typeof params.revisionId === "string" ? { revisionId: params.revisionId } : typeof params.timestamp === "number" ? { timestamp: params.timestamp } : void 0
|
|
972
1064
|
);
|
|
973
1065
|
case "attachments.preparePreviewSession":
|
|
974
1066
|
return await state.getDatabase(String(params.databaseId)).attachments.preparePreviewSession(
|
|
975
1067
|
String(params.docId),
|
|
976
1068
|
String(params.attachmentName),
|
|
977
|
-
typeof params.timestamp === "number" ? { timestamp: params.timestamp } : void 0
|
|
1069
|
+
typeof params.revisionId === "string" ? { revisionId: params.revisionId } : typeof params.timestamp === "number" ? { timestamp: params.timestamp } : void 0
|
|
978
1070
|
);
|
|
979
1071
|
case "viewNavigators.getDefinition":
|
|
980
1072
|
return await (await resolveViewNavigator(String(params.navigatorId))).getDefinition();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { MindooDBAppBooleanExpression, MindooDBAppExpression, MindooDBAppViewSortDirection, MindooDBAppViewTotalMode, MindooDBAppViewDefinition } from 'mindoodb-view-language';
|
|
2
2
|
|
|
3
|
-
/** Launch target used by the
|
|
3
|
+
/** Launch target used by the Haven when opening an app. */
|
|
4
4
|
type MindooDBAppRuntime = "iframe" | "window";
|
|
5
|
-
/** Theme mode currently active in the
|
|
5
|
+
/** Theme mode currently active in the Haven host UI. */
|
|
6
6
|
type MindooDBAppThemeMode = "light" | "dark";
|
|
7
7
|
/** Host theme snapshot exposed to running apps. */
|
|
8
8
|
interface MindooDBAppHostTheme {
|
|
@@ -130,6 +130,8 @@ type MindooDBAppAttachmentPreviewMode = "image" | "pdf" | "text" | "markdown" |
|
|
|
130
130
|
interface MindooDBAppAttachmentPreviewOptions {
|
|
131
131
|
/** Historical snapshot timestamp previously obtained from `documents.history.getAtTimestamp()`. */
|
|
132
132
|
timestamp?: number;
|
|
133
|
+
/** Stable revision id previously obtained from `documents.listHistory()`. */
|
|
134
|
+
revisionId?: MindooDBAppDocumentRevisionId;
|
|
133
135
|
}
|
|
134
136
|
/** Resolved Haven preview session prepared for opening in a separate tab or window. */
|
|
135
137
|
interface MindooDBAppAttachmentPreviewSession {
|
|
@@ -157,12 +159,18 @@ interface MindooDBAppDocumentSummary {
|
|
|
157
159
|
interface MindooDBAppDocument {
|
|
158
160
|
id: string;
|
|
159
161
|
data: Record<string, unknown>;
|
|
162
|
+
/** Current Automerge heads for causal text edit reconciliation. */
|
|
163
|
+
heads?: string[];
|
|
160
164
|
attachments?: MindooDBAppAttachmentInfo[];
|
|
161
165
|
updatedAt?: string;
|
|
162
166
|
}
|
|
167
|
+
/** Opaque persisted id for a document revision in the MindooDB DAG. */
|
|
168
|
+
type MindooDBAppDocumentRevisionId = string;
|
|
163
169
|
/** One entry in the document history timeline. */
|
|
164
170
|
interface MindooDBAppDocumentHistoryEntry {
|
|
171
|
+
revisionId: MindooDBAppDocumentRevisionId;
|
|
165
172
|
timestamp: number;
|
|
173
|
+
heads?: string[];
|
|
166
174
|
publicKey: string;
|
|
167
175
|
publicKeyFingerprint?: string;
|
|
168
176
|
identityLabel?: string;
|
|
@@ -173,9 +181,13 @@ interface MindooDBAppDocumentHistoryEntry {
|
|
|
173
181
|
/** Historical snapshot returned for a document at a specific timestamp. */
|
|
174
182
|
interface MindooDBAppHistoricalDocument {
|
|
175
183
|
id: string;
|
|
184
|
+
revisionId?: MindooDBAppDocumentRevisionId;
|
|
176
185
|
timestamp: number;
|
|
186
|
+
heads?: string[];
|
|
177
187
|
state: "missing" | "deleted" | "exists";
|
|
178
188
|
data: Record<string, unknown> | null;
|
|
189
|
+
attachments?: MindooDBAppAttachmentInfo[];
|
|
190
|
+
attachmentSnapshotRevisionId?: MindooDBAppDocumentRevisionId | null;
|
|
179
191
|
}
|
|
180
192
|
/** Query options for paging through changefeed-backed document listings in a database. */
|
|
181
193
|
interface MindooDBAppDocumentListQuery {
|
|
@@ -220,6 +232,33 @@ interface MindooDBAppCreateDocumentInput {
|
|
|
220
232
|
set: Record<string, unknown>;
|
|
221
233
|
/** Optional named document key. Defaults to `"default"` when omitted. */
|
|
222
234
|
decryptionKeyId?: string;
|
|
235
|
+
/**
|
|
236
|
+
* Optional caller-provided document id. When omitted, MindooDB generates a
|
|
237
|
+
* UUID7. When provided, the id must match `^[A-Za-z][A-Za-z0-9_]*$`: the
|
|
238
|
+
* first character is an ASCII letter and subsequent characters may be ASCII
|
|
239
|
+
* letters, ASCII digits, or `_`.
|
|
240
|
+
*
|
|
241
|
+
* If a document with this id already exists locally, MindooDB returns the
|
|
242
|
+
* existing document instead of creating a new one (idempotent create), and
|
|
243
|
+
* the values in `set` are NOT applied. Caller-provided ids are useful for
|
|
244
|
+
* loading a known well-known document directly without first building a
|
|
245
|
+
* view, and for migrations that want to preserve external ids.
|
|
246
|
+
*
|
|
247
|
+
* Documents created with the same caller-provided id on independent replicas
|
|
248
|
+
* share Automerge ancestry, so subsequent edits on either replica still
|
|
249
|
+
* merge correctly when the replicas sync.
|
|
250
|
+
*/
|
|
251
|
+
id?: string;
|
|
252
|
+
}
|
|
253
|
+
interface MindooDBAppTextEdit {
|
|
254
|
+
index: number;
|
|
255
|
+
deleteCount: number;
|
|
256
|
+
insert?: string;
|
|
257
|
+
}
|
|
258
|
+
interface MindooDBAppTextPatch {
|
|
259
|
+
path: Array<string | number>;
|
|
260
|
+
baseHeads?: string[];
|
|
261
|
+
edits: MindooDBAppTextEdit[];
|
|
223
262
|
}
|
|
224
263
|
/**
|
|
225
264
|
* Sparse patch payload used when updating an existing document.
|
|
@@ -233,6 +272,8 @@ interface MindooDBAppUpdateDocumentInput {
|
|
|
233
272
|
set?: Record<string, unknown>;
|
|
234
273
|
/** Top-level fields to remove from the document entirely. */
|
|
235
274
|
unset?: string[];
|
|
275
|
+
/** Granular text edits to apply at document paths. */
|
|
276
|
+
text?: MindooDBAppTextPatch[];
|
|
236
277
|
}
|
|
237
278
|
/** Query used for history lookups at a specific timestamp. */
|
|
238
279
|
interface MindooDBAppHistoryQuery {
|
|
@@ -244,17 +285,23 @@ interface MindooDBAppBridgeConnectOptions {
|
|
|
244
285
|
targetOrigin?: string;
|
|
245
286
|
connectTimeoutMs?: number;
|
|
246
287
|
}
|
|
247
|
-
/** Initial postMessage handshake sent from the app to the
|
|
288
|
+
/** Initial postMessage handshake sent from the app to the Haven. */
|
|
248
289
|
interface MindooDBAppBridgeConnectMessage {
|
|
249
290
|
protocol: "mindoodb-app-bridge";
|
|
250
291
|
type: "mindoodb-app:connect";
|
|
251
292
|
launchId: string;
|
|
252
293
|
}
|
|
253
|
-
/** Handshake acknowledgement returned by the
|
|
294
|
+
/** Handshake acknowledgement returned by the Haven host. */
|
|
254
295
|
interface MindooDBAppBridgeConnectedMessage {
|
|
255
296
|
protocol: "mindoodb-app-bridge";
|
|
256
297
|
type: "mindoodb-app:connected";
|
|
257
298
|
}
|
|
299
|
+
/** Handshake error returned when the Haven host rejects a launch. */
|
|
300
|
+
interface MindooDBAppBridgeHandshakeErrorMessage {
|
|
301
|
+
protocol: "mindoodb-app-bridge";
|
|
302
|
+
type: "mindoodb-app:error";
|
|
303
|
+
error: string;
|
|
304
|
+
}
|
|
258
305
|
/** Structured error payload transported over bridge RPC or stream messages. */
|
|
259
306
|
interface MindooDBAppBridgeErrorPayload {
|
|
260
307
|
code: string;
|
|
@@ -336,7 +383,7 @@ interface MindooDBAppBridgeStreamError {
|
|
|
336
383
|
}
|
|
337
384
|
/** Union of all non-RPC stream transport messages. */
|
|
338
385
|
type MindooDBAppBridgeStreamMessage = MindooDBAppBridgeStreamReadRequest | MindooDBAppBridgeStreamWriteRequest | MindooDBAppBridgeStreamCloseRequest | MindooDBAppBridgeStreamAbortRequest | MindooDBAppAttachmentChunk | MindooDBAppBridgeStreamAck | MindooDBAppBridgeStreamError;
|
|
339
|
-
/** Host-pushed event emitted when the
|
|
386
|
+
/** Host-pushed event emitted when the Haven theme changes. */
|
|
340
387
|
interface MindooDBAppBridgeThemeChangedMessage {
|
|
341
388
|
protocol: "mindoodb-app-bridge";
|
|
342
389
|
kind: "theme-changed";
|
|
@@ -445,8 +492,12 @@ interface MindooDBAppDocumentApi {
|
|
|
445
492
|
delete(docId: string): Promise<{
|
|
446
493
|
ok: true;
|
|
447
494
|
}>;
|
|
495
|
+
undelete(docId: string): Promise<{
|
|
496
|
+
ok: true;
|
|
497
|
+
}>;
|
|
448
498
|
listHistory(docId: string): Promise<MindooDBAppDocumentHistoryEntry[]>;
|
|
449
499
|
getAtTimestamp(docId: string, timestamp: number): Promise<MindooDBAppHistoricalDocument>;
|
|
500
|
+
getAtRevision(docId: string, revisionId: MindooDBAppDocumentRevisionId): Promise<MindooDBAppHistoricalDocument>;
|
|
450
501
|
}
|
|
451
502
|
type MindooDBAppViewEntryKind = "category" | "document";
|
|
452
503
|
/** Unique document identity within a multi-source view. */
|
|
@@ -570,11 +621,11 @@ interface MindooDBAppViewNavigator {
|
|
|
570
621
|
}
|
|
571
622
|
/** Attachment operations exposed by an opened database handle. */
|
|
572
623
|
interface MindooDBAppAttachmentApi {
|
|
573
|
-
list(docId: string): Promise<MindooDBAppAttachmentInfo[]>;
|
|
624
|
+
list(docId: string, options?: MindooDBAppAttachmentPreviewOptions): Promise<MindooDBAppAttachmentInfo[]>;
|
|
574
625
|
remove(docId: string, attachmentName: string): Promise<{
|
|
575
626
|
ok: true;
|
|
576
627
|
}>;
|
|
577
|
-
openReadStream(docId: string, attachmentName: string): Promise<MindooDBAppReadableAttachmentStream>;
|
|
628
|
+
openReadStream(docId: string, attachmentName: string, options?: MindooDBAppAttachmentPreviewOptions): Promise<MindooDBAppReadableAttachmentStream>;
|
|
578
629
|
openWriteStream(docId: string, attachmentName: string, contentType?: string): Promise<MindooDBAppWritableAttachmentStream>;
|
|
579
630
|
preparePreviewSession(docId: string, attachmentName: string, options?: MindooDBAppAttachmentPreviewOptions): Promise<MindooDBAppAttachmentPreviewSession>;
|
|
580
631
|
openPreview(docId: string, attachmentName: string, options?: MindooDBAppAttachmentPreviewOptions): Promise<{
|
|
@@ -587,7 +638,7 @@ interface MindooDBAppDatabase {
|
|
|
587
638
|
documents: MindooDBAppDocumentApi;
|
|
588
639
|
attachments: MindooDBAppAttachmentApi;
|
|
589
640
|
}
|
|
590
|
-
/** Connected session between the running app and the
|
|
641
|
+
/** Connected session between the running app and the Haven host. */
|
|
591
642
|
interface MindooDBAppSession {
|
|
592
643
|
getLaunchContext(): Promise<MindooDBAppLaunchContext>;
|
|
593
644
|
listDatabases(): Promise<MindooDBAppDatabaseInfo[]>;
|
|
@@ -606,4 +657,4 @@ interface MindooDBAppBridge {
|
|
|
606
657
|
connect(options?: MindooDBAppBridgeConnectOptions): Promise<MindooDBAppSession>;
|
|
607
658
|
}
|
|
608
659
|
|
|
609
|
-
export type {
|
|
660
|
+
export type { MindooDBAppDocumentListQuery as $, MindooDBAppBridgeThemeChangedMessage as A, MindooDBAppBridgeUiPreferencesChangedMessage as B, MindooDBAppBridgeViewportChangedMessage as C, MindooDBAppCapability as D, MindooDBAppConfiguredViewCategorizationStyle as E, MindooDBAppConfiguredViewColumn as F, MindooDBAppConfiguredViewColumnRole as G, MindooDBAppConfiguredViewExpressionMode as H, MindooDBAppConfiguredViewFieldExpression as I, MindooDBAppConfiguredViewFilterDefinition as J, MindooDBAppConfiguredViewFilterMode as K, MindooDBAppConfiguredViewFilterRule as L, MindooDBAppAttachmentPreviewMode as M, MindooDBAppConfiguredViewFormulaExpression as N, MindooDBAppConfiguredViewFormulaFilterDefinition as O, MindooDBAppConfiguredViewPreviewMode as P, MindooDBAppConfiguredViewRuleFilterDefinition as Q, MindooDBAppConfiguredViewRuleMatchMode as R, MindooDBAppConfiguredViewRuleOperator as S, MindooDBAppConfiguredViewValueExpression as T, MindooDBAppCreateDocumentInput as U, MindooDBAppCreateViewInput as V, MindooDBAppCreateViewNavigatorInput as W, MindooDBAppDatabaseInfo as X, MindooDBAppDocumentApi as Y, MindooDBAppDocumentHeadCursorResult as Z, MindooDBAppDocumentHistoryEntry as _, MindooDBAppBridge as a, MindooDBAppDocumentListResult as a0, MindooDBAppDocumentRevisionId as a1, MindooDBAppDocumentSummary as a2, MindooDBAppHistoricalDocument as a3, MindooDBAppHistoryQuery as a4, MindooDBAppHostTheme as a5, MindooDBAppLaunchContext as a6, MindooDBAppMenuAnchor as a7, MindooDBAppMenuApi as a8, MindooDBAppMenuCommandItem as a9, MindooDBAppViewEntry as aA, MindooDBAppViewEntryKind as aB, MindooDBAppViewNavigator as aC, MindooDBAppViewNavigatorExpansionState as aD, MindooDBAppViewNavigatorOpenOptions as aE, MindooDBAppViewNavigatorPageOptions as aF, MindooDBAppViewNavigatorPageResult as aG, MindooDBAppViewNavigatorRangeQuery as aH, MindooDBAppViewNavigatorSelectionState as aI, MindooDBAppViewport as aJ, MindooDBAppWritableAttachmentStream as aK, MindooDBAppMenuDismissReason as aa, MindooDBAppMenuDismissedResult as ab, MindooDBAppMenuItem as ac, MindooDBAppMenuKind as ad, MindooDBAppMenuPlacement as ae, MindooDBAppMenuPointAnchor as af, MindooDBAppMenuRect as ag, MindooDBAppMenuRectAnchor as ah, MindooDBAppMenuSelectionResult as ai, MindooDBAppMenuSeparatorItem as aj, MindooDBAppReadableAttachmentStream as ak, MindooDBAppResolvedViewDefinition as al, MindooDBAppResolvedViewSource as am, MindooDBAppRuntime as an, MindooDBAppScopedDocId as ao, MindooDBAppScopedDocumentSummary as ap, MindooDBAppSession as aq, MindooDBAppShowMenuInput as ar, MindooDBAppShowMenuResult as as, MindooDBAppTextEdit as at, MindooDBAppTextPatch as au, MindooDBAppThemeMode as av, MindooDBAppUiPreferences as aw, MindooDBAppUpdateDocumentInput as ax, MindooDBAppViewCursorDocumentListResult as ay, MindooDBAppViewCursorResult as az, MindooDBAppDatabase as b, MindooDBAppDocument as c, MindooDBAppAttachmentApi as d, MindooDBAppAttachmentChunk as e, MindooDBAppAttachmentInfo as f, MindooDBAppAttachmentPreviewOptions as g, MindooDBAppAttachmentPreviewSession as h, MindooDBAppBridgeConnectMessage as i, MindooDBAppBridgeConnectOptions as j, MindooDBAppBridgeConnectedMessage as k, MindooDBAppBridgeErrorPayload as l, MindooDBAppBridgeHandshakeErrorMessage as m, MindooDBAppBridgePortMessage as n, MindooDBAppBridgeRpcError as o, MindooDBAppBridgeRpcMessage as p, MindooDBAppBridgeRpcRequest as q, MindooDBAppBridgeRpcSuccess as r, MindooDBAppBridgeStreamAbortRequest as s, MindooDBAppBridgeStreamAck as t, MindooDBAppBridgeStreamCloseRequest as u, MindooDBAppBridgeStreamError as v, MindooDBAppBridgeStreamMessage as w, MindooDBAppBridgeStreamOpenResult as x, MindooDBAppBridgeStreamReadRequest as y, MindooDBAppBridgeStreamWriteRequest as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mindoodb-app-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"description": "MindooDB app SDK for building apps that connect to the Haven host bridge",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "Mindoo GmbH",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"prepublishOnly": "npm run build && npm run test"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"mindoodb-view-language": "0.0.
|
|
43
|
+
"mindoodb-view-language": "0.0.11"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "^25.5.0",
|