mindoodb-app-sdk 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -410,20 +410,26 @@ const unsupported = canPreviewAttachment("data.bin", "application/octet-stream")
410
410
 
411
411
  ### Virtual Views
412
412
 
413
- Views let you query documents with categorization, sorting, filtering, and aggregation -- similar to a spreadsheet pivot table. There are two ways to work with views:
413
+ Views let you query documents with categorization, sorting, filtering, and aggregation -- similar to a spreadsheet pivot table. The SDK now exposes a **stateful navigator API** that mirrors the core `VirtualViewNavigator` closely.
414
414
 
415
- **App-defined views** -- create a view definition programmatically:
415
+ There are two ways to open one:
416
+
417
+ **App-defined multi-database views** -- create a view definition programmatically and immediately open a navigator:
416
418
 
417
419
  ```ts
418
420
  import { createViewLanguage } from "mindoodb-app-sdk";
419
421
 
420
422
  const v = createViewLanguage<{ employee: string; hours: number }>();
421
423
 
422
- const view = await session.createView({
423
- databaseId: "main",
424
+ const navigator = await session.createViewNavigator({
425
+ databaseIds: ["main", "archive"],
424
426
  definition: {
425
427
  title: "Hours by employee",
426
428
  defaultExpand: "collapsed",
429
+ filter: {
430
+ mode: "expression",
431
+ expression: v.gt(v.toNumber(v.field("hours")), v.number(0)),
432
+ },
427
433
  columns: [
428
434
  {
429
435
  name: "employee",
@@ -442,27 +448,98 @@ const view = await session.createView({
442
448
  },
443
449
  });
444
450
 
445
- const page = await view.page({ pageSize: 100 });
446
- console.log(page.rows);
447
- await view.dispose();
451
+ const batch = await navigator.entriesForward({ limit: 100 });
452
+ console.log(batch.entries);
453
+
454
+ await navigator.dispose();
448
455
  ```
449
456
 
450
- **Haven-configured views** -- open views that the Haven administrator attached to the app registration:
457
+ **Haven-configured views** -- open a view that Haven attached to the app registration:
451
458
 
452
459
  ```ts
453
460
  const viewDefs = ctx.views; // from launch context
454
461
 
455
- const view = await session.openView(viewDefs[0]!.id);
456
- const page = await view.page({ pageSize: 50 });
462
+ const navigator = await session.openViewNavigator(viewDefs[0]!.id, {
463
+ includeCategories: true,
464
+ includeDocuments: true,
465
+ hideEmptyCategories: true,
466
+ });
467
+
468
+ await navigator.gotoFirst();
469
+ const current = await navigator.getCurrentEntry();
470
+ console.log(current);
471
+
472
+ await navigator.dispose();
473
+ ```
474
+
475
+ #### Common navigator patterns
476
+
477
+ **Single-step traversal**:
478
+
479
+ ```ts
480
+ await navigator.gotoFirst();
481
+
482
+ do {
483
+ const entry = await navigator.getCurrentEntry();
484
+ if (entry) {
485
+ console.log(entry.kind, entry.categoryPath, entry.columnValues);
486
+ }
487
+ } while (await navigator.gotoNext());
488
+ ```
489
+
490
+ **Batch reads for UI rendering**:
491
+
492
+ ```ts
493
+ const page1 = await navigator.entriesForward({ limit: 50 });
494
+ const page2 = page1.nextPosition
495
+ ? await navigator.entriesForward({ limit: 50, startPosition: page1.nextPosition })
496
+ : null;
497
+ ```
498
+
499
+ **Category lookup plus child traversal**:
457
500
 
458
- // Expand/collapse categories
459
- await view.expandAll();
460
- await view.collapse(someCategoryKey);
501
+ ```ts
502
+ const category = await navigator.findCategoryEntryByParts(["Ada"]);
503
+ if (category) {
504
+ const docs = await navigator.childDocuments(category.key);
505
+ console.log(docs.map((entry) => entry.docId));
506
+ }
507
+ ```
461
508
 
462
- await view.dispose();
509
+ **Key lookup and key-range lookup**:
510
+
511
+ ```ts
512
+ const category = await navigator.findCategoryEntryByParts(["Ada"]);
513
+ if (category) {
514
+ const exact = await navigator.childDocumentsByKey(category.key, "2026-04-14", true);
515
+ const range = await navigator.childDocumentsBetween(category.key, {
516
+ startKey: "2026-04-01",
517
+ endKey: "2026-04-30",
518
+ });
519
+ }
463
520
  ```
464
521
 
465
- 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.
522
+ **Expansion and selection state**:
523
+
524
+ ```ts
525
+ await navigator.expandAll();
526
+ await navigator.select("main", "doc-123");
527
+
528
+ const expansion = await navigator.getExpansionState();
529
+ const selection = await navigator.getSelectionState();
530
+
531
+ await navigator.setExpansionState(expansion);
532
+ await navigator.setSelectionState(selection);
533
+ ```
534
+
535
+ 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.
536
+
537
+ #### Performance notes
538
+
539
+ - `goto*()` and `getCurrentEntry()` are lightweight stateful cursor operations. They may still produce many bridge round-trips if you call them for every rendered row.
540
+ - `entriesForward()` and `entriesBackward()` exist specifically to reduce those round-trips for UI rendering.
541
+ - `refresh()` rebuilds or invalidates the host-side navigator state and should be treated as an expensive operation compared to simple cursor movement.
542
+ - Child/key/range helpers operate on the same host-side navigator session. They do not create a separate query engine.
466
543
 
467
544
  Available expression helpers:
468
545
 
@@ -534,8 +611,8 @@ Connect options: `launchId?`, `targetOrigin?`, `connectTimeoutMs?`.
534
611
  | `getLaunchContext()` | `Promise<MindooDBAppLaunchContext>` |
535
612
  | `listDatabases()` | `Promise<MindooDBAppDatabaseInfo[]>` |
536
613
  | `openDatabase(databaseId)` | `Promise<MindooDBAppDatabase>` |
537
- | `createView(input)` | `Promise<MindooDBAppViewHandle>` |
538
- | `openView(viewId)` | `Promise<MindooDBAppViewHandle>` |
614
+ | `createViewNavigator(input)` | `Promise<MindooDBAppViewNavigator>` |
615
+ | `openViewNavigator(viewId, options?)` | `Promise<MindooDBAppViewNavigator>` |
539
616
  | `onThemeChange(listener)` | `() => void` (unsubscribe) |
540
617
  | `onViewportChange(listener)` | `() => void` (unsubscribe) |
541
618
  | `disconnect()` | `Promise<void>` |
@@ -572,23 +649,45 @@ Connect options: `launchId?`, `targetOrigin?`, `connectTimeoutMs?`.
572
649
  | `openWriteStream(docId, attachmentName, contentType?)` | `Promise<MindooDBAppWritableAttachmentStream>` |
573
650
  | `openPreview(docId, attachmentName, options?)` | `Promise<{ ok: true }>` |
574
651
 
575
- ### MindooDBAppViewHandle
652
+ ### MindooDBAppViewNavigator
576
653
 
577
654
  | Method | Returns |
578
655
  |---|---|
579
656
  | `getDefinition()` | `Promise<MindooDBAppViewDefinition>` |
580
657
  | `refresh()` | `Promise<void>` |
581
- | `page(input?)` | `Promise<MindooDBAppViewPageResult>` |
582
- | `getExpansionState()` | `Promise<MindooDBAppViewExpansionState>` |
583
- | `setExpansionState(state)` | `Promise<MindooDBAppViewExpansionState>` |
584
- | `expand(rowKey)` | `Promise<MindooDBAppViewExpansionState>` |
585
- | `collapse(rowKey)` | `Promise<MindooDBAppViewExpansionState>` |
586
- | `expandAll()` | `Promise<MindooDBAppViewExpansionState>` |
587
- | `collapseAll()` | `Promise<MindooDBAppViewExpansionState>` |
588
- | `getRow(rowKey)` | `Promise<MindooDBAppViewRow \| null>` |
589
- | `getCategory(input)` | `Promise<MindooDBAppViewRow \| null>` |
590
- | `pageCategory(categoryKey, input?)` | `Promise<MindooDBAppViewPageResult>` |
591
- | `listCategoryDocumentIds(categoryKey)` | `Promise<string[]>` |
658
+ | `getCurrentEntry()` | `Promise<MindooDBAppViewEntry \| null>` |
659
+ | `gotoFirst()` / `gotoLast()` | `Promise<boolean>` |
660
+ | `gotoNext()` / `gotoPrev()` | `Promise<boolean>` |
661
+ | `gotoNextSibling()` / `gotoPrevSibling()` | `Promise<boolean>` |
662
+ | `gotoParent()` | `Promise<boolean>` |
663
+ | `gotoFirstChild()` / `gotoLastChild()` | `Promise<boolean>` |
664
+ | `gotoPos(position)` | `Promise<boolean>` |
665
+ | `getPos(position)` | `Promise<MindooDBAppViewEntry \| null>` |
666
+ | `findCategoryEntryByParts(parts)` | `Promise<MindooDBAppViewEntry \| null>` |
667
+ | `entriesForward(options?)` | `Promise<MindooDBAppViewNavigatorPageResult>` |
668
+ | `entriesBackward(options?)` | `Promise<MindooDBAppViewNavigatorPageResult>` |
669
+ | `gotoNextSelected()` / `gotoPrevSelected()` | `Promise<boolean>` |
670
+ | `select(origin, docId, selectParentCategories?)` | `Promise<void>` |
671
+ | `deselect(origin, docId)` | `Promise<void>` |
672
+ | `selectAllEntries()` / `deselectAllEntries()` | `Promise<void>` |
673
+ | `isSelected(origin, docId)` | `Promise<boolean>` |
674
+ | `getSelectionState()` | `Promise<MindooDBAppViewNavigatorSelectionState>` |
675
+ | `setSelectionState(state)` | `Promise<void>` |
676
+ | `expand(origin, docId)` / `collapse(origin, docId)` | `Promise<void>` |
677
+ | `expandAll()` / `collapseAll()` | `Promise<void>` |
678
+ | `expandToLevel(level)` | `Promise<void>` |
679
+ | `isExpanded(entryKey)` | `Promise<boolean>` |
680
+ | `getExpansionState()` | `Promise<MindooDBAppViewNavigatorExpansionState>` |
681
+ | `setExpansionState(state)` | `Promise<void>` |
682
+ | `childEntries(entryKey, descending?)` | `Promise<MindooDBAppViewEntry[]>` |
683
+ | `childCategories(entryKey, descending?)` | `Promise<MindooDBAppViewEntry[]>` |
684
+ | `childDocuments(entryKey, descending?)` | `Promise<MindooDBAppViewEntry[]>` |
685
+ | `childCategoriesByKey(entryKey, key, exact?, descending?)` | `Promise<MindooDBAppViewEntry[]>` |
686
+ | `childDocumentsByKey(entryKey, key, exact?, descending?)` | `Promise<MindooDBAppViewEntry[]>` |
687
+ | `childCategoriesBetween(entryKey, range)` | `Promise<MindooDBAppViewEntry[]>` |
688
+ | `childDocumentsBetween(entryKey, range)` | `Promise<MindooDBAppViewEntry[]>` |
689
+ | `getSortedDocIds(descending?)` | `Promise<MindooDBAppScopedDocId[]>` |
690
+ | `getSortedDocIdsScoped(entryKey, descending?)` | `Promise<MindooDBAppScopedDocId[]>` |
592
691
  | `dispose()` | `Promise<void>` |
593
692
 
594
693
  ### Exported functions
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { M as MindooDBAppAttachmentPreviewMode, a as MindooDBAppBridge } from './types-u5bAeQwY.js';
2
- export { b as MindooDBAppAttachmentApi, c as MindooDBAppAttachmentChunk, d as MindooDBAppAttachmentInfo, e as MindooDBAppAttachmentPreviewOptions, f as MindooDBAppAttachmentPreviewSession, g as MindooDBAppBridgeConnectMessage, h as MindooDBAppBridgeConnectOptions, i as MindooDBAppBridgeConnectedMessage, j as MindooDBAppBridgeErrorPayload, k as MindooDBAppBridgePortMessage, l as MindooDBAppBridgeRpcError, m as MindooDBAppBridgeRpcMessage, n as MindooDBAppBridgeRpcRequest, o as MindooDBAppBridgeRpcSuccess, p as MindooDBAppBridgeStreamAbortRequest, q as MindooDBAppBridgeStreamAck, r as MindooDBAppBridgeStreamCloseRequest, s as MindooDBAppBridgeStreamError, t as MindooDBAppBridgeStreamMessage, u as MindooDBAppBridgeStreamOpenResult, v as MindooDBAppBridgeStreamReadRequest, w as MindooDBAppBridgeStreamWriteRequest, x as MindooDBAppBridgeThemeChangedMessage, y as MindooDBAppBridgeViewportChangedMessage, z as MindooDBAppCapability, A as MindooDBAppConfiguredViewCategorizationStyle, B as MindooDBAppConfiguredViewColumn, C as MindooDBAppConfiguredViewColumnRole, D as MindooDBAppConfiguredViewExpressionMode, E as MindooDBAppConfiguredViewFieldExpression, F as MindooDBAppConfiguredViewFilterDefinition, G as MindooDBAppConfiguredViewFilterMode, H as MindooDBAppConfiguredViewFilterRule, I as MindooDBAppConfiguredViewFormulaExpression, J as MindooDBAppConfiguredViewFormulaFilterDefinition, K as MindooDBAppConfiguredViewPreviewMode, L as MindooDBAppConfiguredViewRuleFilterDefinition, N as MindooDBAppConfiguredViewRuleMatchMode, O as MindooDBAppConfiguredViewRuleOperator, P as MindooDBAppConfiguredViewValueExpression, Q as MindooDBAppCreateDocumentInput, R as MindooDBAppCreateViewInput, S as MindooDBAppDatabase, T as MindooDBAppDatabaseInfo, U as MindooDBAppDocument, V as MindooDBAppDocumentApi, W as MindooDBAppDocumentHistoryEntry, X as MindooDBAppDocumentListQuery, Y as MindooDBAppDocumentListResult, Z as MindooDBAppDocumentSummary, _ as MindooDBAppHistoricalDocument, $ as MindooDBAppHistoryQuery, a0 as MindooDBAppHostTheme, a1 as MindooDBAppLaunchContext, a2 as MindooDBAppReadableAttachmentStream, a3 as MindooDBAppResolvedViewDefinition, a4 as MindooDBAppResolvedViewSource, a5 as MindooDBAppRuntime, a6 as MindooDBAppSession, a7 as MindooDBAppThemeMode, a8 as MindooDBAppUpdateDocumentInput, a9 as MindooDBAppViewHandle, aa as MindooDBAppViewport, ab as MindooDBAppWritableAttachmentStream } from './types-u5bAeQwY.js';
1
+ import { M as MindooDBAppAttachmentPreviewMode, a as MindooDBAppBridge } from './types-C_kZcG24.js';
2
+ export { b as MindooDBAppAttachmentApi, c as MindooDBAppAttachmentChunk, d as MindooDBAppAttachmentInfo, e as MindooDBAppAttachmentPreviewOptions, f as MindooDBAppAttachmentPreviewSession, g as MindooDBAppBridgeConnectMessage, h as MindooDBAppBridgeConnectOptions, i as MindooDBAppBridgeConnectedMessage, j as MindooDBAppBridgeErrorPayload, k as MindooDBAppBridgePortMessage, l as MindooDBAppBridgeRpcError, m as MindooDBAppBridgeRpcMessage, n as MindooDBAppBridgeRpcRequest, o as MindooDBAppBridgeRpcSuccess, p as MindooDBAppBridgeStreamAbortRequest, q as MindooDBAppBridgeStreamAck, r as MindooDBAppBridgeStreamCloseRequest, s as MindooDBAppBridgeStreamError, t as MindooDBAppBridgeStreamMessage, u as MindooDBAppBridgeStreamOpenResult, v as MindooDBAppBridgeStreamReadRequest, w as MindooDBAppBridgeStreamWriteRequest, x as MindooDBAppBridgeThemeChangedMessage, y as MindooDBAppBridgeViewportChangedMessage, z as MindooDBAppCapability, A as MindooDBAppConfiguredViewCategorizationStyle, B as MindooDBAppConfiguredViewColumn, C as MindooDBAppConfiguredViewColumnRole, D as MindooDBAppConfiguredViewExpressionMode, E as MindooDBAppConfiguredViewFieldExpression, F as MindooDBAppConfiguredViewFilterDefinition, G as MindooDBAppConfiguredViewFilterMode, H as MindooDBAppConfiguredViewFilterRule, I as MindooDBAppConfiguredViewFormulaExpression, J as MindooDBAppConfiguredViewFormulaFilterDefinition, K as MindooDBAppConfiguredViewPreviewMode, L as MindooDBAppConfiguredViewRuleFilterDefinition, N as MindooDBAppConfiguredViewRuleMatchMode, O as MindooDBAppConfiguredViewRuleOperator, P as MindooDBAppConfiguredViewValueExpression, Q as MindooDBAppCreateDocumentInput, R as MindooDBAppCreateViewInput, S as MindooDBAppCreateViewNavigatorInput, T as MindooDBAppDatabase, U as MindooDBAppDatabaseInfo, V as MindooDBAppDocument, W as MindooDBAppDocumentApi, X as MindooDBAppDocumentHistoryEntry, Y as MindooDBAppDocumentListQuery, Z as MindooDBAppDocumentListResult, _ as MindooDBAppDocumentSummary, $ as MindooDBAppHistoricalDocument, a0 as MindooDBAppHistoryQuery, a1 as MindooDBAppHostTheme, a2 as MindooDBAppLaunchContext, a3 as MindooDBAppReadableAttachmentStream, a4 as MindooDBAppResolvedViewDefinition, a5 as MindooDBAppResolvedViewSource, a6 as MindooDBAppRuntime, a7 as MindooDBAppScopedDocId, a8 as MindooDBAppSession, a9 as MindooDBAppThemeMode, aa as MindooDBAppUpdateDocumentInput, ab as MindooDBAppViewEntry, ac as MindooDBAppViewEntryKind, ad as MindooDBAppViewNavigator, ae as MindooDBAppViewNavigatorExpansionState, af as MindooDBAppViewNavigatorOpenOptions, ag as MindooDBAppViewNavigatorPageOptions, ah as MindooDBAppViewNavigatorPageResult, ai as MindooDBAppViewNavigatorRangeQuery, aj as MindooDBAppViewNavigatorSelectionState, ak as MindooDBAppViewport, al as MindooDBAppWritableAttachmentStream } from './types-C_kZcG24.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
  /**
package/dist/index.js CHANGED
@@ -307,89 +307,163 @@ function waitForConnectedPort(options, launchId) {
307
307
  targetWindow.postMessage(message, targetOrigin, [channel.port2]);
308
308
  });
309
309
  }
310
- var MindooDBAppViewHandleImpl = class {
311
- constructor(rpc, viewId) {
310
+ var MindooDBAppViewNavigatorImpl = class {
311
+ constructor(rpc, navigatorId) {
312
312
  this.rpc = rpc;
313
- this.viewId = viewId;
313
+ this.navigatorId = navigatorId;
314
314
  }
315
- async getDefinition() {
316
- return await this.rpc.call("views.getDefinition", {
317
- viewId: this.viewId
315
+ /** Shorthand: call an RPC method with the navigator ID automatically injected. */
316
+ async call(method, params = {}) {
317
+ return await this.rpc.call(method, {
318
+ navigatorId: this.navigatorId,
319
+ ...params
318
320
  });
319
321
  }
322
+ async getDefinition() {
323
+ return await this.call("viewNavigators.getDefinition");
324
+ }
320
325
  async refresh() {
321
- await this.rpc.call("views.refresh", {
322
- viewId: this.viewId
323
- });
326
+ await this.call("viewNavigators.refresh");
324
327
  }
325
- async page(input) {
326
- return await this.rpc.call("views.page", {
327
- viewId: this.viewId,
328
- request: input ?? {}
329
- });
328
+ async getCurrentEntry() {
329
+ return await this.call("viewNavigators.current.get");
330
330
  }
331
- async getExpansionState() {
332
- return await this.rpc.call("views.expansion.get", {
333
- viewId: this.viewId
334
- });
331
+ async gotoFirst() {
332
+ return await this.call("viewNavigators.goto.first");
335
333
  }
336
- async setExpansionState(state) {
337
- return await this.rpc.call("views.expansion.set", {
338
- viewId: this.viewId,
339
- expansion: state
340
- });
334
+ async gotoLast() {
335
+ return await this.call("viewNavigators.goto.last");
341
336
  }
342
- async expand(rowKey) {
343
- return await this.rpc.call("views.expansion.expand", {
344
- viewId: this.viewId,
345
- rowKey
346
- });
337
+ async gotoNext() {
338
+ return await this.call("viewNavigators.goto.next");
339
+ }
340
+ async gotoPrev() {
341
+ return await this.call("viewNavigators.goto.prev");
342
+ }
343
+ async gotoNextSibling() {
344
+ return await this.call("viewNavigators.goto.nextSibling");
345
+ }
346
+ async gotoPrevSibling() {
347
+ return await this.call("viewNavigators.goto.prevSibling");
347
348
  }
348
- async collapse(rowKey) {
349
- return await this.rpc.call("views.expansion.collapse", {
350
- viewId: this.viewId,
351
- rowKey
349
+ async gotoParent() {
350
+ return await this.call("viewNavigators.goto.parent");
351
+ }
352
+ async gotoFirstChild() {
353
+ return await this.call("viewNavigators.goto.firstChild");
354
+ }
355
+ async gotoLastChild() {
356
+ return await this.call("viewNavigators.goto.lastChild");
357
+ }
358
+ async gotoPos(position) {
359
+ return await this.call("viewNavigators.goto.pos", { position });
360
+ }
361
+ async getPos(position) {
362
+ return await this.call("viewNavigators.pos.get", { position });
363
+ }
364
+ async findCategoryEntryByParts(parts) {
365
+ return await this.call("viewNavigators.category.findByParts", { parts });
366
+ }
367
+ async entriesForward(options) {
368
+ return await this.call("viewNavigators.entries.forward", { options: options ?? {} });
369
+ }
370
+ async entriesBackward(options) {
371
+ return await this.call("viewNavigators.entries.backward", { options: options ?? {} });
372
+ }
373
+ async gotoNextSelected() {
374
+ return await this.call("viewNavigators.goto.nextSelected");
375
+ }
376
+ async gotoPrevSelected() {
377
+ return await this.call("viewNavigators.goto.prevSelected");
378
+ }
379
+ async select(origin, docId, selectParentCategories) {
380
+ await this.call("viewNavigators.selection.select", {
381
+ origin,
382
+ docId,
383
+ selectParentCategories
352
384
  });
353
385
  }
386
+ async deselect(origin, docId) {
387
+ await this.call("viewNavigators.selection.deselect", { origin, docId });
388
+ }
389
+ async selectAllEntries() {
390
+ await this.call("viewNavigators.selection.selectAll");
391
+ }
392
+ async deselectAllEntries() {
393
+ await this.call("viewNavigators.selection.deselectAll");
394
+ }
395
+ async isSelected(origin, docId) {
396
+ return await this.call("viewNavigators.selection.isSelected", { origin, docId });
397
+ }
398
+ async getSelectionState() {
399
+ return await this.call("viewNavigators.selection.get");
400
+ }
401
+ async setSelectionState(state) {
402
+ await this.call("viewNavigators.selection.set", { state });
403
+ }
404
+ async expand(origin, docId) {
405
+ await this.call("viewNavigators.expansion.expand", { origin, docId });
406
+ }
407
+ async collapse(origin, docId) {
408
+ await this.call("viewNavigators.expansion.collapse", { origin, docId });
409
+ }
354
410
  async expandAll() {
355
- return await this.rpc.call("views.expansion.expandAll", {
356
- viewId: this.viewId
357
- });
411
+ await this.call("viewNavigators.expansion.expandAll");
358
412
  }
359
413
  async collapseAll() {
360
- return await this.rpc.call("views.expansion.collapseAll", {
361
- viewId: this.viewId
362
- });
414
+ await this.call("viewNavigators.expansion.collapseAll");
363
415
  }
364
- async getRow(rowKey) {
365
- return await this.rpc.call("views.row.get", {
366
- viewId: this.viewId,
367
- rowKey
368
- });
416
+ async expandToLevel(level) {
417
+ await this.call("viewNavigators.expansion.expandToLevel", { level });
369
418
  }
370
- async getCategory(input) {
371
- return await this.rpc.call("views.category.get", {
372
- viewId: this.viewId,
373
- lookup: input
374
- });
419
+ async isExpanded(entryKey) {
420
+ return await this.call("viewNavigators.expansion.isExpanded", { entryKey });
421
+ }
422
+ async getExpansionState() {
423
+ return await this.call("viewNavigators.expansion.get");
375
424
  }
376
- async pageCategory(categoryKey, input) {
377
- return await this.rpc.call("views.category.page", {
378
- viewId: this.viewId,
379
- categoryKey,
380
- request: input ?? {}
425
+ async setExpansionState(state) {
426
+ await this.call("viewNavigators.expansion.set", { state });
427
+ }
428
+ async childEntries(entryKey, descending) {
429
+ return await this.call("viewNavigators.children.entries", { entryKey, descending });
430
+ }
431
+ async childCategories(entryKey, descending) {
432
+ return await this.call("viewNavigators.children.categories", { entryKey, descending });
433
+ }
434
+ async childDocuments(entryKey, descending) {
435
+ return await this.call("viewNavigators.children.documents", { entryKey, descending });
436
+ }
437
+ async childCategoriesByKey(entryKey, key, exact, descending) {
438
+ return await this.call("viewNavigators.children.categoriesByKey", {
439
+ entryKey,
440
+ key,
441
+ exact,
442
+ descending
381
443
  });
382
444
  }
383
- async listCategoryDocumentIds(categoryKey) {
384
- return await this.rpc.call("views.category.documentIds", {
385
- viewId: this.viewId,
386
- categoryKey
445
+ async childDocumentsByKey(entryKey, key, exact, descending) {
446
+ return await this.call("viewNavigators.children.documentsByKey", {
447
+ entryKey,
448
+ key,
449
+ exact,
450
+ descending
387
451
  });
388
452
  }
453
+ async childCategoriesBetween(entryKey, range) {
454
+ return await this.call("viewNavigators.children.categoriesBetween", { entryKey, range });
455
+ }
456
+ async childDocumentsBetween(entryKey, range) {
457
+ return await this.call("viewNavigators.children.documentsBetween", { entryKey, range });
458
+ }
459
+ async getSortedDocIds(descending) {
460
+ return await this.call("viewNavigators.sortedDocIds.get", { descending });
461
+ }
462
+ async getSortedDocIdsScoped(entryKey, descending) {
463
+ return await this.call("viewNavigators.sortedDocIds.scoped", { entryKey, descending });
464
+ }
389
465
  async dispose() {
390
- await this.rpc.call("views.dispose", {
391
- viewId: this.viewId
392
- });
466
+ await this.call("viewNavigators.dispose");
393
467
  }
394
468
  };
395
469
  var MindooDBAppReadableAttachmentStreamImpl = class {
@@ -638,6 +712,7 @@ var MindooDBAppSessionImpl = class {
638
712
  async getLaunchContext() {
639
713
  return await this.rpc.call("session.getLaunchContext", {});
640
714
  }
715
+ /** Lists the databases that the host has made available for this app session. */
641
716
  async listDatabases() {
642
717
  return await this.rpc.call("session.listDatabases", {});
643
718
  }
@@ -646,14 +721,28 @@ var MindooDBAppSessionImpl = class {
646
721
  await this.rpc.call("session.openDatabase", { databaseId });
647
722
  return new MindooDBAppDatabaseImpl(this.rpc, databaseId);
648
723
  }
649
- async createView(input) {
650
- const result = await this.rpc.call("session.createView", input);
651
- return new MindooDBAppViewHandleImpl(this.rpc, result.viewId);
652
- }
653
- async openView(viewId) {
654
- await this.rpc.call("session.openView", { viewId });
655
- return new MindooDBAppViewHandleImpl(this.rpc, viewId);
656
- }
724
+ /**
725
+ * Create a navigator from an ad-hoc view definition and one or more database bindings.
726
+ *
727
+ * The host builds a `VirtualView` from `input.definition`, optionally applying
728
+ * open options (root scoping, category filtering), and returns a `navigatorId`
729
+ * that all subsequent navigator RPCs reference.
730
+ */
731
+ async createViewNavigator(input) {
732
+ const result = await this.rpc.call("session.createViewNavigator", input);
733
+ return new MindooDBAppViewNavigatorImpl(this.rpc, result.navigatorId);
734
+ }
735
+ /**
736
+ * Open a navigator for a preconfigured view that the host already knows about.
737
+ *
738
+ * `viewId` must match one of the views declared in the launch context. The
739
+ * host resolves the full view definition and database bindings automatically.
740
+ */
741
+ async openViewNavigator(viewId, options) {
742
+ const result = await this.rpc.call("session.openViewNavigator", { viewId, options: options ?? {} });
743
+ return new MindooDBAppViewNavigatorImpl(this.rpc, result.navigatorId);
744
+ }
745
+ /** Subscribe to host-pushed theme changes (dark/light mode, color tokens). */
657
746
  onThemeChange(listener) {
658
747
  return this.rpc.addMessageListener((message) => {
659
748
  if (isThemeChangedMessage(message)) {
@@ -661,6 +750,7 @@ var MindooDBAppSessionImpl = class {
661
750
  }
662
751
  });
663
752
  }
753
+ /** Subscribe to host-pushed viewport dimension changes (resize, orientation). */
664
754
  onViewportChange(listener) {
665
755
  return this.rpc.addMessageListener((message) => {
666
756
  if (isViewportChangedMessage(message)) {
@@ -1,10 +1,10 @@
1
- import { a1 as MindooDBAppLaunchContext, T as MindooDBAppDatabaseInfo, V as MindooDBAppDocumentApi, a9 as MindooDBAppViewHandle, b as MindooDBAppAttachmentApi, a as MindooDBAppBridge, a6 as MindooDBAppSession, n as MindooDBAppBridgeRpcRequest, a0 as MindooDBAppHostTheme, aa as MindooDBAppViewport, k as MindooDBAppBridgePortMessage } from '../types-u5bAeQwY.js';
2
- import { MindooDBAppViewDefinition } from 'mindoodb-view-language';
1
+ import { a2 as MindooDBAppLaunchContext, U as MindooDBAppDatabaseInfo, W as MindooDBAppDocumentApi, S as MindooDBAppCreateViewNavigatorInput, ad as MindooDBAppViewNavigator, af as MindooDBAppViewNavigatorOpenOptions, b as MindooDBAppAttachmentApi, a as MindooDBAppBridge, a8 as MindooDBAppSession, n as MindooDBAppBridgeRpcRequest, a1 as MindooDBAppHostTheme, ak as MindooDBAppViewport, k as MindooDBAppBridgePortMessage } from '../types-C_kZcG24.js';
2
+ import 'mindoodb-view-language';
3
3
 
4
4
  type MaybePromise<T> = T | Promise<T>;
5
5
  type MockViewApi = {
6
- create(definition: MindooDBAppViewDefinition): MaybePromise<MindooDBAppViewHandle>;
7
- open(viewId: string): MaybePromise<MindooDBAppViewHandle>;
6
+ create(input: MindooDBAppCreateViewNavigatorInput): MaybePromise<MindooDBAppViewNavigator>;
7
+ open(viewId: string, options?: MindooDBAppViewNavigatorOpenOptions): MaybePromise<MindooDBAppViewNavigator>;
8
8
  };
9
9
  type MockDatabaseMethods = {
10
10
  documents?: Partial<MindooDBAppDocumentApi>;
@@ -172,17 +172,22 @@ function decodeMockListCursor(cursor) {
172
172
  const offset = Number.parseInt(cursor, 10);
173
173
  return Number.isFinite(offset) && offset >= 0 ? offset : 0;
174
174
  }
175
- function createDefaultViewHandle() {
175
+ function createDefaultViewNavigator() {
176
176
  const definition = {
177
177
  title: "Mock View",
178
178
  columns: []
179
179
  };
180
- const expansion = {
181
- mode: "collapsed",
182
- ids: []
180
+ let expansion = {
181
+ expandAllByDefault: false,
182
+ expandLevel: 0,
183
+ entryKeys: []
184
+ };
185
+ let selection = {
186
+ selectAllByDefault: false,
187
+ entryKeys: []
183
188
  };
184
189
  const emptyPage = {
185
- rows: [],
190
+ entries: [],
186
191
  nextPosition: null,
187
192
  hasMore: false
188
193
  };
@@ -192,43 +197,174 @@ function createDefaultViewHandle() {
192
197
  },
193
198
  async refresh() {
194
199
  },
195
- async page(_input) {
200
+ async getCurrentEntry() {
201
+ return null;
202
+ },
203
+ async gotoFirst() {
204
+ return false;
205
+ },
206
+ async gotoLast() {
207
+ return false;
208
+ },
209
+ async gotoNext() {
210
+ return false;
211
+ },
212
+ async gotoPrev() {
213
+ return false;
214
+ },
215
+ async gotoNextSibling() {
216
+ return false;
217
+ },
218
+ async gotoPrevSibling() {
219
+ return false;
220
+ },
221
+ async gotoParent() {
222
+ return false;
223
+ },
224
+ async gotoFirstChild() {
225
+ return false;
226
+ },
227
+ async gotoLastChild() {
228
+ return false;
229
+ },
230
+ async gotoPos(_position) {
231
+ return false;
232
+ },
233
+ async getPos(_position) {
234
+ return null;
235
+ },
236
+ async findCategoryEntryByParts(_parts) {
237
+ return null;
238
+ },
239
+ async entriesForward(_options) {
196
240
  return emptyPage;
197
241
  },
198
- async getExpansionState() {
199
- return expansion;
242
+ async entriesBackward(_options) {
243
+ return emptyPage;
200
244
  },
201
- async setExpansionState(state) {
202
- return state;
245
+ async gotoNextSelected() {
246
+ return false;
203
247
  },
204
- async expand(rowKey) {
205
- return {
206
- mode: "collapsed",
207
- ids: [rowKey]
248
+ async gotoPrevSelected() {
249
+ return false;
250
+ },
251
+ async select(origin, docId, selectParentCategories = false) {
252
+ const key = `${origin}:${docId}`;
253
+ selection = {
254
+ ...selection,
255
+ entryKeys: Array.from(/* @__PURE__ */ new Set([...selection.entryKeys, key]))
256
+ };
257
+ if (selectParentCategories) {
258
+ selection = {
259
+ ...selection,
260
+ entryKeys: [...selection.entryKeys]
261
+ };
262
+ }
263
+ },
264
+ async deselect(origin, docId) {
265
+ const key = `${origin}:${docId}`;
266
+ selection = {
267
+ ...selection,
268
+ entryKeys: selection.entryKeys.filter((entry) => entry !== key)
208
269
  };
209
270
  },
210
- async collapse(_rowKey) {
211
- return expansion;
271
+ async selectAllEntries() {
272
+ selection = {
273
+ selectAllByDefault: true,
274
+ entryKeys: []
275
+ };
276
+ },
277
+ async deselectAllEntries() {
278
+ selection = {
279
+ selectAllByDefault: false,
280
+ entryKeys: []
281
+ };
282
+ },
283
+ async isSelected(origin, docId) {
284
+ const key = `${origin}:${docId}`;
285
+ return selection.selectAllByDefault ? !selection.entryKeys.includes(key) : selection.entryKeys.includes(key);
286
+ },
287
+ async getSelectionState() {
288
+ return selection;
289
+ },
290
+ async setSelectionState(state) {
291
+ selection = {
292
+ selectAllByDefault: state.selectAllByDefault,
293
+ entryKeys: [...state.entryKeys]
294
+ };
295
+ },
296
+ async expand(origin, docId) {
297
+ const key = `${origin}:${docId}`;
298
+ expansion = {
299
+ ...expansion,
300
+ entryKeys: Array.from(/* @__PURE__ */ new Set([...expansion.entryKeys, key]))
301
+ };
302
+ },
303
+ async collapse(origin, docId) {
304
+ const key = `${origin}:${docId}`;
305
+ expansion = {
306
+ ...expansion,
307
+ entryKeys: expansion.entryKeys.filter((entry) => entry !== key)
308
+ };
212
309
  },
213
310
  async expandAll() {
214
- return {
215
- mode: "expanded",
216
- ids: []
311
+ expansion = {
312
+ expandAllByDefault: true,
313
+ expandLevel: expansion.expandLevel,
314
+ entryKeys: []
217
315
  };
218
316
  },
219
317
  async collapseAll() {
318
+ expansion = {
319
+ expandAllByDefault: false,
320
+ expandLevel: 0,
321
+ entryKeys: []
322
+ };
323
+ },
324
+ async expandToLevel(level) {
325
+ expansion = {
326
+ ...expansion,
327
+ expandLevel: level
328
+ };
329
+ },
330
+ async isExpanded(_entryKey) {
331
+ return expansion.expandAllByDefault;
332
+ },
333
+ async getExpansionState() {
220
334
  return expansion;
221
335
  },
222
- async getRow(_rowKey) {
223
- return null;
336
+ async setExpansionState(state) {
337
+ expansion = {
338
+ expandAllByDefault: state.expandAllByDefault,
339
+ expandLevel: state.expandLevel,
340
+ entryKeys: [...state.entryKeys]
341
+ };
224
342
  },
225
- async getCategory(_input) {
226
- return null;
343
+ async childEntries(_entryKey, _descending) {
344
+ return [];
227
345
  },
228
- async pageCategory(_categoryKey, _input) {
229
- return emptyPage;
346
+ async childCategories(_entryKey, _descending) {
347
+ return [];
348
+ },
349
+ async childDocuments(_entryKey, _descending) {
350
+ return [];
351
+ },
352
+ async childCategoriesByKey(_entryKey, _key, _exact, _descending) {
353
+ return [];
354
+ },
355
+ async childDocumentsByKey(_entryKey, _key, _exact, _descending) {
356
+ return [];
357
+ },
358
+ async childCategoriesBetween(_entryKey, _range) {
359
+ return [];
360
+ },
361
+ async childDocumentsBetween(_entryKey, _range) {
362
+ return [];
230
363
  },
231
- async listCategoryDocumentIds(_categoryKey) {
364
+ async getSortedDocIds(_descending) {
365
+ return [];
366
+ },
367
+ async getSortedDocIdsScoped(_entryKey, _descending) {
232
368
  return [];
233
369
  },
234
370
  async dispose() {
@@ -237,7 +373,7 @@ function createDefaultViewHandle() {
237
373
  }
238
374
  function createDatabaseHandle(definition) {
239
375
  let createCounter = 0;
240
- const defaultViewFactory = async () => createDefaultViewHandle();
376
+ const defaultViewFactory = async () => createDefaultViewNavigator();
241
377
  const storedDocuments = /* @__PURE__ */ new Map();
242
378
  const defaultDocuments = {
243
379
  async list(query) {
@@ -341,7 +477,7 @@ function createDatabaseHandle(definition) {
341
477
  }
342
478
  };
343
479
  const defaultViews = {
344
- async create(_definition) {
480
+ async create(_input) {
345
481
  return await defaultViewFactory();
346
482
  },
347
483
  async open(_viewId) {
@@ -404,11 +540,11 @@ function createMockSessionState(options = {}) {
404
540
  for (const definition of definitions) {
405
541
  databaseHandles.set(definition.info.id, createDatabaseHandle(definition));
406
542
  databaseViewApis.set(definition.info.id, {
407
- async create(_definition) {
408
- return await createDefaultViewHandle();
543
+ async create(_input) {
544
+ return await createDefaultViewNavigator();
409
545
  },
410
546
  async open(_viewId) {
411
- return await createDefaultViewHandle();
547
+ return await createDefaultViewNavigator();
412
548
  },
413
549
  ...definition.methods?.views ?? {}
414
550
  });
@@ -433,17 +569,21 @@ function createMockSessionState(options = {}) {
433
569
  }
434
570
  return database;
435
571
  },
436
- async createView(input) {
437
- const api = databaseViewApis.get(input.databaseId);
572
+ async createViewNavigator(input) {
573
+ const firstDatabaseId = input.databaseIds[0];
574
+ if (!firstDatabaseId) {
575
+ throw new Error("At least one test database is required for view creation.");
576
+ }
577
+ const api = databaseViewApis.get(firstDatabaseId);
438
578
  if (!api) {
439
- throw new Error(`Unknown test database for view creation: ${input.databaseId}`);
579
+ throw new Error(`Unknown test database for view creation: ${firstDatabaseId}`);
440
580
  }
441
- const view = await api.create(input.definition);
581
+ const view = await api.create(input);
442
582
  const viewId = input.definition.id || crypto.randomUUID();
443
583
  sessionViews.set(viewId, view);
444
584
  return view;
445
585
  },
446
- async openView(viewId) {
586
+ async openViewNavigator(viewId, options2) {
447
587
  const existing = sessionViews.get(viewId);
448
588
  if (existing) {
449
589
  return existing;
@@ -456,7 +596,7 @@ function createMockSessionState(options = {}) {
456
596
  if (!api) {
457
597
  throw new Error(`Unknown test database for view ${viewId}: ${sourceDatabaseId}`);
458
598
  }
459
- const view = await api.open(viewId);
599
+ const view = await api.open(viewId, options2);
460
600
  sessionViews.set(viewId, view);
461
601
  return view;
462
602
  },
@@ -503,8 +643,8 @@ function createMockSessionState(options = {}) {
503
643
  }
504
644
  return database;
505
645
  },
506
- createView: session.createView,
507
- openView: session.openView,
646
+ createViewNavigator: session.createViewNavigator,
647
+ openViewNavigator: session.openViewNavigator,
508
648
  bridge,
509
649
  session,
510
650
  emitThemeChange(theme) {
@@ -634,14 +774,14 @@ function createFakeBridgeHost(options = {}) {
634
774
  });
635
775
  installed = true;
636
776
  }
637
- async function resolveViewHandle(viewId) {
777
+ async function resolveViewNavigator(viewId) {
638
778
  const existing = viewSessions.get(viewId);
639
779
  if (existing) {
640
780
  return existing;
641
781
  }
642
- const handle = await state.openView(viewId);
643
- viewSessions.set(viewId, handle);
644
- return handle;
782
+ const navigator = await state.openViewNavigator(viewId);
783
+ viewSessions.set(viewId, navigator);
784
+ return navigator;
645
785
  }
646
786
  function postRpcSuccess(port, requestId, result) {
647
787
  port.postMessage({
@@ -684,18 +824,25 @@ function createFakeBridgeHost(options = {}) {
684
824
  case "session.openDatabase":
685
825
  state.getDatabase(String(params.databaseId));
686
826
  return { ok: true };
687
- case "session.createView": {
688
- const viewId = `view-${viewCounter += 1}`;
689
- const handle = await state.createView({
690
- databaseId: String(params.databaseId),
691
- definition: params.definition
827
+ case "session.createViewNavigator": {
828
+ const navigatorId = `navigator-${viewCounter += 1}`;
829
+ const navigator = await state.createViewNavigator({
830
+ databaseIds: Array.isArray(params.databaseIds) ? params.databaseIds.map((entry) => String(entry)) : [],
831
+ definition: params.definition,
832
+ options: params.options
692
833
  });
693
- viewSessions.set(viewId, handle);
694
- return { viewId };
834
+ viewSessions.set(navigatorId, navigator);
835
+ return { navigatorId };
836
+ }
837
+ case "session.openViewNavigator": {
838
+ const navigatorId = `navigator-${viewCounter += 1}`;
839
+ const navigator = await state.openViewNavigator(
840
+ String(params.viewId),
841
+ params.options
842
+ );
843
+ viewSessions.set(navigatorId, navigator);
844
+ return { navigatorId };
695
845
  }
696
- case "session.openView":
697
- await state.openView(String(params.viewId));
698
- return { ok: true };
699
846
  case "session.disconnect":
700
847
  await state.session.disconnect();
701
848
  return { ok: true };
@@ -757,47 +904,131 @@ function createFakeBridgeHost(options = {}) {
757
904
  String(params.attachmentName),
758
905
  typeof params.timestamp === "number" ? { timestamp: params.timestamp } : void 0
759
906
  );
760
- case "views.getDefinition":
761
- return await (await resolveViewHandle(String(params.viewId))).getDefinition();
762
- case "views.refresh":
763
- return await (await resolveViewHandle(String(params.viewId))).refresh();
764
- case "views.page":
765
- return await (await resolveViewHandle(String(params.viewId))).page(
766
- params.request
907
+ case "viewNavigators.getDefinition":
908
+ return await (await resolveViewNavigator(String(params.navigatorId))).getDefinition();
909
+ case "viewNavigators.refresh":
910
+ return await (await resolveViewNavigator(String(params.navigatorId))).refresh();
911
+ case "viewNavigators.current.get":
912
+ return await (await resolveViewNavigator(String(params.navigatorId))).getCurrentEntry();
913
+ case "viewNavigators.goto.first":
914
+ return await (await resolveViewNavigator(String(params.navigatorId))).gotoFirst();
915
+ case "viewNavigators.goto.last":
916
+ return await (await resolveViewNavigator(String(params.navigatorId))).gotoLast();
917
+ case "viewNavigators.goto.next":
918
+ return await (await resolveViewNavigator(String(params.navigatorId))).gotoNext();
919
+ case "viewNavigators.goto.prev":
920
+ return await (await resolveViewNavigator(String(params.navigatorId))).gotoPrev();
921
+ case "viewNavigators.goto.nextSibling":
922
+ return await (await resolveViewNavigator(String(params.navigatorId))).gotoNextSibling();
923
+ case "viewNavigators.goto.prevSibling":
924
+ return await (await resolveViewNavigator(String(params.navigatorId))).gotoPrevSibling();
925
+ case "viewNavigators.goto.parent":
926
+ return await (await resolveViewNavigator(String(params.navigatorId))).gotoParent();
927
+ case "viewNavigators.goto.firstChild":
928
+ return await (await resolveViewNavigator(String(params.navigatorId))).gotoFirstChild();
929
+ case "viewNavigators.goto.lastChild":
930
+ return await (await resolveViewNavigator(String(params.navigatorId))).gotoLastChild();
931
+ case "viewNavigators.goto.pos":
932
+ return await (await resolveViewNavigator(String(params.navigatorId))).gotoPos(String(params.position));
933
+ case "viewNavigators.pos.get":
934
+ return await (await resolveViewNavigator(String(params.navigatorId))).getPos(String(params.position));
935
+ case "viewNavigators.category.findByParts":
936
+ return await (await resolveViewNavigator(String(params.navigatorId))).findCategoryEntryByParts(
937
+ Array.isArray(params.parts) ? params.parts : []
938
+ );
939
+ case "viewNavigators.entries.forward":
940
+ return await (await resolveViewNavigator(String(params.navigatorId))).entriesForward(
941
+ params.options
942
+ );
943
+ case "viewNavigators.entries.backward":
944
+ return await (await resolveViewNavigator(String(params.navigatorId))).entriesBackward(
945
+ params.options
946
+ );
947
+ case "viewNavigators.goto.nextSelected":
948
+ return await (await resolveViewNavigator(String(params.navigatorId))).gotoNextSelected();
949
+ case "viewNavigators.goto.prevSelected":
950
+ return await (await resolveViewNavigator(String(params.navigatorId))).gotoPrevSelected();
951
+ case "viewNavigators.selection.select":
952
+ return await (await resolveViewNavigator(String(params.navigatorId))).select(
953
+ String(params.origin),
954
+ String(params.docId),
955
+ Boolean(params.selectParentCategories)
956
+ );
957
+ case "viewNavigators.selection.deselect":
958
+ return await (await resolveViewNavigator(String(params.navigatorId))).deselect(String(params.origin), String(params.docId));
959
+ case "viewNavigators.selection.selectAll":
960
+ return await (await resolveViewNavigator(String(params.navigatorId))).selectAllEntries();
961
+ case "viewNavigators.selection.deselectAll":
962
+ return await (await resolveViewNavigator(String(params.navigatorId))).deselectAllEntries();
963
+ case "viewNavigators.selection.isSelected":
964
+ return await (await resolveViewNavigator(String(params.navigatorId))).isSelected(String(params.origin), String(params.docId));
965
+ case "viewNavigators.selection.get":
966
+ return await (await resolveViewNavigator(String(params.navigatorId))).getSelectionState();
967
+ case "viewNavigators.selection.set":
968
+ return await (await resolveViewNavigator(String(params.navigatorId))).setSelectionState(
969
+ params.state
970
+ );
971
+ case "viewNavigators.expansion.expand":
972
+ return await (await resolveViewNavigator(String(params.navigatorId))).expand(String(params.origin), String(params.docId));
973
+ case "viewNavigators.expansion.collapse":
974
+ return await (await resolveViewNavigator(String(params.navigatorId))).collapse(String(params.origin), String(params.docId));
975
+ case "viewNavigators.expansion.expandAll":
976
+ return await (await resolveViewNavigator(String(params.navigatorId))).expandAll();
977
+ case "viewNavigators.expansion.collapseAll":
978
+ return await (await resolveViewNavigator(String(params.navigatorId))).collapseAll();
979
+ case "viewNavigators.expansion.expandToLevel":
980
+ return await (await resolveViewNavigator(String(params.navigatorId))).expandToLevel(Number(params.level));
981
+ case "viewNavigators.expansion.isExpanded":
982
+ return await (await resolveViewNavigator(String(params.navigatorId))).isExpanded(String(params.entryKey));
983
+ case "viewNavigators.expansion.get":
984
+ return await (await resolveViewNavigator(String(params.navigatorId))).getExpansionState();
985
+ case "viewNavigators.expansion.set":
986
+ return await (await resolveViewNavigator(String(params.navigatorId))).setExpansionState(
987
+ params.state
988
+ );
989
+ case "viewNavigators.children.entries":
990
+ return await (await resolveViewNavigator(String(params.navigatorId))).childEntries(String(params.entryKey), Boolean(params.descending));
991
+ case "viewNavigators.children.categories":
992
+ return await (await resolveViewNavigator(String(params.navigatorId))).childCategories(String(params.entryKey), Boolean(params.descending));
993
+ case "viewNavigators.children.documents":
994
+ return await (await resolveViewNavigator(String(params.navigatorId))).childDocuments(String(params.entryKey), Boolean(params.descending));
995
+ case "viewNavigators.children.categoriesByKey":
996
+ return await (await resolveViewNavigator(String(params.navigatorId))).childCategoriesByKey(
997
+ String(params.entryKey),
998
+ params.key,
999
+ typeof params.exact === "boolean" ? params.exact : void 0,
1000
+ typeof params.descending === "boolean" ? params.descending : void 0
1001
+ );
1002
+ case "viewNavigators.children.documentsByKey":
1003
+ return await (await resolveViewNavigator(String(params.navigatorId))).childDocumentsByKey(
1004
+ String(params.entryKey),
1005
+ params.key,
1006
+ typeof params.exact === "boolean" ? params.exact : void 0,
1007
+ typeof params.descending === "boolean" ? params.descending : void 0
767
1008
  );
768
- case "views.expansion.get":
769
- return await (await resolveViewHandle(String(params.viewId))).getExpansionState();
770
- case "views.expansion.set":
771
- return await (await resolveViewHandle(String(params.viewId))).setExpansionState(
772
- params.expansion
1009
+ case "viewNavigators.children.categoriesBetween":
1010
+ return await (await resolveViewNavigator(String(params.navigatorId))).childCategoriesBetween(
1011
+ String(params.entryKey),
1012
+ params.range
773
1013
  );
774
- case "views.expansion.expand":
775
- return await (await resolveViewHandle(String(params.viewId))).expand(String(params.rowKey));
776
- case "views.expansion.collapse":
777
- return await (await resolveViewHandle(String(params.viewId))).collapse(String(params.rowKey));
778
- case "views.expansion.expandAll":
779
- return await (await resolveViewHandle(String(params.viewId))).expandAll();
780
- case "views.expansion.collapseAll":
781
- return await (await resolveViewHandle(String(params.viewId))).collapseAll();
782
- case "views.row.get":
783
- return await (await resolveViewHandle(String(params.viewId))).getRow(String(params.rowKey));
784
- case "views.category.get":
785
- return await (await resolveViewHandle(String(params.viewId))).getCategory(
786
- params.lookup
1014
+ case "viewNavigators.children.documentsBetween":
1015
+ return await (await resolveViewNavigator(String(params.navigatorId))).childDocumentsBetween(
1016
+ String(params.entryKey),
1017
+ params.range
787
1018
  );
788
- case "views.category.page":
789
- return await (await resolveViewHandle(String(params.viewId))).pageCategory(
790
- String(params.categoryKey),
791
- params.request
1019
+ case "viewNavigators.sortedDocIds.get":
1020
+ return await (await resolveViewNavigator(String(params.navigatorId))).getSortedDocIds(
1021
+ typeof params.descending === "boolean" ? params.descending : void 0
792
1022
  );
793
- case "views.category.documentIds":
794
- return await (await resolveViewHandle(String(params.viewId))).listCategoryDocumentIds(
795
- String(params.categoryKey)
1023
+ case "viewNavigators.sortedDocIds.scoped":
1024
+ return await (await resolveViewNavigator(String(params.navigatorId))).getSortedDocIdsScoped(
1025
+ String(params.entryKey),
1026
+ typeof params.descending === "boolean" ? params.descending : void 0
796
1027
  );
797
- case "views.dispose": {
798
- const key = String(params.viewId);
799
- const handle = await resolveViewHandle(String(params.viewId));
800
- await handle.dispose();
1028
+ case "viewNavigators.dispose": {
1029
+ const key = String(params.navigatorId);
1030
+ const navigator = await resolveViewNavigator(key);
1031
+ await navigator.dispose();
801
1032
  viewSessions.delete(key);
802
1033
  return void 0;
803
1034
  }
@@ -877,7 +1108,7 @@ function createFakeBridgeHost(options = {}) {
877
1108
  return;
878
1109
  }
879
1110
  const builtinResult = await handleBuiltinRequest(message);
880
- if (builtinResult === void 0 && message.method !== "views.dispose") {
1111
+ if (builtinResult === void 0 && message.method !== "viewNavigators.dispose") {
881
1112
  postRpcError(port, message.id, {
882
1113
  code: "unsupported-method",
883
1114
  message: `No fake bridge handler is configured for ${message.method}.`
@@ -1,4 +1,4 @@
1
- import { MindooDBAppBooleanExpression, MindooDBAppExpression, MindooDBAppViewSortDirection, MindooDBAppViewTotalMode, MindooDBAppViewDefinition, MindooDBAppViewPageRequest, MindooDBAppViewPageResult, MindooDBAppViewExpansionState, MindooDBAppViewRow, MindooDBAppViewLookupByPath, MindooDBAppViewCategoryChildrenPageRequest } from 'mindoodb-view-language';
1
+ import { MindooDBAppBooleanExpression, MindooDBAppExpression, MindooDBAppViewSortDirection, MindooDBAppViewTotalMode, MindooDBAppViewDefinition } from 'mindoodb-view-language';
2
2
 
3
3
  /** Launch target used by the Administrator when opening an app. */
4
4
  type MindooDBAppRuntime = "iframe" | "window";
@@ -336,28 +336,125 @@ interface MindooDBAppDocumentApi {
336
336
  listHistory(docId: string): Promise<MindooDBAppDocumentHistoryEntry[]>;
337
337
  getAtTimestamp(docId: string, timestamp: number): Promise<MindooDBAppHistoricalDocument>;
338
338
  }
339
- /** Handle for one created or opened virtual view. */
340
- interface MindooDBAppViewHandle {
339
+ type MindooDBAppViewEntryKind = "category" | "document";
340
+ /** Unique document identity within a multi-source view. */
341
+ interface MindooDBAppScopedDocId {
342
+ origin: string;
343
+ docId: string;
344
+ }
345
+ /** Serialized view entry returned by the navigator APIs. */
346
+ interface MindooDBAppViewEntry {
347
+ /** Unique occurrence key within the current navigator session. */
348
+ key: string;
349
+ kind: MindooDBAppViewEntryKind;
350
+ origin: string;
351
+ docId: string | null;
352
+ level: number;
353
+ parentKey: string | null;
354
+ categoryPath: unknown[];
355
+ columnValues: Record<string, unknown>;
356
+ descendantDocumentCount: number;
357
+ childCategoryCount: number;
358
+ childDocumentCount: number;
359
+ /** Stable continuation token for the current occurrence. */
360
+ position: string | null;
361
+ expanded: boolean;
362
+ selected: boolean;
363
+ isVisible: boolean;
364
+ }
365
+ /** Options that shape which subtree and entry kinds a navigator exposes. */
366
+ interface MindooDBAppViewNavigatorOpenOptions {
367
+ includeCategories?: boolean;
368
+ includeDocuments?: boolean;
369
+ hideEmptyCategories?: boolean;
370
+ rootCategoryPath?: unknown[];
371
+ rootEntryKey?: string;
372
+ }
373
+ /** Input used when creating a dynamic view and immediately opening a navigator. */
374
+ interface MindooDBAppCreateViewNavigatorInput {
375
+ databaseIds: string[];
376
+ definition: MindooDBAppViewDefinition;
377
+ options?: MindooDBAppViewNavigatorOpenOptions;
378
+ }
379
+ /** @deprecated Use `MindooDBAppCreateViewNavigatorInput`. */
380
+ type MindooDBAppCreateViewInput = MindooDBAppCreateViewNavigatorInput;
381
+ /** Range query options for key and key-range lookups within a category. */
382
+ interface MindooDBAppViewNavigatorRangeQuery {
383
+ startKey?: unknown;
384
+ endKey?: unknown;
385
+ descending?: boolean;
386
+ exact?: boolean;
387
+ }
388
+ /** Options for batched navigator reads. */
389
+ interface MindooDBAppViewNavigatorPageOptions {
390
+ limit?: number;
391
+ selectedOnly?: boolean;
392
+ startPosition?: string | null;
393
+ }
394
+ /** Paged batch of navigator entries. */
395
+ interface MindooDBAppViewNavigatorPageResult {
396
+ entries: MindooDBAppViewEntry[];
397
+ nextPosition: string | null;
398
+ hasMore: boolean;
399
+ }
400
+ /** Serializable selection state for restoring a navigator session. */
401
+ interface MindooDBAppViewNavigatorSelectionState {
402
+ selectAllByDefault: boolean;
403
+ entryKeys: string[];
404
+ }
405
+ /** Serializable expansion state for restoring a navigator session. */
406
+ interface MindooDBAppViewNavigatorExpansionState {
407
+ expandAllByDefault: boolean;
408
+ expandLevel: number;
409
+ entryKeys: string[];
410
+ }
411
+ /** Stateful view navigator that closely mirrors the core VirtualViewNavigator. */
412
+ interface MindooDBAppViewNavigator {
341
413
  getDefinition(): Promise<MindooDBAppViewDefinition>;
342
414
  refresh(): Promise<void>;
343
- page(input?: MindooDBAppViewPageRequest): Promise<MindooDBAppViewPageResult>;
344
- getExpansionState(): Promise<MindooDBAppViewExpansionState>;
345
- setExpansionState(state: MindooDBAppViewExpansionState): Promise<MindooDBAppViewExpansionState>;
346
- expand(rowKey: string): Promise<MindooDBAppViewExpansionState>;
347
- collapse(rowKey: string): Promise<MindooDBAppViewExpansionState>;
348
- expandAll(): Promise<MindooDBAppViewExpansionState>;
349
- collapseAll(): Promise<MindooDBAppViewExpansionState>;
350
- getRow(rowKey: string): Promise<MindooDBAppViewRow | null>;
351
- getCategory(input: MindooDBAppViewLookupByPath): Promise<MindooDBAppViewRow | null>;
352
- pageCategory(categoryKey: string, input?: MindooDBAppViewCategoryChildrenPageRequest): Promise<MindooDBAppViewPageResult>;
353
- listCategoryDocumentIds(categoryKey: string): Promise<string[]>;
415
+ getCurrentEntry(): Promise<MindooDBAppViewEntry | null>;
416
+ gotoFirst(): Promise<boolean>;
417
+ gotoLast(): Promise<boolean>;
418
+ gotoNext(): Promise<boolean>;
419
+ gotoPrev(): Promise<boolean>;
420
+ gotoNextSibling(): Promise<boolean>;
421
+ gotoPrevSibling(): Promise<boolean>;
422
+ gotoParent(): Promise<boolean>;
423
+ gotoFirstChild(): Promise<boolean>;
424
+ gotoLastChild(): Promise<boolean>;
425
+ gotoPos(position: string): Promise<boolean>;
426
+ getPos(position: string): Promise<MindooDBAppViewEntry | null>;
427
+ findCategoryEntryByParts(parts: unknown[]): Promise<MindooDBAppViewEntry | null>;
428
+ entriesForward(options?: MindooDBAppViewNavigatorPageOptions): Promise<MindooDBAppViewNavigatorPageResult>;
429
+ entriesBackward(options?: MindooDBAppViewNavigatorPageOptions): Promise<MindooDBAppViewNavigatorPageResult>;
430
+ gotoNextSelected(): Promise<boolean>;
431
+ gotoPrevSelected(): Promise<boolean>;
432
+ select(origin: string, docId: string, selectParentCategories?: boolean): Promise<void>;
433
+ deselect(origin: string, docId: string): Promise<void>;
434
+ selectAllEntries(): Promise<void>;
435
+ deselectAllEntries(): Promise<void>;
436
+ isSelected(origin: string, docId: string): Promise<boolean>;
437
+ getSelectionState(): Promise<MindooDBAppViewNavigatorSelectionState>;
438
+ setSelectionState(state: MindooDBAppViewNavigatorSelectionState): Promise<void>;
439
+ expand(origin: string, docId: string): Promise<void>;
440
+ collapse(origin: string, docId: string): Promise<void>;
441
+ expandAll(): Promise<void>;
442
+ collapseAll(): Promise<void>;
443
+ expandToLevel(level: number): Promise<void>;
444
+ isExpanded(entryKey: string): Promise<boolean>;
445
+ getExpansionState(): Promise<MindooDBAppViewNavigatorExpansionState>;
446
+ setExpansionState(state: MindooDBAppViewNavigatorExpansionState): Promise<void>;
447
+ childEntries(entryKey: string, descending?: boolean): Promise<MindooDBAppViewEntry[]>;
448
+ childCategories(entryKey: string, descending?: boolean): Promise<MindooDBAppViewEntry[]>;
449
+ childDocuments(entryKey: string, descending?: boolean): Promise<MindooDBAppViewEntry[]>;
450
+ childCategoriesByKey(entryKey: string, key: unknown, exact?: boolean, descending?: boolean): Promise<MindooDBAppViewEntry[]>;
451
+ childDocumentsByKey(entryKey: string, key: unknown, exact?: boolean, descending?: boolean): Promise<MindooDBAppViewEntry[]>;
452
+ childCategoriesBetween(entryKey: string, range: MindooDBAppViewNavigatorRangeQuery): Promise<MindooDBAppViewEntry[]>;
453
+ childDocumentsBetween(entryKey: string, range: MindooDBAppViewNavigatorRangeQuery): Promise<MindooDBAppViewEntry[]>;
454
+ getSortedDocIds(descending?: boolean): Promise<MindooDBAppScopedDocId[]>;
455
+ getSortedDocIdsScoped(entryKey: string, descending?: boolean): Promise<MindooDBAppScopedDocId[]>;
354
456
  dispose(): Promise<void>;
355
457
  }
356
- /** Payload used when creating one dynamic view inside the current app session. */
357
- interface MindooDBAppCreateViewInput {
358
- databaseId: string;
359
- definition: MindooDBAppViewDefinition;
360
- }
361
458
  /** Attachment operations exposed by an opened database handle. */
362
459
  interface MindooDBAppAttachmentApi {
363
460
  list(docId: string): Promise<MindooDBAppAttachmentInfo[]>;
@@ -382,8 +479,8 @@ interface MindooDBAppSession {
382
479
  getLaunchContext(): Promise<MindooDBAppLaunchContext>;
383
480
  listDatabases(): Promise<MindooDBAppDatabaseInfo[]>;
384
481
  openDatabase(databaseId: string): Promise<MindooDBAppDatabase>;
385
- createView(input: MindooDBAppCreateViewInput): Promise<MindooDBAppViewHandle>;
386
- openView(viewId: string): Promise<MindooDBAppViewHandle>;
482
+ createViewNavigator(input: MindooDBAppCreateViewNavigatorInput): Promise<MindooDBAppViewNavigator>;
483
+ openViewNavigator(viewId: string, options?: MindooDBAppViewNavigatorOpenOptions): Promise<MindooDBAppViewNavigator>;
387
484
  onThemeChange(listener: (theme: MindooDBAppHostTheme) => void): () => void;
388
485
  onViewportChange(listener: (viewport: MindooDBAppViewport) => void): () => void;
389
486
  disconnect(): Promise<void>;
@@ -393,4 +490,4 @@ interface MindooDBAppBridge {
393
490
  connect(options?: MindooDBAppBridgeConnectOptions): Promise<MindooDBAppSession>;
394
491
  }
395
492
 
396
- export type { MindooDBAppHistoryQuery as $, MindooDBAppConfiguredViewCategorizationStyle as A, MindooDBAppConfiguredViewColumn as B, MindooDBAppConfiguredViewColumnRole as C, MindooDBAppConfiguredViewExpressionMode as D, MindooDBAppConfiguredViewFieldExpression as E, MindooDBAppConfiguredViewFilterDefinition as F, MindooDBAppConfiguredViewFilterMode as G, MindooDBAppConfiguredViewFilterRule as H, MindooDBAppConfiguredViewFormulaExpression as I, MindooDBAppConfiguredViewFormulaFilterDefinition as J, MindooDBAppConfiguredViewPreviewMode as K, MindooDBAppConfiguredViewRuleFilterDefinition as L, MindooDBAppAttachmentPreviewMode as M, MindooDBAppConfiguredViewRuleMatchMode as N, MindooDBAppConfiguredViewRuleOperator as O, MindooDBAppConfiguredViewValueExpression as P, MindooDBAppCreateDocumentInput as Q, MindooDBAppCreateViewInput as R, MindooDBAppDatabase as S, MindooDBAppDatabaseInfo as T, MindooDBAppDocument as U, MindooDBAppDocumentApi as V, MindooDBAppDocumentHistoryEntry as W, MindooDBAppDocumentListQuery as X, MindooDBAppDocumentListResult as Y, MindooDBAppDocumentSummary as Z, MindooDBAppHistoricalDocument as _, MindooDBAppBridge as a, MindooDBAppHostTheme as a0, MindooDBAppLaunchContext as a1, MindooDBAppReadableAttachmentStream as a2, MindooDBAppResolvedViewDefinition as a3, MindooDBAppResolvedViewSource as a4, MindooDBAppRuntime as a5, MindooDBAppSession as a6, MindooDBAppThemeMode as a7, MindooDBAppUpdateDocumentInput as a8, MindooDBAppViewHandle as a9, MindooDBAppViewport as aa, MindooDBAppWritableAttachmentStream as ab, MindooDBAppAttachmentApi as b, MindooDBAppAttachmentChunk as c, MindooDBAppAttachmentInfo as d, MindooDBAppAttachmentPreviewOptions as e, MindooDBAppAttachmentPreviewSession as f, MindooDBAppBridgeConnectMessage as g, MindooDBAppBridgeConnectOptions as h, MindooDBAppBridgeConnectedMessage as i, MindooDBAppBridgeErrorPayload as j, MindooDBAppBridgePortMessage as k, MindooDBAppBridgeRpcError as l, MindooDBAppBridgeRpcMessage as m, MindooDBAppBridgeRpcRequest as n, MindooDBAppBridgeRpcSuccess as o, MindooDBAppBridgeStreamAbortRequest as p, MindooDBAppBridgeStreamAck as q, MindooDBAppBridgeStreamCloseRequest as r, MindooDBAppBridgeStreamError as s, MindooDBAppBridgeStreamMessage as t, MindooDBAppBridgeStreamOpenResult as u, MindooDBAppBridgeStreamReadRequest as v, MindooDBAppBridgeStreamWriteRequest as w, MindooDBAppBridgeThemeChangedMessage as x, MindooDBAppBridgeViewportChangedMessage as y, MindooDBAppCapability as z };
493
+ export type { MindooDBAppHistoricalDocument as $, MindooDBAppConfiguredViewCategorizationStyle as A, MindooDBAppConfiguredViewColumn as B, MindooDBAppConfiguredViewColumnRole as C, MindooDBAppConfiguredViewExpressionMode as D, MindooDBAppConfiguredViewFieldExpression as E, MindooDBAppConfiguredViewFilterDefinition as F, MindooDBAppConfiguredViewFilterMode as G, MindooDBAppConfiguredViewFilterRule as H, MindooDBAppConfiguredViewFormulaExpression as I, MindooDBAppConfiguredViewFormulaFilterDefinition as J, MindooDBAppConfiguredViewPreviewMode as K, MindooDBAppConfiguredViewRuleFilterDefinition as L, MindooDBAppAttachmentPreviewMode as M, MindooDBAppConfiguredViewRuleMatchMode as N, MindooDBAppConfiguredViewRuleOperator as O, MindooDBAppConfiguredViewValueExpression as P, MindooDBAppCreateDocumentInput as Q, MindooDBAppCreateViewInput as R, MindooDBAppCreateViewNavigatorInput as S, MindooDBAppDatabase as T, MindooDBAppDatabaseInfo as U, MindooDBAppDocument as V, MindooDBAppDocumentApi as W, MindooDBAppDocumentHistoryEntry as X, MindooDBAppDocumentListQuery as Y, MindooDBAppDocumentListResult as Z, MindooDBAppDocumentSummary as _, MindooDBAppBridge as a, MindooDBAppHistoryQuery as a0, MindooDBAppHostTheme as a1, MindooDBAppLaunchContext as a2, MindooDBAppReadableAttachmentStream as a3, MindooDBAppResolvedViewDefinition as a4, MindooDBAppResolvedViewSource as a5, MindooDBAppRuntime as a6, MindooDBAppScopedDocId as a7, MindooDBAppSession as a8, MindooDBAppThemeMode as a9, MindooDBAppUpdateDocumentInput as aa, MindooDBAppViewEntry as ab, MindooDBAppViewEntryKind as ac, MindooDBAppViewNavigator as ad, MindooDBAppViewNavigatorExpansionState as ae, MindooDBAppViewNavigatorOpenOptions as af, MindooDBAppViewNavigatorPageOptions as ag, MindooDBAppViewNavigatorPageResult as ah, MindooDBAppViewNavigatorRangeQuery as ai, MindooDBAppViewNavigatorSelectionState as aj, MindooDBAppViewport as ak, MindooDBAppWritableAttachmentStream as al, MindooDBAppAttachmentApi as b, MindooDBAppAttachmentChunk as c, MindooDBAppAttachmentInfo as d, MindooDBAppAttachmentPreviewOptions as e, MindooDBAppAttachmentPreviewSession as f, MindooDBAppBridgeConnectMessage as g, MindooDBAppBridgeConnectOptions as h, MindooDBAppBridgeConnectedMessage as i, MindooDBAppBridgeErrorPayload as j, MindooDBAppBridgePortMessage as k, MindooDBAppBridgeRpcError as l, MindooDBAppBridgeRpcMessage as m, MindooDBAppBridgeRpcRequest as n, MindooDBAppBridgeRpcSuccess as o, MindooDBAppBridgeStreamAbortRequest as p, MindooDBAppBridgeStreamAck as q, MindooDBAppBridgeStreamCloseRequest as r, MindooDBAppBridgeStreamError as s, MindooDBAppBridgeStreamMessage as t, MindooDBAppBridgeStreamOpenResult as u, MindooDBAppBridgeStreamReadRequest as v, MindooDBAppBridgeStreamWriteRequest as w, MindooDBAppBridgeThemeChangedMessage as x, MindooDBAppBridgeViewportChangedMessage as y, MindooDBAppCapability as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mindoodb-app-sdk",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
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",