@xata.io/client 0.20.1 → 0.21.0

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/dist/index.mjs CHANGED
@@ -1,5 +1,6 @@
1
- const defaultTrace = async (_name, fn, _options) => {
1
+ const defaultTrace = async (name, fn, _options) => {
2
2
  return await fn({
3
+ name,
3
4
  setAttributes: () => {
4
5
  return;
5
6
  }
@@ -41,6 +42,18 @@ function isStringArray(value) {
41
42
  function isNumber(value) {
42
43
  return isDefined(value) && typeof value === "number";
43
44
  }
45
+ function parseNumber(value) {
46
+ if (isNumber(value)) {
47
+ return value;
48
+ }
49
+ if (isString(value)) {
50
+ const parsed = Number(value);
51
+ if (!Number.isNaN(parsed)) {
52
+ return parsed;
53
+ }
54
+ }
55
+ return void 0;
56
+ }
44
57
  function toBase64(value) {
45
58
  try {
46
59
  return btoa(value);
@@ -60,10 +73,20 @@ function deepMerge(a, b) {
60
73
  }
61
74
  return result;
62
75
  }
76
+ function chunk(array, chunkSize) {
77
+ const result = [];
78
+ for (let i = 0; i < array.length; i += chunkSize) {
79
+ result.push(array.slice(i, i + chunkSize));
80
+ }
81
+ return result;
82
+ }
83
+ async function timeout(ms) {
84
+ return new Promise((resolve) => setTimeout(resolve, ms));
85
+ }
63
86
 
64
87
  function getEnvironment() {
65
88
  try {
66
- if (isObject(process) && isObject(process.env)) {
89
+ if (isDefined(process) && isDefined(process.env)) {
67
90
  return {
68
91
  apiKey: process.env.XATA_API_KEY ?? getGlobalApiKey(),
69
92
  databaseURL: process.env.XATA_DATABASE_URL ?? getGlobalDatabaseURL(),
@@ -172,6 +195,29 @@ function getAPIKey() {
172
195
  }
173
196
  }
174
197
 
198
+ var __accessCheck$8 = (obj, member, msg) => {
199
+ if (!member.has(obj))
200
+ throw TypeError("Cannot " + msg);
201
+ };
202
+ var __privateGet$8 = (obj, member, getter) => {
203
+ __accessCheck$8(obj, member, "read from private field");
204
+ return getter ? getter.call(obj) : member.get(obj);
205
+ };
206
+ var __privateAdd$8 = (obj, member, value) => {
207
+ if (member.has(obj))
208
+ throw TypeError("Cannot add the same private member more than once");
209
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
210
+ };
211
+ var __privateSet$8 = (obj, member, value, setter) => {
212
+ __accessCheck$8(obj, member, "write to private field");
213
+ setter ? setter.call(obj, value) : member.set(obj, value);
214
+ return value;
215
+ };
216
+ var __privateMethod$4 = (obj, member, method) => {
217
+ __accessCheck$8(obj, member, "access private method");
218
+ return method;
219
+ };
220
+ var _fetch, _queue, _concurrency, _enqueue, enqueue_fn;
175
221
  function getFetchImplementation(userFetch) {
176
222
  const globalFetch = typeof fetch !== "undefined" ? fetch : void 0;
177
223
  const fetchImpl = userFetch ?? globalFetch;
@@ -182,8 +228,74 @@ function getFetchImplementation(userFetch) {
182
228
  }
183
229
  return fetchImpl;
184
230
  }
231
+ class ApiRequestPool {
232
+ constructor(concurrency = 10) {
233
+ __privateAdd$8(this, _enqueue);
234
+ __privateAdd$8(this, _fetch, void 0);
235
+ __privateAdd$8(this, _queue, void 0);
236
+ __privateAdd$8(this, _concurrency, void 0);
237
+ __privateSet$8(this, _queue, []);
238
+ __privateSet$8(this, _concurrency, concurrency);
239
+ this.running = 0;
240
+ this.started = 0;
241
+ }
242
+ setFetch(fetch2) {
243
+ __privateSet$8(this, _fetch, fetch2);
244
+ }
245
+ getFetch() {
246
+ if (!__privateGet$8(this, _fetch)) {
247
+ throw new Error("Fetch not set");
248
+ }
249
+ return __privateGet$8(this, _fetch);
250
+ }
251
+ request(url, options) {
252
+ const start = new Date();
253
+ const fetch2 = this.getFetch();
254
+ const runRequest = async (stalled = false) => {
255
+ const response = await fetch2(url, options);
256
+ if (response.status === 429) {
257
+ const rateLimitReset = parseNumber(response.headers?.get("x-ratelimit-reset")) ?? 1;
258
+ await timeout(rateLimitReset * 1e3);
259
+ return await runRequest(true);
260
+ }
261
+ if (stalled) {
262
+ const stalledTime = new Date().getTime() - start.getTime();
263
+ console.warn(`A request to Xata hit your workspace limits, was retried and stalled for ${stalledTime}ms`);
264
+ }
265
+ return response;
266
+ };
267
+ return __privateMethod$4(this, _enqueue, enqueue_fn).call(this, async () => {
268
+ return await runRequest();
269
+ });
270
+ }
271
+ }
272
+ _fetch = new WeakMap();
273
+ _queue = new WeakMap();
274
+ _concurrency = new WeakMap();
275
+ _enqueue = new WeakSet();
276
+ enqueue_fn = function(task) {
277
+ const promise = new Promise((resolve) => __privateGet$8(this, _queue).push(resolve)).finally(() => {
278
+ this.started--;
279
+ this.running++;
280
+ }).then(() => task()).finally(() => {
281
+ this.running--;
282
+ const next = __privateGet$8(this, _queue).shift();
283
+ if (next !== void 0) {
284
+ this.started++;
285
+ next();
286
+ }
287
+ });
288
+ if (this.running + this.started < __privateGet$8(this, _concurrency)) {
289
+ const next = __privateGet$8(this, _queue).shift();
290
+ if (next !== void 0) {
291
+ this.started++;
292
+ next();
293
+ }
294
+ }
295
+ return promise;
296
+ };
185
297
 
186
- const VERSION = "0.20.1";
298
+ const VERSION = "0.21.0";
187
299
 
188
300
  class ErrorWithCause extends Error {
189
301
  constructor(message, options) {
@@ -226,6 +338,7 @@ function getMessage(data) {
226
338
  }
227
339
  }
228
340
 
341
+ const pool = new ApiRequestPool();
229
342
  const resolveUrl = (url, queryParams = {}, pathParams = {}) => {
230
343
  const cleanQueryParams = Object.entries(queryParams).reduce((acc, [key, value]) => {
231
344
  if (value === void 0 || value === null)
@@ -274,11 +387,13 @@ async function fetch$1({
274
387
  signal,
275
388
  clientID,
276
389
  sessionID,
390
+ clientName,
277
391
  fetchOptions = {}
278
392
  }) {
279
- return trace(
393
+ pool.setFetch(fetchImpl);
394
+ return await trace(
280
395
  `${method.toUpperCase()} ${path}`,
281
- async ({ setAttributes }) => {
396
+ async ({ name, setAttributes }) => {
282
397
  const baseUrl = buildBaseUrl({ endpoint, path, workspacesApiUrl, pathParams, apiUrl });
283
398
  const fullUrl = resolveUrl(baseUrl, queryParams, pathParams);
284
399
  const url = fullUrl.includes("localhost") ? fullUrl.replace(/^[^.]+\./, "http://") : fullUrl;
@@ -286,24 +401,26 @@ async function fetch$1({
286
401
  [TraceAttributes.HTTP_URL]: url,
287
402
  [TraceAttributes.HTTP_TARGET]: resolveUrl(path, queryParams, pathParams)
288
403
  });
289
- const response = await fetchImpl(url, {
404
+ const xataAgent = compact([
405
+ ["client", "TS_SDK"],
406
+ ["version", VERSION],
407
+ isDefined(clientName) ? ["service", clientName] : void 0
408
+ ]).map(([key, value]) => `${key}=${value}`).join("; ");
409
+ const response = await pool.request(url, {
290
410
  ...fetchOptions,
291
411
  method: method.toUpperCase(),
292
412
  body: body ? JSON.stringify(body) : void 0,
293
413
  headers: {
294
414
  "Content-Type": "application/json",
295
- "User-Agent": `Xata client-ts/${VERSION}`,
296
415
  "X-Xata-Client-ID": clientID ?? "",
297
416
  "X-Xata-Session-ID": sessionID ?? "",
417
+ "X-Xata-Agent": xataAgent,
298
418
  ...headers,
299
419
  ...hostHeader(fullUrl),
300
420
  Authorization: `Bearer ${apiKey}`
301
421
  },
302
422
  signal
303
423
  });
304
- if (response.status === 204) {
305
- return {};
306
- }
307
424
  const { host, protocol } = parseUrl(response.url);
308
425
  const requestId = response.headers?.get("x-request-id") ?? void 0;
309
426
  setAttributes({
@@ -313,6 +430,12 @@ async function fetch$1({
313
430
  [TraceAttributes.HTTP_HOST]: host,
314
431
  [TraceAttributes.HTTP_SCHEME]: protocol?.replace(":", "")
315
432
  });
433
+ if (response.status === 204) {
434
+ return {};
435
+ }
436
+ if (response.status === 429) {
437
+ throw new FetcherError(response.status, "Rate limit exceeded", requestId);
438
+ }
316
439
  try {
317
440
  const jsonResponse = await response.json();
318
441
  if (response.ok) {
@@ -764,7 +887,8 @@ class XataApiClient {
764
887
  workspacesApiUrl: getHostUrl(provider, "workspaces"),
765
888
  fetchImpl: getFetchImplementation(options.fetch),
766
889
  apiKey,
767
- trace
890
+ trace,
891
+ clientName: options.clientName
768
892
  });
769
893
  }
770
894
  get user() {
@@ -1366,6 +1490,19 @@ class RecordsApi {
1366
1490
  ...this.extraProps
1367
1491
  });
1368
1492
  }
1493
+ branchTransaction({
1494
+ workspace,
1495
+ region,
1496
+ database,
1497
+ branch,
1498
+ operations
1499
+ }) {
1500
+ return operationsByTag.records.branchTransaction({
1501
+ pathParams: { workspace, region, dbBranchName: `${database}:${branch}` },
1502
+ body: { operations },
1503
+ ...this.extraProps
1504
+ });
1505
+ }
1369
1506
  }
1370
1507
  class SearchAndFilterApi {
1371
1508
  constructor(extraProps) {
@@ -2131,7 +2268,8 @@ var __privateMethod$2 = (obj, member, method) => {
2131
2268
  __accessCheck$4(obj, member, "access private method");
2132
2269
  return method;
2133
2270
  };
2134
- var _table, _getFetchProps, _db, _cache, _schemaTables$2, _trace, _insertRecordWithoutId, insertRecordWithoutId_fn, _insertRecordWithId, insertRecordWithId_fn, _bulkInsertTableRecords, bulkInsertTableRecords_fn, _updateRecordWithID, updateRecordWithID_fn, _upsertRecordWithID, upsertRecordWithID_fn, _deleteRecord, deleteRecord_fn, _setCacheQuery, setCacheQuery_fn, _getCacheQuery, getCacheQuery_fn, _getSchemaTables$1, getSchemaTables_fn$1;
2271
+ var _table, _getFetchProps, _db, _cache, _schemaTables$2, _trace, _insertRecordWithoutId, insertRecordWithoutId_fn, _insertRecordWithId, insertRecordWithId_fn, _insertRecords, insertRecords_fn, _updateRecordWithID, updateRecordWithID_fn, _updateRecords, updateRecords_fn, _upsertRecordWithID, upsertRecordWithID_fn, _deleteRecord, deleteRecord_fn, _deleteRecords, deleteRecords_fn, _setCacheQuery, setCacheQuery_fn, _getCacheQuery, getCacheQuery_fn, _getSchemaTables$1, getSchemaTables_fn$1;
2272
+ const BULK_OPERATION_MAX_SIZE = 1e3;
2135
2273
  class Repository extends Query {
2136
2274
  }
2137
2275
  class RestRepository extends Query {
@@ -2143,10 +2281,12 @@ class RestRepository extends Query {
2143
2281
  );
2144
2282
  __privateAdd$4(this, _insertRecordWithoutId);
2145
2283
  __privateAdd$4(this, _insertRecordWithId);
2146
- __privateAdd$4(this, _bulkInsertTableRecords);
2284
+ __privateAdd$4(this, _insertRecords);
2147
2285
  __privateAdd$4(this, _updateRecordWithID);
2286
+ __privateAdd$4(this, _updateRecords);
2148
2287
  __privateAdd$4(this, _upsertRecordWithID);
2149
2288
  __privateAdd$4(this, _deleteRecord);
2289
+ __privateAdd$4(this, _deleteRecords);
2150
2290
  __privateAdd$4(this, _setCacheQuery);
2151
2291
  __privateAdd$4(this, _getCacheQuery);
2152
2292
  __privateAdd$4(this, _getSchemaTables$1);
@@ -2180,20 +2320,22 @@ class RestRepository extends Query {
2180
2320
  if (Array.isArray(a)) {
2181
2321
  if (a.length === 0)
2182
2322
  return [];
2183
- const columns = isStringArray(b) ? b : void 0;
2184
- return __privateMethod$2(this, _bulkInsertTableRecords, bulkInsertTableRecords_fn).call(this, a, columns);
2323
+ const ids = await __privateMethod$2(this, _insertRecords, insertRecords_fn).call(this, a, { ifVersion, createOnly: true });
2324
+ const columns = isStringArray(b) ? b : ["*"];
2325
+ const result = await this.read(ids, columns);
2326
+ return result;
2185
2327
  }
2186
2328
  if (isString(a) && isObject(b)) {
2187
2329
  if (a === "")
2188
2330
  throw new Error("The id can't be empty");
2189
2331
  const columns = isStringArray(c) ? c : void 0;
2190
- return __privateMethod$2(this, _insertRecordWithId, insertRecordWithId_fn).call(this, a, b, columns, { createOnly: true, ifVersion });
2332
+ return await __privateMethod$2(this, _insertRecordWithId, insertRecordWithId_fn).call(this, a, b, columns, { createOnly: true, ifVersion });
2191
2333
  }
2192
2334
  if (isObject(a) && isString(a.id)) {
2193
2335
  if (a.id === "")
2194
2336
  throw new Error("The id can't be empty");
2195
2337
  const columns = isStringArray(b) ? b : void 0;
2196
- return __privateMethod$2(this, _insertRecordWithId, insertRecordWithId_fn).call(this, a.id, { ...a, id: void 0 }, columns, { createOnly: true, ifVersion });
2338
+ return await __privateMethod$2(this, _insertRecordWithId, insertRecordWithId_fn).call(this, a.id, { ...a, id: void 0 }, columns, { createOnly: true, ifVersion });
2197
2339
  }
2198
2340
  if (isObject(a)) {
2199
2341
  const columns = isStringArray(b) ? b : void 0;
@@ -2268,11 +2410,15 @@ class RestRepository extends Query {
2268
2410
  if (Array.isArray(a)) {
2269
2411
  if (a.length === 0)
2270
2412
  return [];
2271
- if (a.length > 100) {
2272
- console.warn("Bulk update operation is not optimized in the Xata API yet, this request might be slow");
2273
- }
2413
+ const existing = await this.read(a, ["id"]);
2414
+ const updates = a.filter((_item, index) => existing[index] !== null);
2415
+ await __privateMethod$2(this, _updateRecords, updateRecords_fn).call(this, updates, {
2416
+ ifVersion,
2417
+ upsert: false
2418
+ });
2274
2419
  const columns = isStringArray(b) ? b : ["*"];
2275
- return Promise.all(a.map((object) => this.update(object, columns)));
2420
+ const result = await this.read(a, columns);
2421
+ return result;
2276
2422
  }
2277
2423
  if (isString(a) && isObject(b)) {
2278
2424
  const columns = isStringArray(c) ? c : void 0;
@@ -2310,11 +2456,13 @@ class RestRepository extends Query {
2310
2456
  if (Array.isArray(a)) {
2311
2457
  if (a.length === 0)
2312
2458
  return [];
2313
- if (a.length > 100) {
2314
- console.warn("Bulk update operation is not optimized in the Xata API yet, this request might be slow");
2315
- }
2459
+ await __privateMethod$2(this, _updateRecords, updateRecords_fn).call(this, a, {
2460
+ ifVersion,
2461
+ upsert: true
2462
+ });
2316
2463
  const columns = isStringArray(b) ? b : ["*"];
2317
- return Promise.all(a.map((object) => this.createOrUpdate(object, columns)));
2464
+ const result = await this.read(a, columns);
2465
+ return result;
2318
2466
  }
2319
2467
  if (isString(a) && isObject(b)) {
2320
2468
  const columns = isStringArray(c) ? c : void 0;
@@ -2333,8 +2481,10 @@ class RestRepository extends Query {
2333
2481
  if (Array.isArray(a)) {
2334
2482
  if (a.length === 0)
2335
2483
  return [];
2484
+ const ids = await __privateMethod$2(this, _insertRecords, insertRecords_fn).call(this, a, { ifVersion, createOnly: false });
2336
2485
  const columns = isStringArray(b) ? b : ["*"];
2337
- return __privateMethod$2(this, _bulkInsertTableRecords, bulkInsertTableRecords_fn).call(this, a, columns);
2486
+ const result = await this.read(ids, columns);
2487
+ return result;
2338
2488
  }
2339
2489
  if (isString(a) && isObject(b)) {
2340
2490
  const columns = isStringArray(c) ? c : void 0;
@@ -2352,10 +2502,17 @@ class RestRepository extends Query {
2352
2502
  if (Array.isArray(a)) {
2353
2503
  if (a.length === 0)
2354
2504
  return [];
2355
- if (a.length > 100) {
2356
- console.warn("Bulk delete operation is not optimized in the Xata API yet, this request might be slow");
2357
- }
2358
- return Promise.all(a.map((id) => this.delete(id, b)));
2505
+ const ids = a.map((o) => {
2506
+ if (isString(o))
2507
+ return o;
2508
+ if (isString(o.id))
2509
+ return o.id;
2510
+ throw new Error("Invalid arguments for delete method");
2511
+ });
2512
+ const columns = isStringArray(b) ? b : ["*"];
2513
+ const result = await this.read(a, columns);
2514
+ await __privateMethod$2(this, _deleteRecords, deleteRecords_fn).call(this, ids);
2515
+ return result;
2359
2516
  }
2360
2517
  if (isString(a)) {
2361
2518
  return __privateMethod$2(this, _deleteRecord, deleteRecord_fn).call(this, a, b);
@@ -2400,7 +2557,9 @@ class RestRepository extends Query {
2400
2557
  prefix: options.prefix,
2401
2558
  highlight: options.highlight,
2402
2559
  filter: options.filter,
2403
- boosters: options.boosters
2560
+ boosters: options.boosters,
2561
+ page: options.page,
2562
+ target: options.target
2404
2563
  },
2405
2564
  ...fetchProps
2406
2565
  });
@@ -2523,31 +2682,40 @@ insertRecordWithId_fn = async function(recordId, object, columns = ["*"], { crea
2523
2682
  const schemaTables = await __privateMethod$2(this, _getSchemaTables$1, getSchemaTables_fn$1).call(this);
2524
2683
  return initObject(__privateGet$4(this, _db), schemaTables, __privateGet$4(this, _table), response, columns);
2525
2684
  };
2526
- _bulkInsertTableRecords = new WeakSet();
2527
- bulkInsertTableRecords_fn = async function(objects, columns = ["*"]) {
2685
+ _insertRecords = new WeakSet();
2686
+ insertRecords_fn = async function(objects, { createOnly, ifVersion }) {
2528
2687
  const fetchProps = await __privateGet$4(this, _getFetchProps).call(this);
2529
- const records = objects.map((object) => transformObjectLinks(object));
2530
- const response = await bulkInsertTableRecords({
2531
- pathParams: {
2532
- workspace: "{workspaceId}",
2533
- dbBranchName: "{dbBranch}",
2534
- region: "{region}",
2535
- tableName: __privateGet$4(this, _table)
2536
- },
2537
- queryParams: { columns },
2538
- body: { records },
2539
- ...fetchProps
2540
- });
2541
- if (!isResponseWithRecords(response)) {
2542
- throw new Error("Request included columns but server didn't include them");
2688
+ const chunkedOperations = chunk(
2689
+ objects.map((object) => ({
2690
+ insert: { table: __privateGet$4(this, _table), record: transformObjectLinks(object), createOnly, ifVersion }
2691
+ })),
2692
+ BULK_OPERATION_MAX_SIZE
2693
+ );
2694
+ const ids = [];
2695
+ for (const operations of chunkedOperations) {
2696
+ const { results } = await branchTransaction({
2697
+ pathParams: {
2698
+ workspace: "{workspaceId}",
2699
+ dbBranchName: "{dbBranch}",
2700
+ region: "{region}"
2701
+ },
2702
+ body: { operations },
2703
+ ...fetchProps
2704
+ });
2705
+ for (const result of results) {
2706
+ if (result.operation === "insert") {
2707
+ ids.push(result.id);
2708
+ } else {
2709
+ ids.push(null);
2710
+ }
2711
+ }
2543
2712
  }
2544
- const schemaTables = await __privateMethod$2(this, _getSchemaTables$1, getSchemaTables_fn$1).call(this);
2545
- return response.records?.map((item) => initObject(__privateGet$4(this, _db), schemaTables, __privateGet$4(this, _table), item, columns));
2713
+ return ids;
2546
2714
  };
2547
2715
  _updateRecordWithID = new WeakSet();
2548
2716
  updateRecordWithID_fn = async function(recordId, object, columns = ["*"], { ifVersion }) {
2549
2717
  const fetchProps = await __privateGet$4(this, _getFetchProps).call(this);
2550
- const record = transformObjectLinks(object);
2718
+ const { id: _id, ...record } = transformObjectLinks(object);
2551
2719
  try {
2552
2720
  const response = await updateRecordWithID({
2553
2721
  pathParams: {
@@ -2570,6 +2738,36 @@ updateRecordWithID_fn = async function(recordId, object, columns = ["*"], { ifVe
2570
2738
  throw e;
2571
2739
  }
2572
2740
  };
2741
+ _updateRecords = new WeakSet();
2742
+ updateRecords_fn = async function(objects, { ifVersion, upsert }) {
2743
+ const fetchProps = await __privateGet$4(this, _getFetchProps).call(this);
2744
+ const chunkedOperations = chunk(
2745
+ objects.map(({ id, ...object }) => ({
2746
+ update: { table: __privateGet$4(this, _table), id, ifVersion, upsert, fields: transformObjectLinks(object) }
2747
+ })),
2748
+ BULK_OPERATION_MAX_SIZE
2749
+ );
2750
+ const ids = [];
2751
+ for (const operations of chunkedOperations) {
2752
+ const { results } = await branchTransaction({
2753
+ pathParams: {
2754
+ workspace: "{workspaceId}",
2755
+ dbBranchName: "{dbBranch}",
2756
+ region: "{region}"
2757
+ },
2758
+ body: { operations },
2759
+ ...fetchProps
2760
+ });
2761
+ for (const result of results) {
2762
+ if (result.operation === "update") {
2763
+ ids.push(result.id);
2764
+ } else {
2765
+ ids.push(null);
2766
+ }
2767
+ }
2768
+ }
2769
+ return ids;
2770
+ };
2573
2771
  _upsertRecordWithID = new WeakSet();
2574
2772
  upsertRecordWithID_fn = async function(recordId, object, columns = ["*"], { ifVersion }) {
2575
2773
  const fetchProps = await __privateGet$4(this, _getFetchProps).call(this);
@@ -2612,6 +2810,25 @@ deleteRecord_fn = async function(recordId, columns = ["*"]) {
2612
2810
  throw e;
2613
2811
  }
2614
2812
  };
2813
+ _deleteRecords = new WeakSet();
2814
+ deleteRecords_fn = async function(recordIds) {
2815
+ const fetchProps = await __privateGet$4(this, _getFetchProps).call(this);
2816
+ const chunkedOperations = chunk(
2817
+ recordIds.map((id) => ({ delete: { table: __privateGet$4(this, _table), id } })),
2818
+ BULK_OPERATION_MAX_SIZE
2819
+ );
2820
+ for (const operations of chunkedOperations) {
2821
+ await branchTransaction({
2822
+ pathParams: {
2823
+ workspace: "{workspaceId}",
2824
+ dbBranchName: "{dbBranch}",
2825
+ region: "{region}"
2826
+ },
2827
+ body: { operations },
2828
+ ...fetchProps
2829
+ });
2830
+ }
2831
+ };
2615
2832
  _setCacheQuery = new WeakSet();
2616
2833
  setCacheQuery_fn = async function(query, meta, records) {
2617
2834
  await __privateGet$4(this, _cache).set(`query_${__privateGet$4(this, _table)}:${query.key()}`, { date: new Date(), meta, records });
@@ -2660,10 +2877,10 @@ const initObject = (db, schemaTables, table, object, selectedColumns) => {
2660
2877
  const value = result[column.name];
2661
2878
  switch (column.type) {
2662
2879
  case "datetime": {
2663
- const date = value !== void 0 ? new Date(value) : void 0;
2664
- if (date && isNaN(date.getTime())) {
2880
+ const date = value !== void 0 ? new Date(value) : null;
2881
+ if (date !== null && isNaN(date.getTime())) {
2665
2882
  console.error(`Failed to parse date ${value} for field ${column.name}`);
2666
- } else if (date) {
2883
+ } else {
2667
2884
  result[column.name] = date;
2668
2885
  }
2669
2886
  break;
@@ -2722,9 +2939,6 @@ const initObject = (db, schemaTables, table, object, selectedColumns) => {
2722
2939
  Object.freeze(result);
2723
2940
  return result;
2724
2941
  };
2725
- function isResponseWithRecords(value) {
2726
- return isObject(value) && Array.isArray(value.records);
2727
- }
2728
2942
  function extractId(value) {
2729
2943
  if (isString(value))
2730
2944
  return value;
@@ -2934,10 +3148,10 @@ _schemaTables = new WeakMap();
2934
3148
  _search = new WeakSet();
2935
3149
  search_fn = async function(query, options, getFetchProps) {
2936
3150
  const fetchProps = await getFetchProps();
2937
- const { tables, fuzziness, highlight, prefix } = options ?? {};
3151
+ const { tables, fuzziness, highlight, prefix, page } = options ?? {};
2938
3152
  const { records } = await searchBranch({
2939
3153
  pathParams: { workspace: "{workspaceId}", dbBranchName: "{dbBranch}", region: "{region}" },
2940
- body: { tables, query, fuzziness, prefix, highlight },
3154
+ body: { tables, query, fuzziness, prefix, highlight, page },
2941
3155
  ...fetchProps
2942
3156
  });
2943
3157
  return records;
@@ -2955,6 +3169,22 @@ getSchemaTables_fn = async function(getFetchProps) {
2955
3169
  return schema.tables;
2956
3170
  };
2957
3171
 
3172
+ class TransactionPlugin extends XataPlugin {
3173
+ build({ getFetchProps }) {
3174
+ return {
3175
+ run: async (operations) => {
3176
+ const fetchProps = await getFetchProps();
3177
+ const response = await branchTransaction({
3178
+ pathParams: { workspace: "{workspaceId}", dbBranchName: "{dbBranch}", region: "{region}" },
3179
+ body: { operations },
3180
+ ...fetchProps
3181
+ });
3182
+ return response;
3183
+ }
3184
+ };
3185
+ }
3186
+ }
3187
+
2958
3188
  const isBranchStrategyBuilder = (strategy) => {
2959
3189
  return typeof strategy === "function";
2960
3190
  };
@@ -3082,8 +3312,10 @@ const buildClient = (plugins) => {
3082
3312
  };
3083
3313
  const db = new SchemaPlugin(schemaTables).build(pluginOptions);
3084
3314
  const search = new SearchPlugin(db, schemaTables).build(pluginOptions);
3315
+ const transactions = new TransactionPlugin().build(pluginOptions);
3085
3316
  this.db = db;
3086
3317
  this.search = search;
3318
+ this.transactions = transactions;
3087
3319
  for (const [key, namespace] of Object.entries(plugins ?? {})) {
3088
3320
  if (namespace === void 0)
3089
3321
  continue;
@@ -3115,6 +3347,7 @@ const buildClient = (plugins) => {
3115
3347
  const apiKey = options?.apiKey || getAPIKey();
3116
3348
  const cache = options?.cache ?? new SimpleCache({ defaultQueryTTL: 0 });
3117
3349
  const trace = options?.trace ?? defaultTrace;
3350
+ const clientName = options?.clientName;
3118
3351
  const branch = async () => options?.branch !== void 0 ? await __privateMethod(this, _evaluateBranch, evaluateBranch_fn).call(this, options.branch) : await getCurrentBranchName({ apiKey, databaseURL, fetchImpl: options?.fetch });
3119
3352
  if (!apiKey) {
3120
3353
  throw new Error("Option apiKey is required");
@@ -3122,8 +3355,16 @@ const buildClient = (plugins) => {
3122
3355
  if (!databaseURL) {
3123
3356
  throw new Error("Option databaseURL is required");
3124
3357
  }
3125
- return { fetch, databaseURL, apiKey, branch, cache, trace, clientID: generateUUID(), enableBrowser };
3126
- }, _getFetchProps = new WeakSet(), getFetchProps_fn = async function({ fetch, apiKey, databaseURL, branch, trace, clientID }) {
3358
+ return { fetch, databaseURL, apiKey, branch, cache, trace, clientID: generateUUID(), enableBrowser, clientName };
3359
+ }, _getFetchProps = new WeakSet(), getFetchProps_fn = async function({
3360
+ fetch,
3361
+ apiKey,
3362
+ databaseURL,
3363
+ branch,
3364
+ trace,
3365
+ clientID,
3366
+ clientName
3367
+ }) {
3127
3368
  const branchValue = await __privateMethod(this, _evaluateBranch, evaluateBranch_fn).call(this, branch);
3128
3369
  if (!branchValue)
3129
3370
  throw new Error("Unable to resolve branch value");
@@ -3137,7 +3378,8 @@ const buildClient = (plugins) => {
3137
3378
  return databaseURL + newPath;
3138
3379
  },
3139
3380
  trace,
3140
- clientID
3381
+ clientID,
3382
+ clientName
3141
3383
  };
3142
3384
  }, _evaluateBranch = new WeakSet(), evaluateBranch_fn = async function(param) {
3143
3385
  if (__privateGet(this, _branch))