mindoodb-app-sdk 0.0.49 → 0.0.51

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.
@@ -1,4 +1,4 @@
1
- import { as as MindooDBAppCreateViewNavigatorInput, cl as MindooDBAppViewNavigator, bd as MindooDBAppLaunchContext, at as MindooDBAppDatabaseInfo, aB as MindooDBAppDocumentApi, cn as MindooDBAppViewNavigatorOpenOptions, v as MindooDBAppAttachmentApi, b1 as MindooDBAppIdentityApi, cb as MindooDBAppTimestampApi, az as MindooDBAppDirectoryApi, j as MindooDBAppDocument, aZ as MindooDBAppFulltextSetup, aY as MindooDBAppExtractionSetup, bs as MindooDBAppProposeAppInput, bt as MindooDBAppProposeAppResult, e as MindooDBAppBridge, c0 as MindooDBAppSession, V as MindooDBAppBridgeRpcRequest, b0 as MindooDBAppHostTheme, ct as MindooDBAppViewport, cf as MindooDBAppUiPreferences, by as MindooDBAppQueryResult, cs as MindooDBAppViewUpdateStats, R as MindooDBAppBridgePortMessage, c as MindooDBAppDragStartResult, aS as MindooDBAppDragProfile } from '../types-C-eyC839.js';
1
+ import { au as MindooDBAppCreateViewNavigatorInput, cw as MindooDBAppViewNavigator, bg as MindooDBAppLaunchContext, av as MindooDBAppDatabaseInfo, aD as MindooDBAppDocumentApi, cy as MindooDBAppViewNavigatorOpenOptions, w as MindooDBAppAttachmentApi, b3 as MindooDBAppIdentityApi, cm as MindooDBAppTimestampApi, aB as MindooDBAppDirectoryApi, j as MindooDBAppDocument, a$ as MindooDBAppFulltextSetup, a_ as MindooDBAppExtractionSetup, ce as MindooDBAppSummarySetup, by as MindooDBAppProposeAppInput, bz as MindooDBAppProposeAppResult, e as MindooDBAppBridge, c6 as MindooDBAppSession, X as MindooDBAppBridgeRpcRequest, b2 as MindooDBAppHostTheme, cE as MindooDBAppViewport, cq as MindooDBAppUiPreferences, bE as MindooDBAppQueryResult, cD as MindooDBAppViewUpdateStats, T as MindooDBAppBridgePortMessage, c as MindooDBAppDragStartResult, aU as MindooDBAppDragProfile } from '../types-BLyV6Ejy.js';
2
2
  import * as mindoodb from 'mindoodb';
3
3
  import 'mindoodb-view-language';
4
4
 
@@ -72,6 +72,13 @@ interface MockMindooDBAppDatabaseDefinition {
72
72
  * their setup/bootstrap logic.
73
73
  */
74
74
  extractionSetup?: MindooDBAppExtractionSetup | null;
75
+ /**
76
+ * Initial summary buffer configuration returned by `getSummarySetup()`.
77
+ * `setSummarySetup()` overwrites it for the lifetime of the handle. The
78
+ * mock's `query()` reads the seeded documents directly and ignores this
79
+ * config — it exists so apps can test their setup/bootstrap logic.
80
+ */
81
+ summarySetup?: MindooDBAppSummarySetup | null;
75
82
  }
76
83
  /**
77
84
  * Stands in for the host-owned sealed channel.
@@ -122,6 +129,8 @@ interface MockMindooDBAppSessionController {
122
129
  emitLocaleChange(locale: string): void;
123
130
  /** Runs the app's `onBeforeClose` listeners, as the host does before a teardown. */
124
131
  emitBeforeClose(): Promise<void>;
132
+ /** Sets whether this mock launch has host focus and notifies listeners. */
133
+ emitHostFocusChange(focused: boolean): void;
125
134
  resolveDrag(result: MindooDBAppDragStartResult): void;
126
135
  getDragProfile(): MindooDBAppDragProfile | null;
127
136
  }
@@ -155,6 +164,7 @@ interface FakeBridgeHostController {
155
164
  emitViewportChange(viewport: MindooDBAppViewport): void;
156
165
  emitUiPreferencesChange(uiPreferences: MindooDBAppUiPreferences): void;
157
166
  emitLocaleChange(locale: string): void;
167
+ emitHostFocusChange(focused: boolean): void;
158
168
  /** Push a live-query result to connected apps, as the Haven host would. */
159
169
  emitQueryResult(subscriptionId: string, result: MindooDBAppQueryResult): void;
160
170
  /** Push a navigator view-changed event to connected apps. */
@@ -1,6 +1,7 @@
1
1
  import {
2
+ MINDOODB_APP_VALUE_TAG,
2
3
  releaseMindooDBAppBridgeSessions
3
- } from "../chunk-TPYDERAK.js";
4
+ } from "../chunk-R76XXRJ6.js";
4
5
 
5
6
  // src/testing/index.ts
6
7
  import * as Automerge from "@automerge/automerge";
@@ -473,7 +474,7 @@ function cloneBytes(chunk) {
473
474
  function applyDocumentUpdatePatch(current, patch) {
474
475
  const next = {
475
476
  ...structuredClone(current),
476
- ...patch.set ? structuredClone(patch.set) : {}
477
+ ...patch.set ? readMockTypedValues(patch.set) : {}
477
478
  };
478
479
  for (const key of patch.unset ?? []) {
479
480
  Reflect.deleteProperty(next, key);
@@ -496,7 +497,7 @@ function applyMockJsonPatch(target, patch) {
496
497
  return;
497
498
  }
498
499
  for (const operation of patch.set ?? []) {
499
- setValueAtPath(target, operation.path, structuredClone(operation.value));
500
+ setValueAtPath(target, operation.path, readMockTypedValues(operation.value));
500
501
  }
501
502
  for (const operation of patch.unset ?? []) {
502
503
  unsetValueAtPath(target, operation.path);
@@ -506,8 +507,13 @@ function applyMockJsonPatch(target, patch) {
506
507
  list.splice(operation.index, operation.deleteCount);
507
508
  }
508
509
  for (const operation of patch.listInsert ?? []) {
510
+ const parent = ensureParentAtPath(target, operation.path);
511
+ const leaf = operation.path[operation.path.length - 1];
512
+ if (parent[leaf] == null) {
513
+ parent[leaf] = [];
514
+ }
509
515
  const list = readListAtPath(target, operation.path);
510
- list.splice(operation.index, 0, ...structuredClone(operation.values));
516
+ list.splice(operation.index, 0, ...readMockTypedValues(operation.values));
511
517
  }
512
518
  for (const operation of patch.textSplice ?? []) {
513
519
  applyMockTextPatch(target, operation.path, [{
@@ -522,6 +528,81 @@ function applyMockJsonPatch(target, patch) {
522
528
  for (const operation of patch.textUnmark ?? []) {
523
529
  applyMockTextMarks(target, operation.path, operation.index, operation.length, Object.fromEntries(operation.names.map((name) => [name, null])), true);
524
530
  }
531
+ for (const operation of patch.counterIncrement ?? []) {
532
+ assertMockCounterAmount(operation.delta, "JSON counterIncrement delta");
533
+ const parent = ensureParentAtPath(target, operation.path);
534
+ const leaf = operation.path[operation.path.length - 1];
535
+ const current = parent[leaf];
536
+ if (current == null) {
537
+ parent[leaf] = operation.delta;
538
+ } else if (typeof current === "number") {
539
+ parent[leaf] = current + operation.delta;
540
+ } else {
541
+ throw new Error(
542
+ `Cannot increment non-counter value at ${operation.path.map(String).join(".")}`
543
+ );
544
+ }
545
+ }
546
+ }
547
+ var MOCK_CURSOR_PREFIX = "mock-cursor:";
548
+ function readMockCursorText(data, path) {
549
+ let value = data;
550
+ for (const segment of path) {
551
+ value = value?.[segment];
552
+ }
553
+ if (typeof value !== "string") {
554
+ throw new Error(
555
+ `Text cursors require an Automerge text field at '${path.map(String).join(".")}'`
556
+ );
557
+ }
558
+ return value;
559
+ }
560
+ function readMockTypedValues(value) {
561
+ if (value === null || typeof value !== "object") {
562
+ return value;
563
+ }
564
+ if (value instanceof Uint8Array) {
565
+ return value.slice();
566
+ }
567
+ if (Array.isArray(value)) {
568
+ return value.map((entry) => readMockTypedValues(entry));
569
+ }
570
+ const record = value;
571
+ if (Object.prototype.hasOwnProperty.call(record, MINDOODB_APP_VALUE_TAG)) {
572
+ switch (record[MINDOODB_APP_VALUE_TAG]) {
573
+ case "atomic":
574
+ if (typeof record.value !== "string") {
575
+ throw new Error('Typed value "atomic" needs a string value');
576
+ }
577
+ return record.value;
578
+ case "counter":
579
+ assertMockCounterAmount(record.value, 'Typed value "counter"');
580
+ return record.value;
581
+ case "timestamp":
582
+ return toMockTimestamp(record.value);
583
+ default:
584
+ throw new Error(
585
+ `Unknown typed value ${JSON.stringify(record[MINDOODB_APP_VALUE_TAG])}; the "${MINDOODB_APP_VALUE_TAG}" key is reserved`
586
+ );
587
+ }
588
+ }
589
+ return Object.fromEntries(
590
+ Object.entries(record).map(([key, entry]) => [key, readMockTypedValues(entry)])
591
+ );
592
+ }
593
+ function toMockTimestamp(value) {
594
+ const date = typeof value === "number" || typeof value === "string" && value.trim() !== "" ? new Date(value) : null;
595
+ if (!date || Number.isNaN(date.getTime())) {
596
+ throw new Error(
597
+ 'Typed value "timestamp" must be epoch milliseconds or an ISO 8601 date-time string'
598
+ );
599
+ }
600
+ return date.toISOString();
601
+ }
602
+ function assertMockCounterAmount(amount, label) {
603
+ if (typeof amount !== "number" || !Number.isSafeInteger(amount)) {
604
+ throw new Error(`${label} must be a safe integer`);
605
+ }
525
606
  }
526
607
  function setValueAtPath(target, path, value) {
527
608
  if (path.length === 0) {
@@ -1737,6 +1818,45 @@ function createDatabaseHandle(definition, peers) {
1737
1818
  spans: structuredClone(readRichTextSpansAtPath(document.data, path))
1738
1819
  };
1739
1820
  },
1821
+ // Mock cursors store the index they were created at and do not follow
1822
+ // later edits; Haven's Automerge-backed cursors do.
1823
+ async getTextCursors(docId, path, positions, options) {
1824
+ const document = storedDocuments.get(docId);
1825
+ if (!document || document.isDeleted) {
1826
+ throw new Error(`Document ${docId} was not found.`);
1827
+ }
1828
+ const text = readMockCursorText(document.data, path);
1829
+ return {
1830
+ path: [...path],
1831
+ heads: options?.heads ? [...options.heads] : [...document.heads ?? []],
1832
+ cursors: positions.map((position) => {
1833
+ if (position === "start") return `${MOCK_CURSOR_PREFIX}0`;
1834
+ if (position === "end") return `${MOCK_CURSOR_PREFIX}end`;
1835
+ if (typeof position !== "number" || !Number.isFinite(position)) {
1836
+ throw new Error('Text cursor positions must be numbers, "start" or "end"');
1837
+ }
1838
+ return `${MOCK_CURSOR_PREFIX}${Math.max(0, Math.min(Math.trunc(position), text.length))}`;
1839
+ })
1840
+ };
1841
+ },
1842
+ async resolveTextCursors(docId, path, cursors, options) {
1843
+ const document = storedDocuments.get(docId);
1844
+ if (!document || document.isDeleted) {
1845
+ throw new Error(`Document ${docId} was not found.`);
1846
+ }
1847
+ const text = readMockCursorText(document.data, path);
1848
+ return {
1849
+ path: [...path],
1850
+ heads: options?.heads ? [...options.heads] : [...document.heads ?? []],
1851
+ positions: cursors.map((cursor) => {
1852
+ if (typeof cursor !== "string" || !cursor.startsWith(MOCK_CURSOR_PREFIX)) {
1853
+ throw new Error(`Unknown text cursor ${String(cursor)}`);
1854
+ }
1855
+ const raw = cursor.slice(MOCK_CURSOR_PREFIX.length);
1856
+ return raw === "end" ? text.length : Math.min(Number(raw), text.length);
1857
+ })
1858
+ };
1859
+ },
1740
1860
  async getAutomergeSnapshot(docId, _options) {
1741
1861
  const document = storedDocuments.get(docId);
1742
1862
  if (!document || document.isDeleted) {
@@ -1785,6 +1905,13 @@ function createDatabaseHandle(definition, peers) {
1785
1905
  changesSince
1786
1906
  };
1787
1907
  },
1908
+ async applyAutomergeChangesBatch(items) {
1909
+ const results = [];
1910
+ for (const item of items) {
1911
+ results.push(await this.applyAutomergeChanges(item.docId, item.patch));
1912
+ }
1913
+ return results;
1914
+ },
1788
1915
  async create(input) {
1789
1916
  if (input.id !== void 0 && input.idPrefix !== void 0) {
1790
1917
  throw new Error("documents.create: id and idPrefix are mutually exclusive");
@@ -1831,7 +1958,7 @@ function createDatabaseHandle(definition, peers) {
1831
1958
  const created = {
1832
1959
  id,
1833
1960
  data: {
1834
- ...input.set,
1961
+ ...readMockTypedValues(input.set ?? {}),
1835
1962
  ...Array.isArray(input.recipients) ? { _encryptFor: mockEncryptForMap(input.recipients) } : {}
1836
1963
  },
1837
1964
  heads: [`mock-head-${++changeCounter}`],
@@ -2119,6 +2246,7 @@ function createDatabaseHandle(definition, peers) {
2119
2246
  const methods = definition.methods ?? {};
2120
2247
  let fulltextSetup = definition.fulltextSetup ?? null;
2121
2248
  let extractionSetup = definition.extractionSetup ?? null;
2249
+ let summarySetup = definition.summarySetup ?? null;
2122
2250
  const databaseHandle = {
2123
2251
  async info() {
2124
2252
  return {
@@ -2157,6 +2285,12 @@ function createDatabaseHandle(definition, peers) {
2157
2285
  },
2158
2286
  async setExtractionSetup(config) {
2159
2287
  extractionSetup = config === null ? null : { ...config };
2288
+ },
2289
+ async getSummarySetup() {
2290
+ return summarySetup === null ? null : structuredClone(summarySetup);
2291
+ },
2292
+ async setSummarySetup(config) {
2293
+ summarySetup = config === null ? null : structuredClone(config);
2160
2294
  }
2161
2295
  };
2162
2296
  return {
@@ -2174,6 +2308,8 @@ function createDatabaseHandle(definition, peers) {
2174
2308
  function createMockSessionState(options = {}) {
2175
2309
  let launchContext = createDefaultLaunchContext(options.launchContext);
2176
2310
  const themeListeners = /* @__PURE__ */ new Set();
2311
+ const hostFocusListeners = /* @__PURE__ */ new Set();
2312
+ let hostFocused = false;
2177
2313
  const viewportListeners = /* @__PURE__ */ new Set();
2178
2314
  const uiPreferencesListeners = /* @__PURE__ */ new Set();
2179
2315
  const localeListeners = /* @__PURE__ */ new Set();
@@ -2465,6 +2601,23 @@ function createMockSessionState(options = {}) {
2465
2601
  beforeCloseListeners.delete(listener);
2466
2602
  };
2467
2603
  },
2604
+ async requestHostFocus() {
2605
+ hostFocused = true;
2606
+ hostFocusListeners.forEach((listener) => listener(true));
2607
+ },
2608
+ async hasHostFocus() {
2609
+ return hostFocused;
2610
+ },
2611
+ onHostFocusChange(listener) {
2612
+ hostFocusListeners.add(listener);
2613
+ return () => {
2614
+ hostFocusListeners.delete(listener);
2615
+ };
2616
+ },
2617
+ async notify(input) {
2618
+ const id = input.id?.trim() || crypto.randomUUID();
2619
+ return { id };
2620
+ },
2468
2621
  async disconnect() {
2469
2622
  await options.onDisconnect?.();
2470
2623
  }
@@ -2527,6 +2680,10 @@ function createMockSessionState(options = {}) {
2527
2680
  async emitBeforeClose() {
2528
2681
  await Promise.all([...beforeCloseListeners].map(async (listener) => listener()));
2529
2682
  },
2683
+ setHostFocused(focused) {
2684
+ hostFocused = focused;
2685
+ hostFocusListeners.forEach((listener) => listener(focused));
2686
+ },
2530
2687
  resolveDrag(result) {
2531
2688
  activeDragResolve?.(result);
2532
2689
  activeDragResolve = null;
@@ -2552,6 +2709,9 @@ function createMockMindooDBAppSession(options = {}) {
2552
2709
  emitUiPreferencesChange: state.emitUiPreferencesChange,
2553
2710
  emitLocaleChange: state.emitLocaleChange,
2554
2711
  emitBeforeClose: state.emitBeforeClose,
2712
+ emitHostFocusChange(focused) {
2713
+ state.setHostFocused(focused);
2714
+ },
2555
2715
  resolveDrag: state.resolveDrag,
2556
2716
  getDragProfile: state.getDragProfile
2557
2717
  };
@@ -2755,6 +2915,15 @@ function createFakeBridgeHost(options = {}) {
2755
2915
  case "menus.hide":
2756
2916
  await state.session.menus.hide();
2757
2917
  return { ok: true };
2918
+ case "session.requestHostFocus":
2919
+ await state.session.requestHostFocus();
2920
+ return null;
2921
+ case "session.hasHostFocus":
2922
+ return { focused: await state.session.hasHostFocus() };
2923
+ case "notifications.show":
2924
+ return await state.session.notify(
2925
+ request.params
2926
+ );
2758
2927
  case "session.disconnect":
2759
2928
  await state.session.disconnect();
2760
2929
  return { ok: true };
@@ -2799,6 +2968,15 @@ function createFakeBridgeHost(options = {}) {
2799
2968
  params.config ?? null
2800
2969
  );
2801
2970
  return { ok: true };
2971
+ case "database.getSummarySetup":
2972
+ return {
2973
+ config: await state.getDatabase(String(params.databaseId)).getSummarySetup()
2974
+ };
2975
+ case "database.setSummarySetup":
2976
+ await state.getDatabase(String(params.databaseId)).setSummarySetup(
2977
+ params.config ?? null
2978
+ );
2979
+ return { ok: true };
2802
2980
  case "documents.query":
2803
2981
  return await state.getDatabase(String(params.databaseId)).documents.query(
2804
2982
  params.query
@@ -2844,6 +3022,23 @@ function createFakeBridgeHost(options = {}) {
2844
3022
  String(params.docId),
2845
3023
  params.path
2846
3024
  );
3025
+ case "documents.textCursors.get":
3026
+ return await state.getDatabase(String(params.databaseId)).documents.getTextCursors(
3027
+ String(params.docId),
3028
+ params.path,
3029
+ params.positions,
3030
+ {
3031
+ heads: params.heads,
3032
+ move: params.move
3033
+ }
3034
+ );
3035
+ case "documents.textCursors.resolve":
3036
+ return await state.getDatabase(String(params.databaseId)).documents.resolveTextCursors(
3037
+ String(params.docId),
3038
+ params.path,
3039
+ params.cursors,
3040
+ { heads: params.heads }
3041
+ );
2847
3042
  case "documents.automerge.getSnapshot":
2848
3043
  return await state.getDatabase(String(params.databaseId)).documents.getAutomergeSnapshot(
2849
3044
  String(params.docId),
@@ -3205,6 +3400,16 @@ function createFakeBridgeHost(options = {}) {
3205
3400
  beforeCloseWaiters.get(message.closeId)?.();
3206
3401
  return;
3207
3402
  }
3403
+ if (message.kind === "workspace-focus-requested") {
3404
+ state.setHostFocused(true);
3405
+ const payload = {
3406
+ protocol: PROTOCOL,
3407
+ kind: "host-focus-changed",
3408
+ focused: true
3409
+ };
3410
+ port.postMessage(payload);
3411
+ return;
3412
+ }
3208
3413
  if (message.kind === "request") {
3209
3414
  requests.push(message);
3210
3415
  try {
@@ -3315,6 +3520,15 @@ function createFakeBridgeHost(options = {}) {
3315
3520
  };
3316
3521
  connectedPorts.forEach((port) => port.postMessage(payload));
3317
3522
  },
3523
+ emitHostFocusChange(focused) {
3524
+ state.setHostFocused(focused);
3525
+ const payload = {
3526
+ protocol: PROTOCOL,
3527
+ kind: "host-focus-changed",
3528
+ focused
3529
+ };
3530
+ connectedPorts.forEach((port) => port.postMessage(payload));
3531
+ },
3318
3532
  emitQueryResult(subscriptionId, result) {
3319
3533
  const payload = {
3320
3534
  protocol: PROTOCOL,