mindoodb-app-sdk 0.0.4
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 +384 -0
- package/TESTING.md +185 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +634 -0
- package/dist/testing/index.d.ts +60 -0
- package/dist/testing/index.js +801 -0
- package/dist/types-BGdIfp-D.d.ts +372 -0
- package/package.json +51 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
// src/client/portRpcClient.ts
|
|
2
|
+
var PROTOCOL = "mindoodb-app-bridge";
|
|
3
|
+
function normalizeRpcValue(value, seen = /* @__PURE__ */ new WeakMap()) {
|
|
4
|
+
if (typeof value === "function") {
|
|
5
|
+
throw new Error("Bridge RPC params cannot include functions.");
|
|
6
|
+
}
|
|
7
|
+
if (typeof value === "symbol") {
|
|
8
|
+
throw new Error("Bridge RPC params cannot include symbols.");
|
|
9
|
+
}
|
|
10
|
+
if (value === null || typeof value !== "object") {
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
if (value instanceof Date) {
|
|
14
|
+
return new Date(value.getTime());
|
|
15
|
+
}
|
|
16
|
+
if (value instanceof ArrayBuffer) {
|
|
17
|
+
return value.slice(0);
|
|
18
|
+
}
|
|
19
|
+
if (ArrayBuffer.isView(value)) {
|
|
20
|
+
return new Uint8Array(value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength));
|
|
21
|
+
}
|
|
22
|
+
if (seen.has(value)) {
|
|
23
|
+
return seen.get(value);
|
|
24
|
+
}
|
|
25
|
+
if (Array.isArray(value)) {
|
|
26
|
+
const copy2 = [];
|
|
27
|
+
seen.set(value, copy2);
|
|
28
|
+
for (const entry of value) {
|
|
29
|
+
copy2.push(normalizeRpcValue(entry, seen));
|
|
30
|
+
}
|
|
31
|
+
return copy2;
|
|
32
|
+
}
|
|
33
|
+
const copy = {};
|
|
34
|
+
seen.set(value, copy);
|
|
35
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
36
|
+
copy[key] = normalizeRpcValue(entry, seen);
|
|
37
|
+
}
|
|
38
|
+
return copy;
|
|
39
|
+
}
|
|
40
|
+
function toBridgeError(error) {
|
|
41
|
+
const wrapped = new Error(error.message);
|
|
42
|
+
wrapped.name = error.code || "MindooDBAppBridgeError";
|
|
43
|
+
return wrapped;
|
|
44
|
+
}
|
|
45
|
+
function isRpcMessage(message) {
|
|
46
|
+
if (!isProtocolMessage(message)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return "id" in message && typeof message.id === "string";
|
|
50
|
+
}
|
|
51
|
+
function isProtocolMessage(message) {
|
|
52
|
+
return Boolean(
|
|
53
|
+
message && typeof message === "object" && "protocol" in message && message.protocol === PROTOCOL
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
var PortRpcClient = class {
|
|
57
|
+
constructor(port) {
|
|
58
|
+
this.port = port;
|
|
59
|
+
this.handleMessage = this.handleMessage.bind(this);
|
|
60
|
+
this.port.addEventListener("message", this.handleMessage);
|
|
61
|
+
this.port.start();
|
|
62
|
+
}
|
|
63
|
+
pending = /* @__PURE__ */ new Map();
|
|
64
|
+
listeners = /* @__PURE__ */ new Set();
|
|
65
|
+
requestCounter = 0;
|
|
66
|
+
disposed = false;
|
|
67
|
+
/** Sends one RPC request and resolves with the typed response payload. */
|
|
68
|
+
async call(method, params) {
|
|
69
|
+
if (this.disposed) {
|
|
70
|
+
throw new Error("The bridge connection has already been closed.");
|
|
71
|
+
}
|
|
72
|
+
const normalizedParams = normalizeRpcValue(params);
|
|
73
|
+
const id = `${Date.now()}-${this.requestCounter += 1}`;
|
|
74
|
+
const message = {
|
|
75
|
+
protocol: PROTOCOL,
|
|
76
|
+
kind: "request",
|
|
77
|
+
id,
|
|
78
|
+
method,
|
|
79
|
+
params: normalizedParams
|
|
80
|
+
};
|
|
81
|
+
return await new Promise((resolve, reject) => {
|
|
82
|
+
this.pending.set(id, { resolve, reject });
|
|
83
|
+
try {
|
|
84
|
+
this.port.postMessage(message);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
this.pending.delete(id);
|
|
87
|
+
console.error("MindooDB app bridge RPC postMessage failed.", { method, params: normalizedParams, error });
|
|
88
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/** Closes the port and rejects any requests that are still waiting for a response. */
|
|
93
|
+
dispose() {
|
|
94
|
+
if (this.disposed) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
this.disposed = true;
|
|
98
|
+
this.port.removeEventListener("message", this.handleMessage);
|
|
99
|
+
this.port.close();
|
|
100
|
+
this.pending.forEach(({ reject }) => reject(new Error("The bridge connection was closed.")));
|
|
101
|
+
this.pending.clear();
|
|
102
|
+
this.listeners.clear();
|
|
103
|
+
}
|
|
104
|
+
/** Subscribes to all protocol messages, including attachment stream traffic. */
|
|
105
|
+
addMessageListener(listener) {
|
|
106
|
+
this.listeners.add(listener);
|
|
107
|
+
return () => {
|
|
108
|
+
this.listeners.delete(listener);
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/** Posts a raw protocol message over the port, optionally with transferables. */
|
|
112
|
+
postMessage(message, transfer = []) {
|
|
113
|
+
if (this.disposed) {
|
|
114
|
+
throw new Error("The bridge connection has already been closed.");
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
this.port.postMessage(message, transfer);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.error("MindooDB app bridge raw postMessage failed.", { message, transferCount: transfer.length, error });
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/** Dispatches incoming messages to listeners and resolves matching RPC requests. */
|
|
124
|
+
handleMessage(event) {
|
|
125
|
+
if (!isProtocolMessage(event.data)) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const message = event.data;
|
|
129
|
+
this.listeners.forEach((listener) => listener(message));
|
|
130
|
+
if (!isRpcMessage(message)) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (message.kind !== "success" && message.kind !== "error") {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const pending = this.pending.get(message.id);
|
|
137
|
+
if (!pending) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
this.pending.delete(message.id);
|
|
141
|
+
if (message.kind === "success") {
|
|
142
|
+
pending.resolve(message.result);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
pending.reject(toBridgeError(message.error));
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// src/client/createMindooDBAppBridge.ts
|
|
150
|
+
var PROTOCOL2 = "mindoodb-app-bridge";
|
|
151
|
+
var DEFAULT_CONNECT_TIMEOUT_MS = 1e4;
|
|
152
|
+
function toTransferableArrayBuffer(chunk) {
|
|
153
|
+
return chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength);
|
|
154
|
+
}
|
|
155
|
+
function isStreamChunkFor(streamId, message) {
|
|
156
|
+
return message.kind === "stream-chunk" && message.streamId === streamId;
|
|
157
|
+
}
|
|
158
|
+
function isStreamAckFor(streamId, message) {
|
|
159
|
+
return message.kind === "stream-ack" && message.streamId === streamId;
|
|
160
|
+
}
|
|
161
|
+
function isStreamErrorFor(streamId, message) {
|
|
162
|
+
return message.kind === "stream-error" && message.streamId === streamId;
|
|
163
|
+
}
|
|
164
|
+
function isThemeChangedMessage(message) {
|
|
165
|
+
return message.kind === "theme-changed";
|
|
166
|
+
}
|
|
167
|
+
function isViewportChangedMessage(message) {
|
|
168
|
+
return message.kind === "viewport-changed";
|
|
169
|
+
}
|
|
170
|
+
function toStreamError(message) {
|
|
171
|
+
const error = new Error(message.error.message);
|
|
172
|
+
error.name = message.error.code || "MindooDBAppBridgeStreamError";
|
|
173
|
+
return error;
|
|
174
|
+
}
|
|
175
|
+
function resolveLaunchId(options) {
|
|
176
|
+
if (options?.launchId) {
|
|
177
|
+
return options.launchId;
|
|
178
|
+
}
|
|
179
|
+
if (typeof window === "undefined") {
|
|
180
|
+
throw new Error("A launchId must be provided when connecting outside the browser.");
|
|
181
|
+
}
|
|
182
|
+
const search = new URLSearchParams(window.location.search);
|
|
183
|
+
const launchId = search.get("mindoodbAppLaunchId");
|
|
184
|
+
if (!launchId) {
|
|
185
|
+
throw new Error("Missing mindoodbAppLaunchId in the current URL.");
|
|
186
|
+
}
|
|
187
|
+
return launchId;
|
|
188
|
+
}
|
|
189
|
+
function resolveTargetWindow() {
|
|
190
|
+
if (typeof window === "undefined") {
|
|
191
|
+
throw new Error("The MindooDB app bridge is only available in the browser.");
|
|
192
|
+
}
|
|
193
|
+
if (window.parent && window.parent !== window) {
|
|
194
|
+
return window.parent;
|
|
195
|
+
}
|
|
196
|
+
if (window.opener) {
|
|
197
|
+
return window.opener;
|
|
198
|
+
}
|
|
199
|
+
throw new Error("Could not find a MindooDB Administrator host window.");
|
|
200
|
+
}
|
|
201
|
+
function waitForConnectedPort(options, launchId) {
|
|
202
|
+
const targetWindow = resolveTargetWindow();
|
|
203
|
+
const targetOrigin = options?.targetOrigin ?? "*";
|
|
204
|
+
const channel = new MessageChannel();
|
|
205
|
+
const timeoutMs = options?.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
|
|
206
|
+
return new Promise((resolve, reject) => {
|
|
207
|
+
let timeoutId = null;
|
|
208
|
+
const cleanup = () => {
|
|
209
|
+
if (timeoutId !== null) {
|
|
210
|
+
window.clearTimeout(timeoutId);
|
|
211
|
+
}
|
|
212
|
+
channel.port1.removeEventListener("message", handleMessage);
|
|
213
|
+
};
|
|
214
|
+
const handleMessage = (event) => {
|
|
215
|
+
const payload = event.data;
|
|
216
|
+
if (!payload || payload.protocol !== PROTOCOL2 || payload.type !== "mindoodb-app:connected") {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
cleanup();
|
|
220
|
+
resolve(channel.port1);
|
|
221
|
+
};
|
|
222
|
+
timeoutId = window.setTimeout(() => {
|
|
223
|
+
cleanup();
|
|
224
|
+
channel.port1.close();
|
|
225
|
+
reject(new Error(`Timed out while connecting to the MindooDB Administrator bridge for launch ${launchId}.`));
|
|
226
|
+
}, timeoutMs);
|
|
227
|
+
channel.port1.addEventListener("message", handleMessage);
|
|
228
|
+
channel.port1.start();
|
|
229
|
+
const message = {
|
|
230
|
+
protocol: PROTOCOL2,
|
|
231
|
+
type: "mindoodb-app:connect",
|
|
232
|
+
launchId
|
|
233
|
+
};
|
|
234
|
+
targetWindow.postMessage(message, targetOrigin, [channel.port2]);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
var MindooDBAppViewHandleImpl = class {
|
|
238
|
+
constructor(rpc, databaseId, viewId) {
|
|
239
|
+
this.rpc = rpc;
|
|
240
|
+
this.databaseId = databaseId;
|
|
241
|
+
this.viewId = viewId;
|
|
242
|
+
}
|
|
243
|
+
async getDefinition() {
|
|
244
|
+
return await this.rpc.call("views.getDefinition", {
|
|
245
|
+
databaseId: this.databaseId,
|
|
246
|
+
viewId: this.viewId
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
async refresh() {
|
|
250
|
+
await this.rpc.call("views.refresh", {
|
|
251
|
+
databaseId: this.databaseId,
|
|
252
|
+
viewId: this.viewId
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
async page(input) {
|
|
256
|
+
return await this.rpc.call("views.page", {
|
|
257
|
+
databaseId: this.databaseId,
|
|
258
|
+
viewId: this.viewId,
|
|
259
|
+
request: input ?? {}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
async getExpansionState() {
|
|
263
|
+
return await this.rpc.call("views.expansion.get", {
|
|
264
|
+
databaseId: this.databaseId,
|
|
265
|
+
viewId: this.viewId
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
async setExpansionState(state) {
|
|
269
|
+
return await this.rpc.call("views.expansion.set", {
|
|
270
|
+
databaseId: this.databaseId,
|
|
271
|
+
viewId: this.viewId,
|
|
272
|
+
expansion: state
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
async expand(rowKey) {
|
|
276
|
+
return await this.rpc.call("views.expansion.expand", {
|
|
277
|
+
databaseId: this.databaseId,
|
|
278
|
+
viewId: this.viewId,
|
|
279
|
+
rowKey
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
async collapse(rowKey) {
|
|
283
|
+
return await this.rpc.call("views.expansion.collapse", {
|
|
284
|
+
databaseId: this.databaseId,
|
|
285
|
+
viewId: this.viewId,
|
|
286
|
+
rowKey
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
async expandAll() {
|
|
290
|
+
return await this.rpc.call("views.expansion.expandAll", {
|
|
291
|
+
databaseId: this.databaseId,
|
|
292
|
+
viewId: this.viewId
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
async collapseAll() {
|
|
296
|
+
return await this.rpc.call("views.expansion.collapseAll", {
|
|
297
|
+
databaseId: this.databaseId,
|
|
298
|
+
viewId: this.viewId
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
async getRow(rowKey) {
|
|
302
|
+
return await this.rpc.call("views.row.get", {
|
|
303
|
+
databaseId: this.databaseId,
|
|
304
|
+
viewId: this.viewId,
|
|
305
|
+
rowKey
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
async getCategory(input) {
|
|
309
|
+
return await this.rpc.call("views.category.get", {
|
|
310
|
+
databaseId: this.databaseId,
|
|
311
|
+
viewId: this.viewId,
|
|
312
|
+
lookup: input
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
async pageCategory(categoryKey, input) {
|
|
316
|
+
return await this.rpc.call("views.category.page", {
|
|
317
|
+
databaseId: this.databaseId,
|
|
318
|
+
viewId: this.viewId,
|
|
319
|
+
categoryKey,
|
|
320
|
+
request: input ?? {}
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
async listCategoryDocumentIds(categoryKey) {
|
|
324
|
+
return await this.rpc.call("views.category.documentIds", {
|
|
325
|
+
databaseId: this.databaseId,
|
|
326
|
+
viewId: this.viewId,
|
|
327
|
+
categoryKey
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
async dispose() {
|
|
331
|
+
await this.rpc.call("views.dispose", {
|
|
332
|
+
databaseId: this.databaseId,
|
|
333
|
+
viewId: this.viewId
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
var MindooDBAppReadableAttachmentStreamImpl = class {
|
|
338
|
+
constructor(rpc, streamId) {
|
|
339
|
+
this.rpc = rpc;
|
|
340
|
+
this.streamId = streamId;
|
|
341
|
+
this.unsubscribe = this.rpc.addMessageListener((message) => {
|
|
342
|
+
if (isStreamChunkFor(this.streamId, message)) {
|
|
343
|
+
const pending = this.pendingRead;
|
|
344
|
+
this.pendingRead = null;
|
|
345
|
+
if (!pending) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
pending.resolve(message.done ? null : new Uint8Array(message.chunk ?? new ArrayBuffer(0)));
|
|
349
|
+
if (message.done) {
|
|
350
|
+
this.closed = true;
|
|
351
|
+
this.unsubscribe();
|
|
352
|
+
}
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
if (isStreamErrorFor(this.streamId, message)) {
|
|
356
|
+
const pending = this.pendingRead;
|
|
357
|
+
this.pendingRead = null;
|
|
358
|
+
pending?.reject(toStreamError(message));
|
|
359
|
+
this.closed = true;
|
|
360
|
+
this.unsubscribe();
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
unsubscribe;
|
|
365
|
+
closed = false;
|
|
366
|
+
pendingRead = null;
|
|
367
|
+
/** Requests and returns the next attachment chunk, or `null` when the stream ends. */
|
|
368
|
+
async read() {
|
|
369
|
+
if (this.closed) {
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
if (this.pendingRead) {
|
|
373
|
+
throw new Error("A read() call is already in progress for this attachment stream.");
|
|
374
|
+
}
|
|
375
|
+
return await new Promise((resolve, reject) => {
|
|
376
|
+
this.pendingRead = { resolve, reject };
|
|
377
|
+
this.rpc.postMessage({
|
|
378
|
+
protocol: PROTOCOL2,
|
|
379
|
+
kind: "stream-read",
|
|
380
|
+
streamId: this.streamId
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
/** Closes the read stream and releases any pending read waiter. */
|
|
385
|
+
async close() {
|
|
386
|
+
if (this.closed) {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
this.closed = true;
|
|
390
|
+
this.pendingRead?.resolve(null);
|
|
391
|
+
this.pendingRead = null;
|
|
392
|
+
this.rpc.postMessage({
|
|
393
|
+
protocol: PROTOCOL2,
|
|
394
|
+
kind: "stream-close",
|
|
395
|
+
streamId: this.streamId
|
|
396
|
+
});
|
|
397
|
+
this.unsubscribe();
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
var MindooDBAppWritableAttachmentStreamImpl = class {
|
|
401
|
+
constructor(rpc, streamId) {
|
|
402
|
+
this.rpc = rpc;
|
|
403
|
+
this.streamId = streamId;
|
|
404
|
+
this.unsubscribe = this.rpc.addMessageListener((message) => {
|
|
405
|
+
if (isStreamAckFor(this.streamId, message)) {
|
|
406
|
+
const inflight = this.inflight;
|
|
407
|
+
this.inflight = null;
|
|
408
|
+
inflight?.resolve();
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
if (isStreamErrorFor(this.streamId, message)) {
|
|
412
|
+
const inflight = this.inflight;
|
|
413
|
+
this.inflight = null;
|
|
414
|
+
inflight?.reject(toStreamError(message));
|
|
415
|
+
this.closed = true;
|
|
416
|
+
this.unsubscribe();
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
unsubscribe;
|
|
421
|
+
closed = false;
|
|
422
|
+
inflight = null;
|
|
423
|
+
queue = Promise.resolve();
|
|
424
|
+
/** Ensures write/close/abort operations run strictly in order. */
|
|
425
|
+
enqueue(operation) {
|
|
426
|
+
const next = this.queue.then(operation);
|
|
427
|
+
this.queue = next.catch(() => void 0);
|
|
428
|
+
return next;
|
|
429
|
+
}
|
|
430
|
+
/** Sends one stream operation and waits for its ack/error response. */
|
|
431
|
+
async waitForAck(send) {
|
|
432
|
+
return await new Promise((resolve, reject) => {
|
|
433
|
+
this.inflight = { resolve, reject };
|
|
434
|
+
send();
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
/** Writes one binary chunk to the host-managed attachment stream. */
|
|
438
|
+
async write(chunk) {
|
|
439
|
+
if (this.closed) {
|
|
440
|
+
throw new Error("The attachment write stream is already closed.");
|
|
441
|
+
}
|
|
442
|
+
return await this.enqueue(async () => {
|
|
443
|
+
const buffer = toTransferableArrayBuffer(chunk);
|
|
444
|
+
await this.waitForAck(() => {
|
|
445
|
+
this.rpc.postMessage({
|
|
446
|
+
protocol: PROTOCOL2,
|
|
447
|
+
kind: "stream-write",
|
|
448
|
+
streamId: this.streamId,
|
|
449
|
+
chunk: buffer
|
|
450
|
+
}, [buffer]);
|
|
451
|
+
});
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
/** Gracefully closes the write stream after any queued writes complete. */
|
|
455
|
+
async close() {
|
|
456
|
+
if (this.closed) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
this.closed = true;
|
|
460
|
+
await this.enqueue(async () => {
|
|
461
|
+
await this.waitForAck(() => {
|
|
462
|
+
this.rpc.postMessage({
|
|
463
|
+
protocol: PROTOCOL2,
|
|
464
|
+
kind: "stream-close",
|
|
465
|
+
streamId: this.streamId
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
this.unsubscribe();
|
|
470
|
+
}
|
|
471
|
+
/** Aborts the write stream after any in-flight work has settled. */
|
|
472
|
+
async abort() {
|
|
473
|
+
if (this.closed) {
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
this.closed = true;
|
|
477
|
+
await this.enqueue(async () => {
|
|
478
|
+
await this.waitForAck(() => {
|
|
479
|
+
this.rpc.postMessage({
|
|
480
|
+
protocol: PROTOCOL2,
|
|
481
|
+
kind: "stream-abort",
|
|
482
|
+
streamId: this.streamId
|
|
483
|
+
});
|
|
484
|
+
});
|
|
485
|
+
});
|
|
486
|
+
this.unsubscribe();
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
var MindooDBAppDatabaseImpl = class {
|
|
490
|
+
constructor(rpc, databaseId) {
|
|
491
|
+
this.rpc = rpc;
|
|
492
|
+
this.databaseId = databaseId;
|
|
493
|
+
this.documents = {
|
|
494
|
+
list: async (query) => await this.rpc.call("documents.list", {
|
|
495
|
+
databaseId: this.databaseId,
|
|
496
|
+
query: query ?? {}
|
|
497
|
+
}),
|
|
498
|
+
get: async (docId) => await this.rpc.call("documents.get", {
|
|
499
|
+
databaseId: this.databaseId,
|
|
500
|
+
docId
|
|
501
|
+
}),
|
|
502
|
+
create: async (input) => await this.rpc.call("documents.create", {
|
|
503
|
+
databaseId: this.databaseId,
|
|
504
|
+
input
|
|
505
|
+
}),
|
|
506
|
+
update: async (docId, patch) => await this.rpc.call("documents.update", {
|
|
507
|
+
databaseId: this.databaseId,
|
|
508
|
+
docId,
|
|
509
|
+
patch
|
|
510
|
+
}),
|
|
511
|
+
delete: async (docId) => await this.rpc.call("documents.delete", {
|
|
512
|
+
databaseId: this.databaseId,
|
|
513
|
+
docId
|
|
514
|
+
}),
|
|
515
|
+
listHistory: async (docId) => await this.rpc.call("documents.history.list", {
|
|
516
|
+
databaseId: this.databaseId,
|
|
517
|
+
docId
|
|
518
|
+
}),
|
|
519
|
+
getAtTimestamp: async (docId, timestamp) => await this.rpc.call("documents.history.getAtTimestamp", {
|
|
520
|
+
databaseId: this.databaseId,
|
|
521
|
+
docId,
|
|
522
|
+
timestamp
|
|
523
|
+
})
|
|
524
|
+
};
|
|
525
|
+
this.views = {
|
|
526
|
+
create: async (definition) => {
|
|
527
|
+
const result = await this.rpc.call("views.create", {
|
|
528
|
+
databaseId: this.databaseId,
|
|
529
|
+
definition
|
|
530
|
+
});
|
|
531
|
+
return new MindooDBAppViewHandleImpl(this.rpc, this.databaseId, result.viewId);
|
|
532
|
+
},
|
|
533
|
+
open: async (viewId) => new MindooDBAppViewHandleImpl(this.rpc, this.databaseId, viewId)
|
|
534
|
+
};
|
|
535
|
+
this.attachments = {
|
|
536
|
+
list: async (docId) => await this.rpc.call("attachments.list", {
|
|
537
|
+
databaseId: this.databaseId,
|
|
538
|
+
docId
|
|
539
|
+
}),
|
|
540
|
+
remove: async (docId, attachmentName) => await this.rpc.call("attachments.remove", {
|
|
541
|
+
databaseId: this.databaseId,
|
|
542
|
+
docId,
|
|
543
|
+
attachmentName
|
|
544
|
+
}),
|
|
545
|
+
openReadStream: async (docId, attachmentName) => {
|
|
546
|
+
const result = await this.rpc.call("attachments.openReadStream", {
|
|
547
|
+
databaseId: this.databaseId,
|
|
548
|
+
docId,
|
|
549
|
+
attachmentName
|
|
550
|
+
});
|
|
551
|
+
return new MindooDBAppReadableAttachmentStreamImpl(this.rpc, result.streamId);
|
|
552
|
+
},
|
|
553
|
+
openWriteStream: async (docId, attachmentName, contentType) => {
|
|
554
|
+
const result = await this.rpc.call("attachments.openWriteStream", {
|
|
555
|
+
databaseId: this.databaseId,
|
|
556
|
+
docId,
|
|
557
|
+
attachmentName,
|
|
558
|
+
contentType
|
|
559
|
+
});
|
|
560
|
+
return new MindooDBAppWritableAttachmentStreamImpl(this.rpc, result.streamId);
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
documents;
|
|
565
|
+
views;
|
|
566
|
+
attachments;
|
|
567
|
+
/** Returns database metadata for the currently opened binding. */
|
|
568
|
+
async info() {
|
|
569
|
+
return await this.rpc.call("databases.info", {
|
|
570
|
+
databaseId: this.databaseId
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
var MindooDBAppSessionImpl = class {
|
|
575
|
+
constructor(rpc) {
|
|
576
|
+
this.rpc = rpc;
|
|
577
|
+
}
|
|
578
|
+
/** Returns the launch context provided by the Administrator host. */
|
|
579
|
+
async getLaunchContext() {
|
|
580
|
+
return await this.rpc.call("session.getLaunchContext", {});
|
|
581
|
+
}
|
|
582
|
+
async listDatabases() {
|
|
583
|
+
return await this.rpc.call("session.listDatabases", {});
|
|
584
|
+
}
|
|
585
|
+
/** Opens one database binding and returns a client facade for it. */
|
|
586
|
+
async openDatabase(databaseId) {
|
|
587
|
+
await this.rpc.call("session.openDatabase", { databaseId });
|
|
588
|
+
return new MindooDBAppDatabaseImpl(this.rpc, databaseId);
|
|
589
|
+
}
|
|
590
|
+
onThemeChange(listener) {
|
|
591
|
+
return this.rpc.addMessageListener((message) => {
|
|
592
|
+
if (isThemeChangedMessage(message)) {
|
|
593
|
+
listener(message.theme);
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
onViewportChange(listener) {
|
|
598
|
+
return this.rpc.addMessageListener((message) => {
|
|
599
|
+
if (isViewportChangedMessage(message)) {
|
|
600
|
+
listener(message.viewport);
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
/** Disconnects from the host and always disposes the underlying port client. */
|
|
605
|
+
async disconnect() {
|
|
606
|
+
try {
|
|
607
|
+
await this.rpc.call("session.disconnect", {});
|
|
608
|
+
} finally {
|
|
609
|
+
this.rpc.dispose();
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
function createMindooDBAppBridge() {
|
|
614
|
+
return {
|
|
615
|
+
async connect(options) {
|
|
616
|
+
const launchId = resolveLaunchId(options);
|
|
617
|
+
const port = await waitForConnectedPort(options, launchId);
|
|
618
|
+
const rpc = new PortRpcClient(port);
|
|
619
|
+
return new MindooDBAppSessionImpl(rpc);
|
|
620
|
+
}
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// src/viewLanguage.ts
|
|
625
|
+
import {
|
|
626
|
+
createViewLanguage,
|
|
627
|
+
getMindooDBViewLanguageHelper,
|
|
628
|
+
mindooDBViewLanguageHelpers,
|
|
629
|
+
mindooDBViewLanguageHelpersByName
|
|
630
|
+
} from "mindoodb-view-language";
|
|
631
|
+
export {
|
|
632
|
+
createMindooDBAppBridge,
|
|
633
|
+
createViewLanguage
|
|
634
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Z as MindooDBAppLaunchContext, P as MindooDBAppDatabaseInfo, R as MindooDBAppDocumentApi, a5 as MindooDBAppViewApi, a as MindooDBAppAttachmentApi, M as MindooDBAppBridge, a2 as MindooDBAppSession, k as MindooDBAppBridgeRpcRequest, Y as MindooDBAppHostTheme, a7 as MindooDBAppViewport, h as MindooDBAppBridgePortMessage } from '../types-BGdIfp-D.js';
|
|
2
|
+
import 'mindoodb-view-language';
|
|
3
|
+
|
|
4
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
5
|
+
type MockDatabaseMethods = {
|
|
6
|
+
documents?: Partial<MindooDBAppDocumentApi>;
|
|
7
|
+
views?: Partial<MindooDBAppViewApi>;
|
|
8
|
+
attachments?: Partial<MindooDBAppAttachmentApi>;
|
|
9
|
+
};
|
|
10
|
+
interface MockMindooDBAppDatabaseDefinition {
|
|
11
|
+
info: MindooDBAppDatabaseInfo;
|
|
12
|
+
methods?: MockDatabaseMethods;
|
|
13
|
+
}
|
|
14
|
+
interface CreateMockMindooDBAppSessionOptions {
|
|
15
|
+
launchContext?: Partial<MindooDBAppLaunchContext>;
|
|
16
|
+
databases?: MockMindooDBAppDatabaseDefinition[];
|
|
17
|
+
onDisconnect?: () => MaybePromise<void>;
|
|
18
|
+
}
|
|
19
|
+
interface MockMindooDBAppSessionController {
|
|
20
|
+
bridge: MindooDBAppBridge;
|
|
21
|
+
session: MindooDBAppSession;
|
|
22
|
+
getLaunchContext(): MindooDBAppLaunchContext;
|
|
23
|
+
setLaunchContext(patch?: Partial<MindooDBAppLaunchContext>): MindooDBAppLaunchContext;
|
|
24
|
+
listDatabases(): MindooDBAppDatabaseInfo[];
|
|
25
|
+
setDatabases(definitions: MockMindooDBAppDatabaseDefinition[]): void;
|
|
26
|
+
emitThemeChange(theme: MindooDBAppHostTheme): void;
|
|
27
|
+
emitViewportChange(viewport: MindooDBAppViewport): void;
|
|
28
|
+
}
|
|
29
|
+
declare function createMockMindooDBAppSession(options?: CreateMockMindooDBAppSessionOptions): MockMindooDBAppSessionController;
|
|
30
|
+
declare function createMockMindooDBAppBridge(options?: CreateMockMindooDBAppSessionOptions): MockMindooDBAppSessionController;
|
|
31
|
+
type FakeBridgeRequestHandler = (params: unknown, context: {
|
|
32
|
+
host: FakeBridgeHostController;
|
|
33
|
+
request: MindooDBAppBridgeRpcRequest;
|
|
34
|
+
port: MessagePort;
|
|
35
|
+
}) => MaybePromise<unknown>;
|
|
36
|
+
type FakeBridgePortMessageHandler = (message: Exclude<MindooDBAppBridgePortMessage, MindooDBAppBridgeRpcRequest>, context: {
|
|
37
|
+
host: FakeBridgeHostController;
|
|
38
|
+
port: MessagePort;
|
|
39
|
+
}) => MaybePromise<boolean | void>;
|
|
40
|
+
interface CreateFakeBridgeHostOptions extends CreateMockMindooDBAppSessionOptions {
|
|
41
|
+
windowMode?: "parent" | "opener";
|
|
42
|
+
requestHandlers?: Record<string, FakeBridgeRequestHandler>;
|
|
43
|
+
onPortMessage?: FakeBridgePortMessageHandler;
|
|
44
|
+
}
|
|
45
|
+
interface FakeBridgeHostController {
|
|
46
|
+
bridge: MindooDBAppBridge;
|
|
47
|
+
session: MindooDBAppSession;
|
|
48
|
+
readonly launchId: string;
|
|
49
|
+
readonly requests: ReadonlyArray<MindooDBAppBridgeRpcRequest>;
|
|
50
|
+
install(): void;
|
|
51
|
+
dispose(): void;
|
|
52
|
+
emitThemeChange(theme: MindooDBAppHostTheme): void;
|
|
53
|
+
emitViewportChange(viewport: MindooDBAppViewport): void;
|
|
54
|
+
postPortMessage(message: MindooDBAppBridgePortMessage, transfer?: Transferable[]): void;
|
|
55
|
+
setRequestHandler(method: string, handler: FakeBridgeRequestHandler): void;
|
|
56
|
+
clearRequestHandler(method: string): void;
|
|
57
|
+
}
|
|
58
|
+
declare function createFakeBridgeHost(options?: CreateFakeBridgeHostOptions): FakeBridgeHostController;
|
|
59
|
+
|
|
60
|
+
export { type CreateFakeBridgeHostOptions, type CreateMockMindooDBAppSessionOptions, type FakeBridgeHostController, type FakeBridgePortMessageHandler, type FakeBridgeRequestHandler, type MockMindooDBAppDatabaseDefinition, type MockMindooDBAppSessionController, createFakeBridgeHost, createMockMindooDBAppBridge, createMockMindooDBAppSession };
|