mindoodb-app-sdk 0.0.14 → 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 +410 -132
- package/dist/index.d.ts +97 -4
- package/dist/index.js +367 -55
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +300 -40
- package/dist/{types-B1iKRIuy.d.ts → types-Dw6YRApH.d.ts} +135 -9
- 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,8 +22,109 @@ 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);
|
|
26
|
+
for (const textPatch of patch.text ?? []) {
|
|
27
|
+
applyMockTextPatch(next, textPatch.path, textPatch.edits);
|
|
28
|
+
}
|
|
23
29
|
return next;
|
|
24
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
|
+
}
|
|
100
|
+
function applyMockTextPatch(target, path, edits) {
|
|
101
|
+
if (path.length === 0) {
|
|
102
|
+
throw new Error("Text patch path must contain at least one segment");
|
|
103
|
+
}
|
|
104
|
+
let parent = target;
|
|
105
|
+
for (let index = 0; index < path.length - 1; index += 1) {
|
|
106
|
+
const segment = path[index];
|
|
107
|
+
const nextSegment = path[index + 1];
|
|
108
|
+
if (parent[segment] == null) {
|
|
109
|
+
parent[segment] = typeof nextSegment === "number" ? [] : {};
|
|
110
|
+
}
|
|
111
|
+
parent = parent[segment];
|
|
112
|
+
}
|
|
113
|
+
const leaf = path[path.length - 1];
|
|
114
|
+
let value = parent[leaf];
|
|
115
|
+
if (value == null) {
|
|
116
|
+
value = "";
|
|
117
|
+
}
|
|
118
|
+
if (typeof value !== "string") {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`Cannot apply text patch to non-string value at ${path.map(String).join(".")}`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
for (const edit of edits) {
|
|
124
|
+
value = value.slice(0, edit.index) + (edit.insert ?? "") + value.slice(edit.index + edit.deleteCount);
|
|
125
|
+
}
|
|
126
|
+
parent[leaf] = value;
|
|
127
|
+
}
|
|
25
128
|
function mergeLaunchContext(current, patch) {
|
|
26
129
|
if (!patch) {
|
|
27
130
|
return {
|
|
@@ -40,7 +143,10 @@ function mergeLaunchContext(current, patch) {
|
|
|
40
143
|
sources: view.sources.map((source) => ({ ...source })),
|
|
41
144
|
columns: view.columns.map((column) => ({
|
|
42
145
|
...column,
|
|
43
|
-
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
|
+
}
|
|
44
150
|
})),
|
|
45
151
|
filter: view.filter.mode === "rules" ? {
|
|
46
152
|
mode: "rules",
|
|
@@ -73,7 +179,10 @@ function mergeLaunchContext(current, patch) {
|
|
|
73
179
|
sources: view.sources.map((source) => ({ ...source })),
|
|
74
180
|
columns: view.columns.map((column) => ({
|
|
75
181
|
...column,
|
|
76
|
-
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
|
+
}
|
|
77
186
|
})),
|
|
78
187
|
filter: view.filter.mode === "rules" ? {
|
|
79
188
|
mode: "rules",
|
|
@@ -88,7 +197,10 @@ function mergeLaunchContext(current, patch) {
|
|
|
88
197
|
sources: view.sources.map((source) => ({ ...source })),
|
|
89
198
|
columns: view.columns.map((column) => ({
|
|
90
199
|
...column,
|
|
91
|
-
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
|
+
}
|
|
92
204
|
})),
|
|
93
205
|
filter: view.filter.mode === "rules" ? {
|
|
94
206
|
mode: "rules",
|
|
@@ -178,7 +290,9 @@ function matchesDocumentFilter(document, filter) {
|
|
|
178
290
|
if (!filter) {
|
|
179
291
|
return true;
|
|
180
292
|
}
|
|
181
|
-
return Object.entries(filter).every(
|
|
293
|
+
return Object.entries(filter).every(
|
|
294
|
+
([field, expected]) => getFieldValue(document.data, field) === expected
|
|
295
|
+
);
|
|
182
296
|
}
|
|
183
297
|
function decodeMockListCursor(cursor) {
|
|
184
298
|
if (!cursor) {
|
|
@@ -393,6 +507,7 @@ function createDefaultViewNavigator() {
|
|
|
393
507
|
}
|
|
394
508
|
function createDatabaseHandle(definition) {
|
|
395
509
|
let createCounter = 0;
|
|
510
|
+
let changeCounter = 0;
|
|
396
511
|
const defaultViewFactory = async () => createDefaultViewNavigator();
|
|
397
512
|
const storedDocuments = /* @__PURE__ */ new Map();
|
|
398
513
|
const defaultDocuments = {
|
|
@@ -402,7 +517,11 @@ function createDatabaseHandle(definition) {
|
|
|
402
517
|
const limit = Math.max(1, query?.limit ?? 50);
|
|
403
518
|
const offset = decodeMockListCursor(query?.cursor) + skip;
|
|
404
519
|
const metadataOnly = query?.metadataOnly ?? false;
|
|
405
|
-
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));
|
|
406
525
|
const page = items.slice(offset, offset + limit).map((document) => {
|
|
407
526
|
if (metadataOnly) {
|
|
408
527
|
return {
|
|
@@ -410,7 +529,12 @@ function createDatabaseHandle(definition) {
|
|
|
410
529
|
isDeleted: document.isDeleted
|
|
411
530
|
};
|
|
412
531
|
}
|
|
413
|
-
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;
|
|
414
538
|
return {
|
|
415
539
|
id: document.id,
|
|
416
540
|
data: projectedData,
|
|
@@ -438,16 +562,42 @@ function createDatabaseHandle(definition) {
|
|
|
438
562
|
return {
|
|
439
563
|
id: document.id,
|
|
440
564
|
data: structuredClone(document.data),
|
|
565
|
+
heads: document.heads ? [...document.heads] : void 0,
|
|
441
566
|
attachments: document.attachments ? structuredClone(document.attachments) : [],
|
|
442
567
|
updatedAt: document.updatedAt
|
|
443
568
|
};
|
|
444
569
|
},
|
|
445
570
|
async create(input) {
|
|
446
|
-
|
|
571
|
+
const callerId = typeof input.id === "string" && input.id.length > 0 ? input.id : null;
|
|
572
|
+
if (callerId) {
|
|
573
|
+
const existing = storedDocuments.get(callerId);
|
|
574
|
+
if (existing) {
|
|
575
|
+
if (existing.isDeleted) {
|
|
576
|
+
existing.isDeleted = false;
|
|
577
|
+
existing.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
578
|
+
existing.heads = [`mock-head-${++changeCounter}`];
|
|
579
|
+
}
|
|
580
|
+
return {
|
|
581
|
+
id: existing.id,
|
|
582
|
+
data: structuredClone(existing.data),
|
|
583
|
+
heads: existing.heads ? [...existing.heads] : void 0,
|
|
584
|
+
attachments: existing.attachments ? structuredClone(existing.attachments) : [],
|
|
585
|
+
updatedAt: existing.updatedAt
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
let id;
|
|
590
|
+
if (callerId) {
|
|
591
|
+
id = callerId;
|
|
592
|
+
} else {
|
|
593
|
+
createCounter += 1;
|
|
594
|
+
id = `doc-${createCounter}`;
|
|
595
|
+
}
|
|
447
596
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
448
597
|
const created = {
|
|
449
|
-
id
|
|
598
|
+
id,
|
|
450
599
|
data: { ...input.set },
|
|
600
|
+
heads: [`mock-head-${++changeCounter}`],
|
|
451
601
|
attachments: [],
|
|
452
602
|
updatedAt: createdAt
|
|
453
603
|
};
|
|
@@ -467,6 +617,7 @@ function createDatabaseHandle(definition) {
|
|
|
467
617
|
const updated = {
|
|
468
618
|
id: docId,
|
|
469
619
|
data: applyDocumentUpdatePatch(existing?.data ?? {}, patch),
|
|
620
|
+
heads: [`mock-head-${++changeCounter}`],
|
|
470
621
|
attachments: existing?.attachments ? structuredClone(existing.attachments) : [],
|
|
471
622
|
updatedAt
|
|
472
623
|
};
|
|
@@ -489,6 +640,18 @@ function createDatabaseHandle(definition) {
|
|
|
489
640
|
}
|
|
490
641
|
return { ok: true };
|
|
491
642
|
},
|
|
643
|
+
async undelete(_docId) {
|
|
644
|
+
const existing = storedDocuments.get(_docId);
|
|
645
|
+
if (existing) {
|
|
646
|
+
storedDocuments.set(_docId, {
|
|
647
|
+
...existing,
|
|
648
|
+
isDeleted: false,
|
|
649
|
+
heads: [`mock-head-${++changeCounter}`],
|
|
650
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
return { ok: true };
|
|
654
|
+
},
|
|
492
655
|
async listHistory(_docId) {
|
|
493
656
|
return [];
|
|
494
657
|
},
|
|
@@ -497,7 +660,19 @@ function createDatabaseHandle(definition) {
|
|
|
497
660
|
id: docId,
|
|
498
661
|
timestamp,
|
|
499
662
|
state: "missing",
|
|
500
|
-
data: null
|
|
663
|
+
data: null,
|
|
664
|
+
attachments: []
|
|
665
|
+
};
|
|
666
|
+
},
|
|
667
|
+
async getAtRevision(docId, revisionId) {
|
|
668
|
+
return {
|
|
669
|
+
id: docId,
|
|
670
|
+
revisionId,
|
|
671
|
+
timestamp: Date.now(),
|
|
672
|
+
heads: [],
|
|
673
|
+
state: "missing",
|
|
674
|
+
data: null,
|
|
675
|
+
attachments: []
|
|
501
676
|
};
|
|
502
677
|
}
|
|
503
678
|
};
|
|
@@ -510,18 +685,29 @@ function createDatabaseHandle(definition) {
|
|
|
510
685
|
}
|
|
511
686
|
};
|
|
512
687
|
const defaultAttachments = {
|
|
513
|
-
async list(_docId) {
|
|
688
|
+
async list(_docId, _options) {
|
|
514
689
|
return [];
|
|
515
690
|
},
|
|
516
691
|
async remove(_docId, _attachmentName) {
|
|
517
692
|
return { ok: true };
|
|
518
693
|
},
|
|
519
|
-
async openReadStream(_docId, _attachmentName) {
|
|
694
|
+
async openReadStream(_docId, _attachmentName, _options) {
|
|
520
695
|
return createDefaultReadableAttachmentStream();
|
|
521
696
|
},
|
|
522
697
|
async openWriteStream(_docId, _attachmentName, _contentType) {
|
|
523
698
|
return createDefaultWritableAttachmentStream();
|
|
524
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
|
+
},
|
|
525
711
|
async preparePreviewSession(_docId, _attachmentName, _options) {
|
|
526
712
|
return {
|
|
527
713
|
sessionId: "preview-session-1",
|
|
@@ -535,7 +721,10 @@ function createDatabaseHandle(definition) {
|
|
|
535
721
|
const methods = definition.methods ?? {};
|
|
536
722
|
return {
|
|
537
723
|
async info() {
|
|
538
|
-
return {
|
|
724
|
+
return {
|
|
725
|
+
...definition.info,
|
|
726
|
+
capabilities: [...definition.info.capabilities]
|
|
727
|
+
};
|
|
539
728
|
},
|
|
540
729
|
documents: {
|
|
541
730
|
...defaultDocuments,
|
|
@@ -596,7 +785,9 @@ function createMockSessionState(options = {}) {
|
|
|
596
785
|
...definition.methods?.views ?? {}
|
|
597
786
|
});
|
|
598
787
|
}
|
|
599
|
-
launchContext = mergeLaunchContext(launchContext, {
|
|
788
|
+
launchContext = mergeLaunchContext(launchContext, {
|
|
789
|
+
databases: databaseInfos
|
|
790
|
+
});
|
|
600
791
|
};
|
|
601
792
|
setDatabases(options.databases ?? []);
|
|
602
793
|
const session = {
|
|
@@ -625,11 +816,15 @@ function createMockSessionState(options = {}) {
|
|
|
625
816
|
async createViewNavigator(input) {
|
|
626
817
|
const firstDatabaseId = input.databaseIds[0];
|
|
627
818
|
if (!firstDatabaseId) {
|
|
628
|
-
throw new Error(
|
|
819
|
+
throw new Error(
|
|
820
|
+
"At least one test database is required for view creation."
|
|
821
|
+
);
|
|
629
822
|
}
|
|
630
823
|
const api = databaseViewApis.get(firstDatabaseId);
|
|
631
824
|
if (!api) {
|
|
632
|
-
throw new Error(
|
|
825
|
+
throw new Error(
|
|
826
|
+
`Unknown test database for view creation: ${firstDatabaseId}`
|
|
827
|
+
);
|
|
633
828
|
}
|
|
634
829
|
const view = await api.create(input);
|
|
635
830
|
const viewId = input.definition.id || crypto.randomUUID();
|
|
@@ -641,13 +836,17 @@ function createMockSessionState(options = {}) {
|
|
|
641
836
|
if (existing) {
|
|
642
837
|
return existing;
|
|
643
838
|
}
|
|
644
|
-
const sourceDatabaseId = launchContext.views.find(
|
|
839
|
+
const sourceDatabaseId = launchContext.views.find(
|
|
840
|
+
(view2) => view2.id === viewId
|
|
841
|
+
)?.sources[0]?.databaseId;
|
|
645
842
|
if (!sourceDatabaseId) {
|
|
646
843
|
throw new Error(`Unknown test view: ${viewId}`);
|
|
647
844
|
}
|
|
648
845
|
const api = databaseViewApis.get(sourceDatabaseId);
|
|
649
846
|
if (!api) {
|
|
650
|
-
throw new Error(
|
|
847
|
+
throw new Error(
|
|
848
|
+
`Unknown test database for view ${viewId}: ${sourceDatabaseId}`
|
|
849
|
+
);
|
|
651
850
|
}
|
|
652
851
|
const view = await api.open(viewId, options2);
|
|
653
852
|
sessionViews.set(viewId, view);
|
|
@@ -709,7 +908,9 @@ function createMockSessionState(options = {}) {
|
|
|
709
908
|
session,
|
|
710
909
|
emitThemeChange(theme) {
|
|
711
910
|
launchContext = mergeLaunchContext(launchContext, { theme });
|
|
712
|
-
themeListeners.forEach(
|
|
911
|
+
themeListeners.forEach(
|
|
912
|
+
(listener) => listener({ ...launchContext.theme })
|
|
913
|
+
);
|
|
713
914
|
},
|
|
714
915
|
emitViewportChange(viewport) {
|
|
715
916
|
launchContext = mergeLaunchContext(launchContext, { viewport });
|
|
@@ -717,7 +918,9 @@ function createMockSessionState(options = {}) {
|
|
|
717
918
|
},
|
|
718
919
|
emitUiPreferencesChange(uiPreferences) {
|
|
719
920
|
launchContext = mergeLaunchContext(launchContext, { uiPreferences });
|
|
720
|
-
uiPreferencesListeners.forEach(
|
|
921
|
+
uiPreferencesListeners.forEach(
|
|
922
|
+
(listener) => listener({ ...launchContext.uiPreferences })
|
|
923
|
+
);
|
|
721
924
|
}
|
|
722
925
|
};
|
|
723
926
|
}
|
|
@@ -740,7 +943,9 @@ function createMockMindooDBAppBridge(options = {}) {
|
|
|
740
943
|
}
|
|
741
944
|
function createFakeBridgeHost(options = {}) {
|
|
742
945
|
const state = createMockSessionState(options);
|
|
743
|
-
const customRequestHandlers = new Map(
|
|
946
|
+
const customRequestHandlers = new Map(
|
|
947
|
+
Object.entries(options.requestHandlers ?? {})
|
|
948
|
+
);
|
|
744
949
|
const requests = [];
|
|
745
950
|
const connectedPorts = /* @__PURE__ */ new Set();
|
|
746
951
|
const viewSessions = /* @__PURE__ */ new Map();
|
|
@@ -748,7 +953,10 @@ function createFakeBridgeHost(options = {}) {
|
|
|
748
953
|
const writeStreams = /* @__PURE__ */ new Map();
|
|
749
954
|
let viewCounter = 0;
|
|
750
955
|
let streamCounter = 0;
|
|
751
|
-
let previousWindowDescriptor = Object.getOwnPropertyDescriptor(
|
|
956
|
+
let previousWindowDescriptor = Object.getOwnPropertyDescriptor(
|
|
957
|
+
globalThis,
|
|
958
|
+
"window"
|
|
959
|
+
);
|
|
752
960
|
let previousWindowValue = typeof window === "undefined" ? void 0 : window;
|
|
753
961
|
let installed = false;
|
|
754
962
|
const hostWindow = {
|
|
@@ -762,7 +970,9 @@ function createFakeBridgeHost(options = {}) {
|
|
|
762
970
|
}
|
|
763
971
|
const port = transfer?.[0];
|
|
764
972
|
if (!port) {
|
|
765
|
-
throw new Error(
|
|
973
|
+
throw new Error(
|
|
974
|
+
"Expected the bridge connection to transfer a MessagePort."
|
|
975
|
+
);
|
|
766
976
|
}
|
|
767
977
|
connectedPorts.add(port);
|
|
768
978
|
port.addEventListener("message", (event) => {
|
|
@@ -804,7 +1014,10 @@ function createFakeBridgeHost(options = {}) {
|
|
|
804
1014
|
if (installed) {
|
|
805
1015
|
return;
|
|
806
1016
|
}
|
|
807
|
-
previousWindowDescriptor = Object.getOwnPropertyDescriptor(
|
|
1017
|
+
previousWindowDescriptor = Object.getOwnPropertyDescriptor(
|
|
1018
|
+
globalThis,
|
|
1019
|
+
"window"
|
|
1020
|
+
);
|
|
808
1021
|
previousWindowValue = typeof window === "undefined" ? void 0 : window;
|
|
809
1022
|
const baseWindow = typeof window === "undefined" ? {} : window;
|
|
810
1023
|
const nextWindow = Object.create(baseWindow);
|
|
@@ -894,6 +1107,7 @@ function createFakeBridgeHost(options = {}) {
|
|
|
894
1107
|
const navigator = await state.createViewNavigator({
|
|
895
1108
|
databaseIds: Array.isArray(params.databaseIds) ? params.databaseIds.map((entry) => String(entry)) : [],
|
|
896
1109
|
definition: params.definition,
|
|
1110
|
+
categorizationStyle: params.categorizationStyle === "category_then_document" ? "category_then_document" : "document_then_category",
|
|
897
1111
|
options: params.options
|
|
898
1112
|
});
|
|
899
1113
|
viewSessions.set(navigatorId, navigator);
|
|
@@ -909,7 +1123,9 @@ function createFakeBridgeHost(options = {}) {
|
|
|
909
1123
|
return { navigatorId };
|
|
910
1124
|
}
|
|
911
1125
|
case "menus.show":
|
|
912
|
-
return await state.session.menus.show(
|
|
1126
|
+
return await state.session.menus.show(
|
|
1127
|
+
request.params
|
|
1128
|
+
);
|
|
913
1129
|
case "menus.hide":
|
|
914
1130
|
await state.session.menus.hide();
|
|
915
1131
|
return { ok: true };
|
|
@@ -917,13 +1133,17 @@ function createFakeBridgeHost(options = {}) {
|
|
|
917
1133
|
await state.session.disconnect();
|
|
918
1134
|
return { ok: true };
|
|
919
1135
|
case "documents.list":
|
|
920
|
-
return await state.getDatabase(String(params.databaseId)).documents.list(
|
|
1136
|
+
return await state.getDatabase(String(params.databaseId)).documents.list(
|
|
1137
|
+
params.query
|
|
1138
|
+
);
|
|
921
1139
|
case "documents.getHeadCursor":
|
|
922
1140
|
return await state.getDatabase(String(params.databaseId)).documents.getHeadCursor();
|
|
923
1141
|
case "documents.get":
|
|
924
1142
|
return await state.getDatabase(String(params.databaseId)).documents.get(String(params.docId));
|
|
925
1143
|
case "documents.create":
|
|
926
|
-
return await state.getDatabase(String(params.databaseId)).documents.create(
|
|
1144
|
+
return await state.getDatabase(String(params.databaseId)).documents.create(
|
|
1145
|
+
params.input
|
|
1146
|
+
);
|
|
927
1147
|
case "documents.update":
|
|
928
1148
|
return await state.getDatabase(String(params.databaseId)).documents.update(
|
|
929
1149
|
String(params.docId),
|
|
@@ -931,6 +1151,8 @@ function createFakeBridgeHost(options = {}) {
|
|
|
931
1151
|
);
|
|
932
1152
|
case "documents.delete":
|
|
933
1153
|
return await state.getDatabase(String(params.databaseId)).documents.delete(String(params.docId));
|
|
1154
|
+
case "documents.undelete":
|
|
1155
|
+
return await state.getDatabase(String(params.databaseId)).documents.undelete(String(params.docId));
|
|
934
1156
|
case "documents.history.list":
|
|
935
1157
|
return await state.getDatabase(String(params.databaseId)).documents.listHistory(String(params.docId));
|
|
936
1158
|
case "documents.history.getAtTimestamp":
|
|
@@ -938,8 +1160,16 @@ function createFakeBridgeHost(options = {}) {
|
|
|
938
1160
|
String(params.docId),
|
|
939
1161
|
Number(params.timestamp)
|
|
940
1162
|
);
|
|
1163
|
+
case "documents.history.getAtRevision":
|
|
1164
|
+
return await state.getDatabase(String(params.databaseId)).documents.getAtRevision(
|
|
1165
|
+
String(params.docId),
|
|
1166
|
+
String(params.revisionId)
|
|
1167
|
+
);
|
|
941
1168
|
case "attachments.list":
|
|
942
|
-
return await state.getDatabase(String(params.databaseId)).attachments.list(
|
|
1169
|
+
return await state.getDatabase(String(params.databaseId)).attachments.list(
|
|
1170
|
+
String(params.docId),
|
|
1171
|
+
typeof params.revisionId === "string" ? { revisionId: params.revisionId } : typeof params.timestamp === "number" ? { timestamp: params.timestamp } : void 0
|
|
1172
|
+
);
|
|
943
1173
|
case "attachments.remove":
|
|
944
1174
|
return await state.getDatabase(String(params.databaseId)).attachments.remove(
|
|
945
1175
|
String(params.docId),
|
|
@@ -948,7 +1178,8 @@ function createFakeBridgeHost(options = {}) {
|
|
|
948
1178
|
case "attachments.openReadStream": {
|
|
949
1179
|
const stream = await state.getDatabase(String(params.databaseId)).attachments.openReadStream(
|
|
950
1180
|
String(params.docId),
|
|
951
|
-
String(params.attachmentName)
|
|
1181
|
+
String(params.attachmentName),
|
|
1182
|
+
typeof params.revisionId === "string" ? { revisionId: params.revisionId } : typeof params.timestamp === "number" ? { timestamp: params.timestamp } : void 0
|
|
952
1183
|
);
|
|
953
1184
|
const streamId = `read-${streamCounter += 1}`;
|
|
954
1185
|
readStreams.set(streamId, stream);
|
|
@@ -964,17 +1195,23 @@ function createFakeBridgeHost(options = {}) {
|
|
|
964
1195
|
writeStreams.set(streamId, stream);
|
|
965
1196
|
return { streamId };
|
|
966
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
|
+
});
|
|
967
1204
|
case "attachments.openPreview":
|
|
968
1205
|
return await state.getDatabase(String(params.databaseId)).attachments.openPreview(
|
|
969
1206
|
String(params.docId),
|
|
970
1207
|
String(params.attachmentName),
|
|
971
|
-
typeof params.timestamp === "number" ? { timestamp: params.timestamp } : void 0
|
|
1208
|
+
typeof params.revisionId === "string" ? { revisionId: params.revisionId } : typeof params.timestamp === "number" ? { timestamp: params.timestamp } : void 0
|
|
972
1209
|
);
|
|
973
1210
|
case "attachments.preparePreviewSession":
|
|
974
1211
|
return await state.getDatabase(String(params.databaseId)).attachments.preparePreviewSession(
|
|
975
1212
|
String(params.docId),
|
|
976
1213
|
String(params.attachmentName),
|
|
977
|
-
typeof params.timestamp === "number" ? { timestamp: params.timestamp } : void 0
|
|
1214
|
+
typeof params.revisionId === "string" ? { revisionId: params.revisionId } : typeof params.timestamp === "number" ? { timestamp: params.timestamp } : void 0
|
|
978
1215
|
);
|
|
979
1216
|
case "viewNavigators.getDefinition":
|
|
980
1217
|
return await (await resolveViewNavigator(String(params.navigatorId))).getDefinition();
|
|
@@ -1112,7 +1349,10 @@ function createFakeBridgeHost(options = {}) {
|
|
|
1112
1349
|
if (message.kind === "stream-read") {
|
|
1113
1350
|
const stream = readStreams.get(message.streamId);
|
|
1114
1351
|
if (!stream) {
|
|
1115
|
-
throw Object.assign(
|
|
1352
|
+
throw Object.assign(
|
|
1353
|
+
new Error(`Unknown read stream: ${message.streamId}`),
|
|
1354
|
+
{ name: "stream-not-found" }
|
|
1355
|
+
);
|
|
1116
1356
|
}
|
|
1117
1357
|
const chunk = await stream.read();
|
|
1118
1358
|
port.postMessage({
|
|
@@ -1130,7 +1370,10 @@ function createFakeBridgeHost(options = {}) {
|
|
|
1130
1370
|
if (message.kind === "stream-write") {
|
|
1131
1371
|
const stream = writeStreams.get(message.streamId);
|
|
1132
1372
|
if (!stream) {
|
|
1133
|
-
throw Object.assign(
|
|
1373
|
+
throw Object.assign(
|
|
1374
|
+
new Error(`Unknown write stream: ${message.streamId}`),
|
|
1375
|
+
{ name: "stream-not-found" }
|
|
1376
|
+
);
|
|
1134
1377
|
}
|
|
1135
1378
|
await stream.write(new Uint8Array(message.chunk));
|
|
1136
1379
|
postStreamAck(port, message.streamId);
|
|
@@ -1151,12 +1394,17 @@ function createFakeBridgeHost(options = {}) {
|
|
|
1151
1394
|
postStreamAck(port, message.streamId);
|
|
1152
1395
|
return true;
|
|
1153
1396
|
}
|
|
1154
|
-
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
|
+
});
|
|
1155
1400
|
}
|
|
1156
1401
|
if (message.kind === "stream-abort") {
|
|
1157
1402
|
const stream = writeStreams.get(message.streamId);
|
|
1158
1403
|
if (!stream) {
|
|
1159
|
-
throw Object.assign(
|
|
1404
|
+
throw Object.assign(
|
|
1405
|
+
new Error(`Unknown write stream: ${message.streamId}`),
|
|
1406
|
+
{ name: "stream-not-found" }
|
|
1407
|
+
);
|
|
1160
1408
|
}
|
|
1161
1409
|
await stream.abort();
|
|
1162
1410
|
writeStreams.delete(message.streamId);
|
|
@@ -1175,7 +1423,11 @@ function createFakeBridgeHost(options = {}) {
|
|
|
1175
1423
|
try {
|
|
1176
1424
|
const customHandler = customRequestHandlers.get(message.method);
|
|
1177
1425
|
if (customHandler) {
|
|
1178
|
-
const result = await customHandler(message.params, {
|
|
1426
|
+
const result = await customHandler(message.params, {
|
|
1427
|
+
host: controller,
|
|
1428
|
+
request: message,
|
|
1429
|
+
port
|
|
1430
|
+
});
|
|
1179
1431
|
postRpcSuccess(port, message.id, result);
|
|
1180
1432
|
return;
|
|
1181
1433
|
}
|
|
@@ -1194,15 +1446,23 @@ function createFakeBridgeHost(options = {}) {
|
|
|
1194
1446
|
return;
|
|
1195
1447
|
}
|
|
1196
1448
|
try {
|
|
1197
|
-
const handledByCustom = await options.onPortMessage?.(message, {
|
|
1449
|
+
const handledByCustom = await options.onPortMessage?.(message, {
|
|
1450
|
+
host: controller,
|
|
1451
|
+
port
|
|
1452
|
+
});
|
|
1198
1453
|
if (handledByCustom) {
|
|
1199
1454
|
return;
|
|
1200
1455
|
}
|
|
1201
1456
|
const handled = await handleStreamMessage(port, message);
|
|
1202
1457
|
if (!handled) {
|
|
1203
|
-
throw Object.assign(
|
|
1204
|
-
|
|
1205
|
-
|
|
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
|
+
);
|
|
1206
1466
|
}
|
|
1207
1467
|
} catch (error) {
|
|
1208
1468
|
const streamId = "streamId" in message ? String(message.streamId) : "unknown";
|