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.
- package/README.md +189 -150
- package/dist/index.d.ts +2 -2
- package/dist/index.js +196 -49
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +200 -32
- package/dist/{types-D0vtIHBf.d.ts → types-Dw6YRApH.d.ts} +76 -1
- package/package.json +13 -11
package/dist/testing/index.js
CHANGED
|
@@ -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(
|
|
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(
|
|
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 } : {
|
|
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 } : {
|
|
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 } : {
|
|
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(
|
|
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(
|
|
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(
|
|
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 {
|
|
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, {
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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}`), {
|
|
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(
|
|
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, {
|
|
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, {
|
|
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(
|
|
1296
|
-
|
|
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,
|
|
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.
|
|
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.
|
|
39
|
+
"mindoodb-view-language": "0.0.12"
|
|
44
40
|
},
|
|
45
41
|
"devDependencies": {
|
|
46
|
-
"@types/node": "
|
|
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
|
+
}
|