mindoodb-app-sdk 0.0.20 → 0.0.26
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 +129 -11
- package/TESTING.md +37 -0
- package/dist/index.d.ts +12 -3
- package/dist/index.js +189 -3
- package/dist/testing/index.d.ts +23 -1
- package/dist/testing/index.js +378 -3803
- package/dist/types-B6vEy1VC.d.ts +1565 -0
- package/package.json +12 -3
- package/dist/chunk-QGM4M3NI.js +0 -37
- package/dist/types-CQt2ObMu.d.ts +0 -888
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# mindoodb-app-sdk
|
|
2
2
|
|
|
3
|
-
Build apps that run inside **MindooDB Haven** -- the browser-based workspace for end-to-end encrypted,
|
|
3
|
+
Build apps that run inside **MindooDB Haven** -- the browser-based workspace for end-to-end encrypted, local-first data.
|
|
4
4
|
|
|
5
5
|
`mindoodb-app-sdk` is the TypeScript SDK that connects your web application to Haven through a secure message bridge. Your app runs in a sandboxed iframe (or a separate browser window) and gains access to databases, documents, attachments, virtual views, and live host events -- all without ever touching encryption keys or raw sync state.
|
|
6
6
|
|
|
7
7
|
## What is a MindooDB App?
|
|
8
8
|
|
|
9
|
-
[MindooDB](https://mindoodb.com) is an **end-to-end encrypted,
|
|
9
|
+
[MindooDB](https://mindoodb.com) is an **end-to-end encrypted, local-first sync database**. Data is encrypted on the client before it ever leaves the device. Under the hood it uses [Automerge](https://automerge.org/) CRDTs so multiple users can edit concurrently and conflicts resolve automatically.
|
|
10
10
|
|
|
11
11
|
**Haven** is the browser-based workspace that sits on top of MindooDB. Users organize databases, applications, notes, and media on a visual grid -- think of it as a customizable home screen for encrypted data that works offline and syncs in the background.
|
|
12
12
|
|
|
@@ -893,9 +893,106 @@ Requires the `update` capability (same as other write operations). For historica
|
|
|
893
893
|
|
|
894
894
|
TeamEdit's Word/.docx mode is why these RPCs exist — see `wordAutomergeHandle.ts` in [`mindoodb-app-teamedit`](https://github.com/klehmann/mindoodb-app-teamedit). Treat it as a reference for an unsupported edge case, not as a pattern to copy into new apps.
|
|
895
895
|
|
|
896
|
+
### Queries & Live Queries
|
|
897
|
+
|
|
898
|
+
`documents.query()` runs ad-hoc queries against the database's **document summary buffer** on the host: declarative filtering, dynamic sorting, paging, and field projection — without materializing documents. This is the fastest way to find and order documents from an app and the right default for lists, search results, and dashboards.
|
|
899
|
+
|
|
900
|
+
```ts
|
|
901
|
+
import { createViewLanguage } from "mindoodb-app-sdk";
|
|
902
|
+
|
|
903
|
+
const v = createViewLanguage<{ type: string; total: number }>();
|
|
904
|
+
|
|
905
|
+
const result = await db.documents.query({
|
|
906
|
+
filter: v.and(
|
|
907
|
+
v.eq(v.field("type"), v.string("invoice")),
|
|
908
|
+
v.gt(v.toNumber(v.field("total")), v.number(100)),
|
|
909
|
+
),
|
|
910
|
+
sortBy: [{ field: "total", direction: "descending" }],
|
|
911
|
+
limit: 50,
|
|
912
|
+
offset: 0,
|
|
913
|
+
fields: ["total", "customer"],
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
console.log(result.total); // matching docs before paging
|
|
917
|
+
console.log(result.coverage); // "full" | "rebuilding" | "full-scan"
|
|
918
|
+
for (const row of result.rows) {
|
|
919
|
+
console.log(row.docId, row.fields, row.lastModified);
|
|
920
|
+
}
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
The `filter` also accepts formula source text, which the SDK parses locally before it crosses the bridge (only the JSON expression AST travels):
|
|
924
|
+
|
|
925
|
+
```ts
|
|
926
|
+
const invoices = await db.documents.query({
|
|
927
|
+
filter: 'v.eq(v.field("type"), "invoice")',
|
|
928
|
+
});
|
|
929
|
+
```
|
|
930
|
+
|
|
931
|
+
Notes:
|
|
932
|
+
|
|
933
|
+
- The host caps `limit` (default 200, maximum 1000) so result payloads stay bounded. Page with `offset` for more rows.
|
|
934
|
+
- `coverage: "rebuilding"` means the summary buffer is still backfilling — results may be incomplete and will improve on their own.
|
|
935
|
+
- Queries that reference encrypted fields or fields outside the summary configuration are rejected with a `query-not-supported` bridge error. Use a view with `useFullDocuments` (see below) or `documents.list()` for those cases.
|
|
936
|
+
- Queries require the `read` capability and are not available in time-travel launches (the summary buffer reflects the live state only).
|
|
937
|
+
|
|
938
|
+
**Full-text search** — a query can additionally carry a `text` clause, evaluated against the database's client-side full-text index on the host and combined with `filter` as a logical AND:
|
|
939
|
+
|
|
940
|
+
```ts
|
|
941
|
+
const result = await db.documents.query({
|
|
942
|
+
text: { query: "solar panels" }, // full-text match + relevance score
|
|
943
|
+
filter: 'v.eq(v.field("type"), "article")', // optional structured filter
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
for (const row of result.rows) {
|
|
947
|
+
console.log(row.docId, row.textScore); // higher score = better match
|
|
948
|
+
}
|
|
949
|
+
```
|
|
950
|
+
|
|
951
|
+
- Options: `fields` (restrict matching to specific index fields), `prefix` (default `true` — `"sol"` matches `"solar"`), `fuzzy` (edit-distance tolerance, default off), `combineWith` (`"AND"` default | `"OR"`).
|
|
952
|
+
- Rows gain a `textScore`; without an explicit `sortBy`, results come best score first. Sorting can reference the score explicitly with `sortBy: [{ special: "textScore", direction: "descending" }]`.
|
|
953
|
+
- Full-text indexing is **opt-in per database** (`fulltextSetup` in the `dbsetup` document). A `text` clause against a database without it is rejected with a `fulltext-not-enabled` bridge error — catch it and hide/disable the search UI.
|
|
954
|
+
- `liveQuery` supports `text` clauses unchanged; the host rounds scores in its result fingerprint so minor relevance drift does not spam your callback.
|
|
955
|
+
|
|
956
|
+
**Enabling full-text indexing** — apps turn indexing on themselves through the database handle. The configuration is stored in the synced `dbsetup` document, so it applies on every replica (each device builds its own local, encrypted index):
|
|
957
|
+
|
|
958
|
+
```ts
|
|
959
|
+
// Idempotent — safe to call on every app start (no write when unchanged).
|
|
960
|
+
// Requires the `update` capability.
|
|
961
|
+
await db.setFulltextSetup({
|
|
962
|
+
enabled: true,
|
|
963
|
+
attachments: true, // index text extracted from attachments (PDF, Office, …)
|
|
964
|
+
language: "de", // BCP-47 tag steering tokenization; omit for language-neutral
|
|
965
|
+
});
|
|
966
|
+
|
|
967
|
+
const setup = await db.getFulltextSetup(); // null when never configured
|
|
968
|
+
```
|
|
969
|
+
|
|
970
|
+
- Without `include`, every non-underscore top-level field with extractable text is indexed (auto mode). Pass `include: ["subject", "body"]` to pin the indexed fields, including nested/long-text fields outside the summary buffer.
|
|
971
|
+
- `attachments: true` indexes attachment text under the synthetic `_attachments` field using the host's extractors (Haven ships PDF, Office, and plain-text extractors). Restrict a query to attachment content with `text: { query, fields: ["_attachments"] }`.
|
|
972
|
+
- Changing the configuration (including `language`) rebuilds the index in the background; queries during the rebuild report `coverage: "rebuilding"`.
|
|
973
|
+
|
|
974
|
+
**Live queries** keep a query result up to date. The callback receives the initial result and runs again whenever the result actually changed — the host coalesces bursts of writes and fingerprints results, so you only hear about real changes:
|
|
975
|
+
|
|
976
|
+
```ts
|
|
977
|
+
const subscription = await db.documents.liveQuery(
|
|
978
|
+
{ filter: 'v.eq(v.field("status"), "open")', limit: 100 },
|
|
979
|
+
(result) => {
|
|
980
|
+
renderList(result.rows);
|
|
981
|
+
},
|
|
982
|
+
);
|
|
983
|
+
|
|
984
|
+
// Force a re-evaluation (delivers a result even when nothing changed):
|
|
985
|
+
await subscription.refresh();
|
|
986
|
+
|
|
987
|
+
// Always dispose when the consuming UI goes away:
|
|
988
|
+
await subscription.dispose();
|
|
989
|
+
```
|
|
990
|
+
|
|
991
|
+
Live query results are pushed from the host over the bridge port — no polling. Subscriptions are cleaned up automatically when the app disconnects, but dispose them explicitly when the UI that consumes them unmounts.
|
|
992
|
+
|
|
896
993
|
### Incremental sync
|
|
897
994
|
|
|
898
|
-
The changefeed-backed `documents.list()` API is also the right primitive for app-side indexes, search, and other derived caches.
|
|
995
|
+
The changefeed-backed `documents.list()` API is also the right primitive for app-side indexes, search, and other derived caches. For plain "show me matching documents" use cases, prefer [`documents.query()`](#queries--live-queries); the changefeed shines when you need deletions and a durable resume checkpoint for derived state.
|
|
899
996
|
|
|
900
997
|
**Initial scan from the beginning:**
|
|
901
998
|
|
|
@@ -1225,13 +1322,28 @@ await navigator.setExpansionState(expansion);
|
|
|
1225
1322
|
await navigator.setSelectionState(selection);
|
|
1226
1323
|
```
|
|
1227
1324
|
|
|
1325
|
+
**Live updates** -- the host keeps the view bound to its source databases' change feeds. Subscribe with `onDidUpdate` and re-read the visible page when it fires; there is no need to poll or call `refresh()`:
|
|
1326
|
+
|
|
1327
|
+
```ts
|
|
1328
|
+
const unsubscribe = navigator.onDidUpdate(({ addedCount, removedCount }) => {
|
|
1329
|
+
console.log(`view changed: +${addedCount} / -${removedCount}`);
|
|
1330
|
+
void rerenderVisiblePage();
|
|
1331
|
+
});
|
|
1332
|
+
|
|
1333
|
+
// later, when the consuming UI unmounts:
|
|
1334
|
+
unsubscribe();
|
|
1335
|
+
```
|
|
1336
|
+
|
|
1228
1337
|
The expression language is fully declarative: apps define filter and column logic through a typed builder API that compiles to JSON-safe expression objects. No app-provided JavaScript runs inside the bridge host.
|
|
1229
1338
|
|
|
1230
1339
|
#### Performance notes
|
|
1231
1340
|
|
|
1341
|
+
- Navigator views are built **summary-first**: whenever the view definition (filter + column expressions) can be answered from the database's document summary buffer, the host feeds the view from the summary without materializing a single document. Views fall back to the (slower) document path automatically when they need decrypted fields, JS value functions, or fields outside the summary configuration.
|
|
1342
|
+
- Pass `useFullDocuments: true` in `createViewNavigator` input to force the document path explicitly — the escape hatch for views that deliberately need full document data.
|
|
1232
1343
|
- `goto*()` and `getCurrentEntry()` are lightweight stateful cursor operations. They may still produce many bridge round-trips if you call them for every rendered row.
|
|
1233
1344
|
- `entriesForward()` and `entriesBackward()` exist specifically to reduce those round-trips for UI rendering.
|
|
1234
|
-
- `refresh()`
|
|
1345
|
+
- `refresh()` performs an incremental catch-up on the host-side view (no pipeline rebuild). With `onDidUpdate` in place you rarely need it — the host pushes updates on its own.
|
|
1346
|
+
- `session.listDocumentsSinceViewCursor(cursor)` remains available as a **legacy polling/delta-sync path**; prefer `onDidUpdate` pushes and `documents.liveQuery()` for keeping UI current.
|
|
1235
1347
|
- Child/key/range helpers operate on the same host-side navigator session. They do not create a separate query engine.
|
|
1236
1348
|
|
|
1237
1349
|
Available expression helpers:
|
|
@@ -1243,7 +1355,7 @@ Available expression helpers:
|
|
|
1243
1355
|
- **String helpers:** `concat()`, `lower()`, `upper()`, `trim()`, `contains()`, `startsWith()`, `endsWith()`
|
|
1244
1356
|
- **Null/existence:** `coalesce()`, `exists()`, `notExists()`
|
|
1245
1357
|
- **Date/path:** `datePart()`, `pathJoin()`
|
|
1246
|
-
- **Control flow:** `ifElse()`, `let()`
|
|
1358
|
+
- **Control flow:** `ifElse()`, `let()` — `ifElse()` accepts multiple condition/value pairs followed by a default, like Domino's `@If`: `v.ifElse(cond1, val1, cond2, val2, default)`
|
|
1247
1359
|
|
|
1248
1360
|
The full language guide lives in the `mindoodb-view-language` package. The SDK re-exports `createViewLanguage()` for convenience.
|
|
1249
1361
|
|
|
@@ -1314,16 +1426,20 @@ Connect options: `launchId?`, `targetOrigin?`, `connectTimeoutMs?`.
|
|
|
1314
1426
|
|
|
1315
1427
|
### MindooDBAppDatabase
|
|
1316
1428
|
|
|
1317
|
-
| Property / Method
|
|
1318
|
-
|
|
|
1319
|
-
| `info()`
|
|
1320
|
-
| `documents`
|
|
1321
|
-
| `attachments`
|
|
1429
|
+
| Property / Method | Returns |
|
|
1430
|
+
| ---------------------------- | ---------------------------------------------- |
|
|
1431
|
+
| `info()` | `Promise<MindooDBAppDatabaseInfo>` |
|
|
1432
|
+
| `documents` | `MindooDBAppDocumentApi` |
|
|
1433
|
+
| `attachments` | `MindooDBAppAttachmentApi` |
|
|
1434
|
+
| `getFulltextSetup()` | `Promise<MindooDBAppFulltextSetup \| null>` |
|
|
1435
|
+
| `setFulltextSetup(config)` | `Promise<void>` |
|
|
1322
1436
|
|
|
1323
1437
|
### MindooDBAppDocumentApi
|
|
1324
1438
|
|
|
1325
1439
|
| Method | Returns |
|
|
1326
1440
|
| ---------------------------------- | -------------------------------------------- |
|
|
1441
|
+
| `query(query?)` | `Promise<MindooDBAppQueryResult>` |
|
|
1442
|
+
| `liveQuery(query, onResult)` | `Promise<MindooDBAppLiveQuerySubscription>` |
|
|
1327
1443
|
| `list(query?)` | `Promise<MindooDBAppDocumentListResult>` |
|
|
1328
1444
|
| `get(docId)` | `Promise<MindooDBAppDocument \| null>` |
|
|
1329
1445
|
| `getRichText(docId, path, opts?)` | `Promise<MindooDBAppRichTextSnapshot>` |
|
|
@@ -1378,7 +1494,9 @@ interface MindooDBAppUpdateDocumentInput {
|
|
|
1378
1494
|
| Method | Returns |
|
|
1379
1495
|
| ---------------------------------------------------------- | ------------------------------------------------- |
|
|
1380
1496
|
| `getDefinition()` | `Promise<MindooDBAppViewDefinition>` |
|
|
1381
|
-
| `refresh()` | `Promise<
|
|
1497
|
+
| `refresh()` | `Promise<string \| null>` (new view cursor) |
|
|
1498
|
+
| `onDidUpdate(listener)` | `() => void` (unsubscribe) |
|
|
1499
|
+
| `getViewCursor()` | `Promise<string \| null>` |
|
|
1382
1500
|
| `getCurrentEntry()` | `Promise<MindooDBAppViewEntry \| null>` |
|
|
1383
1501
|
| `gotoFirst()` / `gotoLast()` | `Promise<boolean>` |
|
|
1384
1502
|
| `gotoNext()` / `gotoPrev()` | `Promise<boolean>` |
|
package/TESTING.md
CHANGED
|
@@ -12,6 +12,15 @@ import {
|
|
|
12
12
|
} from "mindoodb-app-sdk/testing";
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
The testing entrypoint emulates document storage with real Automerge documents,
|
|
16
|
+
so `@automerge/automerge` is declared as an optional peer dependency. Add it to
|
|
17
|
+
your app's `devDependencies` when you import `mindoodb-app-sdk/testing`
|
|
18
|
+
(the runtime SDK entrypoint does not need it):
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add -D @automerge/automerge
|
|
22
|
+
```
|
|
23
|
+
|
|
15
24
|
## Pick a level
|
|
16
25
|
|
|
17
26
|
### Level 1: simple app tests
|
|
@@ -93,6 +102,30 @@ Each database entry can provide:
|
|
|
93
102
|
- `methods.documents`
|
|
94
103
|
- `methods.views` for session-level `createView()` and `openView()` calls
|
|
95
104
|
- `methods.attachments`
|
|
105
|
+
- `fulltextSetup` — the initial config returned by `db.getFulltextSetup()`; `db.setFulltextSetup()` overwrites it for the lifetime of the handle. Use this to test your app's full-text bootstrap logic. Note the mock evaluates `text` query clauses regardless of this config.
|
|
106
|
+
|
|
107
|
+
The default in-memory document store also implements `documents.query()` and `documents.liveQuery()`: expression and formula-string filters are evaluated against the seeded documents, `sortBy`/`limit`/`offset` work as documented, and live query callbacks fire automatically after `create`/`update`/`delete`/`undelete` mutations. Full-text `text` clauses are supported with a deterministic mock implementation (token matching with prefix/AND semantics and an occurrence-count `textScore`) — assert on membership and relative ordering, not absolute scores, since real hosts use a BM25-style engine. That means app code built on queries and live queries is testable at Level 1 without any extra setup:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
const session = await mock.bridge.connect();
|
|
111
|
+
const db = await session.openDatabase("main");
|
|
112
|
+
|
|
113
|
+
await db.documents.create({ set: { type: "invoice", total: 120 } });
|
|
114
|
+
|
|
115
|
+
const result = await db.documents.query({
|
|
116
|
+
filter: 'v.eq(v.field("type"), "invoice")',
|
|
117
|
+
sortBy: [{ field: "total", direction: "descending" }],
|
|
118
|
+
});
|
|
119
|
+
expect(result.rows).toHaveLength(1);
|
|
120
|
+
|
|
121
|
+
const updates: number[] = [];
|
|
122
|
+
const sub = await db.documents.liveQuery(
|
|
123
|
+
{ filter: 'v.eq(v.field("type"), "invoice")' },
|
|
124
|
+
(r) => updates.push(r.total),
|
|
125
|
+
);
|
|
126
|
+
await db.documents.create({ set: { type: "invoice", total: 50 } });
|
|
127
|
+
await sub.dispose();
|
|
128
|
+
```
|
|
96
129
|
|
|
97
130
|
## Level 2 example
|
|
98
131
|
|
|
@@ -161,10 +194,14 @@ Useful Level 2 methods:
|
|
|
161
194
|
- `dispose()`
|
|
162
195
|
- `emitThemeChange()`
|
|
163
196
|
- `emitViewportChange()`
|
|
197
|
+
- `emitQueryResult()` — push a `query-result` message to live query subscribers
|
|
198
|
+
- `emitViewChanged()` — push a `view-changed` message to navigator `onDidUpdate` listeners
|
|
164
199
|
- `setRequestHandler()`
|
|
165
200
|
- `clearRequestHandler()`
|
|
166
201
|
- `postPortMessage()`
|
|
167
202
|
|
|
203
|
+
The built-in request handling also covers `documents.query` and the `documents.liveQuery.*` RPCs against the seeded documents, so `db.documents.query()` / `db.documents.liveQuery()` and `navigator.onDidUpdate()` work end-to-end over the real bridge transport in Level 2 tests.
|
|
204
|
+
|
|
168
205
|
## When to use which level
|
|
169
206
|
|
|
170
207
|
Choose Level 1 when:
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { M as MindooDBAppAttachmentPreviewMode, a as MindooDBAppBridge, b as MindooDBAppDatabase, c as MindooDBAppDocument, d as MindooDBAppRichTextSpan, e as MindooDBAppRichTextSnapshot } from './types-
|
|
2
|
-
export { f as
|
|
1
|
+
import { M as MindooDBAppAttachmentPreviewMode, a as MindooDBAppBridge, b as MindooDBAppDatabase, c as MindooDBAppDocument, d as MindooDBAppRichTextSpan, e as MindooDBAppRichTextSnapshot } from './types-B6vEy1VC.js';
|
|
2
|
+
export { f as MindooDBAppAccessDecision, g as MindooDBAppAccessTier, h as MindooDBAppAttachmentApi, i as MindooDBAppAttachmentChunk, j as MindooDBAppAttachmentInfo, k as MindooDBAppAttachmentPreviewOptions, l as MindooDBAppAttachmentPreviewSession, m as MindooDBAppAutomergeChangesPatch, n as MindooDBAppAutomergeChangesSince, o as MindooDBAppAutomergeGetOptions, p as MindooDBAppAutomergePatchResult, q as MindooDBAppAutomergeSnapshot, r as MindooDBAppBridgeConnectMessage, s as MindooDBAppBridgeConnectOptions, t as MindooDBAppBridgeConnectedMessage, u as MindooDBAppBridgeErrorPayload, v as MindooDBAppBridgeHandshakeErrorMessage, w as MindooDBAppBridgeLocaleChangedMessage, x as MindooDBAppBridgePortMessage, y as MindooDBAppBridgeQueryResultMessage, z as MindooDBAppBridgeRpcError, A as MindooDBAppBridgeRpcMessage, B as MindooDBAppBridgeRpcRequest, C as MindooDBAppBridgeRpcSuccess, D as MindooDBAppBridgeStreamAbortRequest, E as MindooDBAppBridgeStreamAck, F as MindooDBAppBridgeStreamCloseRequest, G as MindooDBAppBridgeStreamError, H as MindooDBAppBridgeStreamMessage, I as MindooDBAppBridgeStreamOpenResult, J as MindooDBAppBridgeStreamReadRequest, K as MindooDBAppBridgeStreamWriteRequest, L as MindooDBAppBridgeThemeChangedMessage, N as MindooDBAppBridgeUiPreferencesChangedMessage, O as MindooDBAppBridgeViewChangedMessage, P as MindooDBAppBridgeViewportChangedMessage, Q as MindooDBAppCapability, R as MindooDBAppConfiguredViewCategorizationStyle, S as MindooDBAppConfiguredViewColumn, T as MindooDBAppConfiguredViewColumnRole, U as MindooDBAppConfiguredViewExpressionMode, V as MindooDBAppConfiguredViewFieldExpression, W as MindooDBAppConfiguredViewFilterDefinition, X as MindooDBAppConfiguredViewFilterMode, Y as MindooDBAppConfiguredViewFilterRule, Z as MindooDBAppConfiguredViewFormulaExpression, _ as MindooDBAppConfiguredViewFormulaFilterDefinition, $ as MindooDBAppConfiguredViewPreviewMode, a0 as MindooDBAppConfiguredViewRuleFilterDefinition, a1 as MindooDBAppConfiguredViewRuleMatchMode, a2 as MindooDBAppConfiguredViewRuleOperator, a3 as MindooDBAppConfiguredViewValueExpression, a4 as MindooDBAppCreateDocumentInput, a5 as MindooDBAppCreateViewInput, a6 as MindooDBAppCreateViewNavigatorInput, a7 as MindooDBAppDatabaseInfo, a8 as MindooDBAppDocumentApi, a9 as MindooDBAppDocumentHeadCursorResult, aa as MindooDBAppDocumentHistoryEntry, ab as MindooDBAppDocumentListQuery, ac as MindooDBAppDocumentListResult, ad as MindooDBAppDocumentQuery, ae as MindooDBAppDocumentRevisionId, af as MindooDBAppDocumentScanPreset, ag as MindooDBAppDocumentSummary, ah as MindooDBAppExtractionSetup, ai as MindooDBAppFulltextSetup, aj as MindooDBAppHistoricalDocument, ak as MindooDBAppHistoryQuery, al as MindooDBAppHostTheme, am as MindooDBAppJsonListDeletePatch, an as MindooDBAppJsonListInsertPatch, ao as MindooDBAppJsonPatch, ap as MindooDBAppJsonSetPatch, aq as MindooDBAppJsonTextMarkPatch, ar as MindooDBAppJsonTextSplicePatch, as as MindooDBAppJsonTextUnmarkPatch, at as MindooDBAppJsonUnsetPatch, au as MindooDBAppLaunchContext, av as MindooDBAppLiveQuerySubscription, aw as MindooDBAppMenuAnchor, ax as MindooDBAppMenuApi, ay as MindooDBAppMenuCommandItem, az as MindooDBAppMenuDismissReason, aA as MindooDBAppMenuDismissedResult, aB as MindooDBAppMenuItem, aC as MindooDBAppMenuKind, aD as MindooDBAppMenuPlacement, aE as MindooDBAppMenuPointAnchor, aF as MindooDBAppMenuRect, aG as MindooDBAppMenuRectAnchor, aH as MindooDBAppMenuSelectionResult, aI as MindooDBAppMenuSeparatorItem, aJ as MindooDBAppQueryCoverage, aK as MindooDBAppQueryResult, aL as MindooDBAppQueryRow, aM as MindooDBAppQuerySortKey, aN as MindooDBAppQueryTextClause, aO as MindooDBAppReadableAttachmentStream, aP as MindooDBAppResolvedViewDefinition, aQ as MindooDBAppResolvedViewSource, aR as MindooDBAppRichTextBlockSpan, aS as MindooDBAppRichTextGetOptions, aT as MindooDBAppRichTextImmutableString, aU as MindooDBAppRichTextMarkRange, aV as MindooDBAppRichTextMaterializeValue, aW as MindooDBAppRichTextPatch, aX as MindooDBAppRichTextScalar, aY as MindooDBAppRichTextSpliceStep, aZ as MindooDBAppRichTextStep, a_ as MindooDBAppRichTextStepPatch, a$ as MindooDBAppRichTextTextSpan, b0 as MindooDBAppRuntime, b1 as MindooDBAppScanAttachmentOptions, b2 as MindooDBAppScanAttachmentResult, b3 as MindooDBAppScopedDocId, b4 as MindooDBAppScopedDocumentSummary, b5 as MindooDBAppSession, b6 as MindooDBAppShowMenuInput, b7 as MindooDBAppShowMenuResult, b8 as MindooDBAppTextEdit, b9 as MindooDBAppTextPatch, ba as MindooDBAppThemeMode, bb as MindooDBAppUiPreferences, bc as MindooDBAppUpdateDocumentInput, bd as MindooDBAppViewCursorDocumentListResult, be as MindooDBAppViewCursorResult, bf as MindooDBAppViewEntry, bg as MindooDBAppViewEntryKind, bh as MindooDBAppViewNavigator, bi as MindooDBAppViewNavigatorExpansionState, bj as MindooDBAppViewNavigatorOpenOptions, bk as MindooDBAppViewNavigatorPageOptions, bl as MindooDBAppViewNavigatorPageResult, bm as MindooDBAppViewNavigatorRangeQuery, bn as MindooDBAppViewNavigatorSelectionState, bo as MindooDBAppViewUpdateStats, bp as MindooDBAppViewport, bq as MindooDBAppWritableAttachmentStream } from './types-B6vEy1VC.js';
|
|
3
|
+
import { MindooDBAppBooleanExpression } from 'mindoodb-view-language';
|
|
3
4
|
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';
|
|
5
|
+
import { MindooDB, MindooQuerySortKey, MindooQueryOptions, MindooQueryResult } from 'mindoodb';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Resolves whether Haven can render a built-in preview for an attachment.
|
|
@@ -177,4 +179,11 @@ declare class MindooDBTextBuffer {
|
|
|
177
179
|
/** Create a local text buffer for one string field in a document. */
|
|
178
180
|
declare function createMindooDBTextBuffer(options: CreateMindooDBTextBufferOptions): MindooDBTextBuffer;
|
|
179
181
|
|
|
180
|
-
|
|
182
|
+
/**
|
|
183
|
+
* Thin convenience wrapper around `db.query()`: accepts the filter either
|
|
184
|
+
* as a prebuilt expression (from `createViewLanguage()`) or as formula
|
|
185
|
+
* source text, which is parsed with the shared formula parser.
|
|
186
|
+
*/
|
|
187
|
+
declare function queryDocuments(db: Pick<MindooDB, "query">, filter: MindooDBAppBooleanExpression | string, sortBy?: MindooQuerySortKey[], options?: MindooQueryOptions): Promise<MindooQueryResult>;
|
|
188
|
+
|
|
189
|
+
export { type CreateMindooDBRichTextHandleOptions, type CreateMindooDBTextBufferOptions, MindooDBAppAttachmentPreviewMode, MindooDBAppBridge, MindooDBAppDatabase, MindooDBAppDocument, MindooDBAppRichTextSnapshot, MindooDBAppRichTextSpan, MindooDBRichTextHandle, type MindooDBRichTextHandleChangeListener, type MindooDBRichTextHandleFlushResult, MindooDBTextBuffer, type MindooDBTextBufferFlushResult, abbreviateCanonicalName, canPreviewAttachment, createMindooDBAppBridge, createMindooDBRichTextHandle, createMindooDBTextBuffer, expandAbbreviatedName, queryDocuments };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import "./chunk-QGM4M3NI.js";
|
|
2
|
-
|
|
3
1
|
// src/attachmentPreview.ts
|
|
4
2
|
function canPreviewAttachment(fileName, mimeType) {
|
|
5
3
|
const normalizedMimeType = mimeType.toLowerCase();
|
|
@@ -82,6 +80,9 @@ function expandAbbreviatedName(value) {
|
|
|
82
80
|
].join("/");
|
|
83
81
|
}
|
|
84
82
|
|
|
83
|
+
// src/client/createMindooDBAppBridge.ts
|
|
84
|
+
import { parseMindooDBFormulaBooleanExpression } from "mindoodb-view-language";
|
|
85
|
+
|
|
85
86
|
// src/client/portRpcClient.ts
|
|
86
87
|
var PROTOCOL = "mindoodb-app-bridge";
|
|
87
88
|
function normalizeRpcValue(value, seen = /* @__PURE__ */ new WeakMap()) {
|
|
@@ -234,6 +235,9 @@ var PortRpcClient = class {
|
|
|
234
235
|
// src/client/createMindooDBAppBridge.ts
|
|
235
236
|
var PROTOCOL2 = "mindoodb-app-bridge";
|
|
236
237
|
var DEFAULT_CONNECT_TIMEOUT_MS = 1e4;
|
|
238
|
+
function isMethodNotFoundError(error) {
|
|
239
|
+
return error instanceof Error && error.name === "method-not-found";
|
|
240
|
+
}
|
|
237
241
|
function toTransferableArrayBuffer(chunk) {
|
|
238
242
|
return chunk.buffer.slice(
|
|
239
243
|
chunk.byteOffset,
|
|
@@ -249,6 +253,24 @@ function isStreamAckFor(streamId, message) {
|
|
|
249
253
|
function isStreamErrorFor(streamId, message) {
|
|
250
254
|
return message.kind === "stream-error" && message.streamId === streamId;
|
|
251
255
|
}
|
|
256
|
+
function isQueryResultFor(subscriptionId, message) {
|
|
257
|
+
return message.kind === "query-result" && message.subscriptionId === subscriptionId;
|
|
258
|
+
}
|
|
259
|
+
function isViewChangedFor(navigatorId, message) {
|
|
260
|
+
return message.kind === "view-changed" && message.navigatorId === navigatorId;
|
|
261
|
+
}
|
|
262
|
+
function normalizeDocumentQuery(query) {
|
|
263
|
+
if (!query) {
|
|
264
|
+
return {};
|
|
265
|
+
}
|
|
266
|
+
const { filter, ...rest } = query;
|
|
267
|
+
return {
|
|
268
|
+
...rest,
|
|
269
|
+
...filter !== void 0 ? {
|
|
270
|
+
filter: typeof filter === "string" ? parseMindooDBFormulaBooleanExpression(filter) : filter
|
|
271
|
+
} : {}
|
|
272
|
+
};
|
|
273
|
+
}
|
|
252
274
|
function isThemeChangedMessage(message) {
|
|
253
275
|
return message.kind === "theme-changed";
|
|
254
276
|
}
|
|
@@ -258,6 +280,9 @@ function isViewportChangedMessage(message) {
|
|
|
258
280
|
function isUiPreferencesChangedMessage(message) {
|
|
259
281
|
return message.kind === "ui-preferences-changed";
|
|
260
282
|
}
|
|
283
|
+
function isLocaleChangedMessage(message) {
|
|
284
|
+
return message.kind === "locale-changed";
|
|
285
|
+
}
|
|
261
286
|
function toStreamError(message) {
|
|
262
287
|
const error = new Error(message.error.message);
|
|
263
288
|
error.name = message.error.code || "MindooDBAppBridgeStreamError";
|
|
@@ -380,6 +405,13 @@ var MindooDBAppViewNavigatorImpl = class {
|
|
|
380
405
|
this.viewCursor = result.viewCursor;
|
|
381
406
|
return this.viewCursor;
|
|
382
407
|
}
|
|
408
|
+
onDidUpdate(listener) {
|
|
409
|
+
return this.rpc.addMessageListener((message) => {
|
|
410
|
+
if (isViewChangedFor(this.navigatorId, message)) {
|
|
411
|
+
listener(message.stats);
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
}
|
|
383
415
|
async getCurrentEntry() {
|
|
384
416
|
return await this.call("viewNavigators.current.get");
|
|
385
417
|
}
|
|
@@ -721,6 +753,44 @@ var MindooDBAppDatabaseImpl = class {
|
|
|
721
753
|
databaseId: this.databaseId,
|
|
722
754
|
query: query ?? {}
|
|
723
755
|
}),
|
|
756
|
+
query: async (query) => await this.rpc.call("documents.query", {
|
|
757
|
+
databaseId: this.databaseId,
|
|
758
|
+
query: normalizeDocumentQuery(query)
|
|
759
|
+
}),
|
|
760
|
+
liveQuery: async (query, onResult) => {
|
|
761
|
+
const { subscriptionId, result } = await this.rpc.call("documents.liveQuery.subscribe", {
|
|
762
|
+
databaseId: this.databaseId,
|
|
763
|
+
query: normalizeDocumentQuery(query)
|
|
764
|
+
});
|
|
765
|
+
let disposed = false;
|
|
766
|
+
const unsubscribe = this.rpc.addMessageListener((message) => {
|
|
767
|
+
if (!disposed && isQueryResultFor(subscriptionId, message)) {
|
|
768
|
+
onResult(message.result);
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
onResult(result);
|
|
772
|
+
const subscription = {
|
|
773
|
+
refresh: async () => {
|
|
774
|
+
if (disposed) {
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
await this.rpc.call("documents.liveQuery.refresh", {
|
|
778
|
+
subscriptionId
|
|
779
|
+
});
|
|
780
|
+
},
|
|
781
|
+
dispose: async () => {
|
|
782
|
+
if (disposed) {
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
disposed = true;
|
|
786
|
+
unsubscribe();
|
|
787
|
+
await this.rpc.call("documents.liveQuery.unsubscribe", {
|
|
788
|
+
subscriptionId
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
};
|
|
792
|
+
return subscription;
|
|
793
|
+
},
|
|
724
794
|
getHeadCursor: async () => await this.rpc.call("documents.getHeadCursor", {
|
|
725
795
|
databaseId: this.databaseId
|
|
726
796
|
}),
|
|
@@ -748,6 +818,30 @@ var MindooDBAppDatabaseImpl = class {
|
|
|
748
818
|
databaseId: this.databaseId,
|
|
749
819
|
input
|
|
750
820
|
}),
|
|
821
|
+
createMany: async (inputs) => {
|
|
822
|
+
if (inputs.length === 0) {
|
|
823
|
+
return { ids: [] };
|
|
824
|
+
}
|
|
825
|
+
try {
|
|
826
|
+
return await this.rpc.call("documents.createMany", {
|
|
827
|
+
databaseId: this.databaseId,
|
|
828
|
+
inputs
|
|
829
|
+
});
|
|
830
|
+
} catch (error) {
|
|
831
|
+
if (!isMethodNotFoundError(error)) {
|
|
832
|
+
throw error;
|
|
833
|
+
}
|
|
834
|
+
const ids = [];
|
|
835
|
+
for (const input of inputs) {
|
|
836
|
+
const document = await this.rpc.call("documents.create", {
|
|
837
|
+
databaseId: this.databaseId,
|
|
838
|
+
input
|
|
839
|
+
});
|
|
840
|
+
ids.push(document.id);
|
|
841
|
+
}
|
|
842
|
+
return { ids };
|
|
843
|
+
}
|
|
844
|
+
},
|
|
751
845
|
update: async (docId, patch) => await this.rpc.call("documents.update", {
|
|
752
846
|
databaseId: this.databaseId,
|
|
753
847
|
docId,
|
|
@@ -757,10 +851,51 @@ var MindooDBAppDatabaseImpl = class {
|
|
|
757
851
|
databaseId: this.databaseId,
|
|
758
852
|
docId
|
|
759
853
|
}),
|
|
854
|
+
deleteMany: async (docIds) => {
|
|
855
|
+
if (docIds.length === 0) {
|
|
856
|
+
return { ok: true };
|
|
857
|
+
}
|
|
858
|
+
try {
|
|
859
|
+
return await this.rpc.call("documents.deleteMany", {
|
|
860
|
+
databaseId: this.databaseId,
|
|
861
|
+
docIds
|
|
862
|
+
});
|
|
863
|
+
} catch (error) {
|
|
864
|
+
if (!isMethodNotFoundError(error)) {
|
|
865
|
+
throw error;
|
|
866
|
+
}
|
|
867
|
+
for (const docId of docIds) {
|
|
868
|
+
await this.rpc.call("documents.delete", {
|
|
869
|
+
databaseId: this.databaseId,
|
|
870
|
+
docId
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
return { ok: true };
|
|
874
|
+
}
|
|
875
|
+
},
|
|
760
876
|
undelete: async (docId) => await this.rpc.call("documents.undelete", {
|
|
761
877
|
databaseId: this.databaseId,
|
|
762
878
|
docId
|
|
763
879
|
}),
|
|
880
|
+
canCreate: async (input) => await this.rpc.call("documents.canCreate", {
|
|
881
|
+
databaseId: this.databaseId,
|
|
882
|
+
input: input ?? {}
|
|
883
|
+
}),
|
|
884
|
+
canChange: async (docId) => await this.rpc.call("documents.canChange", {
|
|
885
|
+
databaseId: this.databaseId,
|
|
886
|
+
docId
|
|
887
|
+
}),
|
|
888
|
+
canDelete: async (docId) => await this.rpc.call("documents.canDelete", {
|
|
889
|
+
databaseId: this.databaseId,
|
|
890
|
+
docId
|
|
891
|
+
}),
|
|
892
|
+
canUndelete: async (docId) => await this.rpc.call("documents.canUndelete", {
|
|
893
|
+
databaseId: this.databaseId,
|
|
894
|
+
docId
|
|
895
|
+
}),
|
|
896
|
+
getDefaultCreateKeyId: async () => await this.rpc.call("documents.getDefaultCreateKeyId", {
|
|
897
|
+
databaseId: this.databaseId
|
|
898
|
+
}),
|
|
764
899
|
listHistory: async (docId) => await this.rpc.call("documents.history.list", {
|
|
765
900
|
databaseId: this.databaseId,
|
|
766
901
|
docId
|
|
@@ -901,6 +1036,36 @@ var MindooDBAppDatabaseImpl = class {
|
|
|
901
1036
|
databaseId: this.databaseId
|
|
902
1037
|
});
|
|
903
1038
|
}
|
|
1039
|
+
/** Reads the full-text configuration from the synced `dbsetup` document. */
|
|
1040
|
+
async getFulltextSetup() {
|
|
1041
|
+
const result = await this.rpc.call(
|
|
1042
|
+
"database.getFulltextSetup",
|
|
1043
|
+
{ databaseId: this.databaseId }
|
|
1044
|
+
);
|
|
1045
|
+
return result.config;
|
|
1046
|
+
}
|
|
1047
|
+
/** Writes (or removes, with `null`) the full-text configuration. */
|
|
1048
|
+
async setFulltextSetup(config) {
|
|
1049
|
+
await this.rpc.call("database.setFulltextSetup", {
|
|
1050
|
+
databaseId: this.databaseId,
|
|
1051
|
+
config
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1054
|
+
/** Reads the attachment extraction configuration from the synced `dbsetup` document. */
|
|
1055
|
+
async getExtractionSetup() {
|
|
1056
|
+
const result = await this.rpc.call(
|
|
1057
|
+
"database.getExtractionSetup",
|
|
1058
|
+
{ databaseId: this.databaseId }
|
|
1059
|
+
);
|
|
1060
|
+
return result.config;
|
|
1061
|
+
}
|
|
1062
|
+
/** Writes (or removes, with `null`) the attachment extraction configuration. */
|
|
1063
|
+
async setExtractionSetup(config) {
|
|
1064
|
+
await this.rpc.call("database.setExtractionSetup", {
|
|
1065
|
+
databaseId: this.databaseId,
|
|
1066
|
+
config
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
904
1069
|
};
|
|
905
1070
|
var MindooDBAppSessionImpl = class {
|
|
906
1071
|
constructor(rpc) {
|
|
@@ -918,6 +1083,10 @@ var MindooDBAppSessionImpl = class {
|
|
|
918
1083
|
async getLaunchContext() {
|
|
919
1084
|
return await this.rpc.call("session.getLaunchContext", {});
|
|
920
1085
|
}
|
|
1086
|
+
/** Returns the product names currently licensed in the Haven host. */
|
|
1087
|
+
async getLicensedProducts() {
|
|
1088
|
+
return await this.rpc.call("session.getLicensedProducts", {});
|
|
1089
|
+
}
|
|
921
1090
|
/** Lists the databases that the host has made available for this app session. */
|
|
922
1091
|
async listDatabases() {
|
|
923
1092
|
return await this.rpc.call("session.listDatabases", {});
|
|
@@ -985,6 +1154,14 @@ var MindooDBAppSessionImpl = class {
|
|
|
985
1154
|
}
|
|
986
1155
|
});
|
|
987
1156
|
}
|
|
1157
|
+
/** Subscribe to host-pushed UI language changes. */
|
|
1158
|
+
onLocaleChange(listener) {
|
|
1159
|
+
return this.rpc.addMessageListener((message) => {
|
|
1160
|
+
if (isLocaleChangedMessage(message)) {
|
|
1161
|
+
listener(message.locale);
|
|
1162
|
+
}
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
988
1165
|
/** Disconnects from the host and always disposes the underlying port client. */
|
|
989
1166
|
async disconnect() {
|
|
990
1167
|
try {
|
|
@@ -1345,12 +1522,20 @@ function computeSingleSplice2(previous, next) {
|
|
|
1345
1522
|
}
|
|
1346
1523
|
|
|
1347
1524
|
// src/viewLanguage.ts
|
|
1525
|
+
import { parseMindooDBFormulaBooleanExpression as parseMindooDBFormulaBooleanExpression2 } from "mindoodb-view-language";
|
|
1348
1526
|
import {
|
|
1349
1527
|
createViewLanguage,
|
|
1350
1528
|
getMindooDBViewLanguageHelper,
|
|
1351
1529
|
mindooDBViewLanguageHelpers,
|
|
1352
1530
|
mindooDBViewLanguageHelpersByName
|
|
1353
1531
|
} from "mindoodb-view-language";
|
|
1532
|
+
async function queryDocuments(db, filter, sortBy, options) {
|
|
1533
|
+
if (!db.query) {
|
|
1534
|
+
throw new Error("This MindooDB instance does not support ad-hoc queries.");
|
|
1535
|
+
}
|
|
1536
|
+
const expression = typeof filter === "string" ? parseMindooDBFormulaBooleanExpression2(filter) : filter;
|
|
1537
|
+
return db.query({ filter: expression, sortBy }, options);
|
|
1538
|
+
}
|
|
1354
1539
|
export {
|
|
1355
1540
|
MindooDBRichTextHandle,
|
|
1356
1541
|
MindooDBTextBuffer,
|
|
@@ -1360,5 +1545,6 @@ export {
|
|
|
1360
1545
|
createMindooDBRichTextHandle,
|
|
1361
1546
|
createMindooDBTextBuffer,
|
|
1362
1547
|
createViewLanguage,
|
|
1363
|
-
expandAbbreviatedName
|
|
1548
|
+
expandAbbreviatedName,
|
|
1549
|
+
queryDocuments
|
|
1364
1550
|
};
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { au as MindooDBAppLaunchContext, a7 as MindooDBAppDatabaseInfo, a8 as MindooDBAppDocumentApi, a6 as MindooDBAppCreateViewNavigatorInput, bh as MindooDBAppViewNavigator, bj as MindooDBAppViewNavigatorOpenOptions, h as MindooDBAppAttachmentApi, ai as MindooDBAppFulltextSetup, ah as MindooDBAppExtractionSetup, a as MindooDBAppBridge, b5 as MindooDBAppSession, B as MindooDBAppBridgeRpcRequest, al as MindooDBAppHostTheme, bp as MindooDBAppViewport, bb as MindooDBAppUiPreferences, aK as MindooDBAppQueryResult, bo as MindooDBAppViewUpdateStats, x as MindooDBAppBridgePortMessage } from '../types-B6vEy1VC.js';
|
|
2
2
|
import 'mindoodb-view-language';
|
|
3
3
|
|
|
4
4
|
type MaybePromise<T> = T | Promise<T>;
|
|
@@ -14,6 +14,21 @@ type MockDatabaseMethods = {
|
|
|
14
14
|
interface MockMindooDBAppDatabaseDefinition {
|
|
15
15
|
info: MindooDBAppDatabaseInfo;
|
|
16
16
|
methods?: MockDatabaseMethods;
|
|
17
|
+
/**
|
|
18
|
+
* Initial full-text configuration returned by `getFulltextSetup()`.
|
|
19
|
+
* `setFulltextSetup()` overwrites it for the lifetime of the handle.
|
|
20
|
+
* Note the mock evaluates `text` query clauses regardless of this
|
|
21
|
+
* config (see TESTING.md) — it exists so apps can test their setup/
|
|
22
|
+
* bootstrap logic.
|
|
23
|
+
*/
|
|
24
|
+
fulltextSetup?: MindooDBAppFulltextSetup | null;
|
|
25
|
+
/**
|
|
26
|
+
* Initial extraction configuration returned by `getExtractionSetup()`.
|
|
27
|
+
* `setExtractionSetup()` overwrites it for the lifetime of the handle.
|
|
28
|
+
* The mock runs no extraction service — this exists so apps can test
|
|
29
|
+
* their setup/bootstrap logic.
|
|
30
|
+
*/
|
|
31
|
+
extractionSetup?: MindooDBAppExtractionSetup | null;
|
|
17
32
|
}
|
|
18
33
|
interface CreateMockMindooDBAppSessionOptions {
|
|
19
34
|
launchContext?: Partial<MindooDBAppLaunchContext>;
|
|
@@ -25,11 +40,13 @@ interface MockMindooDBAppSessionController {
|
|
|
25
40
|
session: MindooDBAppSession;
|
|
26
41
|
getLaunchContext(): MindooDBAppLaunchContext;
|
|
27
42
|
setLaunchContext(patch?: Partial<MindooDBAppLaunchContext>): MindooDBAppLaunchContext;
|
|
43
|
+
getLicensedProducts(): string[];
|
|
28
44
|
listDatabases(): MindooDBAppDatabaseInfo[];
|
|
29
45
|
setDatabases(definitions: MockMindooDBAppDatabaseDefinition[]): void;
|
|
30
46
|
emitThemeChange(theme: MindooDBAppHostTheme): void;
|
|
31
47
|
emitViewportChange(viewport: MindooDBAppViewport): void;
|
|
32
48
|
emitUiPreferencesChange(uiPreferences: MindooDBAppUiPreferences): void;
|
|
49
|
+
emitLocaleChange(locale: string): void;
|
|
33
50
|
}
|
|
34
51
|
declare function createMockMindooDBAppSession(options?: CreateMockMindooDBAppSessionOptions): MockMindooDBAppSessionController;
|
|
35
52
|
declare function createMockMindooDBAppBridge(options?: CreateMockMindooDBAppSessionOptions): MockMindooDBAppSessionController;
|
|
@@ -57,6 +74,11 @@ interface FakeBridgeHostController {
|
|
|
57
74
|
emitThemeChange(theme: MindooDBAppHostTheme): void;
|
|
58
75
|
emitViewportChange(viewport: MindooDBAppViewport): void;
|
|
59
76
|
emitUiPreferencesChange(uiPreferences: MindooDBAppUiPreferences): void;
|
|
77
|
+
emitLocaleChange(locale: string): void;
|
|
78
|
+
/** Push a live-query result to connected apps, as the Haven host would. */
|
|
79
|
+
emitQueryResult(subscriptionId: string, result: MindooDBAppQueryResult): void;
|
|
80
|
+
/** Push a navigator view-changed event to connected apps. */
|
|
81
|
+
emitViewChanged(navigatorId: string, stats: MindooDBAppViewUpdateStats): void;
|
|
60
82
|
postPortMessage(message: MindooDBAppBridgePortMessage, transfer?: Transferable[]): void;
|
|
61
83
|
setRequestHandler(method: string, handler: FakeBridgeRequestHandler): void;
|
|
62
84
|
clearRequestHandler(method: string): void;
|