@meshagent/meshagent 0.29.4 → 0.30.1
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/CHANGELOG.md +9 -0
- package/dist/browser/agent-client.js +3 -28
- package/dist/browser/agent.js +6 -6
- package/dist/browser/containers-client.d.ts +125 -0
- package/dist/browser/containers-client.js +458 -0
- package/dist/browser/database-client.d.ts +42 -6
- package/dist/browser/database-client.js +610 -77
- package/dist/browser/developer-client.d.ts +2 -2
- package/dist/browser/developer-client.js +60 -15
- package/dist/browser/helpers.js +4 -3
- package/dist/browser/index.d.ts +1 -0
- package/dist/browser/index.js +1 -0
- package/dist/browser/lk-client.js +12 -3
- package/dist/browser/meshagent-client.d.ts +5 -0
- package/dist/browser/messaging-client.d.ts +1 -0
- package/dist/browser/messaging-client.js +52 -8
- package/dist/browser/queues-client.d.ts +2 -0
- package/dist/browser/queues-client.js +34 -7
- package/dist/browser/response.d.ts +28 -0
- package/dist/browser/response.js +76 -1
- package/dist/browser/room-client.d.ts +43 -1
- package/dist/browser/room-client.js +204 -0
- package/dist/browser/secrets-client.d.ts +1 -0
- package/dist/browser/secrets-client.js +32 -27
- package/dist/browser/storage-client.d.ts +22 -7
- package/dist/browser/storage-client.js +353 -15
- package/dist/browser/sync-client.d.ts +12 -13
- package/dist/browser/sync-client.js +263 -65
- package/dist/esm/agent-client.js +3 -28
- package/dist/esm/agent.js +6 -6
- package/dist/esm/containers-client.d.ts +125 -0
- package/dist/esm/containers-client.js +453 -0
- package/dist/esm/database-client.d.ts +42 -6
- package/dist/esm/database-client.js +611 -78
- package/dist/esm/developer-client.d.ts +2 -2
- package/dist/esm/developer-client.js +61 -16
- package/dist/esm/helpers.js +4 -3
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/lk-client.js +12 -3
- package/dist/esm/meshagent-client.d.ts +5 -0
- package/dist/esm/messaging-client.d.ts +1 -0
- package/dist/esm/messaging-client.js +52 -8
- package/dist/esm/queues-client.d.ts +2 -0
- package/dist/esm/queues-client.js +35 -8
- package/dist/esm/response.d.ts +28 -0
- package/dist/esm/response.js +73 -0
- package/dist/esm/room-client.d.ts +43 -1
- package/dist/esm/room-client.js +207 -3
- package/dist/esm/secrets-client.d.ts +1 -0
- package/dist/esm/secrets-client.js +33 -28
- package/dist/esm/storage-client.d.ts +22 -7
- package/dist/esm/storage-client.js +353 -15
- package/dist/esm/sync-client.d.ts +12 -13
- package/dist/esm/sync-client.js +263 -64
- package/dist/node/agent-client.js +3 -28
- package/dist/node/agent.js +6 -6
- package/dist/node/containers-client.d.ts +125 -0
- package/dist/node/containers-client.js +458 -0
- package/dist/node/database-client.d.ts +42 -6
- package/dist/node/database-client.js +610 -77
- package/dist/node/developer-client.d.ts +2 -2
- package/dist/node/developer-client.js +60 -15
- package/dist/node/helpers.js +4 -3
- package/dist/node/index.d.ts +1 -0
- package/dist/node/index.js +1 -0
- package/dist/node/lk-client.js +12 -3
- package/dist/node/meshagent-client.d.ts +5 -0
- package/dist/node/messaging-client.d.ts +1 -0
- package/dist/node/messaging-client.js +52 -8
- package/dist/node/queues-client.d.ts +2 -0
- package/dist/node/queues-client.js +34 -7
- package/dist/node/response.d.ts +28 -0
- package/dist/node/response.js +76 -1
- package/dist/node/room-client.d.ts +43 -1
- package/dist/node/room-client.js +204 -0
- package/dist/node/secrets-client.d.ts +1 -0
- package/dist/node/secrets-client.js +32 -27
- package/dist/node/storage-client.d.ts +22 -7
- package/dist/node/storage-client.js +353 -15
- package/dist/node/sync-client.d.ts +12 -13
- package/dist/node/sync-client.js +263 -65
- package/package.json +1 -1
|
@@ -1,123 +1,656 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DataType } from "./data-types";
|
|
2
|
+
import { RoomServerException } from "./room-server-client";
|
|
3
|
+
import { ControlContent, ErrorContent, JsonContent } from "./response";
|
|
4
|
+
const globalScope = globalThis;
|
|
5
|
+
function bytesToBase64(bytes) {
|
|
6
|
+
if (globalScope.Buffer) {
|
|
7
|
+
return globalScope.Buffer.from(bytes).toString("base64");
|
|
8
|
+
}
|
|
9
|
+
if (!globalScope.btoa) {
|
|
10
|
+
throw new Error("base64 encoding is not available in this runtime");
|
|
11
|
+
}
|
|
12
|
+
let binary = "";
|
|
13
|
+
for (const byte of bytes) {
|
|
14
|
+
binary += String.fromCharCode(byte);
|
|
15
|
+
}
|
|
16
|
+
return globalScope.btoa(binary);
|
|
17
|
+
}
|
|
18
|
+
function base64ToBytes(base64) {
|
|
19
|
+
if (globalScope.Buffer) {
|
|
20
|
+
return Uint8Array.from(globalScope.Buffer.from(base64, "base64"));
|
|
21
|
+
}
|
|
22
|
+
if (!globalScope.atob) {
|
|
23
|
+
throw new Error("base64 decoding is not available in this runtime");
|
|
24
|
+
}
|
|
25
|
+
const binary = globalScope.atob(base64);
|
|
26
|
+
const bytes = new Uint8Array(binary.length);
|
|
27
|
+
for (let index = 0; index < binary.length; index += 1) {
|
|
28
|
+
bytes[index] = binary.charCodeAt(index);
|
|
29
|
+
}
|
|
30
|
+
return bytes;
|
|
31
|
+
}
|
|
32
|
+
function isRecord(value) {
|
|
33
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
34
|
+
}
|
|
35
|
+
function metadataEntries(metadata) {
|
|
36
|
+
if (metadata == null) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return Object.entries(metadata).map(([key, value]) => ({
|
|
40
|
+
key,
|
|
41
|
+
value: typeof value === "string" ? value : JSON.stringify(encodeLegacyValue(value)),
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
function toolkitDataTypeJson(dataType) {
|
|
45
|
+
const json = dataType.toJson();
|
|
46
|
+
const payload = {
|
|
47
|
+
type: json.type,
|
|
48
|
+
nullable: json.nullable ?? null,
|
|
49
|
+
metadata: metadataEntries(json.metadata),
|
|
50
|
+
};
|
|
51
|
+
if (json.type === "vector" || json.type === "list") {
|
|
52
|
+
payload.element_type = toolkitDataTypeJson(DataType.fromJson(json.element_type));
|
|
53
|
+
}
|
|
54
|
+
else if (json.type === "struct") {
|
|
55
|
+
const fields = json.fields;
|
|
56
|
+
if (!Array.isArray(fields)) {
|
|
57
|
+
throw new RoomServerException("unexpected return type from database.inspect");
|
|
58
|
+
}
|
|
59
|
+
payload.fields = fields.map((field) => {
|
|
60
|
+
if (!isRecord(field) || typeof field.name !== "string" || !isRecord(field.data_type)) {
|
|
61
|
+
throw new RoomServerException("unexpected return type from database.inspect");
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
name: field.name,
|
|
65
|
+
data_type: toolkitDataTypeJson(DataType.fromJson(field.data_type)),
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
if (json.type === "vector") {
|
|
70
|
+
payload.size = json.size;
|
|
71
|
+
}
|
|
72
|
+
return payload;
|
|
73
|
+
}
|
|
74
|
+
function schemaEntries(schema) {
|
|
75
|
+
if (schema == null) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
return Object.entries(schema).map(([name, dataType]) => ({
|
|
79
|
+
name,
|
|
80
|
+
data_type: toolkitDataTypeJson(dataType),
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
function publicDataTypeJson(value) {
|
|
84
|
+
if (!isRecord(value)) {
|
|
85
|
+
throw new RoomServerException("unexpected return type from database.inspect");
|
|
86
|
+
}
|
|
87
|
+
const type = value.type;
|
|
88
|
+
if (typeof type !== "string") {
|
|
89
|
+
throw new RoomServerException("unexpected return type from database.inspect");
|
|
90
|
+
}
|
|
91
|
+
const metadataList = value.metadata;
|
|
92
|
+
let metadata;
|
|
93
|
+
if (metadataList != null) {
|
|
94
|
+
if (!Array.isArray(metadataList)) {
|
|
95
|
+
throw new RoomServerException("unexpected return type from database.inspect");
|
|
96
|
+
}
|
|
97
|
+
metadata = {};
|
|
98
|
+
for (const entry of metadataList) {
|
|
99
|
+
if (!isRecord(entry) || typeof entry.key !== "string" || typeof entry.value !== "string") {
|
|
100
|
+
throw new RoomServerException("unexpected return type from database.inspect");
|
|
101
|
+
}
|
|
102
|
+
metadata[entry.key] = entry.value;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const payload = {
|
|
106
|
+
type,
|
|
107
|
+
nullable: value.nullable,
|
|
108
|
+
metadata,
|
|
109
|
+
};
|
|
110
|
+
if (type === "vector") {
|
|
111
|
+
payload.size = value.size;
|
|
112
|
+
payload.element_type = publicDataTypeJson(value.element_type);
|
|
113
|
+
}
|
|
114
|
+
else if (type === "list") {
|
|
115
|
+
payload.element_type = publicDataTypeJson(value.element_type);
|
|
116
|
+
}
|
|
117
|
+
else if (type === "struct") {
|
|
118
|
+
const rawFields = value.fields;
|
|
119
|
+
if (!Array.isArray(rawFields)) {
|
|
120
|
+
throw new RoomServerException("unexpected return type from database.inspect");
|
|
121
|
+
}
|
|
122
|
+
payload.fields = Object.fromEntries(rawFields.map((field) => {
|
|
123
|
+
if (!isRecord(field) || typeof field.name !== "string") {
|
|
124
|
+
throw new RoomServerException("unexpected return type from database.inspect");
|
|
125
|
+
}
|
|
126
|
+
return [field.name, publicDataTypeJson(field.data_type)];
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
return payload;
|
|
130
|
+
}
|
|
131
|
+
function encodeLegacyValue(value) {
|
|
132
|
+
if (value instanceof Uint8Array) {
|
|
133
|
+
return {
|
|
134
|
+
encoding: "base64",
|
|
135
|
+
data: bytesToBase64(value),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
if (value instanceof Date) {
|
|
139
|
+
return value.toISOString().replace("+00:00", "Z");
|
|
140
|
+
}
|
|
141
|
+
if (Array.isArray(value)) {
|
|
142
|
+
return value.map((item) => encodeLegacyValue(item));
|
|
143
|
+
}
|
|
144
|
+
if (isRecord(value)) {
|
|
145
|
+
return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [key, encodeLegacyValue(entryValue)]));
|
|
146
|
+
}
|
|
147
|
+
return value;
|
|
148
|
+
}
|
|
149
|
+
function encodeStreamValue(value) {
|
|
150
|
+
if (value == null) {
|
|
151
|
+
return { type: "null" };
|
|
152
|
+
}
|
|
153
|
+
if (typeof value === "boolean") {
|
|
154
|
+
return { type: "bool", value };
|
|
155
|
+
}
|
|
156
|
+
if (typeof value === "number") {
|
|
157
|
+
if (Number.isInteger(value)) {
|
|
158
|
+
return { type: "int", value };
|
|
159
|
+
}
|
|
160
|
+
return { type: "float", value };
|
|
161
|
+
}
|
|
162
|
+
if (typeof value === "string") {
|
|
163
|
+
return { type: "text", value };
|
|
164
|
+
}
|
|
165
|
+
if (value instanceof Uint8Array) {
|
|
166
|
+
return {
|
|
167
|
+
type: "binary",
|
|
168
|
+
data: bytesToBase64(value),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
if (value instanceof Date) {
|
|
172
|
+
return {
|
|
173
|
+
type: "timestamp",
|
|
174
|
+
value: value.toISOString().replace("+00:00", "Z"),
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
if (Array.isArray(value)) {
|
|
178
|
+
return {
|
|
179
|
+
type: "list",
|
|
180
|
+
items: value.map((item) => encodeStreamValue(item)),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
if (isRecord(value)) {
|
|
184
|
+
return {
|
|
185
|
+
type: "struct",
|
|
186
|
+
fields: Object.entries(value).map(([name, fieldValue]) => ({
|
|
187
|
+
name,
|
|
188
|
+
value: encodeStreamValue(fieldValue),
|
|
189
|
+
})),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
throw new RoomServerException(`database stream does not support value type ${typeof value}`);
|
|
193
|
+
}
|
|
194
|
+
function decodeStreamValue(value, operation) {
|
|
195
|
+
if (!isRecord(value) || typeof value.type !== "string") {
|
|
196
|
+
throw new RoomServerException(`unexpected return type from database.${operation}`);
|
|
197
|
+
}
|
|
198
|
+
switch (value.type) {
|
|
199
|
+
case "null":
|
|
200
|
+
return null;
|
|
201
|
+
case "bool":
|
|
202
|
+
if (typeof value.value !== "boolean") {
|
|
203
|
+
throw new RoomServerException(`unexpected return type from database.${operation}`);
|
|
204
|
+
}
|
|
205
|
+
return value.value;
|
|
206
|
+
case "int":
|
|
207
|
+
case "float":
|
|
208
|
+
if (typeof value.value !== "number") {
|
|
209
|
+
throw new RoomServerException(`unexpected return type from database.${operation}`);
|
|
210
|
+
}
|
|
211
|
+
return value.value;
|
|
212
|
+
case "text":
|
|
213
|
+
case "date":
|
|
214
|
+
case "timestamp":
|
|
215
|
+
if (typeof value.value !== "string") {
|
|
216
|
+
throw new RoomServerException(`unexpected return type from database.${operation}`);
|
|
217
|
+
}
|
|
218
|
+
return value.value;
|
|
219
|
+
case "binary":
|
|
220
|
+
if (typeof value.data !== "string") {
|
|
221
|
+
throw new RoomServerException(`unexpected return type from database.${operation}`);
|
|
222
|
+
}
|
|
223
|
+
return base64ToBytes(value.data);
|
|
224
|
+
case "list":
|
|
225
|
+
if (!Array.isArray(value.items)) {
|
|
226
|
+
throw new RoomServerException(`unexpected return type from database.${operation}`);
|
|
227
|
+
}
|
|
228
|
+
return value.items.map((item) => decodeStreamValue(item, operation));
|
|
229
|
+
case "struct":
|
|
230
|
+
if (!Array.isArray(value.fields)) {
|
|
231
|
+
throw new RoomServerException(`unexpected return type from database.${operation}`);
|
|
232
|
+
}
|
|
233
|
+
return Object.fromEntries(value.fields.map((field) => {
|
|
234
|
+
if (!isRecord(field) || typeof field.name !== "string") {
|
|
235
|
+
throw new RoomServerException(`unexpected return type from database.${operation}`);
|
|
236
|
+
}
|
|
237
|
+
return [field.name, decodeStreamValue(field.value, operation)];
|
|
238
|
+
}));
|
|
239
|
+
default:
|
|
240
|
+
throw new RoomServerException(`unexpected return type from database.${operation}`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function rowsChunk(records) {
|
|
244
|
+
return {
|
|
245
|
+
kind: "rows",
|
|
246
|
+
rows: records.map((record) => ({
|
|
247
|
+
columns: Object.entries(record).map(([name, value]) => ({
|
|
248
|
+
name,
|
|
249
|
+
value: encodeStreamValue(value),
|
|
250
|
+
})),
|
|
251
|
+
})),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function recordsFromRowsChunk(payload, operation) {
|
|
255
|
+
if (!isRecord(payload) || payload.kind !== "rows" || !Array.isArray(payload.rows)) {
|
|
256
|
+
throw new RoomServerException(`unexpected return type from database.${operation}`);
|
|
257
|
+
}
|
|
258
|
+
return payload.rows.map((row) => {
|
|
259
|
+
if (!isRecord(row) || !Array.isArray(row.columns)) {
|
|
260
|
+
throw new RoomServerException(`unexpected return type from database.${operation}`);
|
|
261
|
+
}
|
|
262
|
+
return Object.fromEntries(row.columns.map((column) => {
|
|
263
|
+
if (!isRecord(column) || typeof column.name !== "string") {
|
|
264
|
+
throw new RoomServerException(`unexpected return type from database.${operation}`);
|
|
265
|
+
}
|
|
266
|
+
return [column.name, decodeStreamValue(column.value, operation)];
|
|
267
|
+
}));
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
function rowChunkList(records, rowsPerChunk = 128) {
|
|
271
|
+
if (rowsPerChunk <= 0) {
|
|
272
|
+
throw new RoomServerException("rowsPerChunk must be greater than zero");
|
|
273
|
+
}
|
|
274
|
+
const chunks = [];
|
|
275
|
+
for (let index = 0; index < records.length; index += rowsPerChunk) {
|
|
276
|
+
chunks.push(records.slice(index, index + rowsPerChunk));
|
|
277
|
+
}
|
|
278
|
+
return chunks;
|
|
279
|
+
}
|
|
280
|
+
async function* toAsyncIterable(chunks) {
|
|
281
|
+
if (Symbol.asyncIterator in Object(chunks)) {
|
|
282
|
+
for await (const chunk of chunks) {
|
|
283
|
+
yield chunk;
|
|
284
|
+
}
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
for (const chunk of chunks) {
|
|
288
|
+
yield chunk;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
function buildWhereClause(where) {
|
|
292
|
+
if (where != null && typeof where === "object" && !Array.isArray(where)) {
|
|
293
|
+
return Object.entries(where)
|
|
294
|
+
.map(([key, value]) => `${key} = ${JSON.stringify(encodeLegacyValue(value))}`)
|
|
295
|
+
.join(" AND ");
|
|
296
|
+
}
|
|
297
|
+
if (typeof where === "string") {
|
|
298
|
+
return where;
|
|
299
|
+
}
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
class DatabaseWriteInputStream {
|
|
303
|
+
constructor(start, chunks) {
|
|
304
|
+
this.start = start;
|
|
305
|
+
this.pulls = [];
|
|
306
|
+
this.closed = false;
|
|
307
|
+
this.source = toAsyncIterable(chunks)[Symbol.asyncIterator]();
|
|
308
|
+
}
|
|
309
|
+
requestNext() {
|
|
310
|
+
if (this.closed) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
const waiter = this.pulls.shift();
|
|
314
|
+
if (waiter) {
|
|
315
|
+
waiter();
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
this.pulls.push(() => undefined);
|
|
319
|
+
}
|
|
320
|
+
close() {
|
|
321
|
+
if (this.closed) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
this.closed = true;
|
|
325
|
+
while (this.pulls.length > 0) {
|
|
326
|
+
const waiter = this.pulls.shift();
|
|
327
|
+
waiter?.();
|
|
328
|
+
}
|
|
329
|
+
void this.source.return?.();
|
|
330
|
+
}
|
|
331
|
+
async waitForPull() {
|
|
332
|
+
if (this.closed) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const waiter = this.pulls.shift();
|
|
336
|
+
if (waiter) {
|
|
337
|
+
waiter();
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
await new Promise((resolve) => {
|
|
341
|
+
this.pulls.push(resolve);
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
async *stream() {
|
|
345
|
+
yield new JsonContent({ json: this.start });
|
|
346
|
+
while (!this.closed) {
|
|
347
|
+
await this.waitForPull();
|
|
348
|
+
if (this.closed) {
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
const nextChunk = await this.source.next();
|
|
352
|
+
if (nextChunk.done) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
if (nextChunk.value.length === 0) {
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
yield new JsonContent({ json: rowsChunk(nextChunk.value) });
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
class DatabaseReadInputStream {
|
|
363
|
+
constructor(start) {
|
|
364
|
+
this.start = start;
|
|
365
|
+
this.pulls = [];
|
|
366
|
+
this.closed = false;
|
|
367
|
+
}
|
|
368
|
+
requestNext() {
|
|
369
|
+
if (this.closed) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
const waiter = this.pulls.shift();
|
|
373
|
+
if (waiter) {
|
|
374
|
+
waiter();
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
this.pulls.push(() => undefined);
|
|
378
|
+
}
|
|
379
|
+
close() {
|
|
380
|
+
if (this.closed) {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
this.closed = true;
|
|
384
|
+
while (this.pulls.length > 0) {
|
|
385
|
+
const waiter = this.pulls.shift();
|
|
386
|
+
waiter?.();
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
async waitForPull() {
|
|
390
|
+
if (this.closed) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
const waiter = this.pulls.shift();
|
|
394
|
+
if (waiter) {
|
|
395
|
+
waiter();
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
await new Promise((resolve) => {
|
|
399
|
+
this.pulls.push(resolve);
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
async *stream() {
|
|
403
|
+
yield new JsonContent({ json: this.start });
|
|
404
|
+
while (!this.closed) {
|
|
405
|
+
await this.waitForPull();
|
|
406
|
+
if (this.closed) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
yield new JsonContent({ json: { kind: "pull" } });
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
2
413
|
export class DatabaseClient {
|
|
3
414
|
constructor({ room }) {
|
|
4
415
|
this.room = room;
|
|
5
416
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
417
|
+
_unexpectedResponseError(operation) {
|
|
418
|
+
return new RoomServerException(`unexpected return type from database.${operation}`);
|
|
419
|
+
}
|
|
420
|
+
async invoke(operation, input) {
|
|
421
|
+
const response = await this.room.invoke({ toolkit: "database", tool: operation, input });
|
|
422
|
+
if (response instanceof JsonContent) {
|
|
423
|
+
return response;
|
|
424
|
+
}
|
|
425
|
+
if (response == null) {
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
return null;
|
|
9
429
|
}
|
|
10
|
-
async
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
430
|
+
async invokeStream(operation, input) {
|
|
431
|
+
return await this.room.invokeStream({ toolkit: "database", tool: operation, input });
|
|
432
|
+
}
|
|
433
|
+
async drainWriteStream(operation, input) {
|
|
434
|
+
const response = await this.invokeStream(operation, input.stream());
|
|
435
|
+
try {
|
|
436
|
+
for await (const chunk of response) {
|
|
437
|
+
if (chunk instanceof ErrorContent) {
|
|
438
|
+
throw new RoomServerException(chunk.text, chunk.code);
|
|
439
|
+
}
|
|
440
|
+
if (chunk instanceof ControlContent) {
|
|
441
|
+
if (chunk.method === "close") {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
throw this._unexpectedResponseError(operation);
|
|
445
|
+
}
|
|
446
|
+
if (!(chunk instanceof JsonContent) || chunk.json.kind !== "pull") {
|
|
447
|
+
throw this._unexpectedResponseError(operation);
|
|
448
|
+
}
|
|
449
|
+
input.requestNext();
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
finally {
|
|
453
|
+
input.close();
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
async *streamRows(operation, start) {
|
|
457
|
+
const input = new DatabaseReadInputStream(start);
|
|
458
|
+
const response = await this.invokeStream(operation, input.stream());
|
|
459
|
+
input.requestNext();
|
|
460
|
+
try {
|
|
461
|
+
for await (const chunk of response) {
|
|
462
|
+
if (chunk instanceof ErrorContent) {
|
|
463
|
+
throw new RoomServerException(chunk.text, chunk.code);
|
|
464
|
+
}
|
|
465
|
+
if (chunk instanceof ControlContent) {
|
|
466
|
+
if (chunk.method === "close") {
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
throw this._unexpectedResponseError(operation);
|
|
470
|
+
}
|
|
471
|
+
if (!(chunk instanceof JsonContent)) {
|
|
472
|
+
throw this._unexpectedResponseError(operation);
|
|
473
|
+
}
|
|
474
|
+
yield recordsFromRowsChunk(chunk.json, operation);
|
|
475
|
+
input.requestNext();
|
|
16
476
|
}
|
|
17
477
|
}
|
|
18
|
-
|
|
478
|
+
finally {
|
|
479
|
+
input.close();
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
async listTables() {
|
|
483
|
+
const response = await this.invoke("list_tables", { namespace: null });
|
|
484
|
+
if (!(response instanceof JsonContent)) {
|
|
485
|
+
throw this._unexpectedResponseError("list_tables");
|
|
486
|
+
}
|
|
487
|
+
return Array.isArray(response.json.tables) ? response.json.tables : [];
|
|
488
|
+
}
|
|
489
|
+
async createTable({ name, data, schema, mode = "create", }) {
|
|
490
|
+
const input = new DatabaseWriteInputStream({
|
|
491
|
+
kind: "start",
|
|
19
492
|
name,
|
|
20
|
-
|
|
21
|
-
schema: schemaDict,
|
|
493
|
+
fields: schemaEntries(schema),
|
|
22
494
|
mode,
|
|
23
|
-
|
|
24
|
-
|
|
495
|
+
namespace: null,
|
|
496
|
+
metadata: null,
|
|
497
|
+
}, data ?? []);
|
|
498
|
+
await this.drainWriteStream("create_table", input);
|
|
25
499
|
}
|
|
26
500
|
async createTableWithSchema({ name, schema, data, mode = "create" }) {
|
|
27
|
-
return this.createTable({
|
|
501
|
+
return this.createTable({
|
|
502
|
+
name,
|
|
503
|
+
schema,
|
|
504
|
+
data: data == null ? undefined : rowChunkList(data),
|
|
505
|
+
mode,
|
|
506
|
+
});
|
|
28
507
|
}
|
|
29
508
|
async createTableFromData({ name, data, mode = "create" }) {
|
|
30
|
-
return this.createTable({
|
|
509
|
+
return this.createTable({
|
|
510
|
+
name,
|
|
511
|
+
data: data == null ? undefined : rowChunkList(data),
|
|
512
|
+
mode,
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
async createTableFromDataStream({ name, chunks, schema, mode = "create" }) {
|
|
516
|
+
return this.createTable({ name, data: chunks, schema, mode });
|
|
31
517
|
}
|
|
32
518
|
async dropTable({ name, ignoreMissing = false }) {
|
|
33
|
-
await this.room.
|
|
519
|
+
await this.room.invoke({
|
|
520
|
+
toolkit: "database",
|
|
521
|
+
tool: "drop_table",
|
|
522
|
+
input: { name, ignore_missing: ignoreMissing, namespace: null },
|
|
523
|
+
});
|
|
34
524
|
}
|
|
35
525
|
async addColumns({ table, newColumns }) {
|
|
36
|
-
await this.room.
|
|
37
|
-
|
|
38
|
-
|
|
526
|
+
await this.room.invoke({
|
|
527
|
+
toolkit: "database",
|
|
528
|
+
tool: "add_columns",
|
|
529
|
+
input: {
|
|
530
|
+
table,
|
|
531
|
+
columns: Object.entries(newColumns).map(([name, valueSql]) => ({ name, value_sql: valueSql, data_type: null })),
|
|
532
|
+
namespace: null,
|
|
533
|
+
},
|
|
39
534
|
});
|
|
40
535
|
}
|
|
41
536
|
async dropColumns({ table, columns }) {
|
|
42
|
-
await this.room.
|
|
537
|
+
await this.room.invoke({
|
|
538
|
+
toolkit: "database",
|
|
539
|
+
tool: "drop_columns",
|
|
540
|
+
input: { table, columns, namespace: null },
|
|
541
|
+
});
|
|
43
542
|
}
|
|
44
543
|
async insert({ table, records }) {
|
|
45
|
-
await this.
|
|
544
|
+
await this.insertStream({ table, chunks: rowChunkList(records) });
|
|
46
545
|
}
|
|
47
|
-
async
|
|
48
|
-
const
|
|
546
|
+
async insertStream({ table, chunks }) {
|
|
547
|
+
const input = new DatabaseWriteInputStream({
|
|
548
|
+
kind: "start",
|
|
49
549
|
table,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
550
|
+
namespace: null,
|
|
551
|
+
}, chunks);
|
|
552
|
+
await this.drainWriteStream("insert", input);
|
|
553
|
+
}
|
|
554
|
+
async update({ table, where, values, valuesSql }) {
|
|
555
|
+
await this.room.invoke({
|
|
556
|
+
toolkit: "database",
|
|
557
|
+
tool: "update",
|
|
558
|
+
input: {
|
|
559
|
+
table,
|
|
560
|
+
where,
|
|
561
|
+
values: values == null ? null : Object.entries(values).map(([column, value]) => ({ column, value_json: JSON.stringify(encodeLegacyValue(value)) })),
|
|
562
|
+
values_sql: valuesSql == null ? null : Object.entries(valuesSql).map(([column, expression]) => ({ column, expression })),
|
|
563
|
+
namespace: null,
|
|
564
|
+
},
|
|
565
|
+
});
|
|
55
566
|
}
|
|
56
567
|
async delete({ table, where }) {
|
|
57
|
-
await this.room.
|
|
568
|
+
await this.room.invoke({
|
|
569
|
+
toolkit: "database",
|
|
570
|
+
tool: "delete",
|
|
571
|
+
input: { table, where, namespace: null },
|
|
572
|
+
});
|
|
58
573
|
}
|
|
59
574
|
async merge({ table, on, records }) {
|
|
60
|
-
await this.
|
|
575
|
+
await this.mergeStream({ table, on, chunks: rowChunkList(records) });
|
|
576
|
+
}
|
|
577
|
+
async mergeStream({ table, on, chunks }) {
|
|
578
|
+
const input = new DatabaseWriteInputStream({
|
|
579
|
+
kind: "start",
|
|
580
|
+
table,
|
|
581
|
+
on,
|
|
582
|
+
namespace: null,
|
|
583
|
+
}, chunks);
|
|
584
|
+
await this.drainWriteStream("merge", input);
|
|
61
585
|
}
|
|
62
586
|
async sql({ query, tables, params }) {
|
|
63
|
-
const
|
|
587
|
+
const rows = [];
|
|
588
|
+
for await (const chunk of this.sqlStream({ query, tables, params })) {
|
|
589
|
+
rows.push(...chunk);
|
|
590
|
+
}
|
|
591
|
+
return rows;
|
|
592
|
+
}
|
|
593
|
+
async *sqlStream({ query, tables, params }) {
|
|
594
|
+
yield* this.streamRows("sql", {
|
|
595
|
+
kind: "start",
|
|
64
596
|
query,
|
|
65
597
|
tables,
|
|
66
|
-
params,
|
|
67
|
-
};
|
|
68
|
-
const response = await this.room.sendRequest("database.sql", payload);
|
|
69
|
-
if (response instanceof JsonContent) {
|
|
70
|
-
if (response?.json?.results) {
|
|
71
|
-
return response.json.results;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return [];
|
|
598
|
+
params_json: params == null ? null : JSON.stringify(encodeLegacyValue(params)),
|
|
599
|
+
});
|
|
75
600
|
}
|
|
76
601
|
async search({ table, text, vector, where, limit, select }) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
for (const [key, value] of Object.entries(where)) {
|
|
81
|
-
parts.push(`${key} = ${JSON.stringify(value)}`);
|
|
82
|
-
}
|
|
83
|
-
whereClause = parts.join(" AND ");
|
|
602
|
+
const rows = [];
|
|
603
|
+
for await (const chunk of this.searchStream({ table, text, vector, where, limit, select })) {
|
|
604
|
+
rows.push(...chunk);
|
|
84
605
|
}
|
|
85
|
-
|
|
606
|
+
return rows;
|
|
607
|
+
}
|
|
608
|
+
async *searchStream({ table, text, vector, where, limit, select }) {
|
|
609
|
+
yield* this.streamRows("search", {
|
|
610
|
+
kind: "start",
|
|
86
611
|
table,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
if (vector !== undefined) {
|
|
97
|
-
payload.vector = vector;
|
|
98
|
-
}
|
|
99
|
-
const response = await this.room.sendRequest("database.search", payload);
|
|
100
|
-
if (response instanceof JsonContent) {
|
|
101
|
-
if (response?.json?.results) {
|
|
102
|
-
return response.json.results;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return [];
|
|
612
|
+
text: text ?? null,
|
|
613
|
+
vector: vector ?? null,
|
|
614
|
+
text_columns: null,
|
|
615
|
+
where: buildWhereClause(where),
|
|
616
|
+
offset: null,
|
|
617
|
+
limit: limit ?? null,
|
|
618
|
+
select: select ?? null,
|
|
619
|
+
namespace: null,
|
|
620
|
+
});
|
|
106
621
|
}
|
|
107
622
|
async optimize(table) {
|
|
108
|
-
await this.room.
|
|
623
|
+
await this.room.invoke({ toolkit: "database", tool: "optimize", input: { table, namespace: null } });
|
|
109
624
|
}
|
|
110
|
-
async createVectorIndex({ table, column }) {
|
|
111
|
-
await this.room.
|
|
625
|
+
async createVectorIndex({ table, column, replace = false }) {
|
|
626
|
+
await this.room.invoke({
|
|
627
|
+
toolkit: "database",
|
|
628
|
+
tool: "create_vector_index",
|
|
629
|
+
input: { table, column, replace, namespace: null },
|
|
630
|
+
});
|
|
112
631
|
}
|
|
113
|
-
async createScalarIndex({ table, column }) {
|
|
114
|
-
await this.room.
|
|
632
|
+
async createScalarIndex({ table, column, replace = false }) {
|
|
633
|
+
await this.room.invoke({
|
|
634
|
+
toolkit: "database",
|
|
635
|
+
tool: "create_scalar_index",
|
|
636
|
+
input: { table, column, replace, namespace: null },
|
|
637
|
+
});
|
|
115
638
|
}
|
|
116
|
-
async createFullTextSearchIndex({ table, column }) {
|
|
117
|
-
await this.room.
|
|
639
|
+
async createFullTextSearchIndex({ table, column, replace = false }) {
|
|
640
|
+
await this.room.invoke({
|
|
641
|
+
toolkit: "database",
|
|
642
|
+
tool: "create_full_text_search_index",
|
|
643
|
+
input: { table, column, replace, namespace: null },
|
|
644
|
+
});
|
|
118
645
|
}
|
|
119
646
|
async listIndexes({ table }) {
|
|
120
|
-
const response = await this.
|
|
121
|
-
|
|
647
|
+
const response = await this.invoke("list_indexes", { table, namespace: null });
|
|
648
|
+
if (!(response instanceof JsonContent)) {
|
|
649
|
+
throw this._unexpectedResponseError("list_indexes");
|
|
650
|
+
}
|
|
651
|
+
if (!Array.isArray(response.json.indexes)) {
|
|
652
|
+
throw this._unexpectedResponseError("list_indexes");
|
|
653
|
+
}
|
|
654
|
+
return response.json.indexes;
|
|
122
655
|
}
|
|
123
656
|
}
|