mindoodb-app-sdk 0.0.16 → 0.0.17

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.
@@ -10,7 +10,9 @@ function createBridgeErrorPayload(error, fallbackCode = "bridge-error") {
10
10
  return { code: fallbackCode, message: String(error) };
11
11
  }
12
12
  function cloneBytes(chunk) {
13
- return new Uint8Array(chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength));
13
+ return new Uint8Array(
14
+ chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength)
15
+ );
14
16
  }
15
17
  function applyDocumentUpdatePatch(current, patch) {
16
18
  const next = {
@@ -20,11 +22,81 @@ function applyDocumentUpdatePatch(current, patch) {
20
22
  for (const key of patch.unset ?? []) {
21
23
  Reflect.deleteProperty(next, key);
22
24
  }
25
+ applyMockJsonPatch(next, patch.json);
23
26
  for (const textPatch of patch.text ?? []) {
24
27
  applyMockTextPatch(next, textPatch.path, textPatch.edits);
25
28
  }
26
29
  return next;
27
30
  }
31
+ function applyMockJsonPatch(target, patch) {
32
+ if (!patch) {
33
+ return;
34
+ }
35
+ for (const operation of patch.set ?? []) {
36
+ setValueAtPath(target, operation.path, structuredClone(operation.value));
37
+ }
38
+ for (const operation of patch.unset ?? []) {
39
+ unsetValueAtPath(target, operation.path);
40
+ }
41
+ for (const operation of patch.listDelete ?? []) {
42
+ const list = readListAtPath(target, operation.path);
43
+ list.splice(operation.index, operation.deleteCount);
44
+ }
45
+ for (const operation of patch.listInsert ?? []) {
46
+ const list = readListAtPath(target, operation.path);
47
+ list.splice(operation.index, 0, ...structuredClone(operation.values));
48
+ }
49
+ }
50
+ function setValueAtPath(target, path, value) {
51
+ if (path.length === 0) {
52
+ throw new Error("JSON set path must contain at least one segment");
53
+ }
54
+ const parent = ensureParentAtPath(target, path);
55
+ parent[path[path.length - 1]] = value;
56
+ }
57
+ function unsetValueAtPath(target, path) {
58
+ if (path.length === 0) {
59
+ throw new Error("JSON unset path must contain at least one segment");
60
+ }
61
+ const parent = readParentAtPath(target, path);
62
+ Reflect.deleteProperty(parent, path[path.length - 1]);
63
+ }
64
+ function readListAtPath(target, path) {
65
+ let value = target;
66
+ for (const segment of path) {
67
+ value = value?.[segment];
68
+ }
69
+ if (!Array.isArray(value)) {
70
+ throw new Error(
71
+ `Cannot apply list operation to non-array value at ${path.map(String).join(".")}`
72
+ );
73
+ }
74
+ return value;
75
+ }
76
+ function ensureParentAtPath(target, path) {
77
+ let parent = target;
78
+ for (let index = 0; index < path.length - 1; index += 1) {
79
+ const segment = path[index];
80
+ const nextSegment = path[index + 1];
81
+ if (parent[segment] == null) {
82
+ parent[segment] = typeof nextSegment === "number" ? [] : {};
83
+ }
84
+ parent = parent[segment];
85
+ }
86
+ return parent;
87
+ }
88
+ function readParentAtPath(target, path) {
89
+ let parent = target;
90
+ for (let index = 0; index < path.length - 1; index += 1) {
91
+ parent = parent?.[path[index]];
92
+ }
93
+ if (parent == null || typeof parent !== "object") {
94
+ throw new Error(
95
+ `Cannot resolve JSON parent at ${path.map(String).join(".")}`
96
+ );
97
+ }
98
+ return parent;
99
+ }
28
100
  function applyMockTextPatch(target, path, edits) {
29
101
  if (path.length === 0) {
30
102
  throw new Error("Text patch path must contain at least one segment");
@@ -44,7 +116,9 @@ function applyMockTextPatch(target, path, edits) {
44
116
  value = "";
45
117
  }
46
118
  if (typeof value !== "string") {
47
- throw new Error(`Cannot apply text patch to non-string value at ${path.map(String).join(".")}`);
119
+ throw new Error(
120
+ `Cannot apply text patch to non-string value at ${path.map(String).join(".")}`
121
+ );
48
122
  }
49
123
  for (const edit of edits) {
50
124
  value = value.slice(0, edit.index) + (edit.insert ?? "") + value.slice(edit.index + edit.deleteCount);
@@ -69,7 +143,10 @@ function mergeLaunchContext(current, patch) {
69
143
  sources: view.sources.map((source) => ({ ...source })),
70
144
  columns: view.columns.map((column) => ({
71
145
  ...column,
72
- expression: column.expression.mode === "field" ? { ...column.expression } : { mode: "formula", expression: structuredClone(column.expression.expression) }
146
+ expression: column.expression.mode === "field" ? { ...column.expression } : {
147
+ mode: "formula",
148
+ expression: structuredClone(column.expression.expression)
149
+ }
73
150
  })),
74
151
  filter: view.filter.mode === "rules" ? {
75
152
  mode: "rules",
@@ -102,7 +179,10 @@ function mergeLaunchContext(current, patch) {
102
179
  sources: view.sources.map((source) => ({ ...source })),
103
180
  columns: view.columns.map((column) => ({
104
181
  ...column,
105
- expression: column.expression.mode === "field" ? { ...column.expression } : { mode: "formula", expression: structuredClone(column.expression.expression) }
182
+ expression: column.expression.mode === "field" ? { ...column.expression } : {
183
+ mode: "formula",
184
+ expression: structuredClone(column.expression.expression)
185
+ }
106
186
  })),
107
187
  filter: view.filter.mode === "rules" ? {
108
188
  mode: "rules",
@@ -117,7 +197,10 @@ function mergeLaunchContext(current, patch) {
117
197
  sources: view.sources.map((source) => ({ ...source })),
118
198
  columns: view.columns.map((column) => ({
119
199
  ...column,
120
- expression: column.expression.mode === "field" ? { ...column.expression } : { mode: "formula", expression: structuredClone(column.expression.expression) }
200
+ expression: column.expression.mode === "field" ? { ...column.expression } : {
201
+ mode: "formula",
202
+ expression: structuredClone(column.expression.expression)
203
+ }
121
204
  })),
122
205
  filter: view.filter.mode === "rules" ? {
123
206
  mode: "rules",
@@ -207,7 +290,9 @@ function matchesDocumentFilter(document, filter) {
207
290
  if (!filter) {
208
291
  return true;
209
292
  }
210
- return Object.entries(filter).every(([field, expected]) => getFieldValue(document.data, field) === expected);
293
+ return Object.entries(filter).every(
294
+ ([field, expected]) => getFieldValue(document.data, field) === expected
295
+ );
211
296
  }
212
297
  function decodeMockListCursor(cursor) {
213
298
  if (!cursor) {
@@ -432,7 +517,11 @@ function createDatabaseHandle(definition) {
432
517
  const limit = Math.max(1, query?.limit ?? 50);
433
518
  const offset = decodeMockListCursor(query?.cursor) + skip;
434
519
  const metadataOnly = query?.metadataOnly ?? false;
435
- const items = Array.from(storedDocuments.values()).filter((document) => status === "all" ? true : status === "deleted" ? document.isDeleted : !document.isDeleted).filter((document) => metadataOnly ? true : matchesDocumentFilter(document, query?.filter)).sort((left, right) => left.id.localeCompare(right.id));
520
+ const items = Array.from(storedDocuments.values()).filter(
521
+ (document) => status === "all" ? true : status === "deleted" ? document.isDeleted : !document.isDeleted
522
+ ).filter(
523
+ (document) => metadataOnly ? true : matchesDocumentFilter(document, query?.filter)
524
+ ).sort((left, right) => left.id.localeCompare(right.id));
436
525
  const page = items.slice(offset, offset + limit).map((document) => {
437
526
  if (metadataOnly) {
438
527
  return {
@@ -440,7 +529,12 @@ function createDatabaseHandle(definition) {
440
529
  isDeleted: document.isDeleted
441
530
  };
442
531
  }
443
- const projectedData = query?.fields ? Object.fromEntries(query.fields.map((field) => [field, getFieldValue(document.data, field)])) : document.data;
532
+ const projectedData = query?.fields ? Object.fromEntries(
533
+ query.fields.map((field) => [
534
+ field,
535
+ getFieldValue(document.data, field)
536
+ ])
537
+ ) : document.data;
444
538
  return {
445
539
  id: document.id,
446
540
  data: projectedData,
@@ -603,6 +697,17 @@ function createDatabaseHandle(definition) {
603
697
  async openWriteStream(_docId, _attachmentName, _contentType) {
604
698
  return createDefaultWritableAttachmentStream();
605
699
  },
700
+ async scan(_docId, options) {
701
+ return {
702
+ ok: true,
703
+ attachment: {
704
+ attachmentId: "scan-attachment-1",
705
+ fileName: options?.defaultFileName ?? "scan.jpg",
706
+ mimeType: options?.mimeType ?? "image/jpeg",
707
+ size: 0
708
+ }
709
+ };
710
+ },
606
711
  async preparePreviewSession(_docId, _attachmentName, _options) {
607
712
  return {
608
713
  sessionId: "preview-session-1",
@@ -616,7 +721,10 @@ function createDatabaseHandle(definition) {
616
721
  const methods = definition.methods ?? {};
617
722
  return {
618
723
  async info() {
619
- return { ...definition.info, capabilities: [...definition.info.capabilities] };
724
+ return {
725
+ ...definition.info,
726
+ capabilities: [...definition.info.capabilities]
727
+ };
620
728
  },
621
729
  documents: {
622
730
  ...defaultDocuments,
@@ -677,7 +785,9 @@ function createMockSessionState(options = {}) {
677
785
  ...definition.methods?.views ?? {}
678
786
  });
679
787
  }
680
- launchContext = mergeLaunchContext(launchContext, { databases: databaseInfos });
788
+ launchContext = mergeLaunchContext(launchContext, {
789
+ databases: databaseInfos
790
+ });
681
791
  };
682
792
  setDatabases(options.databases ?? []);
683
793
  const session = {
@@ -706,11 +816,15 @@ function createMockSessionState(options = {}) {
706
816
  async createViewNavigator(input) {
707
817
  const firstDatabaseId = input.databaseIds[0];
708
818
  if (!firstDatabaseId) {
709
- throw new Error("At least one test database is required for view creation.");
819
+ throw new Error(
820
+ "At least one test database is required for view creation."
821
+ );
710
822
  }
711
823
  const api = databaseViewApis.get(firstDatabaseId);
712
824
  if (!api) {
713
- throw new Error(`Unknown test database for view creation: ${firstDatabaseId}`);
825
+ throw new Error(
826
+ `Unknown test database for view creation: ${firstDatabaseId}`
827
+ );
714
828
  }
715
829
  const view = await api.create(input);
716
830
  const viewId = input.definition.id || crypto.randomUUID();
@@ -722,13 +836,17 @@ function createMockSessionState(options = {}) {
722
836
  if (existing) {
723
837
  return existing;
724
838
  }
725
- const sourceDatabaseId = launchContext.views.find((view2) => view2.id === viewId)?.sources[0]?.databaseId;
839
+ const sourceDatabaseId = launchContext.views.find(
840
+ (view2) => view2.id === viewId
841
+ )?.sources[0]?.databaseId;
726
842
  if (!sourceDatabaseId) {
727
843
  throw new Error(`Unknown test view: ${viewId}`);
728
844
  }
729
845
  const api = databaseViewApis.get(sourceDatabaseId);
730
846
  if (!api) {
731
- throw new Error(`Unknown test database for view ${viewId}: ${sourceDatabaseId}`);
847
+ throw new Error(
848
+ `Unknown test database for view ${viewId}: ${sourceDatabaseId}`
849
+ );
732
850
  }
733
851
  const view = await api.open(viewId, options2);
734
852
  sessionViews.set(viewId, view);
@@ -790,7 +908,9 @@ function createMockSessionState(options = {}) {
790
908
  session,
791
909
  emitThemeChange(theme) {
792
910
  launchContext = mergeLaunchContext(launchContext, { theme });
793
- themeListeners.forEach((listener) => listener({ ...launchContext.theme }));
911
+ themeListeners.forEach(
912
+ (listener) => listener({ ...launchContext.theme })
913
+ );
794
914
  },
795
915
  emitViewportChange(viewport) {
796
916
  launchContext = mergeLaunchContext(launchContext, { viewport });
@@ -798,7 +918,9 @@ function createMockSessionState(options = {}) {
798
918
  },
799
919
  emitUiPreferencesChange(uiPreferences) {
800
920
  launchContext = mergeLaunchContext(launchContext, { uiPreferences });
801
- uiPreferencesListeners.forEach((listener) => listener({ ...launchContext.uiPreferences }));
921
+ uiPreferencesListeners.forEach(
922
+ (listener) => listener({ ...launchContext.uiPreferences })
923
+ );
802
924
  }
803
925
  };
804
926
  }
@@ -821,7 +943,9 @@ function createMockMindooDBAppBridge(options = {}) {
821
943
  }
822
944
  function createFakeBridgeHost(options = {}) {
823
945
  const state = createMockSessionState(options);
824
- const customRequestHandlers = new Map(Object.entries(options.requestHandlers ?? {}));
946
+ const customRequestHandlers = new Map(
947
+ Object.entries(options.requestHandlers ?? {})
948
+ );
825
949
  const requests = [];
826
950
  const connectedPorts = /* @__PURE__ */ new Set();
827
951
  const viewSessions = /* @__PURE__ */ new Map();
@@ -829,7 +953,10 @@ function createFakeBridgeHost(options = {}) {
829
953
  const writeStreams = /* @__PURE__ */ new Map();
830
954
  let viewCounter = 0;
831
955
  let streamCounter = 0;
832
- let previousWindowDescriptor = Object.getOwnPropertyDescriptor(globalThis, "window");
956
+ let previousWindowDescriptor = Object.getOwnPropertyDescriptor(
957
+ globalThis,
958
+ "window"
959
+ );
833
960
  let previousWindowValue = typeof window === "undefined" ? void 0 : window;
834
961
  let installed = false;
835
962
  const hostWindow = {
@@ -843,7 +970,9 @@ function createFakeBridgeHost(options = {}) {
843
970
  }
844
971
  const port = transfer?.[0];
845
972
  if (!port) {
846
- throw new Error("Expected the bridge connection to transfer a MessagePort.");
973
+ throw new Error(
974
+ "Expected the bridge connection to transfer a MessagePort."
975
+ );
847
976
  }
848
977
  connectedPorts.add(port);
849
978
  port.addEventListener("message", (event) => {
@@ -885,7 +1014,10 @@ function createFakeBridgeHost(options = {}) {
885
1014
  if (installed) {
886
1015
  return;
887
1016
  }
888
- previousWindowDescriptor = Object.getOwnPropertyDescriptor(globalThis, "window");
1017
+ previousWindowDescriptor = Object.getOwnPropertyDescriptor(
1018
+ globalThis,
1019
+ "window"
1020
+ );
889
1021
  previousWindowValue = typeof window === "undefined" ? void 0 : window;
890
1022
  const baseWindow = typeof window === "undefined" ? {} : window;
891
1023
  const nextWindow = Object.create(baseWindow);
@@ -975,6 +1107,7 @@ function createFakeBridgeHost(options = {}) {
975
1107
  const navigator = await state.createViewNavigator({
976
1108
  databaseIds: Array.isArray(params.databaseIds) ? params.databaseIds.map((entry) => String(entry)) : [],
977
1109
  definition: params.definition,
1110
+ categorizationStyle: params.categorizationStyle === "category_then_document" ? "category_then_document" : "document_then_category",
978
1111
  options: params.options
979
1112
  });
980
1113
  viewSessions.set(navigatorId, navigator);
@@ -990,7 +1123,9 @@ function createFakeBridgeHost(options = {}) {
990
1123
  return { navigatorId };
991
1124
  }
992
1125
  case "menus.show":
993
- return await state.session.menus.show(request.params);
1126
+ return await state.session.menus.show(
1127
+ request.params
1128
+ );
994
1129
  case "menus.hide":
995
1130
  await state.session.menus.hide();
996
1131
  return { ok: true };
@@ -998,13 +1133,17 @@ function createFakeBridgeHost(options = {}) {
998
1133
  await state.session.disconnect();
999
1134
  return { ok: true };
1000
1135
  case "documents.list":
1001
- return await state.getDatabase(String(params.databaseId)).documents.list(params.query);
1136
+ return await state.getDatabase(String(params.databaseId)).documents.list(
1137
+ params.query
1138
+ );
1002
1139
  case "documents.getHeadCursor":
1003
1140
  return await state.getDatabase(String(params.databaseId)).documents.getHeadCursor();
1004
1141
  case "documents.get":
1005
1142
  return await state.getDatabase(String(params.databaseId)).documents.get(String(params.docId));
1006
1143
  case "documents.create":
1007
- return await state.getDatabase(String(params.databaseId)).documents.create(params.input);
1144
+ return await state.getDatabase(String(params.databaseId)).documents.create(
1145
+ params.input
1146
+ );
1008
1147
  case "documents.update":
1009
1148
  return await state.getDatabase(String(params.databaseId)).documents.update(
1010
1149
  String(params.docId),
@@ -1056,6 +1195,12 @@ function createFakeBridgeHost(options = {}) {
1056
1195
  writeStreams.set(streamId, stream);
1057
1196
  return { streamId };
1058
1197
  }
1198
+ case "attachments.scanAndWrite":
1199
+ return await state.getDatabase(String(params.databaseId)).attachments.scan(String(params.docId), {
1200
+ defaultFileName: typeof params.defaultFileName === "string" ? params.defaultFileName : void 0,
1201
+ preset: typeof params.preset === "string" ? params.preset : void 0,
1202
+ mimeType: params.mimeType === "image/png" || params.mimeType === "image/jpeg" || params.mimeType === "application/pdf" ? params.mimeType : void 0
1203
+ });
1059
1204
  case "attachments.openPreview":
1060
1205
  return await state.getDatabase(String(params.databaseId)).attachments.openPreview(
1061
1206
  String(params.docId),
@@ -1204,7 +1349,10 @@ function createFakeBridgeHost(options = {}) {
1204
1349
  if (message.kind === "stream-read") {
1205
1350
  const stream = readStreams.get(message.streamId);
1206
1351
  if (!stream) {
1207
- throw Object.assign(new Error(`Unknown read stream: ${message.streamId}`), { name: "stream-not-found" });
1352
+ throw Object.assign(
1353
+ new Error(`Unknown read stream: ${message.streamId}`),
1354
+ { name: "stream-not-found" }
1355
+ );
1208
1356
  }
1209
1357
  const chunk = await stream.read();
1210
1358
  port.postMessage({
@@ -1222,7 +1370,10 @@ function createFakeBridgeHost(options = {}) {
1222
1370
  if (message.kind === "stream-write") {
1223
1371
  const stream = writeStreams.get(message.streamId);
1224
1372
  if (!stream) {
1225
- throw Object.assign(new Error(`Unknown write stream: ${message.streamId}`), { name: "stream-not-found" });
1373
+ throw Object.assign(
1374
+ new Error(`Unknown write stream: ${message.streamId}`),
1375
+ { name: "stream-not-found" }
1376
+ );
1226
1377
  }
1227
1378
  await stream.write(new Uint8Array(message.chunk));
1228
1379
  postStreamAck(port, message.streamId);
@@ -1243,12 +1394,17 @@ function createFakeBridgeHost(options = {}) {
1243
1394
  postStreamAck(port, message.streamId);
1244
1395
  return true;
1245
1396
  }
1246
- throw Object.assign(new Error(`Unknown stream: ${message.streamId}`), { name: "stream-not-found" });
1397
+ throw Object.assign(new Error(`Unknown stream: ${message.streamId}`), {
1398
+ name: "stream-not-found"
1399
+ });
1247
1400
  }
1248
1401
  if (message.kind === "stream-abort") {
1249
1402
  const stream = writeStreams.get(message.streamId);
1250
1403
  if (!stream) {
1251
- throw Object.assign(new Error(`Unknown write stream: ${message.streamId}`), { name: "stream-not-found" });
1404
+ throw Object.assign(
1405
+ new Error(`Unknown write stream: ${message.streamId}`),
1406
+ { name: "stream-not-found" }
1407
+ );
1252
1408
  }
1253
1409
  await stream.abort();
1254
1410
  writeStreams.delete(message.streamId);
@@ -1267,7 +1423,11 @@ function createFakeBridgeHost(options = {}) {
1267
1423
  try {
1268
1424
  const customHandler = customRequestHandlers.get(message.method);
1269
1425
  if (customHandler) {
1270
- const result = await customHandler(message.params, { host: controller, request: message, port });
1426
+ const result = await customHandler(message.params, {
1427
+ host: controller,
1428
+ request: message,
1429
+ port
1430
+ });
1271
1431
  postRpcSuccess(port, message.id, result);
1272
1432
  return;
1273
1433
  }
@@ -1286,15 +1446,23 @@ function createFakeBridgeHost(options = {}) {
1286
1446
  return;
1287
1447
  }
1288
1448
  try {
1289
- const handledByCustom = await options.onPortMessage?.(message, { host: controller, port });
1449
+ const handledByCustom = await options.onPortMessage?.(message, {
1450
+ host: controller,
1451
+ port
1452
+ });
1290
1453
  if (handledByCustom) {
1291
1454
  return;
1292
1455
  }
1293
1456
  const handled = await handleStreamMessage(port, message);
1294
1457
  if (!handled) {
1295
- throw Object.assign(new Error(`No fake bridge port handler is configured for ${message.kind}.`), {
1296
- name: "unsupported-message"
1297
- });
1458
+ throw Object.assign(
1459
+ new Error(
1460
+ `No fake bridge port handler is configured for ${message.kind}.`
1461
+ ),
1462
+ {
1463
+ name: "unsupported-message"
1464
+ }
1465
+ );
1298
1466
  }
1299
1467
  } catch (error) {
1300
1468
  const streamId = "streamId" in message ? String(message.streamId) : "unknown";
@@ -109,6 +109,11 @@ interface MindooDBAppLaunchContext {
109
109
  uiPreferences: MindooDBAppUiPreferences;
110
110
  tenantId?: string;
111
111
  preferredDatabaseId?: string;
112
+ /**
113
+ * Epoch-millisecond cutoff when the host opened app databases in time travel
114
+ * read-only mode. Absent/null means the app is looking at live data.
115
+ */
116
+ timeTravelDate?: number | null;
112
117
  user: {
113
118
  id: string;
114
119
  username: string;
@@ -133,6 +138,16 @@ interface MindooDBAppAttachmentPreviewOptions {
133
138
  /** Stable revision id previously obtained from `documents.listHistory()`. */
134
139
  revisionId?: MindooDBAppDocumentRevisionId;
135
140
  }
141
+ type MindooDBAppDocumentScanPreset = "auto" | "a4-portrait" | "a4-landscape" | "letter-portrait" | "letter-landscape";
142
+ interface MindooDBAppScanAttachmentOptions {
143
+ defaultFileName?: string;
144
+ preset?: MindooDBAppDocumentScanPreset;
145
+ mimeType?: "image/jpeg" | "image/png" | "application/pdf";
146
+ }
147
+ interface MindooDBAppScanAttachmentResult {
148
+ ok: boolean;
149
+ attachment?: MindooDBAppAttachmentInfo | null;
150
+ }
136
151
  /** Resolved Haven preview session prepared for opening in a separate tab or window. */
137
152
  interface MindooDBAppAttachmentPreviewSession {
138
153
  sessionId: string;
@@ -150,6 +165,7 @@ interface MindooDBAppDocumentSummary {
150
165
  id: string;
151
166
  data?: Record<string, unknown>;
152
167
  attachmentCount?: number;
168
+ createdAt?: string;
153
169
  updatedAt?: string;
154
170
  identityLabel?: string;
155
171
  publicKeyFingerprint?: string;
@@ -162,6 +178,7 @@ interface MindooDBAppDocument {
162
178
  /** Current Automerge heads for causal text edit reconciliation. */
163
179
  heads?: string[];
164
180
  attachments?: MindooDBAppAttachmentInfo[];
181
+ createdAt?: string;
165
182
  updatedAt?: string;
166
183
  }
167
184
  /** Opaque persisted id for a document revision in the MindooDB DAG. */
@@ -260,6 +277,60 @@ interface MindooDBAppTextPatch {
260
277
  baseHeads?: string[];
261
278
  edits: MindooDBAppTextEdit[];
262
279
  }
280
+ /**
281
+ * Sets the value at `path` inside the document payload.
282
+ *
283
+ * Creates the field if it does not exist, or replaces the existing value.
284
+ * `path` addresses a property using object keys and list indices, for example
285
+ * `["workbook", "worksheetsById", "ws-1", "title"]`.
286
+ */
287
+ interface MindooDBAppJsonSetPatch {
288
+ path: Array<string | number>;
289
+ value: unknown;
290
+ }
291
+ /**
292
+ * Removes the value at `path` from the document payload.
293
+ *
294
+ * For object properties this deletes the key; for list entries the host
295
+ * decides whether unset is supported and may reject the patch.
296
+ */
297
+ interface MindooDBAppJsonUnsetPatch {
298
+ path: Array<string | number>;
299
+ }
300
+ /**
301
+ * Inserts one or more values into the list located at `path`.
302
+ *
303
+ * `index` is the insertion point within the current list, where `0` prepends
304
+ * and `list.length` appends. Existing entries at or after `index` shift right.
305
+ */
306
+ interface MindooDBAppJsonListInsertPatch {
307
+ path: Array<string | number>;
308
+ index: number;
309
+ values: unknown[];
310
+ }
311
+ /**
312
+ * Deletes a contiguous run of entries from the list located at `path`.
313
+ *
314
+ * Removes `deleteCount` entries starting at `index`. Subsequent entries shift
315
+ * left to fill the gap.
316
+ */
317
+ interface MindooDBAppJsonListDeletePatch {
318
+ path: Array<string | number>;
319
+ index: number;
320
+ deleteCount: number;
321
+ }
322
+ interface MindooDBAppJsonPatch {
323
+ /**
324
+ * Automerge heads of the document snapshot this JSON patch was authored
325
+ * against. Hosts can use this to apply order-sensitive edits at the original
326
+ * causal version and merge them with concurrent changes.
327
+ */
328
+ baseHeads?: string[];
329
+ set?: MindooDBAppJsonSetPatch[];
330
+ unset?: MindooDBAppJsonUnsetPatch[];
331
+ listInsert?: MindooDBAppJsonListInsertPatch[];
332
+ listDelete?: MindooDBAppJsonListDeletePatch[];
333
+ }
263
334
  /**
264
335
  * Sparse patch payload used when updating an existing document.
265
336
  *
@@ -272,6 +343,8 @@ interface MindooDBAppUpdateDocumentInput {
272
343
  set?: Record<string, unknown>;
273
344
  /** Top-level fields to remove from the document entirely. */
274
345
  unset?: string[];
346
+ /** Granular JSON operations to apply at document paths. */
347
+ json?: MindooDBAppJsonPatch;
275
348
  /** Granular text edits to apply at document paths. */
276
349
  text?: MindooDBAppTextPatch[];
277
350
  }
@@ -537,6 +610,7 @@ interface MindooDBAppViewNavigatorOpenOptions {
537
610
  interface MindooDBAppCreateViewNavigatorInput {
538
611
  databaseIds: string[];
539
612
  definition: MindooDBAppViewDefinition;
613
+ categorizationStyle?: MindooDBAppConfiguredViewCategorizationStyle;
540
614
  options?: MindooDBAppViewNavigatorOpenOptions;
541
615
  }
542
616
  /** @deprecated Use `MindooDBAppCreateViewNavigatorInput`. */
@@ -627,6 +701,7 @@ interface MindooDBAppAttachmentApi {
627
701
  }>;
628
702
  openReadStream(docId: string, attachmentName: string, options?: MindooDBAppAttachmentPreviewOptions): Promise<MindooDBAppReadableAttachmentStream>;
629
703
  openWriteStream(docId: string, attachmentName: string, contentType?: string): Promise<MindooDBAppWritableAttachmentStream>;
704
+ scan(docId: string, options?: MindooDBAppScanAttachmentOptions): Promise<MindooDBAppScanAttachmentResult>;
630
705
  preparePreviewSession(docId: string, attachmentName: string, options?: MindooDBAppAttachmentPreviewOptions): Promise<MindooDBAppAttachmentPreviewSession>;
631
706
  openPreview(docId: string, attachmentName: string, options?: MindooDBAppAttachmentPreviewOptions): Promise<{
632
707
  ok: true;
@@ -657,4 +732,4 @@ interface MindooDBAppBridge {
657
732
  connect(options?: MindooDBAppBridgeConnectOptions): Promise<MindooDBAppSession>;
658
733
  }
659
734
 
660
- export type { MindooDBAppDocumentListQuery as $, MindooDBAppBridgeThemeChangedMessage as A, MindooDBAppBridgeUiPreferencesChangedMessage as B, MindooDBAppBridgeViewportChangedMessage as C, MindooDBAppCapability as D, MindooDBAppConfiguredViewCategorizationStyle as E, MindooDBAppConfiguredViewColumn as F, MindooDBAppConfiguredViewColumnRole as G, MindooDBAppConfiguredViewExpressionMode as H, MindooDBAppConfiguredViewFieldExpression as I, MindooDBAppConfiguredViewFilterDefinition as J, MindooDBAppConfiguredViewFilterMode as K, MindooDBAppConfiguredViewFilterRule as L, MindooDBAppAttachmentPreviewMode as M, MindooDBAppConfiguredViewFormulaExpression as N, MindooDBAppConfiguredViewFormulaFilterDefinition as O, MindooDBAppConfiguredViewPreviewMode as P, MindooDBAppConfiguredViewRuleFilterDefinition as Q, MindooDBAppConfiguredViewRuleMatchMode as R, MindooDBAppConfiguredViewRuleOperator as S, MindooDBAppConfiguredViewValueExpression as T, MindooDBAppCreateDocumentInput as U, MindooDBAppCreateViewInput as V, MindooDBAppCreateViewNavigatorInput as W, MindooDBAppDatabaseInfo as X, MindooDBAppDocumentApi as Y, MindooDBAppDocumentHeadCursorResult as Z, MindooDBAppDocumentHistoryEntry as _, MindooDBAppBridge as a, MindooDBAppDocumentListResult as a0, MindooDBAppDocumentRevisionId as a1, MindooDBAppDocumentSummary as a2, MindooDBAppHistoricalDocument as a3, MindooDBAppHistoryQuery as a4, MindooDBAppHostTheme as a5, MindooDBAppLaunchContext as a6, MindooDBAppMenuAnchor as a7, MindooDBAppMenuApi as a8, MindooDBAppMenuCommandItem as a9, MindooDBAppViewEntry as aA, MindooDBAppViewEntryKind as aB, MindooDBAppViewNavigator as aC, MindooDBAppViewNavigatorExpansionState as aD, MindooDBAppViewNavigatorOpenOptions as aE, MindooDBAppViewNavigatorPageOptions as aF, MindooDBAppViewNavigatorPageResult as aG, MindooDBAppViewNavigatorRangeQuery as aH, MindooDBAppViewNavigatorSelectionState as aI, MindooDBAppViewport as aJ, MindooDBAppWritableAttachmentStream as aK, MindooDBAppMenuDismissReason as aa, MindooDBAppMenuDismissedResult as ab, MindooDBAppMenuItem as ac, MindooDBAppMenuKind as ad, MindooDBAppMenuPlacement as ae, MindooDBAppMenuPointAnchor as af, MindooDBAppMenuRect as ag, MindooDBAppMenuRectAnchor as ah, MindooDBAppMenuSelectionResult as ai, MindooDBAppMenuSeparatorItem as aj, MindooDBAppReadableAttachmentStream as ak, MindooDBAppResolvedViewDefinition as al, MindooDBAppResolvedViewSource as am, MindooDBAppRuntime as an, MindooDBAppScopedDocId as ao, MindooDBAppScopedDocumentSummary as ap, MindooDBAppSession as aq, MindooDBAppShowMenuInput as ar, MindooDBAppShowMenuResult as as, MindooDBAppTextEdit as at, MindooDBAppTextPatch as au, MindooDBAppThemeMode as av, MindooDBAppUiPreferences as aw, MindooDBAppUpdateDocumentInput as ax, MindooDBAppViewCursorDocumentListResult as ay, MindooDBAppViewCursorResult as az, MindooDBAppDatabase as b, MindooDBAppDocument as c, MindooDBAppAttachmentApi as d, MindooDBAppAttachmentChunk as e, MindooDBAppAttachmentInfo as f, MindooDBAppAttachmentPreviewOptions as g, MindooDBAppAttachmentPreviewSession as h, MindooDBAppBridgeConnectMessage as i, MindooDBAppBridgeConnectOptions as j, MindooDBAppBridgeConnectedMessage as k, MindooDBAppBridgeErrorPayload as l, MindooDBAppBridgeHandshakeErrorMessage as m, MindooDBAppBridgePortMessage as n, MindooDBAppBridgeRpcError as o, MindooDBAppBridgeRpcMessage as p, MindooDBAppBridgeRpcRequest as q, MindooDBAppBridgeRpcSuccess as r, MindooDBAppBridgeStreamAbortRequest as s, MindooDBAppBridgeStreamAck as t, MindooDBAppBridgeStreamCloseRequest as u, MindooDBAppBridgeStreamError as v, MindooDBAppBridgeStreamMessage as w, MindooDBAppBridgeStreamOpenResult as x, MindooDBAppBridgeStreamReadRequest as y, MindooDBAppBridgeStreamWriteRequest as z };
735
+ export type { MindooDBAppDocumentListQuery as $, MindooDBAppBridgeThemeChangedMessage as A, MindooDBAppBridgeUiPreferencesChangedMessage as B, MindooDBAppBridgeViewportChangedMessage as C, MindooDBAppCapability as D, MindooDBAppConfiguredViewCategorizationStyle as E, MindooDBAppConfiguredViewColumn as F, MindooDBAppConfiguredViewColumnRole as G, MindooDBAppConfiguredViewExpressionMode as H, MindooDBAppConfiguredViewFieldExpression as I, MindooDBAppConfiguredViewFilterDefinition as J, MindooDBAppConfiguredViewFilterMode as K, MindooDBAppConfiguredViewFilterRule as L, MindooDBAppAttachmentPreviewMode as M, MindooDBAppConfiguredViewFormulaExpression as N, MindooDBAppConfiguredViewFormulaFilterDefinition as O, MindooDBAppConfiguredViewPreviewMode as P, MindooDBAppConfiguredViewRuleFilterDefinition as Q, MindooDBAppConfiguredViewRuleMatchMode as R, MindooDBAppConfiguredViewRuleOperator as S, MindooDBAppConfiguredViewValueExpression as T, MindooDBAppCreateDocumentInput as U, MindooDBAppCreateViewInput as V, MindooDBAppCreateViewNavigatorInput as W, MindooDBAppDatabaseInfo as X, MindooDBAppDocumentApi as Y, MindooDBAppDocumentHeadCursorResult as Z, MindooDBAppDocumentHistoryEntry as _, MindooDBAppBridge as a, MindooDBAppDocumentListResult as a0, MindooDBAppDocumentRevisionId as a1, MindooDBAppDocumentScanPreset as a2, MindooDBAppDocumentSummary as a3, MindooDBAppHistoricalDocument as a4, MindooDBAppHistoryQuery as a5, MindooDBAppHostTheme as a6, MindooDBAppJsonListDeletePatch as a7, MindooDBAppJsonListInsertPatch as a8, MindooDBAppJsonPatch as a9, MindooDBAppShowMenuResult as aA, MindooDBAppTextEdit as aB, MindooDBAppTextPatch as aC, MindooDBAppThemeMode as aD, MindooDBAppUiPreferences as aE, MindooDBAppUpdateDocumentInput as aF, MindooDBAppViewCursorDocumentListResult as aG, MindooDBAppViewCursorResult as aH, MindooDBAppViewEntry as aI, MindooDBAppViewEntryKind as aJ, MindooDBAppViewNavigator as aK, MindooDBAppViewNavigatorExpansionState as aL, MindooDBAppViewNavigatorOpenOptions as aM, MindooDBAppViewNavigatorPageOptions as aN, MindooDBAppViewNavigatorPageResult as aO, MindooDBAppViewNavigatorRangeQuery as aP, MindooDBAppViewNavigatorSelectionState as aQ, MindooDBAppViewport as aR, MindooDBAppWritableAttachmentStream as aS, MindooDBAppJsonSetPatch as aa, MindooDBAppJsonUnsetPatch as ab, MindooDBAppLaunchContext as ac, MindooDBAppMenuAnchor as ad, MindooDBAppMenuApi as ae, MindooDBAppMenuCommandItem as af, MindooDBAppMenuDismissReason as ag, MindooDBAppMenuDismissedResult as ah, MindooDBAppMenuItem as ai, MindooDBAppMenuKind as aj, MindooDBAppMenuPlacement as ak, MindooDBAppMenuPointAnchor as al, MindooDBAppMenuRect as am, MindooDBAppMenuRectAnchor as an, MindooDBAppMenuSelectionResult as ao, MindooDBAppMenuSeparatorItem as ap, MindooDBAppReadableAttachmentStream as aq, MindooDBAppResolvedViewDefinition as ar, MindooDBAppResolvedViewSource as as, MindooDBAppRuntime as at, MindooDBAppScanAttachmentOptions as au, MindooDBAppScanAttachmentResult as av, MindooDBAppScopedDocId as aw, MindooDBAppScopedDocumentSummary as ax, MindooDBAppSession as ay, MindooDBAppShowMenuInput as az, MindooDBAppDatabase as b, MindooDBAppDocument as c, MindooDBAppAttachmentApi as d, MindooDBAppAttachmentChunk as e, MindooDBAppAttachmentInfo as f, MindooDBAppAttachmentPreviewOptions as g, MindooDBAppAttachmentPreviewSession as h, MindooDBAppBridgeConnectMessage as i, MindooDBAppBridgeConnectOptions as j, MindooDBAppBridgeConnectedMessage as k, MindooDBAppBridgeErrorPayload as l, MindooDBAppBridgeHandshakeErrorMessage as m, MindooDBAppBridgePortMessage as n, MindooDBAppBridgeRpcError as o, MindooDBAppBridgeRpcMessage as p, MindooDBAppBridgeRpcRequest as q, MindooDBAppBridgeRpcSuccess as r, MindooDBAppBridgeStreamAbortRequest as s, MindooDBAppBridgeStreamAck as t, MindooDBAppBridgeStreamCloseRequest as u, MindooDBAppBridgeStreamError as v, MindooDBAppBridgeStreamMessage as w, MindooDBAppBridgeStreamOpenResult as x, MindooDBAppBridgeStreamReadRequest as y, MindooDBAppBridgeStreamWriteRequest as z };
package/package.json CHANGED
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "name": "mindoodb-app-sdk",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
4
+ "engines": {
5
+ "node": ">=22.13.0"
6
+ },
4
7
  "description": "MindooDB app SDK for building apps that connect to the Haven host bridge",
5
8
  "license": "ISC",
6
9
  "author": "Mindoo GmbH",
@@ -32,20 +35,19 @@
32
35
  "default": "./dist/testing/index.js"
33
36
  }
34
37
  },
35
- "scripts": {
36
- "build": "tsup src/index.ts src/testing/index.ts --format esm --dts --clean --tsconfig tsconfig.build.json",
37
- "typecheck": "tsc --noEmit -p tsconfig.json",
38
- "test": "vitest run",
39
- "test:watch": "vitest",
40
- "prepublishOnly": "npm run build && npm run test"
41
- },
42
38
  "dependencies": {
43
- "mindoodb-view-language": "0.0.11"
39
+ "mindoodb-view-language": "0.0.12"
44
40
  },
45
41
  "devDependencies": {
46
- "@types/node": "^25.5.0",
42
+ "@types/node": "25.5.0",
47
43
  "tsup": "^8.5.1",
48
44
  "typescript": "^6.0.2",
49
45
  "vitest": "^4.1.2"
46
+ },
47
+ "scripts": {
48
+ "build": "tsup src/index.ts src/testing/index.ts --format esm --dts --clean --tsconfig tsconfig.build.json",
49
+ "typecheck": "tsc --noEmit -p tsconfig.json",
50
+ "test": "vitest run",
51
+ "test:watch": "vitest"
50
52
  }
51
- }
53
+ }