mindoodb-app-sdk 0.0.19 → 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.
@@ -1,4 +1,9 @@
1
1
  // src/testing/index.ts
2
+ import * as Automerge from "@automerge/automerge";
3
+ import {
4
+ evaluateExpression,
5
+ parseMindooDBFormulaBooleanExpression
6
+ } from "mindoodb-view-language";
2
7
  var PROTOCOL = "mindoodb-app-bridge";
3
8
  function createBridgeErrorPayload(error, fallbackCode = "bridge-error") {
4
9
  if (error && typeof error === "object" && "message" in error) {
@@ -27,7 +32,11 @@ function applyDocumentUpdatePatch(current, patch) {
27
32
  applyMockTextPatch(next, textPatch.path, textPatch.edits);
28
33
  }
29
34
  for (const richTextPatch of patch.richText ?? []) {
30
- setValueAtPath(next, richTextPatch.path, structuredClone(richTextPatch.spans));
35
+ const spans = richTextPatch.spansSequence?.at(-1) ?? richTextPatch.spans ?? [];
36
+ setValueAtPath(next, richTextPatch.path, structuredClone(spans));
37
+ }
38
+ for (const richTextStepPatch of patch.richTextSteps ?? []) {
39
+ applyMockRichTextSteps(next, richTextStepPatch.path, richTextStepPatch.steps);
31
40
  }
32
41
  return next;
33
42
  }
@@ -49,6 +58,19 @@ function applyMockJsonPatch(target, patch) {
49
58
  const list = readListAtPath(target, operation.path);
50
59
  list.splice(operation.index, 0, ...structuredClone(operation.values));
51
60
  }
61
+ for (const operation of patch.textSplice ?? []) {
62
+ applyMockTextPatch(target, operation.path, [{
63
+ index: operation.index,
64
+ deleteCount: operation.deleteCount,
65
+ ...operation.insert !== void 0 ? { insert: operation.insert } : {}
66
+ }]);
67
+ }
68
+ for (const operation of patch.textMark ?? []) {
69
+ applyMockTextMarks(target, operation.path, operation.index, operation.length, operation.marks, false);
70
+ }
71
+ for (const operation of patch.textUnmark ?? []) {
72
+ applyMockTextMarks(target, operation.path, operation.index, operation.length, Object.fromEntries(operation.names.map((name) => [name, null])), true);
73
+ }
52
74
  }
53
75
  function setValueAtPath(target, path, value) {
54
76
  if (path.length === 0) {
@@ -128,6 +150,21 @@ function applyMockTextPatch(target, path, edits) {
128
150
  }
129
151
  parent[leaf] = value;
130
152
  }
153
+ function applyMockTextMarks(target, path, index, length, marks, remove) {
154
+ const parent = ensureParentAtPath(target, path);
155
+ const leaf = path[path.length - 1];
156
+ const marksKey = `${String(leaf)}__marks`;
157
+ const existing = Array.isArray(parent[marksKey]) ? parent[marksKey] : [];
158
+ parent[marksKey] = [
159
+ ...existing,
160
+ {
161
+ index,
162
+ length,
163
+ marks: structuredClone(marks),
164
+ remove
165
+ }
166
+ ];
167
+ }
131
168
  function readRichTextSpansAtPath(target, path) {
132
169
  let value = target;
133
170
  for (const segment of path) {
@@ -136,8 +173,38 @@ function readRichTextSpansAtPath(target, path) {
136
173
  }
137
174
  value = value[segment];
138
175
  }
176
+ if (typeof value === "string") {
177
+ return value.length > 0 ? [{ type: "text", value }] : [];
178
+ }
139
179
  return Array.isArray(value) ? value : [];
140
180
  }
181
+ function applyMockRichTextSteps(target, path, steps) {
182
+ if (path.length === 0) {
183
+ throw new Error("Rich-text steps path must contain at least one segment");
184
+ }
185
+ const parent = ensureParentAtPath(target, path);
186
+ const leaf = path[path.length - 1];
187
+ let text = materializeMockRichTextValue(parent[leaf]);
188
+ for (const step of steps) {
189
+ text = text.slice(0, step.index) + (step.insert ?? "") + text.slice(step.index + step.deleteCount);
190
+ }
191
+ parent[leaf] = text;
192
+ }
193
+ function materializeMockRichTextValue(value) {
194
+ if (typeof value === "string") {
195
+ return value;
196
+ }
197
+ if (!Array.isArray(value)) {
198
+ return "";
199
+ }
200
+ return value.map((span) => {
201
+ if (!span || typeof span !== "object") {
202
+ return "";
203
+ }
204
+ const record = span;
205
+ return record.type === "text" && typeof record.value === "string" ? record.value : "";
206
+ }).join("");
207
+ }
141
208
  function mergeLaunchContext(current, patch) {
142
209
  if (!patch) {
143
210
  return {
@@ -244,10 +311,12 @@ function createDefaultLaunchContext(patch) {
244
311
  uiPreferences: {
245
312
  iosMultitaskingOptimized: false
246
313
  },
314
+ locale: "en",
247
315
  user: {
248
316
  id: "user-1",
249
317
  username: "Test User"
250
318
  },
319
+ licensedProducts: [],
251
320
  launchParameters: {},
252
321
  databases: [],
253
322
  views: []
@@ -291,6 +360,22 @@ function createDefaultWritableAttachmentStream() {
291
360
  }
292
361
  };
293
362
  }
363
+ function loadMockAutomergeDocument(document) {
364
+ if (document.automergeBinary) {
365
+ return Automerge.load(document.automergeBinary);
366
+ }
367
+ const initialDoc = Automerge.from({
368
+ ...structuredClone(document.data),
369
+ body: typeof document.data.body === "string" ? document.data.body : ""
370
+ });
371
+ document.automergeBinary = Automerge.save(initialDoc);
372
+ return initialDoc;
373
+ }
374
+ function persistMockAutomergeDocument(document, automergeDoc) {
375
+ document.automergeBinary = Automerge.save(automergeDoc);
376
+ document.data = structuredClone(automergeDoc);
377
+ document.heads = Automerge.getHeads(automergeDoc);
378
+ }
294
379
  function getFieldValue(source, field) {
295
380
  return field.split(".").reduce((current, part) => {
296
381
  if (current && typeof current === "object" && part in current) {
@@ -314,6 +399,138 @@ function decodeMockListCursor(cursor) {
314
399
  const offset = Number.parseInt(cursor, 10);
315
400
  return Number.isFinite(offset) && offset >= 0 ? offset : 0;
316
401
  }
402
+ function mockExpressionToBoolean(value) {
403
+ if (typeof value === "boolean") {
404
+ return value;
405
+ }
406
+ if (typeof value === "number") {
407
+ return value !== 0;
408
+ }
409
+ if (typeof value === "string") {
410
+ const normalized = value.trim().toLowerCase();
411
+ return normalized !== "" && normalized !== "false" && normalized !== "0" && normalized !== "no";
412
+ }
413
+ return Boolean(value);
414
+ }
415
+ function compareMockQueryValues(left, right) {
416
+ const leftNumber = typeof left === "number" ? left : Number(left);
417
+ const rightNumber = typeof right === "number" ? right : Number(right);
418
+ if (Number.isFinite(leftNumber) && Number.isFinite(rightNumber)) {
419
+ return leftNumber - rightNumber;
420
+ }
421
+ return String(left ?? "").localeCompare(String(right ?? ""), void 0, {
422
+ sensitivity: "base"
423
+ });
424
+ }
425
+ function collectMockText(value, depth = 0) {
426
+ if (typeof value === "string") {
427
+ return value;
428
+ }
429
+ if (value === null || typeof value !== "object" || depth > 8) {
430
+ return "";
431
+ }
432
+ const parts = [];
433
+ for (const item of Array.isArray(value) ? value : Object.values(value)) {
434
+ const text = collectMockText(item, depth + 1);
435
+ if (text.length > 0) {
436
+ parts.push(text);
437
+ }
438
+ }
439
+ return parts.join(" ");
440
+ }
441
+ function mockTokenize(text) {
442
+ return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((token) => token.length > 0);
443
+ }
444
+ function computeMockTextScore(document, clause) {
445
+ const terms = mockTokenize(clause.query);
446
+ if (terms.length === 0) {
447
+ return void 0;
448
+ }
449
+ const haystack = clause.fields ? clause.fields.map((field) => collectMockText(getFieldValue(document.data, field))).join(" ") : collectMockText(
450
+ Object.fromEntries(
451
+ Object.entries(document.data).filter(([key]) => !key.startsWith("_"))
452
+ )
453
+ );
454
+ const tokens = mockTokenize(haystack);
455
+ const prefix = clause.prefix ?? true;
456
+ const combineWith = clause.combineWith ?? "AND";
457
+ let matchedTerms = 0;
458
+ let score = 0;
459
+ for (const term of terms) {
460
+ const occurrences = tokens.filter(
461
+ (token) => prefix ? token.startsWith(term) : token === term
462
+ ).length;
463
+ if (occurrences > 0) {
464
+ matchedTerms++;
465
+ score += occurrences;
466
+ }
467
+ }
468
+ const matches = combineWith === "AND" ? matchedTerms === terms.length : matchedTerms > 0;
469
+ return matches ? score : void 0;
470
+ }
471
+ function runMockDocumentQuery(storedDocuments, databaseId, query) {
472
+ const filter = typeof query?.filter === "string" ? parseMindooDBFormulaBooleanExpression(query.filter) : query?.filter;
473
+ const sortBy = query?.sortBy && query.sortBy.length > 0 ? query.sortBy : query?.text ? [{ special: "textScore", direction: "descending" }] : [];
474
+ const matches = [];
475
+ for (const document of storedDocuments.values()) {
476
+ if (document.isDeleted) {
477
+ continue;
478
+ }
479
+ let textScore;
480
+ if (query?.text) {
481
+ textScore = computeMockTextScore(document, query.text);
482
+ if (textScore === void 0) {
483
+ continue;
484
+ }
485
+ }
486
+ const context = {
487
+ doc: document.data,
488
+ values: {},
489
+ origin: databaseId,
490
+ variables: {}
491
+ };
492
+ if (filter && !mockExpressionToBoolean(evaluateExpression(filter, context))) {
493
+ continue;
494
+ }
495
+ const sortValues = sortBy.map((key) => {
496
+ if (key.special === "textScore") {
497
+ return textScore ?? 0;
498
+ }
499
+ return key.expression ? evaluateExpression(key.expression, context) : getFieldValue(document.data, key.field ?? "");
500
+ });
501
+ matches.push({ document, sortValues, textScore });
502
+ }
503
+ if (sortBy.length > 0) {
504
+ matches.sort((left, right) => {
505
+ for (let i = 0; i < sortBy.length; i++) {
506
+ const result = compareMockQueryValues(
507
+ left.sortValues[i],
508
+ right.sortValues[i]
509
+ );
510
+ if (result !== 0) {
511
+ return sortBy[i].direction === "descending" ? -result : result;
512
+ }
513
+ }
514
+ return left.document.id.localeCompare(right.document.id);
515
+ });
516
+ } else {
517
+ matches.sort((left, right) => left.document.id.localeCompare(right.document.id));
518
+ }
519
+ const offset = Math.max(0, query?.offset ?? 0);
520
+ const limit = Math.max(1, query?.limit ?? 200);
521
+ const rows = matches.slice(offset, offset + limit).map(({ document, textScore }) => ({
522
+ docId: document.id,
523
+ fields: query?.fields ? Object.fromEntries(
524
+ query.fields.map((field) => [
525
+ field,
526
+ getFieldValue(document.data, field)
527
+ ])
528
+ ) : structuredClone(document.data),
529
+ lastModified: document.updatedAt ? Date.parse(document.updatedAt) || 0 : 0,
530
+ ...textScore === void 0 ? {} : { textScore }
531
+ }));
532
+ return { rows, total: matches.length, coverage: "full" };
533
+ }
317
534
  function createDefaultViewNavigator() {
318
535
  const definition = {
319
536
  title: "Mock View",
@@ -344,6 +561,10 @@ function createDefaultViewNavigator() {
344
561
  async refresh() {
345
562
  return viewCursor;
346
563
  },
564
+ onDidUpdate(_listener) {
565
+ return () => {
566
+ };
567
+ },
347
568
  async getCurrentEntry() {
348
569
  return null;
349
570
  },
@@ -523,7 +744,56 @@ function createDatabaseHandle(definition) {
523
744
  let changeCounter = 0;
524
745
  const defaultViewFactory = async () => createDefaultViewNavigator();
525
746
  const storedDocuments = /* @__PURE__ */ new Map();
747
+ const liveQuerySubscriptions = /* @__PURE__ */ new Set();
748
+ const notifyLiveQueries = () => {
749
+ for (const subscription of liveQuerySubscriptions) {
750
+ const result = runMockDocumentQuery(
751
+ storedDocuments,
752
+ definition.info.id,
753
+ subscription.query
754
+ );
755
+ const resultJson = JSON.stringify(result);
756
+ if (resultJson !== subscription.lastResultJson) {
757
+ subscription.lastResultJson = resultJson;
758
+ subscription.onResult(result);
759
+ }
760
+ }
761
+ };
526
762
  const defaultDocuments = {
763
+ async query(query) {
764
+ return runMockDocumentQuery(storedDocuments, definition.info.id, query);
765
+ },
766
+ async liveQuery(query, onResult) {
767
+ const initial = runMockDocumentQuery(
768
+ storedDocuments,
769
+ definition.info.id,
770
+ query
771
+ );
772
+ const subscription = {
773
+ query,
774
+ onResult,
775
+ lastResultJson: JSON.stringify(initial)
776
+ };
777
+ liveQuerySubscriptions.add(subscription);
778
+ onResult(initial);
779
+ return {
780
+ refresh: async () => {
781
+ if (!liveQuerySubscriptions.has(subscription)) {
782
+ return;
783
+ }
784
+ const result = runMockDocumentQuery(
785
+ storedDocuments,
786
+ definition.info.id,
787
+ query
788
+ );
789
+ subscription.lastResultJson = JSON.stringify(result);
790
+ onResult(result);
791
+ },
792
+ dispose: async () => {
793
+ liveQuerySubscriptions.delete(subscription);
794
+ }
795
+ };
796
+ },
527
797
  async list(query) {
528
798
  const status = query?.status ?? "existing";
529
799
  const skip = Math.max(0, query?.skip ?? 0);
@@ -591,6 +861,53 @@ function createDatabaseHandle(definition) {
591
861
  spans: structuredClone(readRichTextSpansAtPath(document.data, path))
592
862
  };
593
863
  },
864
+ async getAutomergeSnapshot(docId, _options) {
865
+ const document = storedDocuments.get(docId);
866
+ if (!document || document.isDeleted) {
867
+ throw new Error(`Document ${docId} was not found.`);
868
+ }
869
+ const automergeDoc = loadMockAutomergeDocument(document);
870
+ return {
871
+ binary: Automerge.save(automergeDoc),
872
+ heads: Automerge.getHeads(automergeDoc)
873
+ };
874
+ },
875
+ async applyAutomergeChanges(docId, patch) {
876
+ const document = storedDocuments.get(docId);
877
+ if (!document || document.isDeleted) {
878
+ throw new Error(`Document ${docId} was not found.`);
879
+ }
880
+ const currentDoc = loadMockAutomergeDocument(document);
881
+ const [mergedDoc] = Automerge.applyChanges(
882
+ currentDoc,
883
+ patch.changes.map((change) => new Uint8Array(change))
884
+ );
885
+ persistMockAutomergeDocument(document, mergedDoc);
886
+ document.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
887
+ const mergedHeads = document.heads ? [...document.heads] : [];
888
+ let changesSince;
889
+ if (patch.replicaHeads?.length) {
890
+ const missingChanges = Automerge.getChangesSince(
891
+ mergedDoc,
892
+ patch.replicaHeads
893
+ );
894
+ changesSince = {
895
+ sinceHeads: [...patch.replicaHeads],
896
+ changes: missingChanges.map((change) => cloneBytes(new Uint8Array(change)))
897
+ };
898
+ }
899
+ return {
900
+ document: {
901
+ id: document.id,
902
+ data: structuredClone(document.data),
903
+ heads: mergedHeads,
904
+ attachments: document.attachments ? structuredClone(document.attachments) : [],
905
+ updatedAt: document.updatedAt
906
+ },
907
+ heads: mergedHeads,
908
+ changesSince
909
+ };
910
+ },
594
911
  async create(input) {
595
912
  const callerId = typeof input.id === "string" && input.id.length > 0 ? input.id : null;
596
913
  if (callerId) {
@@ -600,6 +917,7 @@ function createDatabaseHandle(definition) {
600
917
  existing.isDeleted = false;
601
918
  existing.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
602
919
  existing.heads = [`mock-head-${++changeCounter}`];
920
+ notifyLiveQueries();
603
921
  }
604
922
  return {
605
923
  id: existing.id,
@@ -631,10 +949,19 @@ function createDatabaseHandle(definition) {
631
949
  attachments: [],
632
950
  isDeleted: false
633
951
  });
952
+ notifyLiveQueries();
634
953
  return {
635
954
  ...created
636
955
  };
637
956
  },
957
+ async createMany(inputs) {
958
+ const ids = [];
959
+ for (const input of inputs) {
960
+ const created = await defaultDocuments.create(input);
961
+ ids.push(created.id);
962
+ }
963
+ return { ids };
964
+ },
638
965
  async update(docId, patch) {
639
966
  const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
640
967
  const existing = storedDocuments.get(docId);
@@ -649,8 +976,10 @@ function createDatabaseHandle(definition) {
649
976
  ...updated,
650
977
  data: structuredClone(updated.data),
651
978
  attachments: updated.attachments ? structuredClone(updated.attachments) : [],
652
- isDeleted: false
979
+ isDeleted: false,
980
+ automergeBinary: void 0
653
981
  });
982
+ notifyLiveQueries();
654
983
  return updated;
655
984
  },
656
985
  async delete(_docId) {
@@ -661,6 +990,13 @@ function createDatabaseHandle(definition) {
661
990
  isDeleted: true,
662
991
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
663
992
  });
993
+ notifyLiveQueries();
994
+ }
995
+ return { ok: true };
996
+ },
997
+ async deleteMany(docIds) {
998
+ for (const docId of docIds) {
999
+ await defaultDocuments.delete(docId);
664
1000
  }
665
1001
  return { ok: true };
666
1002
  },
@@ -673,9 +1009,25 @@ function createDatabaseHandle(definition) {
673
1009
  heads: [`mock-head-${++changeCounter}`],
674
1010
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
675
1011
  });
1012
+ notifyLiveQueries();
676
1013
  }
677
1014
  return { ok: true };
678
1015
  },
1016
+ async canCreate() {
1017
+ return { allowed: true, reason: "allowed (test host)", tier: "tier1" };
1018
+ },
1019
+ async canChange(_docId) {
1020
+ return { allowed: true, reason: "allowed (test host)", tier: "tier1" };
1021
+ },
1022
+ async canDelete(_docId) {
1023
+ return { allowed: true, reason: "allowed (test host)", tier: "tier1" };
1024
+ },
1025
+ async canUndelete(_docId) {
1026
+ return { allowed: true, reason: "allowed (test host)", tier: "tier1" };
1027
+ },
1028
+ async getDefaultCreateKeyId() {
1029
+ return "default";
1030
+ },
679
1031
  async listHistory(_docId) {
680
1032
  return [];
681
1033
  },
@@ -743,6 +1095,8 @@ function createDatabaseHandle(definition) {
743
1095
  }
744
1096
  };
745
1097
  const methods = definition.methods ?? {};
1098
+ let fulltextSetup = definition.fulltextSetup ?? null;
1099
+ let extractionSetup = definition.extractionSetup ?? null;
746
1100
  return {
747
1101
  async info() {
748
1102
  return {
@@ -757,6 +1111,18 @@ function createDatabaseHandle(definition) {
757
1111
  attachments: {
758
1112
  ...defaultAttachments,
759
1113
  ...methods.attachments
1114
+ },
1115
+ async getFulltextSetup() {
1116
+ return fulltextSetup === null ? null : { ...fulltextSetup };
1117
+ },
1118
+ async setFulltextSetup(config) {
1119
+ fulltextSetup = config === null ? null : { ...config };
1120
+ },
1121
+ async getExtractionSetup() {
1122
+ return extractionSetup === null ? null : { ...extractionSetup };
1123
+ },
1124
+ async setExtractionSetup(config) {
1125
+ extractionSetup = config === null ? null : { ...config };
760
1126
  }
761
1127
  };
762
1128
  }
@@ -765,6 +1131,7 @@ function createMockSessionState(options = {}) {
765
1131
  const themeListeners = /* @__PURE__ */ new Set();
766
1132
  const viewportListeners = /* @__PURE__ */ new Set();
767
1133
  const uiPreferencesListeners = /* @__PURE__ */ new Set();
1134
+ const localeListeners = /* @__PURE__ */ new Set();
768
1135
  const databaseHandles = /* @__PURE__ */ new Map();
769
1136
  const databaseViewApis = /* @__PURE__ */ new Map();
770
1137
  const sessionViews = /* @__PURE__ */ new Map();
@@ -818,6 +1185,9 @@ function createMockSessionState(options = {}) {
818
1185
  async getLaunchContext() {
819
1186
  return mergeLaunchContext(launchContext);
820
1187
  },
1188
+ async getLicensedProducts() {
1189
+ return [...launchContext.licensedProducts ?? []];
1190
+ },
821
1191
  async listDatabases() {
822
1192
  return databaseInfos.map((entry) => ({
823
1193
  ...entry,
@@ -895,6 +1265,12 @@ function createMockSessionState(options = {}) {
895
1265
  uiPreferencesListeners.delete(listener);
896
1266
  };
897
1267
  },
1268
+ onLocaleChange(listener) {
1269
+ localeListeners.add(listener);
1270
+ return () => {
1271
+ localeListeners.delete(listener);
1272
+ };
1273
+ },
898
1274
  async disconnect() {
899
1275
  await options.onDisconnect?.();
900
1276
  }
@@ -926,6 +1302,9 @@ function createMockSessionState(options = {}) {
926
1302
  }
927
1303
  return database;
928
1304
  },
1305
+ getLicensedProducts() {
1306
+ return [...launchContext.licensedProducts ?? []];
1307
+ },
929
1308
  createViewNavigator: session.createViewNavigator,
930
1309
  openViewNavigator: session.openViewNavigator,
931
1310
  bridge,
@@ -945,6 +1324,10 @@ function createMockSessionState(options = {}) {
945
1324
  uiPreferencesListeners.forEach(
946
1325
  (listener) => listener({ ...launchContext.uiPreferences })
947
1326
  );
1327
+ },
1328
+ emitLocaleChange(locale) {
1329
+ launchContext = mergeLaunchContext(launchContext, { locale });
1330
+ localeListeners.forEach((listener) => listener(launchContext.locale));
948
1331
  }
949
1332
  };
950
1333
  }
@@ -955,11 +1338,13 @@ function createMockMindooDBAppSession(options = {}) {
955
1338
  session: state.session,
956
1339
  getLaunchContext: state.getLaunchContext,
957
1340
  setLaunchContext: state.setLaunchContext,
1341
+ getLicensedProducts: state.getLicensedProducts,
958
1342
  listDatabases: state.listDatabaseInfos,
959
1343
  setDatabases: state.setDatabases,
960
1344
  emitThemeChange: state.emitThemeChange,
961
1345
  emitViewportChange: state.emitViewportChange,
962
- emitUiPreferencesChange: state.emitUiPreferencesChange
1346
+ emitUiPreferencesChange: state.emitUiPreferencesChange,
1347
+ emitLocaleChange: state.emitLocaleChange
963
1348
  };
964
1349
  }
965
1350
  function createMockMindooDBAppBridge(options = {}) {
@@ -975,8 +1360,10 @@ function createFakeBridgeHost(options = {}) {
975
1360
  const viewSessions = /* @__PURE__ */ new Map();
976
1361
  const readStreams = /* @__PURE__ */ new Map();
977
1362
  const writeStreams = /* @__PURE__ */ new Map();
1363
+ const liveQueries = /* @__PURE__ */ new Map();
978
1364
  let viewCounter = 0;
979
1365
  let streamCounter = 0;
1366
+ let liveQueryCounter = 0;
980
1367
  let previousWindowDescriptor = Object.getOwnPropertyDescriptor(
981
1368
  globalThis,
982
1369
  "window"
@@ -1121,6 +1508,8 @@ function createFakeBridgeHost(options = {}) {
1121
1508
  switch (request.method) {
1122
1509
  case "session.getLaunchContext":
1123
1510
  return state.getLaunchContext();
1511
+ case "session.getLicensedProducts":
1512
+ return state.getLicensedProducts();
1124
1513
  case "session.listDatabases":
1125
1514
  return state.listDatabaseInfos();
1126
1515
  case "session.openDatabase":
@@ -1162,6 +1551,62 @@ function createFakeBridgeHost(options = {}) {
1162
1551
  );
1163
1552
  case "documents.getHeadCursor":
1164
1553
  return await state.getDatabase(String(params.databaseId)).documents.getHeadCursor();
1554
+ case "database.getFulltextSetup":
1555
+ return {
1556
+ config: await state.getDatabase(String(params.databaseId)).getFulltextSetup()
1557
+ };
1558
+ case "database.setFulltextSetup":
1559
+ await state.getDatabase(String(params.databaseId)).setFulltextSetup(
1560
+ params.config ?? null
1561
+ );
1562
+ return { ok: true };
1563
+ case "database.getExtractionSetup":
1564
+ return {
1565
+ config: await state.getDatabase(String(params.databaseId)).getExtractionSetup()
1566
+ };
1567
+ case "database.setExtractionSetup":
1568
+ await state.getDatabase(String(params.databaseId)).setExtractionSetup(
1569
+ params.config ?? null
1570
+ );
1571
+ return { ok: true };
1572
+ case "documents.query":
1573
+ return await state.getDatabase(String(params.databaseId)).documents.query(
1574
+ params.query
1575
+ );
1576
+ case "documents.liveQuery.subscribe": {
1577
+ const subscriptionId = `live-query-${liveQueryCounter += 1}`;
1578
+ let initialResult = null;
1579
+ let initialDelivered = false;
1580
+ const handle = await state.getDatabase(String(params.databaseId)).documents.liveQuery(
1581
+ params.query,
1582
+ (result) => {
1583
+ if (!initialDelivered) {
1584
+ initialDelivered = true;
1585
+ initialResult = result;
1586
+ return;
1587
+ }
1588
+ const payload = {
1589
+ protocol: PROTOCOL,
1590
+ kind: "query-result",
1591
+ subscriptionId,
1592
+ result
1593
+ };
1594
+ connectedPorts.forEach((port) => port.postMessage(payload));
1595
+ }
1596
+ );
1597
+ liveQueries.set(subscriptionId, handle);
1598
+ return { subscriptionId, result: initialResult };
1599
+ }
1600
+ case "documents.liveQuery.refresh": {
1601
+ await liveQueries.get(String(params.subscriptionId))?.refresh();
1602
+ return { ok: true };
1603
+ }
1604
+ case "documents.liveQuery.unsubscribe": {
1605
+ const key = String(params.subscriptionId);
1606
+ await liveQueries.get(key)?.dispose();
1607
+ liveQueries.delete(key);
1608
+ return { ok: true };
1609
+ }
1165
1610
  case "documents.get":
1166
1611
  return await state.getDatabase(String(params.databaseId)).documents.get(String(params.docId));
1167
1612
  case "documents.richText.get":
@@ -1169,6 +1614,16 @@ function createFakeBridgeHost(options = {}) {
1169
1614
  String(params.docId),
1170
1615
  params.path
1171
1616
  );
1617
+ case "documents.automerge.getSnapshot":
1618
+ return await state.getDatabase(String(params.databaseId)).documents.getAutomergeSnapshot(
1619
+ String(params.docId),
1620
+ { revisionId: params.revisionId }
1621
+ );
1622
+ case "documents.automerge.applyChanges":
1623
+ return await state.getDatabase(String(params.databaseId)).documents.applyAutomergeChanges(
1624
+ String(params.docId),
1625
+ params.patch
1626
+ );
1172
1627
  case "documents.create":
1173
1628
  return await state.getDatabase(String(params.databaseId)).documents.create(
1174
1629
  params.input
@@ -1182,6 +1637,18 @@ function createFakeBridgeHost(options = {}) {
1182
1637
  return await state.getDatabase(String(params.databaseId)).documents.delete(String(params.docId));
1183
1638
  case "documents.undelete":
1184
1639
  return await state.getDatabase(String(params.databaseId)).documents.undelete(String(params.docId));
1640
+ case "documents.canCreate":
1641
+ return await state.getDatabase(String(params.databaseId)).documents.canCreate(
1642
+ params.input
1643
+ );
1644
+ case "documents.canChange":
1645
+ return await state.getDatabase(String(params.databaseId)).documents.canChange(String(params.docId));
1646
+ case "documents.canDelete":
1647
+ return await state.getDatabase(String(params.databaseId)).documents.canDelete(String(params.docId));
1648
+ case "documents.canUndelete":
1649
+ return await state.getDatabase(String(params.databaseId)).documents.canUndelete(String(params.docId));
1650
+ case "documents.getDefaultCreateKeyId":
1651
+ return await state.getDatabase(String(params.databaseId)).documents.getDefaultCreateKeyId();
1185
1652
  case "documents.history.list":
1186
1653
  return await state.getDatabase(String(params.databaseId)).documents.listHistory(String(params.docId));
1187
1654
  case "documents.history.getAtTimestamp":
@@ -1513,6 +1980,10 @@ function createFakeBridgeHost(options = {}) {
1513
1980
  viewSessions.clear();
1514
1981
  readStreams.clear();
1515
1982
  writeStreams.clear();
1983
+ liveQueries.forEach((handle) => {
1984
+ void handle.dispose();
1985
+ });
1986
+ liveQueries.clear();
1516
1987
  },
1517
1988
  emitThemeChange(theme) {
1518
1989
  state.emitThemeChange(theme);
@@ -1541,6 +2012,33 @@ function createFakeBridgeHost(options = {}) {
1541
2012
  };
1542
2013
  connectedPorts.forEach((port) => port.postMessage(payload));
1543
2014
  },
2015
+ emitLocaleChange(locale) {
2016
+ state.emitLocaleChange(locale);
2017
+ const payload = {
2018
+ protocol: PROTOCOL,
2019
+ kind: "locale-changed",
2020
+ locale
2021
+ };
2022
+ connectedPorts.forEach((port) => port.postMessage(payload));
2023
+ },
2024
+ emitQueryResult(subscriptionId, result) {
2025
+ const payload = {
2026
+ protocol: PROTOCOL,
2027
+ kind: "query-result",
2028
+ subscriptionId,
2029
+ result
2030
+ };
2031
+ connectedPorts.forEach((port) => port.postMessage(payload));
2032
+ },
2033
+ emitViewChanged(navigatorId, stats) {
2034
+ const payload = {
2035
+ protocol: PROTOCOL,
2036
+ kind: "view-changed",
2037
+ navigatorId,
2038
+ stats
2039
+ };
2040
+ connectedPorts.forEach((port) => port.postMessage(payload));
2041
+ },
1544
2042
  postPortMessage(message, transfer = []) {
1545
2043
  connectedPorts.forEach((port) => port.postMessage(message, transfer));
1546
2044
  },