@meshagent/meshagent 0.36.3 → 0.37.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/browser/agent-client.d.ts +2 -10
  3. package/dist/browser/agent-client.js +2 -30
  4. package/dist/browser/agent.d.ts +22 -22
  5. package/dist/browser/agent.js +36 -16
  6. package/dist/browser/containers-client.d.ts +7 -19
  7. package/dist/browser/containers-client.js +27 -21
  8. package/dist/browser/data-types.d.ts +12 -0
  9. package/dist/browser/data-types.js +39 -1
  10. package/dist/browser/database-client.d.ts +134 -47
  11. package/dist/browser/database-client.js +359 -133
  12. package/dist/browser/index.d.ts +1 -0
  13. package/dist/browser/index.js +1 -0
  14. package/dist/browser/meshagent-client.js +12 -1
  15. package/dist/browser/participant-token.d.ts +189 -22
  16. package/dist/browser/participant-token.js +1001 -189
  17. package/dist/browser/room-client.d.ts +1 -1
  18. package/dist/browser/services-client.d.ts +1 -1
  19. package/dist/browser/version.d.ts +1 -0
  20. package/dist/browser/version.js +4 -0
  21. package/dist/esm/agent-client.d.ts +2 -10
  22. package/dist/esm/agent-client.js +1 -28
  23. package/dist/esm/agent.d.ts +22 -22
  24. package/dist/esm/agent.js +33 -14
  25. package/dist/esm/containers-client.d.ts +7 -19
  26. package/dist/esm/containers-client.js +27 -21
  27. package/dist/esm/data-types.d.ts +12 -0
  28. package/dist/esm/data-types.js +36 -0
  29. package/dist/esm/database-client.d.ts +134 -47
  30. package/dist/esm/database-client.js +352 -132
  31. package/dist/esm/index.d.ts +1 -0
  32. package/dist/esm/index.js +1 -0
  33. package/dist/esm/meshagent-client.js +12 -1
  34. package/dist/esm/participant-token.d.ts +189 -22
  35. package/dist/esm/participant-token.js +992 -188
  36. package/dist/esm/room-client.d.ts +1 -1
  37. package/dist/esm/services-client.d.ts +1 -1
  38. package/dist/esm/version.d.ts +1 -0
  39. package/dist/esm/version.js +1 -0
  40. package/dist/node/agent-client.d.ts +2 -10
  41. package/dist/node/agent-client.js +2 -30
  42. package/dist/node/agent.d.ts +22 -22
  43. package/dist/node/agent.js +36 -16
  44. package/dist/node/containers-client.d.ts +7 -19
  45. package/dist/node/containers-client.js +27 -21
  46. package/dist/node/data-types.d.ts +12 -0
  47. package/dist/node/data-types.js +39 -1
  48. package/dist/node/database-client.d.ts +134 -47
  49. package/dist/node/database-client.js +359 -133
  50. package/dist/node/index.d.ts +1 -0
  51. package/dist/node/index.js +1 -0
  52. package/dist/node/meshagent-client.js +12 -1
  53. package/dist/node/participant-token.d.ts +189 -22
  54. package/dist/node/participant-token.js +1001 -189
  55. package/dist/node/room-client.d.ts +1 -1
  56. package/dist/node/services-client.d.ts +1 -1
  57. package/dist/node/version.d.ts +1 -0
  58. package/dist/node/version.js +4 -0
  59. package/package.json +1 -1
@@ -1,7 +1,103 @@
1
1
  import { DataType } from "./data-types";
2
2
  import { RoomServerException } from "./room-server-client";
3
3
  import { ControlContent, ErrorContent, JsonContent } from "./response";
4
+ export class DatabaseValueEncoder {
5
+ }
6
+ export class DatabaseExpression extends DatabaseValueEncoder {
7
+ constructor(expression) {
8
+ super();
9
+ const normalized = expression.trim();
10
+ if (normalized === "") {
11
+ throw new TypeError("database expression must not be empty");
12
+ }
13
+ this.expression = normalized;
14
+ }
15
+ encodeDatabaseValue() {
16
+ return {
17
+ expression: this.expression,
18
+ };
19
+ }
20
+ toString() {
21
+ return this.expression;
22
+ }
23
+ }
24
+ export class DatabaseDate extends DatabaseValueEncoder {
25
+ constructor(value) {
26
+ super();
27
+ const normalized = value.trim();
28
+ const parsed = new Date(`${normalized}T00:00:00Z`);
29
+ if (!ISO_DATE_REGEX.test(normalized) || Number.isNaN(parsed.getTime()) || parsed.toISOString().slice(0, 10) !== normalized) {
30
+ throw new TypeError("invalid database date format");
31
+ }
32
+ this.value = normalized;
33
+ }
34
+ encodeDatabaseValue() {
35
+ return {
36
+ date: this.value,
37
+ };
38
+ }
39
+ toString() {
40
+ return this.value;
41
+ }
42
+ }
43
+ export class DatabaseStruct extends DatabaseValueEncoder {
44
+ constructor(fields) {
45
+ super();
46
+ this.fields = Object.fromEntries(Object.entries(fields).map(([key, value]) => {
47
+ if (typeof key !== "string") {
48
+ throw new TypeError("database struct keys must be strings");
49
+ }
50
+ return [key, value];
51
+ }));
52
+ }
53
+ toJson() {
54
+ return Object.fromEntries(Object.entries(this.fields).map(([key, value]) => [key, encodeRecordValue(value)]));
55
+ }
56
+ encodeDatabaseValue() {
57
+ return {
58
+ struct: this.toJson(),
59
+ };
60
+ }
61
+ }
62
+ export class DatabaseJson extends DatabaseValueEncoder {
63
+ constructor(value) {
64
+ super();
65
+ this.value = normalizeDatabaseJsonValue(value);
66
+ }
67
+ toJson() {
68
+ return this.value;
69
+ }
70
+ encodeDatabaseValue() {
71
+ return {
72
+ json: this.value,
73
+ };
74
+ }
75
+ }
4
76
  const globalScope = globalThis;
77
+ const UUID_HEX_REGEX = /^[0-9a-f]{32}$/;
78
+ const ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
79
+ function normalizeUuidHex(value) {
80
+ const normalized = value.trim().toLowerCase().replace(/-/g, "");
81
+ if (!UUID_HEX_REGEX.test(normalized)) {
82
+ throw new RoomServerException("invalid uuid format");
83
+ }
84
+ return normalized;
85
+ }
86
+ function formatUuidHex(value) {
87
+ return (`${value.substring(0, 8)}-` +
88
+ `${value.substring(8, 12)}-` +
89
+ `${value.substring(12, 16)}-` +
90
+ `${value.substring(16, 20)}-` +
91
+ `${value.substring(20)}`);
92
+ }
93
+ export class DatabaseUuid {
94
+ constructor(value) {
95
+ this.value = formatUuidHex(normalizeUuidHex(value));
96
+ }
97
+ toString() {
98
+ return this.value;
99
+ }
100
+ }
5
101
  function bytesToBase64(bytes) {
6
102
  if (globalScope.Buffer) {
7
103
  return globalScope.Buffer.from(bytes).toString("base64");
@@ -32,13 +128,32 @@ function base64ToBytes(base64) {
32
128
  function isRecord(value) {
33
129
  return typeof value === "object" && value !== null && !Array.isArray(value);
34
130
  }
131
+ function isPlainRecord(value) {
132
+ return isRecord(value) && (Object.getPrototypeOf(value) === Object.prototype
133
+ || Object.getPrototypeOf(value) === null);
134
+ }
135
+ function normalizeDatabaseJsonValue(value) {
136
+ if (value === null ||
137
+ typeof value === "boolean" ||
138
+ typeof value === "number" ||
139
+ typeof value === "string") {
140
+ return value;
141
+ }
142
+ if (Array.isArray(value)) {
143
+ return value.map((item) => normalizeDatabaseJsonValue(item));
144
+ }
145
+ if (isPlainRecord(value)) {
146
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, normalizeDatabaseJsonValue(item)]));
147
+ }
148
+ throw new TypeError("database json values must be valid JSON");
149
+ }
35
150
  function metadataEntries(metadata) {
36
151
  if (metadata == null) {
37
152
  return null;
38
153
  }
39
154
  return Object.entries(metadata).map(([key, value]) => ({
40
155
  key,
41
- value: typeof value === "string" ? value : JSON.stringify(encodeLegacyValue(value)),
156
+ value: typeof value === "string" ? value : JSON.stringify(value),
42
157
  }));
43
158
  }
44
159
  function toolkitDataTypeJson(dataType) {
@@ -128,125 +243,124 @@ function publicDataTypeJson(value) {
128
243
  }
129
244
  return payload;
130
245
  }
131
- function encodeLegacyValue(value) {
246
+ function encodeRecordValue(value) {
247
+ if (value instanceof DatabaseValueEncoder) {
248
+ return value.encodeDatabaseValue();
249
+ }
250
+ if (value instanceof DatabaseUuid) {
251
+ return {
252
+ uuid: value.toString(),
253
+ };
254
+ }
132
255
  if (value instanceof Uint8Array) {
133
256
  return {
134
- encoding: "base64",
135
- data: bytesToBase64(value),
257
+ binary: bytesToBase64(value),
136
258
  };
137
259
  }
138
260
  if (value instanceof Date) {
139
- return value.toISOString().replace("+00:00", "Z");
261
+ return {
262
+ timestamp: value.toISOString().replace("+00:00", "Z"),
263
+ };
140
264
  }
141
265
  if (Array.isArray(value)) {
142
- return value.map((item) => encodeLegacyValue(item));
266
+ return {
267
+ list: value.map((item) => encodeRecordValue(item)),
268
+ };
143
269
  }
144
270
  if (isRecord(value)) {
145
- return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [key, encodeLegacyValue(entryValue)]));
271
+ throw new RoomServerException("database object values must use DatabaseStruct or DatabaseJson");
146
272
  }
147
273
  return value;
148
274
  }
149
- function encodeStreamValue(value) {
150
- if (value == null) {
151
- return { type: "null" };
275
+ function databaseSqlLiteral(value) {
276
+ if (value instanceof DatabaseUuid) {
277
+ return `X'${normalizeUuidHex(value.toString())}'`;
152
278
  }
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 };
279
+ if (value instanceof DatabaseDate) {
280
+ return JSON.stringify(value.toString());
161
281
  }
162
- if (typeof value === "string") {
163
- return { type: "text", value };
282
+ if (value instanceof Date) {
283
+ return JSON.stringify(value.toISOString().replace("+00:00", "Z"));
164
284
  }
165
- if (value instanceof Uint8Array) {
166
- return {
167
- type: "binary",
168
- data: bytesToBase64(value),
169
- };
285
+ if (value instanceof DatabaseJson) {
286
+ return JSON.stringify(JSON.stringify(value.toJson()));
170
287
  }
171
- if (value instanceof Date) {
172
- return {
173
- type: "timestamp",
174
- value: value.toISOString().replace("+00:00", "Z"),
175
- };
288
+ if (value instanceof DatabaseStruct) {
289
+ const fields = Object.entries(value.fields).map(([key, fieldValue]) => (`${JSON.stringify(key)}, ${databaseSqlLiteral(fieldValue)}`));
290
+ return `named_struct(${fields.join(", ")})`;
176
291
  }
292
+ return JSON.stringify(encodeRecordValue(value));
293
+ }
294
+ function decodeRecordValue(value) {
177
295
  if (Array.isArray(value)) {
178
- return {
179
- type: "list",
180
- items: value.map((item) => encodeStreamValue(item)),
181
- };
296
+ throw new RoomServerException("database list values must use a {'list': [...]} wrapper");
182
297
  }
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
- };
298
+ if (!isRecord(value)) {
299
+ return value;
191
300
  }
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}`);
301
+ const entries = Object.entries(value);
302
+ if (entries.length !== 1) {
303
+ throw new RoomServerException("database object values must use a single-key type wrapper");
197
304
  }
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}`);
305
+ const [wrapper, payload] = entries[0];
306
+ switch (wrapper) {
307
+ case "binary":
308
+ if (typeof payload !== "string") {
309
+ throw new RoomServerException("database binary values must be base64 strings");
204
310
  }
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}`);
311
+ return base64ToBytes(payload);
312
+ case "uuid":
313
+ if (typeof payload !== "string") {
314
+ throw new RoomServerException("database uuid values must be strings");
315
+ }
316
+ return new DatabaseUuid(payload);
317
+ case "expression":
318
+ if (typeof payload !== "string") {
319
+ throw new RoomServerException("database expression values must be strings");
210
320
  }
211
- return value.value;
212
- case "text":
321
+ return new DatabaseExpression(payload);
213
322
  case "date":
323
+ if (typeof payload !== "string") {
324
+ throw new RoomServerException("database date values must be strings");
325
+ }
326
+ return new DatabaseDate(payload);
214
327
  case "timestamp":
215
- if (typeof value.value !== "string") {
216
- throw new RoomServerException(`unexpected return type from database.${operation}`);
328
+ if (typeof payload !== "string") {
329
+ throw new RoomServerException("database timestamp values must be strings");
217
330
  }
218
- return value.value;
219
- case "binary":
220
- if (typeof value.data !== "string") {
221
- throw new RoomServerException(`unexpected return type from database.${operation}`);
331
+ {
332
+ const parsed = new Date(payload);
333
+ if (Number.isNaN(parsed.getTime())) {
334
+ throw new RoomServerException("database timestamp value is not valid");
335
+ }
336
+ return parsed;
222
337
  }
223
- return base64ToBytes(value.data);
224
338
  case "list":
225
- if (!Array.isArray(value.items)) {
226
- throw new RoomServerException(`unexpected return type from database.${operation}`);
339
+ if (!Array.isArray(payload)) {
340
+ throw new RoomServerException("database list values must be arrays");
227
341
  }
228
- return value.items.map((item) => decodeStreamValue(item, operation));
342
+ return payload.map((item) => decodeRecordValue(item));
229
343
  case "struct":
230
- if (!Array.isArray(value.fields)) {
231
- throw new RoomServerException(`unexpected return type from database.${operation}`);
344
+ if (!isRecord(payload)) {
345
+ throw new RoomServerException("database struct values must be objects");
232
346
  }
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
- }));
347
+ return new DatabaseStruct(Object.fromEntries(Object.entries(payload).map(([key, item]) => [key, decodeRecordValue(item)])));
348
+ case "json":
349
+ return new DatabaseJson(normalizeDatabaseJsonValue(payload));
239
350
  default:
240
- throw new RoomServerException(`unexpected return type from database.${operation}`);
351
+ throw new RoomServerException(`unsupported database value wrapper '${wrapper}'`);
241
352
  }
242
353
  }
354
+ function encodeDatabaseRecord(record) {
355
+ return Object.fromEntries(Object.entries(record).map(([key, value]) => [key, encodeRecordValue(value)]));
356
+ }
243
357
  function rowsChunk(records) {
244
358
  return {
245
359
  kind: "rows",
246
360
  rows: records.map((record) => ({
247
361
  columns: Object.entries(record).map(([name, value]) => ({
248
362
  name,
249
- value: encodeStreamValue(value),
363
+ value: encodeRecordValue(value),
250
364
  })),
251
365
  })),
252
366
  };
@@ -263,7 +377,12 @@ function recordsFromRowsChunk(payload, operation) {
263
377
  if (!isRecord(column) || typeof column.name !== "string") {
264
378
  throw new RoomServerException(`unexpected return type from database.${operation}`);
265
379
  }
266
- return [column.name, decodeStreamValue(column.value, operation)];
380
+ try {
381
+ return [column.name, decodeRecordValue(column.value)];
382
+ }
383
+ catch {
384
+ throw new RoomServerException(`unexpected return type from database.${operation}`);
385
+ }
267
386
  }));
268
387
  });
269
388
  }
@@ -291,7 +410,7 @@ async function* toAsyncIterable(chunks) {
291
410
  function buildWhereClause(where) {
292
411
  if (where != null && typeof where === "object" && !Array.isArray(where)) {
293
412
  return Object.entries(where)
294
- .map(([key, value]) => `${key} = ${JSON.stringify(encodeLegacyValue(value))}`)
413
+ .map(([key, value]) => `${key} = ${databaseSqlLiteral(value)}`)
295
414
  .join(" AND ");
296
415
  }
297
416
  if (typeof where === "string") {
@@ -341,6 +460,39 @@ function tableVersionFromJson(value) {
341
460
  metadata,
342
461
  };
343
462
  }
463
+ function tableBranchFromJson(value) {
464
+ if (!isRecord(value) || typeof value.name !== "string") {
465
+ throw new RoomServerException("unexpected return type from database.list_branches");
466
+ }
467
+ if (value.parent_branch != null && typeof value.parent_branch !== "string") {
468
+ throw new RoomServerException("unexpected return type from database.list_branches");
469
+ }
470
+ if (value.parent_version != null
471
+ && (typeof value.parent_version !== "number" || !Number.isInteger(value.parent_version))) {
472
+ throw new RoomServerException("unexpected return type from database.list_branches");
473
+ }
474
+ if (value.manifest_size != null
475
+ && (typeof value.manifest_size !== "number" || !Number.isInteger(value.manifest_size))) {
476
+ throw new RoomServerException("unexpected return type from database.list_branches");
477
+ }
478
+ let createdAt = null;
479
+ if (value.created_at != null) {
480
+ if (typeof value.created_at !== "string") {
481
+ throw new RoomServerException("unexpected return type from database.list_branches");
482
+ }
483
+ createdAt = new Date(value.created_at);
484
+ if (Number.isNaN(createdAt.getTime())) {
485
+ throw new RoomServerException("unexpected return type from database.list_branches");
486
+ }
487
+ }
488
+ return {
489
+ name: value.name,
490
+ parentBranch: value.parent_branch ?? null,
491
+ parentVersion: value.parent_version ?? null,
492
+ createdAt,
493
+ manifestSize: value.manifest_size ?? null,
494
+ };
495
+ }
344
496
  class DatabaseWriteInputStream {
345
497
  constructor(start, chunks) {
346
498
  this.start = start;
@@ -521,61 +673,72 @@ export class DatabaseClient {
521
673
  input.close();
522
674
  }
523
675
  }
524
- async listTables({ namespace } = {}) {
525
- const response = await this.invoke("list_tables", { namespace: namespace ?? null });
676
+ async listTables({ namespace, branch } = {}) {
677
+ const response = await this.invoke("list_tables", {
678
+ namespace: namespace ?? null,
679
+ branch: branch ?? null,
680
+ });
526
681
  if (!(response instanceof JsonContent)) {
527
682
  throw this._unexpectedResponseError("list_tables");
528
683
  }
529
684
  return Array.isArray(response.json.tables) ? response.json.tables : [];
530
685
  }
531
- async createTable({ name, data, schema, mode = "create", namespace, metadata, }) {
686
+ async createTable({ name, data, schema, mode = "create", namespace, branch, metadata, }) {
532
687
  const input = new DatabaseWriteInputStream({
533
688
  kind: "start",
534
689
  name,
535
690
  fields: schemaEntries(schema),
536
691
  mode,
537
692
  namespace: namespace ?? null,
693
+ branch: branch ?? null,
538
694
  metadata: metadataEntries(metadata),
539
695
  }, data ?? []);
540
696
  await this.drainWriteStream("create_table", input);
541
697
  }
542
- async createTableWithSchema({ name, schema, data, mode = "create", namespace, metadata }) {
698
+ async createTableWithSchema({ name, schema, data, mode = "create", namespace, branch, metadata }) {
543
699
  return this.createTable({
544
700
  name,
545
701
  schema,
546
702
  data: data == null ? undefined : rowChunkList(data),
547
703
  mode,
548
704
  namespace,
705
+ branch,
549
706
  metadata,
550
707
  });
551
708
  }
552
- async createTableFromData({ name, data, mode = "create", namespace, metadata }) {
709
+ async createTableFromData({ name, data, mode = "create", namespace, branch, metadata }) {
553
710
  return this.createTable({
554
711
  name,
555
712
  data: data == null ? undefined : rowChunkList(data),
556
713
  mode,
557
714
  namespace,
715
+ branch,
558
716
  metadata,
559
717
  });
560
718
  }
561
- async createTableFromDataStream({ name, chunks, schema, mode = "create", namespace, metadata }) {
562
- return this.createTable({ name, data: chunks, schema, mode, namespace, metadata });
719
+ async createTableFromDataStream({ name, chunks, schema, mode = "create", namespace, branch, metadata }) {
720
+ return this.createTable({ name, data: chunks, schema, mode, namespace, branch, metadata });
563
721
  }
564
- async dropTable({ name, ignoreMissing = false, namespace }) {
722
+ async dropTable({ name, ignoreMissing = false, namespace, branch }) {
565
723
  await this.room.invoke({
566
724
  toolkit: "database",
567
725
  tool: "drop_table",
568
- input: { name, ignore_missing: ignoreMissing, namespace: namespace ?? null },
726
+ input: {
727
+ name,
728
+ ignore_missing: ignoreMissing,
729
+ namespace: namespace ?? null,
730
+ branch: branch ?? null,
731
+ },
569
732
  });
570
733
  }
571
- async dropIndex({ table, name, namespace }) {
734
+ async dropIndex({ table, name, namespace, branch }) {
572
735
  await this.room.invoke({
573
736
  toolkit: "database",
574
737
  tool: "drop_index",
575
- input: { table, name, namespace: namespace ?? null },
738
+ input: { table, name, namespace: namespace ?? null, branch: branch ?? null },
576
739
  });
577
740
  }
578
- async addColumns({ table, newColumns, namespace }) {
741
+ async addColumns({ table, newColumns, namespace, branch }) {
579
742
  await this.room.invoke({
580
743
  toolkit: "database",
581
744
  tool: "add_columns",
@@ -585,56 +748,59 @@ export class DatabaseClient {
585
748
  ? { name, value_sql: null, data_type: toolkitDataTypeJson(value) }
586
749
  : { name, value_sql: value, data_type: null })),
587
750
  namespace: namespace ?? null,
751
+ branch: branch ?? null,
588
752
  },
589
753
  });
590
754
  }
591
- async dropColumns({ table, columns, namespace }) {
755
+ async dropColumns({ table, columns, namespace, branch }) {
592
756
  await this.room.invoke({
593
757
  toolkit: "database",
594
758
  tool: "drop_columns",
595
- input: { table, columns, namespace: namespace ?? null },
759
+ input: { table, columns, namespace: namespace ?? null, branch: branch ?? null },
596
760
  });
597
761
  }
598
- async insert({ table, records, namespace }) {
599
- await this.insertStream({ table, chunks: rowChunkList(records), namespace });
762
+ async insert({ table, records, namespace, branch }) {
763
+ await this.insertStream({ table, chunks: rowChunkList(records), namespace, branch });
600
764
  }
601
- async insertStream({ table, chunks, namespace }) {
765
+ async insertStream({ table, chunks, namespace, branch }) {
602
766
  const input = new DatabaseWriteInputStream({
603
767
  kind: "start",
604
768
  table,
605
769
  namespace: namespace ?? null,
770
+ branch: branch ?? null,
606
771
  }, chunks);
607
772
  await this.drainWriteStream("insert", input);
608
773
  }
609
- async update({ table, where, values, valuesSql, namespace }) {
774
+ async update({ table, where, values, namespace, branch }) {
610
775
  await this.room.invoke({
611
776
  toolkit: "database",
612
777
  tool: "update",
613
778
  input: {
614
779
  table,
615
780
  where,
616
- values: values == null ? null : Object.entries(values).map(([column, value]) => ({ column, value_json: JSON.stringify(encodeLegacyValue(value)) })),
617
- values_sql: valuesSql == null ? null : Object.entries(valuesSql).map(([column, expression]) => ({ column, expression })),
781
+ values: Object.entries(values).map(([column, value]) => ({ column, value_json: JSON.stringify(encodeRecordValue(value)) })),
618
782
  namespace: namespace ?? null,
783
+ branch: branch ?? null,
619
784
  },
620
785
  });
621
786
  }
622
- async delete({ table, where, namespace }) {
787
+ async delete({ table, where, namespace, branch }) {
623
788
  await this.room.invoke({
624
789
  toolkit: "database",
625
790
  tool: "delete",
626
- input: { table, where, namespace: namespace ?? null },
791
+ input: { table, where, namespace: namespace ?? null, branch: branch ?? null },
627
792
  });
628
793
  }
629
- async merge({ table, on, records, namespace }) {
630
- await this.mergeStream({ table, on, chunks: rowChunkList(records), namespace });
794
+ async merge({ table, on, records, namespace, branch }) {
795
+ await this.mergeStream({ table, on, chunks: rowChunkList(records), namespace, branch });
631
796
  }
632
- async mergeStream({ table, on, chunks, namespace }) {
797
+ async mergeStream({ table, on, chunks, namespace, branch }) {
633
798
  const input = new DatabaseWriteInputStream({
634
799
  kind: "start",
635
800
  table,
636
801
  on,
637
802
  namespace: namespace ?? null,
803
+ branch: branch ?? null,
638
804
  }, chunks);
639
805
  await this.drainWriteStream("merge", input);
640
806
  }
@@ -650,17 +816,28 @@ export class DatabaseClient {
650
816
  kind: "start",
651
817
  query,
652
818
  tables: normalizeTableRefs(tables),
653
- params_json: params == null ? null : JSON.stringify(encodeLegacyValue(params)),
819
+ params_json: params == null ? null : JSON.stringify(encodeDatabaseRecord(params)),
654
820
  });
655
821
  }
656
- async search({ table, text, vector, where, offset, limit, select, namespace }) {
822
+ async search({ table, text, vector, where, offset, limit, select, namespace, branch, version }) {
657
823
  const rows = [];
658
- for await (const chunk of this.searchStream({ table, text, vector, where, offset, limit, select, namespace })) {
824
+ for await (const chunk of this.searchStream({
825
+ table,
826
+ text,
827
+ vector,
828
+ where,
829
+ offset,
830
+ limit,
831
+ select,
832
+ namespace,
833
+ branch,
834
+ version,
835
+ })) {
659
836
  rows.push(...chunk);
660
837
  }
661
838
  return rows;
662
839
  }
663
- async *searchStream({ table, text, vector, where, offset, limit, select, namespace }) {
840
+ async *searchStream({ table, text, vector, where, offset, limit, select, namespace, branch, version }) {
664
841
  yield* this.streamRows("search", {
665
842
  kind: "start",
666
843
  table,
@@ -672,9 +849,11 @@ export class DatabaseClient {
672
849
  limit: limit ?? null,
673
850
  select: select ?? null,
674
851
  namespace: namespace ?? null,
852
+ branch: branch ?? null,
853
+ version: version ?? null,
675
854
  });
676
855
  }
677
- async count({ table, text, vector, where, namespace }) {
856
+ async count({ table, text, vector, where, namespace, branch, version }) {
678
857
  const response = await this.invoke("count", {
679
858
  table,
680
859
  text: text ?? null,
@@ -682,14 +861,21 @@ export class DatabaseClient {
682
861
  text_columns: null,
683
862
  where: buildWhereClause(where),
684
863
  namespace: namespace ?? null,
864
+ branch: branch ?? null,
865
+ version: version ?? null,
685
866
  });
686
867
  if (!(response instanceof JsonContent) || typeof response.json.count !== "number" || !Number.isInteger(response.json.count)) {
687
868
  throw this._unexpectedResponseError("count");
688
869
  }
689
870
  return response.json.count;
690
871
  }
691
- async inspect({ table, namespace }) {
692
- const response = await this.invoke("inspect", { table, namespace: namespace ?? null });
872
+ async inspect({ table, namespace, branch, version }) {
873
+ const response = await this.invoke("inspect", {
874
+ table,
875
+ namespace: namespace ?? null,
876
+ branch: branch ?? null,
877
+ version: version ?? null,
878
+ });
693
879
  if (!(response instanceof JsonContent) || !Array.isArray(response.json.fields)) {
694
880
  throw this._unexpectedResponseError("inspect");
695
881
  }
@@ -703,55 +889,89 @@ export class DatabaseClient {
703
889
  async optimize(tableOrParams) {
704
890
  const table = typeof tableOrParams === "string" ? tableOrParams : tableOrParams.table;
705
891
  const namespace = typeof tableOrParams === "string" ? undefined : tableOrParams.namespace;
706
- await this.room.invoke({ toolkit: "database", tool: "optimize", input: { table, namespace: namespace ?? null } });
707
- }
708
- async restore({ table, version, namespace }) {
892
+ const branch = typeof tableOrParams === "string" ? undefined : tableOrParams.branch;
709
893
  await this.room.invoke({
710
894
  toolkit: "database",
711
- tool: "restore",
712
- input: { table, version, namespace: namespace ?? null },
895
+ tool: "optimize",
896
+ input: { table, namespace: namespace ?? null, branch: branch ?? null },
713
897
  });
714
898
  }
715
- async checkout({ table, version, namespace }) {
899
+ async restore({ table, version, namespace, branch }) {
716
900
  await this.room.invoke({
717
901
  toolkit: "database",
718
- tool: "checkout",
719
- input: { table, version, namespace: namespace ?? null },
902
+ tool: "restore",
903
+ input: { table, version, namespace: namespace ?? null, branch: branch ?? null },
720
904
  });
721
905
  }
722
- async listVersions({ table, namespace }) {
723
- const response = await this.invoke("list_versions", { table, namespace: namespace ?? null });
906
+ async listVersions({ table, namespace, branch }) {
907
+ const response = await this.invoke("list_versions", {
908
+ table,
909
+ namespace: namespace ?? null,
910
+ branch: branch ?? null,
911
+ });
724
912
  if (!(response instanceof JsonContent) || !Array.isArray(response.json.versions)) {
725
913
  throw this._unexpectedResponseError("list_versions");
726
914
  }
727
915
  return response.json.versions.map((version) => tableVersionFromJson(version));
728
916
  }
729
- async createVectorIndex({ table, column, replace = false, namespace }) {
917
+ async createVectorIndex({ table, column, replace = false, namespace, branch }) {
730
918
  await this.room.invoke({
731
919
  toolkit: "database",
732
920
  tool: "create_vector_index",
733
- input: { table, column, replace, namespace: namespace ?? null },
921
+ input: { table, column, replace, namespace: namespace ?? null, branch: branch ?? null },
734
922
  });
735
923
  }
736
- async createScalarIndex({ table, column, replace = false, namespace }) {
924
+ async createScalarIndex({ table, column, replace = false, namespace, branch }) {
737
925
  await this.room.invoke({
738
926
  toolkit: "database",
739
927
  tool: "create_scalar_index",
740
- input: { table, column, replace, namespace: namespace ?? null },
928
+ input: { table, column, replace, namespace: namespace ?? null, branch: branch ?? null },
741
929
  });
742
930
  }
743
- async createFullTextSearchIndex({ table, column, replace = false, namespace }) {
931
+ async createFullTextSearchIndex({ table, column, replace = false, namespace, branch }) {
744
932
  await this.room.invoke({
745
933
  toolkit: "database",
746
934
  tool: "create_full_text_search_index",
747
- input: { table, column, replace, namespace: namespace ?? null },
935
+ input: { table, column, replace, namespace: namespace ?? null, branch: branch ?? null },
748
936
  });
749
937
  }
750
- async listIndexes({ table, namespace }) {
751
- const response = await this.invoke("list_indexes", { table, namespace: namespace ?? null });
938
+ async listIndexes({ table, namespace, branch, version }) {
939
+ const response = await this.invoke("list_indexes", {
940
+ table,
941
+ namespace: namespace ?? null,
942
+ branch: branch ?? null,
943
+ version: version ?? null,
944
+ });
752
945
  if (!(response instanceof JsonContent) || !Array.isArray(response.json.indexes)) {
753
946
  throw this._unexpectedResponseError("list_indexes");
754
947
  }
755
948
  return response.json.indexes.map((index) => tableIndexFromJson(index));
756
949
  }
950
+ async listBranches({ namespace } = {}) {
951
+ const response = await this.invoke("list_branches", {
952
+ namespace: namespace ?? null,
953
+ });
954
+ if (!(response instanceof JsonContent) || !Array.isArray(response.json.branches)) {
955
+ throw this._unexpectedResponseError("list_branches");
956
+ }
957
+ return response.json.branches.map((branch) => tableBranchFromJson(branch));
958
+ }
959
+ async createBranch({ branch, fromBranch, namespace }) {
960
+ await this.room.invoke({
961
+ toolkit: "database",
962
+ tool: "create_branch",
963
+ input: {
964
+ branch,
965
+ from_branch: fromBranch ?? null,
966
+ namespace: namespace ?? null,
967
+ },
968
+ });
969
+ }
970
+ async deleteBranch({ branch, namespace }) {
971
+ await this.room.invoke({
972
+ toolkit: "database",
973
+ tool: "delete_branch",
974
+ input: { branch, namespace: namespace ?? null },
975
+ });
976
+ }
757
977
  }