@xata.io/client 0.0.0-alpha.vfd68d20 → 0.0.0-alpha.vfda8f2e

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
@@ -41,6 +41,18 @@ function isStringArray(value) {
41
41
  function isNumber(value) {
42
42
  return isDefined(value) && typeof value === "number";
43
43
  }
44
+ function parseNumber(value) {
45
+ if (isNumber(value)) {
46
+ return value;
47
+ }
48
+ if (isString(value)) {
49
+ const parsed = Number(value);
50
+ if (!Number.isNaN(parsed)) {
51
+ return parsed;
52
+ }
53
+ }
54
+ return void 0;
55
+ }
44
56
  function toBase64(value) {
45
57
  try {
46
58
  return btoa(value);
@@ -60,6 +72,16 @@ function deepMerge(a, b) {
60
72
  }
61
73
  return result;
62
74
  }
75
+ function chunk(array, chunkSize) {
76
+ const result = [];
77
+ for (let i = 0; i < array.length; i += chunkSize) {
78
+ result.push(array.slice(i, i + chunkSize));
79
+ }
80
+ return result;
81
+ }
82
+ async function timeout(ms) {
83
+ return new Promise((resolve) => setTimeout(resolve, ms));
84
+ }
63
85
 
64
86
  function getEnvironment() {
65
87
  try {
@@ -172,6 +194,29 @@ function getAPIKey() {
172
194
  }
173
195
  }
174
196
 
197
+ var __accessCheck$8 = (obj, member, msg) => {
198
+ if (!member.has(obj))
199
+ throw TypeError("Cannot " + msg);
200
+ };
201
+ var __privateGet$8 = (obj, member, getter) => {
202
+ __accessCheck$8(obj, member, "read from private field");
203
+ return getter ? getter.call(obj) : member.get(obj);
204
+ };
205
+ var __privateAdd$8 = (obj, member, value) => {
206
+ if (member.has(obj))
207
+ throw TypeError("Cannot add the same private member more than once");
208
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
209
+ };
210
+ var __privateSet$8 = (obj, member, value, setter) => {
211
+ __accessCheck$8(obj, member, "write to private field");
212
+ setter ? setter.call(obj, value) : member.set(obj, value);
213
+ return value;
214
+ };
215
+ var __privateMethod$4 = (obj, member, method) => {
216
+ __accessCheck$8(obj, member, "access private method");
217
+ return method;
218
+ };
219
+ var _fetch, _queue, _concurrency, _enqueue, enqueue_fn;
175
220
  function getFetchImplementation(userFetch) {
176
221
  const globalFetch = typeof fetch !== "undefined" ? fetch : void 0;
177
222
  const fetchImpl = userFetch ?? globalFetch;
@@ -182,8 +227,70 @@ function getFetchImplementation(userFetch) {
182
227
  }
183
228
  return fetchImpl;
184
229
  }
230
+ class ApiRequestPool {
231
+ constructor(concurrency = 10) {
232
+ __privateAdd$8(this, _enqueue);
233
+ __privateAdd$8(this, _fetch, void 0);
234
+ __privateAdd$8(this, _queue, void 0);
235
+ __privateAdd$8(this, _concurrency, void 0);
236
+ __privateSet$8(this, _queue, []);
237
+ __privateSet$8(this, _concurrency, concurrency);
238
+ this.running = 0;
239
+ this.started = 0;
240
+ }
241
+ setFetch(fetch2) {
242
+ __privateSet$8(this, _fetch, fetch2);
243
+ }
244
+ getFetch() {
245
+ if (!__privateGet$8(this, _fetch)) {
246
+ throw new Error("Fetch not set");
247
+ }
248
+ return __privateGet$8(this, _fetch);
249
+ }
250
+ request(url, options, context = { start: new Date(), stalled: false }) {
251
+ const fetch2 = this.getFetch();
252
+ return __privateMethod$4(this, _enqueue, enqueue_fn).call(this, async () => {
253
+ const response = await fetch2(url, options);
254
+ if (response.status === 429) {
255
+ const rateLimitReset = parseNumber(response.headers?.get("x-ratelimit-reset")) ?? 1;
256
+ await timeout(rateLimitReset * 1e3);
257
+ return await this.request(url, options, { ...context, stalled: true });
258
+ }
259
+ if (context.stalled) {
260
+ const stalledTime = new Date().getTime() - context.start.getTime();
261
+ console.warn(`A request to Xata hit your workspace limits, was retried and stalled for ${stalledTime}ms`);
262
+ }
263
+ return response;
264
+ });
265
+ }
266
+ }
267
+ _fetch = new WeakMap();
268
+ _queue = new WeakMap();
269
+ _concurrency = new WeakMap();
270
+ _enqueue = new WeakSet();
271
+ enqueue_fn = function(task) {
272
+ const promise = new Promise((resolve) => __privateGet$8(this, _queue).push(resolve)).finally(() => {
273
+ this.started--;
274
+ this.running++;
275
+ }).then(() => task()).finally(() => {
276
+ this.running--;
277
+ const next = __privateGet$8(this, _queue).shift();
278
+ if (next !== void 0) {
279
+ this.started++;
280
+ next();
281
+ }
282
+ });
283
+ if (this.running + this.started < __privateGet$8(this, _concurrency)) {
284
+ const next = __privateGet$8(this, _queue).shift();
285
+ if (next !== void 0) {
286
+ this.started++;
287
+ next();
288
+ }
289
+ }
290
+ return promise;
291
+ };
185
292
 
186
- const VERSION = "0.0.0-alpha.vfd68d20";
293
+ const VERSION = "0.0.0-alpha.vfda8f2e";
187
294
 
188
295
  class ErrorWithCause extends Error {
189
296
  constructor(message, options) {
@@ -226,6 +333,7 @@ function getMessage(data) {
226
333
  }
227
334
  }
228
335
 
336
+ const pool = new ApiRequestPool();
229
337
  const resolveUrl = (url, queryParams = {}, pathParams = {}) => {
230
338
  const cleanQueryParams = Object.entries(queryParams).reduce((acc, [key, value]) => {
231
339
  if (value === void 0 || value === null)
@@ -276,7 +384,8 @@ async function fetch$1({
276
384
  sessionID,
277
385
  fetchOptions = {}
278
386
  }) {
279
- return trace(
387
+ pool.setFetch(fetchImpl);
388
+ return await trace(
280
389
  `${method.toUpperCase()} ${path}`,
281
390
  async ({ setAttributes }) => {
282
391
  const baseUrl = buildBaseUrl({ endpoint, path, workspacesApiUrl, pathParams, apiUrl });
@@ -286,7 +395,7 @@ async function fetch$1({
286
395
  [TraceAttributes.HTTP_URL]: url,
287
396
  [TraceAttributes.HTTP_TARGET]: resolveUrl(path, queryParams, pathParams)
288
397
  });
289
- const response = await fetchImpl(url, {
398
+ const response = await pool.request(url, {
290
399
  ...fetchOptions,
291
400
  method: method.toUpperCase(),
292
401
  body: body ? JSON.stringify(body) : void 0,
@@ -301,9 +410,6 @@ async function fetch$1({
301
410
  },
302
411
  signal
303
412
  });
304
- if (response.status === 204) {
305
- return {};
306
- }
307
413
  const { host, protocol } = parseUrl(response.url);
308
414
  const requestId = response.headers?.get("x-request-id") ?? void 0;
309
415
  setAttributes({
@@ -313,6 +419,12 @@ async function fetch$1({
313
419
  [TraceAttributes.HTTP_HOST]: host,
314
420
  [TraceAttributes.HTTP_SCHEME]: protocol?.replace(":", "")
315
421
  });
422
+ if (response.status === 204) {
423
+ return {};
424
+ }
425
+ if (response.status === 429) {
426
+ throw new FetcherError(response.status, "Rate limit exceeded", requestId);
427
+ }
316
428
  try {
317
429
  const jsonResponse = await response.json();
318
430
  if (response.ok) {
@@ -1366,6 +1478,19 @@ class RecordsApi {
1366
1478
  ...this.extraProps
1367
1479
  });
1368
1480
  }
1481
+ branchTransaction({
1482
+ workspace,
1483
+ region,
1484
+ database,
1485
+ branch,
1486
+ operations
1487
+ }) {
1488
+ return operationsByTag.records.branchTransaction({
1489
+ pathParams: { workspace, region, dbBranchName: `${database}:${branch}` },
1490
+ body: { operations },
1491
+ ...this.extraProps
1492
+ });
1493
+ }
1369
1494
  }
1370
1495
  class SearchAndFilterApi {
1371
1496
  constructor(extraProps) {
@@ -2131,7 +2256,8 @@ var __privateMethod$2 = (obj, member, method) => {
2131
2256
  __accessCheck$4(obj, member, "access private method");
2132
2257
  return method;
2133
2258
  };
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;
2259
+ 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;
2260
+ const BULK_OPERATION_MAX_SIZE = 1e3;
2135
2261
  class Repository extends Query {
2136
2262
  }
2137
2263
  class RestRepository extends Query {
@@ -2143,10 +2269,12 @@ class RestRepository extends Query {
2143
2269
  );
2144
2270
  __privateAdd$4(this, _insertRecordWithoutId);
2145
2271
  __privateAdd$4(this, _insertRecordWithId);
2146
- __privateAdd$4(this, _bulkInsertTableRecords);
2272
+ __privateAdd$4(this, _insertRecords);
2147
2273
  __privateAdd$4(this, _updateRecordWithID);
2274
+ __privateAdd$4(this, _updateRecords);
2148
2275
  __privateAdd$4(this, _upsertRecordWithID);
2149
2276
  __privateAdd$4(this, _deleteRecord);
2277
+ __privateAdd$4(this, _deleteRecords);
2150
2278
  __privateAdd$4(this, _setCacheQuery);
2151
2279
  __privateAdd$4(this, _getCacheQuery);
2152
2280
  __privateAdd$4(this, _getSchemaTables$1);
@@ -2180,20 +2308,22 @@ class RestRepository extends Query {
2180
2308
  if (Array.isArray(a)) {
2181
2309
  if (a.length === 0)
2182
2310
  return [];
2183
- const columns = isStringArray(b) ? b : void 0;
2184
- return __privateMethod$2(this, _bulkInsertTableRecords, bulkInsertTableRecords_fn).call(this, a, columns);
2311
+ const ids = await __privateMethod$2(this, _insertRecords, insertRecords_fn).call(this, a, { ifVersion, createOnly: true });
2312
+ const columns = isStringArray(b) ? b : ["*"];
2313
+ const result = await this.read(ids, columns);
2314
+ return result;
2185
2315
  }
2186
2316
  if (isString(a) && isObject(b)) {
2187
2317
  if (a === "")
2188
2318
  throw new Error("The id can't be empty");
2189
2319
  const columns = isStringArray(c) ? c : void 0;
2190
- return __privateMethod$2(this, _insertRecordWithId, insertRecordWithId_fn).call(this, a, b, columns, { createOnly: true, ifVersion });
2320
+ return await __privateMethod$2(this, _insertRecordWithId, insertRecordWithId_fn).call(this, a, b, columns, { createOnly: true, ifVersion });
2191
2321
  }
2192
2322
  if (isObject(a) && isString(a.id)) {
2193
2323
  if (a.id === "")
2194
2324
  throw new Error("The id can't be empty");
2195
2325
  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 });
2326
+ return await __privateMethod$2(this, _insertRecordWithId, insertRecordWithId_fn).call(this, a.id, { ...a, id: void 0 }, columns, { createOnly: true, ifVersion });
2197
2327
  }
2198
2328
  if (isObject(a)) {
2199
2329
  const columns = isStringArray(b) ? b : void 0;
@@ -2268,11 +2398,15 @@ class RestRepository extends Query {
2268
2398
  if (Array.isArray(a)) {
2269
2399
  if (a.length === 0)
2270
2400
  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
- }
2401
+ const existing = await this.read(a, ["id"]);
2402
+ const updates = a.filter((_item, index) => existing[index] !== null);
2403
+ await __privateMethod$2(this, _updateRecords, updateRecords_fn).call(this, updates, {
2404
+ ifVersion,
2405
+ upsert: false
2406
+ });
2274
2407
  const columns = isStringArray(b) ? b : ["*"];
2275
- return Promise.all(a.map((object) => this.update(object, columns)));
2408
+ const result = await this.read(a, columns);
2409
+ return result;
2276
2410
  }
2277
2411
  if (isString(a) && isObject(b)) {
2278
2412
  const columns = isStringArray(c) ? c : void 0;
@@ -2310,11 +2444,13 @@ class RestRepository extends Query {
2310
2444
  if (Array.isArray(a)) {
2311
2445
  if (a.length === 0)
2312
2446
  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
- }
2447
+ await __privateMethod$2(this, _updateRecords, updateRecords_fn).call(this, a, {
2448
+ ifVersion,
2449
+ upsert: true
2450
+ });
2316
2451
  const columns = isStringArray(b) ? b : ["*"];
2317
- return Promise.all(a.map((object) => this.createOrUpdate(object, columns)));
2452
+ const result = await this.read(a, columns);
2453
+ return result;
2318
2454
  }
2319
2455
  if (isString(a) && isObject(b)) {
2320
2456
  const columns = isStringArray(c) ? c : void 0;
@@ -2333,8 +2469,10 @@ class RestRepository extends Query {
2333
2469
  if (Array.isArray(a)) {
2334
2470
  if (a.length === 0)
2335
2471
  return [];
2472
+ const ids = await __privateMethod$2(this, _insertRecords, insertRecords_fn).call(this, a, { ifVersion, createOnly: false });
2336
2473
  const columns = isStringArray(b) ? b : ["*"];
2337
- return __privateMethod$2(this, _bulkInsertTableRecords, bulkInsertTableRecords_fn).call(this, a, columns);
2474
+ const result = await this.read(ids, columns);
2475
+ return result;
2338
2476
  }
2339
2477
  if (isString(a) && isObject(b)) {
2340
2478
  const columns = isStringArray(c) ? c : void 0;
@@ -2352,10 +2490,17 @@ class RestRepository extends Query {
2352
2490
  if (Array.isArray(a)) {
2353
2491
  if (a.length === 0)
2354
2492
  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)));
2493
+ const ids = a.map((o) => {
2494
+ if (isString(o))
2495
+ return o;
2496
+ if (isString(o.id))
2497
+ return o.id;
2498
+ throw new Error("Invalid arguments for delete method");
2499
+ });
2500
+ const columns = isStringArray(b) ? b : ["*"];
2501
+ const result = await this.read(a, columns);
2502
+ await __privateMethod$2(this, _deleteRecords, deleteRecords_fn).call(this, ids);
2503
+ return result;
2359
2504
  }
2360
2505
  if (isString(a)) {
2361
2506
  return __privateMethod$2(this, _deleteRecord, deleteRecord_fn).call(this, a, b);
@@ -2523,31 +2668,40 @@ insertRecordWithId_fn = async function(recordId, object, columns = ["*"], { crea
2523
2668
  const schemaTables = await __privateMethod$2(this, _getSchemaTables$1, getSchemaTables_fn$1).call(this);
2524
2669
  return initObject(__privateGet$4(this, _db), schemaTables, __privateGet$4(this, _table), response, columns);
2525
2670
  };
2526
- _bulkInsertTableRecords = new WeakSet();
2527
- bulkInsertTableRecords_fn = async function(objects, columns = ["*"]) {
2671
+ _insertRecords = new WeakSet();
2672
+ insertRecords_fn = async function(objects, { createOnly, ifVersion }) {
2528
2673
  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");
2674
+ const chunkedOperations = chunk(
2675
+ objects.map((object) => ({
2676
+ insert: { table: __privateGet$4(this, _table), record: transformObjectLinks(object), createOnly, ifVersion }
2677
+ })),
2678
+ BULK_OPERATION_MAX_SIZE
2679
+ );
2680
+ const ids = [];
2681
+ for (const operations of chunkedOperations) {
2682
+ const { results } = await branchTransaction({
2683
+ pathParams: {
2684
+ workspace: "{workspaceId}",
2685
+ dbBranchName: "{dbBranch}",
2686
+ region: "{region}"
2687
+ },
2688
+ body: { operations },
2689
+ ...fetchProps
2690
+ });
2691
+ for (const result of results) {
2692
+ if (result.operation === "insert") {
2693
+ ids.push(result.id);
2694
+ } else {
2695
+ ids.push(null);
2696
+ }
2697
+ }
2543
2698
  }
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));
2699
+ return ids;
2546
2700
  };
2547
2701
  _updateRecordWithID = new WeakSet();
2548
2702
  updateRecordWithID_fn = async function(recordId, object, columns = ["*"], { ifVersion }) {
2549
2703
  const fetchProps = await __privateGet$4(this, _getFetchProps).call(this);
2550
- const record = transformObjectLinks(object);
2704
+ const { id: _id, ...record } = transformObjectLinks(object);
2551
2705
  try {
2552
2706
  const response = await updateRecordWithID({
2553
2707
  pathParams: {
@@ -2570,6 +2724,36 @@ updateRecordWithID_fn = async function(recordId, object, columns = ["*"], { ifVe
2570
2724
  throw e;
2571
2725
  }
2572
2726
  };
2727
+ _updateRecords = new WeakSet();
2728
+ updateRecords_fn = async function(objects, { ifVersion, upsert }) {
2729
+ const fetchProps = await __privateGet$4(this, _getFetchProps).call(this);
2730
+ const chunkedOperations = chunk(
2731
+ objects.map(({ id, ...object }) => ({
2732
+ update: { table: __privateGet$4(this, _table), id, ifVersion, upsert, fields: transformObjectLinks(object) }
2733
+ })),
2734
+ BULK_OPERATION_MAX_SIZE
2735
+ );
2736
+ const ids = [];
2737
+ for (const operations of chunkedOperations) {
2738
+ const { results } = await branchTransaction({
2739
+ pathParams: {
2740
+ workspace: "{workspaceId}",
2741
+ dbBranchName: "{dbBranch}",
2742
+ region: "{region}"
2743
+ },
2744
+ body: { operations },
2745
+ ...fetchProps
2746
+ });
2747
+ for (const result of results) {
2748
+ if (result.operation === "update") {
2749
+ ids.push(result.id);
2750
+ } else {
2751
+ ids.push(null);
2752
+ }
2753
+ }
2754
+ }
2755
+ return ids;
2756
+ };
2573
2757
  _upsertRecordWithID = new WeakSet();
2574
2758
  upsertRecordWithID_fn = async function(recordId, object, columns = ["*"], { ifVersion }) {
2575
2759
  const fetchProps = await __privateGet$4(this, _getFetchProps).call(this);
@@ -2612,6 +2796,25 @@ deleteRecord_fn = async function(recordId, columns = ["*"]) {
2612
2796
  throw e;
2613
2797
  }
2614
2798
  };
2799
+ _deleteRecords = new WeakSet();
2800
+ deleteRecords_fn = async function(recordIds) {
2801
+ const fetchProps = await __privateGet$4(this, _getFetchProps).call(this);
2802
+ const chunkedOperations = chunk(
2803
+ recordIds.map((id) => ({ delete: { table: __privateGet$4(this, _table), id } })),
2804
+ BULK_OPERATION_MAX_SIZE
2805
+ );
2806
+ for (const operations of chunkedOperations) {
2807
+ await branchTransaction({
2808
+ pathParams: {
2809
+ workspace: "{workspaceId}",
2810
+ dbBranchName: "{dbBranch}",
2811
+ region: "{region}"
2812
+ },
2813
+ body: { operations },
2814
+ ...fetchProps
2815
+ });
2816
+ }
2817
+ };
2615
2818
  _setCacheQuery = new WeakSet();
2616
2819
  setCacheQuery_fn = async function(query, meta, records) {
2617
2820
  await __privateGet$4(this, _cache).set(`query_${__privateGet$4(this, _table)}:${query.key()}`, { date: new Date(), meta, records });
@@ -2722,9 +2925,6 @@ const initObject = (db, schemaTables, table, object, selectedColumns) => {
2722
2925
  Object.freeze(result);
2723
2926
  return result;
2724
2927
  };
2725
- function isResponseWithRecords(value) {
2726
- return isObject(value) && Array.isArray(value.records);
2727
- }
2728
2928
  function extractId(value) {
2729
2929
  if (isString(value))
2730
2930
  return value;