@boltic/sdk 0.0.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.
@@ -0,0 +1,4053 @@
1
+ class ValidationError extends Error {
2
+ constructor(message, failures = []) {
3
+ super(message);
4
+ this.name = "ValidationError";
5
+ this.failures = failures;
6
+ }
7
+ }
8
+ class ApiError extends Error {
9
+ constructor(message, statusCode, response) {
10
+ super(message);
11
+ this.name = "ApiError";
12
+ this.statusCode = statusCode;
13
+ this.response = response;
14
+ }
15
+ }
16
+ function createErrorWithContext(message, context) {
17
+ const error = new Error(message);
18
+ if (context) {
19
+ error.context = context;
20
+ }
21
+ return error;
22
+ }
23
+ function isNetworkError(error) {
24
+ return error instanceof Error && (error.message.includes("network") || error.message.includes("fetch") || error.message.includes("timeout") || error.name === "AbortError");
25
+ }
26
+ function getHttpStatusCode(error) {
27
+ if (error && typeof error === "object") {
28
+ if ("response" in error && error.response && typeof error.response === "object") {
29
+ const response = error.response;
30
+ if ("status" in response && typeof response.status === "number") {
31
+ return response.status;
32
+ }
33
+ }
34
+ if ("status" in error && typeof error.status === "number") {
35
+ return error.status;
36
+ }
37
+ }
38
+ return null;
39
+ }
40
+ function formatError(error) {
41
+ if (error instanceof Error) {
42
+ const context = error.context;
43
+ const statusCode = getHttpStatusCode(error);
44
+ let formatted = `${error.name}: ${error.message}`;
45
+ if (statusCode) {
46
+ formatted += ` (HTTP ${statusCode})`;
47
+ }
48
+ if (context) {
49
+ formatted += `
50
+ Context: ${JSON.stringify(context, null, 2)}`;
51
+ }
52
+ return formatted;
53
+ }
54
+ return String(error);
55
+ }
56
+ class AuthManager {
57
+ constructor(config) {
58
+ this.tokenInfo = null;
59
+ this.config = {
60
+ maxRetries: 3,
61
+ ...config
62
+ };
63
+ this.validateApiKey(config.apiKey);
64
+ }
65
+ validateApiKey(apiKey) {
66
+ if (!apiKey || typeof apiKey !== "string" || apiKey.trim().length === 0) {
67
+ throw createErrorWithContext(
68
+ "API key is required and must be a non-empty string",
69
+ {
70
+ name: "AuthenticationError",
71
+ code: "INVALID_API_KEY"
72
+ }
73
+ );
74
+ }
75
+ if (apiKey.length < 10) {
76
+ throw createErrorWithContext(
77
+ "API key appears to be invalid (too short)",
78
+ {
79
+ name: "AuthenticationError",
80
+ code: "INVALID_API_KEY_FORMAT"
81
+ }
82
+ );
83
+ }
84
+ }
85
+ getAuthHeaders() {
86
+ return {
87
+ "x-boltic-token": this.config.apiKey
88
+ };
89
+ }
90
+ updateApiKey(newApiKey) {
91
+ this.validateApiKey(newApiKey);
92
+ this.config.apiKey = newApiKey;
93
+ this.tokenInfo = null;
94
+ }
95
+ isAuthenticated() {
96
+ return !!this.config.apiKey;
97
+ }
98
+ async validateApiKeyAsync() {
99
+ try {
100
+ this.validateApiKey(this.config.apiKey);
101
+ return true;
102
+ } catch {
103
+ return false;
104
+ }
105
+ }
106
+ getTokenInfo() {
107
+ return this.tokenInfo ? { ...this.tokenInfo } : null;
108
+ }
109
+ getMaxRetries() {
110
+ return this.config.maxRetries || 3;
111
+ }
112
+ }
113
+ class AxiosAdapter {
114
+ constructor() {
115
+ try {
116
+ this.axios = require("axios");
117
+ } catch (error) {
118
+ throw createErrorWithContext(
119
+ "Axios is required for Node.js < 18. Please install axios: npm install axios",
120
+ { error }
121
+ );
122
+ }
123
+ }
124
+ async request(config) {
125
+ var _a;
126
+ try {
127
+ const axiosConfig = {
128
+ url: config.url,
129
+ method: config.method.toLowerCase(),
130
+ headers: config.headers,
131
+ params: config.params,
132
+ data: config.data,
133
+ timeout: config.timeout,
134
+ signal: config.signal,
135
+ validateStatus: () => true
136
+ // Don't throw on non-2xx status codes
137
+ };
138
+ const response = await this.axios(axiosConfig);
139
+ return {
140
+ data: response.data,
141
+ status: response.status,
142
+ statusText: response.statusText,
143
+ headers: response.headers || {}
144
+ };
145
+ } catch (error) {
146
+ const axiosError = error;
147
+ if (axiosError.code === "ECONNABORTED" || ((_a = axiosError.message) == null ? void 0 : _a.includes("timeout"))) {
148
+ throw createErrorWithContext("Request timeout", {
149
+ url: config.url,
150
+ method: config.method,
151
+ timeout: config.timeout
152
+ });
153
+ }
154
+ if (axiosError.name === "AbortError" || axiosError.code === "ERR_CANCELED") {
155
+ throw createErrorWithContext("Request was aborted", {
156
+ url: config.url,
157
+ method: config.method
158
+ });
159
+ }
160
+ throw createErrorWithContext(
161
+ `HTTP request failed: ${axiosError.message || "Unknown error"}`,
162
+ {
163
+ url: config.url,
164
+ method: config.method,
165
+ originalError: error
166
+ }
167
+ );
168
+ }
169
+ }
170
+ }
171
+ class FetchAdapter {
172
+ async request(config) {
173
+ const url = new URL(config.url);
174
+ if (config.params) {
175
+ Object.entries(config.params).forEach(([key, value]) => {
176
+ if (value !== void 0 && value !== null) {
177
+ url.searchParams.append(key, String(value));
178
+ }
179
+ });
180
+ }
181
+ const init = {
182
+ method: config.method,
183
+ headers: {
184
+ "Content-Type": "application/json",
185
+ ...config.headers
186
+ },
187
+ signal: config.signal
188
+ };
189
+ if (config.data && ["POST", "PUT", "PATCH", "DELETE"].includes(config.method)) {
190
+ init.body = JSON.stringify(config.data);
191
+ }
192
+ try {
193
+ const controller = new AbortController();
194
+ let timeoutId;
195
+ if (config.timeout) {
196
+ timeoutId = setTimeout(() => controller.abort(), config.timeout);
197
+ init.signal = config.signal ? (() => {
198
+ const combinedController = new AbortController();
199
+ config.signal.addEventListener(
200
+ "abort",
201
+ () => combinedController.abort()
202
+ );
203
+ controller.signal.addEventListener(
204
+ "abort",
205
+ () => combinedController.abort()
206
+ );
207
+ return combinedController.signal;
208
+ })() : controller.signal;
209
+ }
210
+ const response = await fetch(url.toString(), init);
211
+ if (timeoutId) {
212
+ clearTimeout(timeoutId);
213
+ }
214
+ const contentType = response.headers.get("content-type");
215
+ let data;
216
+ if (contentType == null ? void 0 : contentType.includes("application/json")) {
217
+ data = await response.json();
218
+ } else {
219
+ data = await response.text();
220
+ }
221
+ const headers = {};
222
+ response.headers.forEach((value, key) => {
223
+ headers[key] = value;
224
+ });
225
+ const httpResponse = {
226
+ data,
227
+ status: response.status,
228
+ statusText: response.statusText,
229
+ headers
230
+ };
231
+ return httpResponse;
232
+ } catch (error) {
233
+ if (error instanceof Error && error.name === "AbortError") {
234
+ throw createErrorWithContext("Request was aborted", {
235
+ type: "AbortError",
236
+ url: config.url,
237
+ method: config.method
238
+ });
239
+ }
240
+ throw createErrorWithContext(
241
+ `HTTP request failed: ${error instanceof Error ? error.message : "Unknown error"}`,
242
+ {
243
+ url: config.url,
244
+ method: config.method,
245
+ originalError: error
246
+ }
247
+ );
248
+ }
249
+ }
250
+ }
251
+ function createHttpAdapter() {
252
+ if (typeof fetch !== "undefined") {
253
+ return new FetchAdapter();
254
+ }
255
+ try {
256
+ return new AxiosAdapter();
257
+ } catch (error) {
258
+ throw createErrorWithContext(
259
+ "No suitable HTTP adapter found. Please use Node.js >= 18 or install axios: npm install axios",
260
+ { error }
261
+ );
262
+ }
263
+ }
264
+ class InterceptorManagerImpl {
265
+ constructor() {
266
+ this.requestInterceptors = /* @__PURE__ */ new Map();
267
+ this.responseInterceptors = /* @__PURE__ */ new Map();
268
+ this.nextId = 0;
269
+ this.request = {
270
+ use: (interceptor) => {
271
+ const id = this.nextId++;
272
+ this.requestInterceptors.set(id, interceptor);
273
+ return id;
274
+ },
275
+ eject: (id) => {
276
+ this.requestInterceptors.delete(id);
277
+ }
278
+ };
279
+ this.response = {
280
+ use: (onFulfilled, onRejected) => {
281
+ const id = this.nextId++;
282
+ this.responseInterceptors.set(id, {
283
+ fulfilled: onFulfilled,
284
+ rejected: onRejected
285
+ });
286
+ return id;
287
+ },
288
+ eject: (id) => {
289
+ this.responseInterceptors.delete(id);
290
+ }
291
+ };
292
+ }
293
+ async executeRequestInterceptors(config) {
294
+ let result = config;
295
+ for (const interceptor of this.requestInterceptors.values()) {
296
+ result = await interceptor(result);
297
+ }
298
+ return result;
299
+ }
300
+ async executeResponseInterceptors(response) {
301
+ let result = response;
302
+ for (const { fulfilled } of this.responseInterceptors.values()) {
303
+ if (fulfilled) {
304
+ result = await fulfilled(result);
305
+ }
306
+ }
307
+ return result;
308
+ }
309
+ async executeErrorInterceptors(error) {
310
+ let result = error;
311
+ for (const { rejected } of this.responseInterceptors.values()) {
312
+ if (rejected) {
313
+ result = await rejected(result);
314
+ }
315
+ }
316
+ return result;
317
+ }
318
+ }
319
+ class BaseClient {
320
+ constructor(config, authManager) {
321
+ this.config = config;
322
+ this.authManager = authManager;
323
+ this.httpAdapter = createHttpAdapter();
324
+ this.interceptors = new InterceptorManagerImpl();
325
+ this.setupDefaultInterceptors();
326
+ }
327
+ setupDefaultInterceptors() {
328
+ this.interceptors.request.use((config) => {
329
+ const authHeaders = this.authManager.getAuthHeaders();
330
+ config.headers = {
331
+ ...config.headers,
332
+ ...authHeaders,
333
+ ...this.config.headers
334
+ };
335
+ return config;
336
+ });
337
+ this.interceptors.response.use(
338
+ (response) => {
339
+ if (this.config.debug) {
340
+ console.log("HTTP Response:", response);
341
+ }
342
+ return response;
343
+ },
344
+ (error) => {
345
+ return this.handleError(error);
346
+ }
347
+ );
348
+ }
349
+ handleError(error) {
350
+ var _a;
351
+ if (this.config.debug) {
352
+ console.error("HTTP Error:", error);
353
+ }
354
+ if (error instanceof Error && error.context) {
355
+ throw error;
356
+ }
357
+ const statusCode = getHttpStatusCode(error);
358
+ if (!statusCode) {
359
+ throw createErrorWithContext("Network request failed", {
360
+ name: "NetworkError",
361
+ originalError: error
362
+ });
363
+ }
364
+ const errorData = ((_a = error.response) == null ? void 0 : _a.data) || error.data;
365
+ const message = (errorData == null ? void 0 : errorData.message) || (errorData == null ? void 0 : errorData.error) || `HTTP ${statusCode} error`;
366
+ throw createErrorWithContext(message, {
367
+ name: "ApiError",
368
+ statusCode,
369
+ response: errorData,
370
+ isClientError: statusCode >= 400 && statusCode < 500,
371
+ isServerError: statusCode >= 500,
372
+ isAuthError: statusCode === 401 || statusCode === 403,
373
+ isNotFoundError: statusCode === 404,
374
+ isRateLimitError: statusCode === 429
375
+ });
376
+ }
377
+ async request(config) {
378
+ let lastError;
379
+ const maxRetries = this.config.maxRetries;
380
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
381
+ try {
382
+ if (!config.url.startsWith("http")) {
383
+ config.url = `${this.config.baseURL}${config.url}`;
384
+ }
385
+ if (!config.timeout) {
386
+ config.timeout = this.config.timeout;
387
+ }
388
+ const requestConfig = await this.interceptors.executeRequestInterceptors(config);
389
+ const response = await this.httpAdapter.request(requestConfig);
390
+ if (response.status >= 400) {
391
+ const error = createErrorWithContext(
392
+ `HTTP ${response.status} error`,
393
+ {
394
+ name: "ApiError",
395
+ statusCode: response.status,
396
+ response: response.data,
397
+ statusText: response.statusText
398
+ }
399
+ );
400
+ throw await this.interceptors.executeErrorInterceptors(error);
401
+ }
402
+ return await this.interceptors.executeResponseInterceptors(
403
+ response
404
+ );
405
+ } catch (error) {
406
+ lastError = error;
407
+ if (attempt === maxRetries) {
408
+ break;
409
+ }
410
+ const statusCode = getHttpStatusCode(error);
411
+ if (statusCode && statusCode >= 400 && statusCode < 500) {
412
+ break;
413
+ }
414
+ if (attempt < maxRetries) {
415
+ const delay = this.config.retryDelay * Math.pow(2, attempt);
416
+ await new Promise((resolve) => setTimeout(resolve, delay));
417
+ }
418
+ }
419
+ }
420
+ throw await this.interceptors.executeErrorInterceptors(lastError);
421
+ }
422
+ get(url, config) {
423
+ return this.request({ ...config, method: "GET", url });
424
+ }
425
+ post(url, data, config) {
426
+ return this.request({ ...config, method: "POST", url, data });
427
+ }
428
+ put(url, data, config) {
429
+ return this.request({ ...config, method: "PUT", url, data });
430
+ }
431
+ patch(url, data, config) {
432
+ return this.request({ ...config, method: "PATCH", url, data });
433
+ }
434
+ delete(url, config) {
435
+ return this.request({ ...config, method: "DELETE", url });
436
+ }
437
+ getInterceptors() {
438
+ return this.interceptors;
439
+ }
440
+ updateConfig(updates) {
441
+ this.config = { ...this.config, ...updates };
442
+ }
443
+ getConfig() {
444
+ return { ...this.config };
445
+ }
446
+ }
447
+ const REGION_CONFIGS = {
448
+ "asia-south1": {
449
+ local: {
450
+ baseURL: "http://localhost:8000",
451
+ timeout: 3e4,
452
+ debug: true
453
+ },
454
+ sit: {
455
+ baseURL: "https://asia-south1.api.fcz0.de/service/sdk/boltic-tables",
456
+ timeout: 15e3
457
+ },
458
+ uat: {
459
+ baseURL: "https://asia-south1.api.uat.fcz0.de/service/sdk/boltic-tables",
460
+ timeout: 15e3
461
+ },
462
+ prod: {
463
+ baseURL: "https://asia-south1.api.boltic.io/service/sdk/boltic-tables",
464
+ timeout: 1e4
465
+ }
466
+ },
467
+ "us-central1": {
468
+ local: {
469
+ baseURL: "http://localhost:8000",
470
+ timeout: 3e4,
471
+ debug: true
472
+ },
473
+ sit: {
474
+ baseURL: "https://us-central1.api.fcz0.de/service/sdk/boltic-tables",
475
+ timeout: 15e3
476
+ },
477
+ uat: {
478
+ baseURL: "https://us-central1.api.uat.fcz0.de/service/sdk/boltic-tables",
479
+ timeout: 15e3
480
+ },
481
+ prod: {
482
+ baseURL: "https://us-central1.api.boltic.io/service/sdk/boltic-tables",
483
+ timeout: 1e4
484
+ }
485
+ }
486
+ };
487
+ const ENV_CONFIGS = REGION_CONFIGS["asia-south1"];
488
+ class ConfigManager {
489
+ constructor(apiKey, environment = "prod", region = "asia-south1", overrides) {
490
+ const envConfig = REGION_CONFIGS[region][environment];
491
+ this.config = {
492
+ apiKey,
493
+ environment,
494
+ region,
495
+ retryAttempts: 3,
496
+ retryDelay: 1e3,
497
+ maxRetries: 3,
498
+ debug: false,
499
+ headers: {},
500
+ ...envConfig,
501
+ ...overrides
502
+ };
503
+ }
504
+ getConfig() {
505
+ return { ...this.config };
506
+ }
507
+ updateConfig(updates) {
508
+ this.config = { ...this.config, ...updates };
509
+ }
510
+ }
511
+ function filterObjectFields(obj, fields) {
512
+ if (!fields || fields.length === 0) {
513
+ return obj;
514
+ }
515
+ const filtered = {};
516
+ for (const field of fields) {
517
+ if (field in obj) {
518
+ filtered[field] = obj[field];
519
+ }
520
+ }
521
+ return filtered;
522
+ }
523
+ function filterArrayFields(arr, fields) {
524
+ if (!fields || fields.length === 0) {
525
+ return arr;
526
+ }
527
+ return arr.map((obj) => filterObjectFields(obj, fields));
528
+ }
529
+ const COLUMN_ENDPOINTS = {
530
+ list: {
531
+ path: "/tables/{table_id}/fields/list",
532
+ method: "POST",
533
+ authenticated: true,
534
+ rateLimit: { requests: 200, window: 6e4 }
535
+ },
536
+ create: {
537
+ path: "/tables/{table_id}/fields",
538
+ method: "POST",
539
+ authenticated: true
540
+ },
541
+ get: {
542
+ path: "/tables/{table_id}/fields/{field_id}",
543
+ method: "GET",
544
+ authenticated: true,
545
+ rateLimit: { requests: 300, window: 6e4 }
546
+ },
547
+ update: {
548
+ path: "/tables/{table_id}/fields/{field_id}",
549
+ method: "PATCH",
550
+ authenticated: true
551
+ },
552
+ delete: {
553
+ path: "/tables/{table_id}/fields/{field_id}",
554
+ method: "DELETE",
555
+ authenticated: true
556
+ }
557
+ };
558
+ const buildEndpointPath$1 = (endpoint, params = {}) => {
559
+ let path = endpoint.path;
560
+ Object.entries(params).forEach(([key, value]) => {
561
+ path = path.replace(`{${key}}`, encodeURIComponent(value));
562
+ });
563
+ const unreplacedParams = path.match(/\{([^}]+)\}/g);
564
+ if (unreplacedParams) {
565
+ throw new Error(`Missing path parameters: ${unreplacedParams.join(", ")}`);
566
+ }
567
+ return path;
568
+ };
569
+ const DateFormatEnum = Object.freeze({
570
+ MMDDYY: "%m/%d/%y",
571
+ MMDDYYYY: "%m/%d/%Y",
572
+ MM_DD_YYYY: "%m-%d-%Y",
573
+ DD_MM_YYYY: "%d-%m-%Y",
574
+ DDMMYYYY: "%d/%m/%Y",
575
+ DDMMYY: "%d/%m/%y",
576
+ YYYY_MM_DD: "%Y-%m-%d",
577
+ MMMM__DD__YYYY: "%B %d %Y",
578
+ MMM__DD__YYYY: "%b %d %Y",
579
+ ddd__MMM__DD__YYYY: "%a %b %d %Y"
580
+ });
581
+ const TimeFormatEnum = Object.freeze({
582
+ HH_mm_ss: "%H:%M:%S",
583
+ HH_mm_ssZ: "%H:%M:%SZ",
584
+ HH_mm_ss_SSS: "%H:%M:%S.%f",
585
+ HH_mm_ss__Z: "%H:%M:%S %Z",
586
+ HH_mm__AMPM: "%I:%M %p",
587
+ // 12-hour format with AM/PM
588
+ HH_mm_ss__AMPM: "%I:%M:%S %p"
589
+ });
590
+ function transformColumnCreateRequest(request) {
591
+ if (!request || typeof request !== "object") {
592
+ throw new Error("Invalid request: single column data is required");
593
+ }
594
+ if (!request.name || !request.type) {
595
+ throw new Error("Column name and type are required");
596
+ }
597
+ return transformFieldDefinition$1(request);
598
+ }
599
+ function transformFieldDefinition$1(field) {
600
+ return {
601
+ name: field.name,
602
+ type: field.type,
603
+ is_nullable: field.is_nullable ?? true,
604
+ is_primary_key: field.is_primary_key ?? false,
605
+ is_unique: field.is_unique ?? false,
606
+ is_visible: field.is_visible ?? true,
607
+ is_readonly: field.is_readonly ?? false,
608
+ is_indexed: field.is_indexed ?? false,
609
+ field_order: field.field_order ?? 1,
610
+ alignment: field.alignment ?? "left",
611
+ timezone: field.timezone ?? void 0,
612
+ date_format: field.date_format ? transformDateFormat(field.date_format) : void 0,
613
+ time_format: field.time_format ? transformTimeFormat(field.time_format) : void 0,
614
+ decimals: field.decimals ?? void 0,
615
+ currency_format: field.currency_format ?? void 0,
616
+ selection_source: field.type === "dropdown" && !field.selection_source ? "provide-static-list" : field.selection_source ?? void 0,
617
+ selectable_items: field.selectable_items ?? void 0,
618
+ multiple_selections: field.multiple_selections ?? void 0,
619
+ phone_format: field.phone_format ?? void 0,
620
+ vector_dimension: field.vector_dimension ?? void 0,
621
+ description: field.description ?? void 0,
622
+ default_value: field.default_value ?? void 0
623
+ };
624
+ }
625
+ function transformColumnUpdateRequest(updates) {
626
+ const apiRequest = {};
627
+ if (updates.name !== void 0) apiRequest.name = updates.name;
628
+ if (updates.type !== void 0) apiRequest.type = updates.type;
629
+ if (updates.description !== void 0)
630
+ apiRequest.description = updates.description;
631
+ if (updates.is_nullable !== void 0)
632
+ apiRequest.is_nullable = updates.is_nullable;
633
+ if (updates.is_unique !== void 0) apiRequest.is_unique = updates.is_unique;
634
+ if (updates.is_primary_key !== void 0)
635
+ apiRequest.is_primary_key = updates.is_primary_key;
636
+ if (updates.is_indexed !== void 0)
637
+ apiRequest.is_indexed = updates.is_indexed;
638
+ if (updates.is_visible !== void 0)
639
+ apiRequest.is_visible = updates.is_visible;
640
+ if (updates.is_readonly !== void 0)
641
+ apiRequest.is_readonly = updates.is_readonly;
642
+ if (updates.default_value !== void 0)
643
+ apiRequest.default_value = updates.default_value;
644
+ if (updates.field_order !== void 0)
645
+ apiRequest.field_order = updates.field_order;
646
+ if (updates.alignment !== void 0) apiRequest.alignment = updates.alignment;
647
+ if (updates.decimals !== void 0) apiRequest.decimals = updates.decimals;
648
+ if (updates.currency_format !== void 0)
649
+ apiRequest.currency_format = updates.currency_format;
650
+ if (updates.type === "dropdown") {
651
+ apiRequest.selection_source = "provide-static-list";
652
+ } else if (updates.selectable_items !== void 0) {
653
+ apiRequest.selection_source = "provide-static-list";
654
+ } else if (updates.selection_source !== void 0) {
655
+ apiRequest.selection_source = updates.selection_source;
656
+ }
657
+ if (updates.selectable_items !== void 0)
658
+ apiRequest.selectable_items = updates.selectable_items;
659
+ if (updates.multiple_selections !== void 0)
660
+ apiRequest.multiple_selections = updates.multiple_selections;
661
+ if (updates.phone_format !== void 0)
662
+ apiRequest.phone_format = updates.phone_format;
663
+ if (updates.timezone !== void 0) apiRequest.timezone = updates.timezone;
664
+ if (updates.vector_dimension !== void 0)
665
+ apiRequest.vector_dimension = updates.vector_dimension;
666
+ if (updates.date_format !== void 0) {
667
+ apiRequest.date_format = transformDateFormat(updates.date_format);
668
+ }
669
+ if (updates.time_format !== void 0) {
670
+ apiRequest.time_format = transformTimeFormat(updates.time_format);
671
+ }
672
+ return apiRequest;
673
+ }
674
+ function transformDateFormat(dateFormat) {
675
+ return DateFormatEnum[dateFormat] || dateFormat;
676
+ }
677
+ function transformTimeFormat(timeFormat) {
678
+ return TimeFormatEnum[timeFormat] || timeFormat;
679
+ }
680
+ class ColumnsApiClient {
681
+ constructor(apiKey, config = {}) {
682
+ this.config = { apiKey, ...config };
683
+ this.httpAdapter = createHttpAdapter();
684
+ const environment = config.environment || "prod";
685
+ const region = config.region || "asia-south1";
686
+ this.baseURL = this.getBaseURL(environment, region);
687
+ }
688
+ getBaseURL(environment, region) {
689
+ const regionConfig = REGION_CONFIGS[region];
690
+ if (!regionConfig) {
691
+ throw new Error(`Unsupported region: ${region}`);
692
+ }
693
+ const envConfig = regionConfig[environment];
694
+ if (!envConfig) {
695
+ throw new Error(
696
+ `Unsupported environment: ${environment} for region: ${region}`
697
+ );
698
+ }
699
+ return `${envConfig.baseURL}/v1`;
700
+ }
701
+ /**
702
+ * Create a single column in a table
703
+ */
704
+ async createColumn(tableId, request) {
705
+ try {
706
+ const endpoint = COLUMN_ENDPOINTS.create;
707
+ const url = `${this.baseURL}${buildEndpointPath$1(endpoint, { table_id: tableId })}`;
708
+ const transformedRequest = transformColumnCreateRequest(request);
709
+ const response = await this.httpAdapter.request({
710
+ url,
711
+ method: endpoint.method,
712
+ headers: this.buildHeaders(),
713
+ data: transformedRequest,
714
+ timeout: this.config.timeout
715
+ });
716
+ if (this.config.debug) {
717
+ console.log(
718
+ "Column API Response:",
719
+ JSON.stringify(response.data, null, 2)
720
+ );
721
+ }
722
+ return response.data;
723
+ } catch (error) {
724
+ return this.formatErrorResponse(error);
725
+ }
726
+ }
727
+ /**
728
+ * Create multiple columns in a table (one by one)
729
+ */
730
+ async createColumns(tableId, request) {
731
+ try {
732
+ const columns = request.columns;
733
+ const createdColumns = [];
734
+ for (const column of columns) {
735
+ const result = await this.createColumn(tableId, column);
736
+ if ("error" in result) {
737
+ return result;
738
+ }
739
+ createdColumns.push(result.data);
740
+ }
741
+ if (request.fields && createdColumns.length > 0) {
742
+ const filteredColumns = filterArrayFields(
743
+ createdColumns,
744
+ request.fields
745
+ );
746
+ createdColumns.splice(0, createdColumns.length, ...filteredColumns);
747
+ }
748
+ return {
749
+ data: createdColumns,
750
+ message: "Columns created successfully"
751
+ };
752
+ } catch (error) {
753
+ return this.formatErrorResponse(error);
754
+ }
755
+ }
756
+ /**
757
+ * List columns in a table with filtering and pagination
758
+ */
759
+ async listColumns(tableId, options = {}) {
760
+ try {
761
+ const endpoint = COLUMN_ENDPOINTS.list;
762
+ const url = `${this.baseURL}${buildEndpointPath$1(endpoint, { table_id: tableId })}?no_cache=true`;
763
+ const response = await this.httpAdapter.request({
764
+ url,
765
+ method: endpoint.method,
766
+ headers: this.buildHeaders(),
767
+ data: options,
768
+ timeout: this.config.timeout
769
+ });
770
+ const responseData = response.data;
771
+ if (options.fields && responseData.data) {
772
+ responseData.data = filterArrayFields(
773
+ responseData.data,
774
+ options.fields
775
+ );
776
+ }
777
+ return responseData;
778
+ } catch (error) {
779
+ return this.formatErrorResponse(error);
780
+ }
781
+ }
782
+ /**
783
+ * Get a single column by ID
784
+ */
785
+ async getColumn(tableId, columnId, options = {}) {
786
+ try {
787
+ const endpoint = COLUMN_ENDPOINTS.get;
788
+ const url = `${this.baseURL}${buildEndpointPath$1(endpoint, {
789
+ table_id: tableId,
790
+ field_id: columnId
791
+ })}`;
792
+ const response = await this.httpAdapter.request({
793
+ url,
794
+ method: endpoint.method,
795
+ headers: this.buildHeaders(),
796
+ timeout: this.config.timeout
797
+ });
798
+ if (this.config.debug) {
799
+ console.log(
800
+ "Column API Response:",
801
+ JSON.stringify(response.data, null, 2)
802
+ );
803
+ }
804
+ const responseData = response.data;
805
+ if (options.fields && responseData.data) {
806
+ responseData.data = filterObjectFields(
807
+ responseData.data,
808
+ options.fields
809
+ );
810
+ }
811
+ return responseData;
812
+ } catch (error) {
813
+ return this.formatErrorResponse(error);
814
+ }
815
+ }
816
+ /**
817
+ * Update a column
818
+ */
819
+ async updateColumn(tableId, columnId, updates) {
820
+ try {
821
+ const endpoint = COLUMN_ENDPOINTS.update;
822
+ const url = `${this.baseURL}${buildEndpointPath$1(endpoint, {
823
+ table_id: tableId,
824
+ field_id: columnId
825
+ })}`;
826
+ const transformedUpdates = transformColumnUpdateRequest(updates);
827
+ const response = await this.httpAdapter.request({
828
+ url,
829
+ method: endpoint.method,
830
+ headers: this.buildHeaders(),
831
+ data: transformedUpdates,
832
+ timeout: this.config.timeout
833
+ });
834
+ const responseData = response.data;
835
+ if (updates.fields && responseData.data) {
836
+ responseData.data = filterObjectFields(
837
+ responseData.data,
838
+ updates.fields
839
+ );
840
+ }
841
+ return responseData;
842
+ } catch (error) {
843
+ return this.formatErrorResponse(error);
844
+ }
845
+ }
846
+ /**
847
+ * Delete a column
848
+ */
849
+ async deleteColumn(tableId, columnId) {
850
+ try {
851
+ const endpoint = COLUMN_ENDPOINTS.delete;
852
+ const url = `${this.baseURL}${buildEndpointPath$1(endpoint, {
853
+ table_id: tableId,
854
+ field_id: columnId
855
+ })}`;
856
+ const response = await this.httpAdapter.request({
857
+ url,
858
+ method: endpoint.method,
859
+ headers: this.buildHeaders(),
860
+ timeout: this.config.timeout
861
+ });
862
+ return response.data;
863
+ } catch (error) {
864
+ return this.formatErrorResponse(error);
865
+ }
866
+ }
867
+ /**
868
+ * Find column by name in a table
869
+ */
870
+ async findColumnByName(tableId, columnName) {
871
+ try {
872
+ const apiRequest = {
873
+ page: { page_no: 1, page_size: 1 },
874
+ filters: [
875
+ {
876
+ field: "name",
877
+ operator: "=",
878
+ values: [columnName]
879
+ }
880
+ ],
881
+ sort: []
882
+ };
883
+ const listResult = await this.listColumns(
884
+ tableId,
885
+ apiRequest
886
+ );
887
+ if ("error" in listResult) {
888
+ return listResult;
889
+ }
890
+ const column = listResult.data[0] || null;
891
+ return {
892
+ data: column,
893
+ message: column ? "Column found" : "Column not found"
894
+ };
895
+ } catch (error) {
896
+ return this.formatErrorResponse(error);
897
+ }
898
+ }
899
+ /**
900
+ * Helper function to convert ColumnDetails to ColumnUpdateRequest format
901
+ */
902
+ convertColumnDetailsToUpdateRequest(columnDetails) {
903
+ return {
904
+ name: columnDetails.name,
905
+ type: columnDetails.type,
906
+ description: columnDetails.description,
907
+ is_nullable: columnDetails.is_nullable,
908
+ is_unique: columnDetails.is_unique,
909
+ is_indexed: columnDetails.is_indexed,
910
+ is_visible: columnDetails.is_visible,
911
+ is_primary_key: columnDetails.is_primary_key,
912
+ is_readonly: columnDetails.is_readonly,
913
+ default_value: columnDetails.default_value,
914
+ field_order: columnDetails.field_order,
915
+ alignment: columnDetails.alignment,
916
+ decimals: columnDetails.decimals,
917
+ currency_format: columnDetails.currency_format,
918
+ selection_source: columnDetails.selection_source,
919
+ selectable_items: columnDetails.selectable_items,
920
+ multiple_selections: columnDetails.multiple_selections,
921
+ phone_format: columnDetails.phone_format,
922
+ date_format: columnDetails.date_format,
923
+ time_format: columnDetails.time_format,
924
+ timezone: columnDetails.timezone,
925
+ vector_dimension: columnDetails.vector_dimension
926
+ };
927
+ }
928
+ /**
929
+ * Update a column by name
930
+ */
931
+ async updateColumnByName(tableId, columnName, updates) {
932
+ try {
933
+ const findResult = await this.findColumnByName(tableId, columnName);
934
+ if ("error" in findResult) {
935
+ return findResult;
936
+ }
937
+ if (!findResult.data) {
938
+ return {
939
+ data: {},
940
+ error: {
941
+ code: "COLUMN_NOT_FOUND",
942
+ message: `Column '${columnName}' not found in table`,
943
+ meta: ["404"]
944
+ }
945
+ };
946
+ }
947
+ const existingColumnAsUpdate = this.convertColumnDetailsToUpdateRequest(
948
+ findResult.data
949
+ );
950
+ const mergedUpdates = {
951
+ ...existingColumnAsUpdate,
952
+ ...updates
953
+ };
954
+ return await this.updateColumn(
955
+ tableId,
956
+ findResult.data.id,
957
+ mergedUpdates
958
+ );
959
+ } catch (error) {
960
+ return this.formatErrorResponse(error);
961
+ }
962
+ }
963
+ /**
964
+ * Delete column by name
965
+ */
966
+ async deleteColumnByName(tableId, columnName) {
967
+ try {
968
+ const findResult = await this.findColumnByName(tableId, columnName);
969
+ if ("error" in findResult) {
970
+ return findResult;
971
+ }
972
+ if (!findResult.data) {
973
+ return {
974
+ data: {},
975
+ error: {
976
+ code: "COLUMN_NOT_FOUND",
977
+ message: `Column '${columnName}' not found in table`,
978
+ meta: ["Column not found"]
979
+ }
980
+ };
981
+ }
982
+ return await this.deleteColumn(tableId, findResult.data.id);
983
+ } catch (error) {
984
+ return this.formatErrorResponse(error);
985
+ }
986
+ }
987
+ buildHeaders() {
988
+ return {
989
+ "Content-Type": "application/json",
990
+ Accept: "application/json",
991
+ "x-boltic-token": this.config.apiKey
992
+ };
993
+ }
994
+ formatErrorResponse(error) {
995
+ var _a, _b, _c;
996
+ if (this.config.debug) {
997
+ console.error("Columns API Error:", error);
998
+ }
999
+ if (error && typeof error === "object" && "response" in error) {
1000
+ const apiError = error;
1001
+ if ((_b = (_a = apiError.response) == null ? void 0 : _a.data) == null ? void 0 : _b.error) {
1002
+ return apiError.response.data;
1003
+ }
1004
+ return {
1005
+ data: {},
1006
+ error: {
1007
+ code: "API_ERROR",
1008
+ message: error.message || "Unknown API error",
1009
+ meta: [`Status: ${((_c = apiError.response) == null ? void 0 : _c.status) || "unknown"}`]
1010
+ }
1011
+ };
1012
+ }
1013
+ if (error && typeof error === "object" && "message" in error) {
1014
+ return {
1015
+ data: {},
1016
+ error: {
1017
+ code: "CLIENT_ERROR",
1018
+ message: error.message,
1019
+ meta: ["Client-side error occurred"]
1020
+ }
1021
+ };
1022
+ }
1023
+ return {
1024
+ data: {},
1025
+ error: {
1026
+ code: "UNKNOWN_ERROR",
1027
+ message: "An unexpected error occurred",
1028
+ meta: ["Unknown error type"]
1029
+ }
1030
+ };
1031
+ }
1032
+ }
1033
+ const TABLE_ENDPOINTS = {
1034
+ list: {
1035
+ path: "/tables/list",
1036
+ method: "POST",
1037
+ authenticated: true,
1038
+ rateLimit: { requests: 200, window: 6e4 }
1039
+ },
1040
+ create: {
1041
+ path: "/tables",
1042
+ method: "POST",
1043
+ authenticated: true
1044
+ },
1045
+ get: {
1046
+ path: "/tables/{table_id}",
1047
+ method: "GET",
1048
+ authenticated: true,
1049
+ rateLimit: { requests: 300, window: 6e4 }
1050
+ },
1051
+ update: {
1052
+ path: "/tables/{table_id}",
1053
+ method: "PATCH",
1054
+ authenticated: true
1055
+ },
1056
+ delete: {
1057
+ path: "/tables/{table_id}",
1058
+ method: "DELETE",
1059
+ authenticated: true
1060
+ }
1061
+ };
1062
+ const buildEndpointPath = (endpoint, params = {}) => {
1063
+ let path = endpoint.path;
1064
+ Object.entries(params).forEach(([key, value]) => {
1065
+ path = path.replace(`{${key}}`, encodeURIComponent(value));
1066
+ });
1067
+ const unreplacedParams = path.match(/\{([^}]+)\}/g);
1068
+ if (unreplacedParams) {
1069
+ throw new Error(`Missing path parameters: ${unreplacedParams.join(", ")}`);
1070
+ }
1071
+ return path;
1072
+ };
1073
+ const FILTER_OPERATORS = {
1074
+ // Relational operators
1075
+ EQUALS: "=",
1076
+ NOT_EQUALS: "!=",
1077
+ GREATER_THAN: ">",
1078
+ GREATER_THAN_EQUAL: ">=",
1079
+ LESS_THAN: "<",
1080
+ LESS_THAN_EQUAL: "<=",
1081
+ // String operators
1082
+ LIKE: "LIKE",
1083
+ // contains (case-sensitive)
1084
+ ILIKE: "ILIKE",
1085
+ // contains (case-insensitive)
1086
+ STARTS_WITH: "STARTS WITH",
1087
+ // Array/Set operators
1088
+ IN: "IN",
1089
+ // is one of
1090
+ NOT_IN: "NOT IN",
1091
+ // is not one of
1092
+ // Special operators
1093
+ IS_EMPTY: "IS EMPTY",
1094
+ IS_NULL: "IS NULL",
1095
+ IS_NOT_NULL: "IS NOT NULL",
1096
+ BETWEEN: "BETWEEN",
1097
+ // Dropdown/Array specific operators
1098
+ ARRAY_CONTAINS: "@>",
1099
+ // is exactly for dropdown
1100
+ ARRAY_NOT_CONTAINS: "NOT @>",
1101
+ // is different from for dropdown
1102
+ ANY: "ANY",
1103
+ // contains (case-sensitive) for dropdown
1104
+ IS_ONE_OF_ARRAY: "IS ONE OF",
1105
+ // is one of for dropdown
1106
+ DROPDOWN_ITEM_STARTS_WITH: "DROPDOWN ITEM STARTS WITH",
1107
+ // Date operators
1108
+ WITHIN: "WITHIN"
1109
+ // date range operator
1110
+ };
1111
+ const OPERATOR_MAPPING = {
1112
+ // Basic comparisons
1113
+ $eq: FILTER_OPERATORS.EQUALS,
1114
+ $ne: FILTER_OPERATORS.NOT_EQUALS,
1115
+ $gt: FILTER_OPERATORS.GREATER_THAN,
1116
+ $gte: FILTER_OPERATORS.GREATER_THAN_EQUAL,
1117
+ $lt: FILTER_OPERATORS.LESS_THAN,
1118
+ $lte: FILTER_OPERATORS.LESS_THAN_EQUAL,
1119
+ // String operations
1120
+ $like: FILTER_OPERATORS.LIKE,
1121
+ $ilike: FILTER_OPERATORS.ILIKE,
1122
+ $startsWith: FILTER_OPERATORS.STARTS_WITH,
1123
+ // Array operations
1124
+ $in: FILTER_OPERATORS.IN,
1125
+ $notIn: FILTER_OPERATORS.NOT_IN,
1126
+ // Special operations
1127
+ $between: FILTER_OPERATORS.BETWEEN,
1128
+ $isEmpty: FILTER_OPERATORS.IS_EMPTY,
1129
+ $isNull: FILTER_OPERATORS.IS_NULL,
1130
+ $isNotNull: FILTER_OPERATORS.IS_NOT_NULL,
1131
+ // Array/dropdown operations
1132
+ $arrayContains: FILTER_OPERATORS.ARRAY_CONTAINS,
1133
+ $arrayNotContains: FILTER_OPERATORS.ARRAY_NOT_CONTAINS,
1134
+ $any: FILTER_OPERATORS.ANY,
1135
+ $isOneOfArray: FILTER_OPERATORS.IS_ONE_OF_ARRAY,
1136
+ $dropdownItemStartsWith: FILTER_OPERATORS.DROPDOWN_ITEM_STARTS_WITH,
1137
+ // Date operations
1138
+ $within: FILTER_OPERATORS.WITHIN
1139
+ };
1140
+ function normalizeFilters(filters) {
1141
+ if (Array.isArray(filters)) {
1142
+ if (filters.length > 0 && typeof filters[0] === "object" && "field" in filters[0] && "operator" in filters[0] && "values" in filters[0]) {
1143
+ return filters;
1144
+ }
1145
+ console.warn(
1146
+ "Legacy Record<string, unknown>[] filter format detected. Please migrate to the new filter format."
1147
+ );
1148
+ return [];
1149
+ }
1150
+ return mapWhereToFilters(filters);
1151
+ }
1152
+ function mapWhereToFilters(where) {
1153
+ const filters = [];
1154
+ Object.entries(where).forEach(([field, condition]) => {
1155
+ if (typeof condition !== "object" || Array.isArray(condition) || condition === null) {
1156
+ filters.push({
1157
+ field,
1158
+ operator: FILTER_OPERATORS.EQUALS,
1159
+ values: [condition]
1160
+ });
1161
+ return;
1162
+ }
1163
+ Object.entries(condition).forEach(([operator, value]) => {
1164
+ const apiOperator = OPERATOR_MAPPING[operator];
1165
+ if (!apiOperator) {
1166
+ throw new Error(`Unsupported operator: ${operator}`);
1167
+ }
1168
+ let values;
1169
+ if (apiOperator === FILTER_OPERATORS.BETWEEN && Array.isArray(value) && value.length === 2) {
1170
+ values = value;
1171
+ } else if ((apiOperator === FILTER_OPERATORS.IN || apiOperator === FILTER_OPERATORS.NOT_IN || apiOperator === FILTER_OPERATORS.IS_ONE_OF_ARRAY) && Array.isArray(value)) {
1172
+ values = value;
1173
+ } else if (apiOperator === FILTER_OPERATORS.IS_NULL || apiOperator === FILTER_OPERATORS.IS_NOT_NULL || apiOperator === FILTER_OPERATORS.IS_EMPTY) {
1174
+ values = [];
1175
+ } else {
1176
+ values = [value];
1177
+ }
1178
+ filters.push({
1179
+ field,
1180
+ operator: apiOperator,
1181
+ values
1182
+ });
1183
+ });
1184
+ });
1185
+ return filters;
1186
+ }
1187
+ function buildApiFilters(whereOrFilters, whereOperator = "AND") {
1188
+ const filters = normalizeFilters(whereOrFilters);
1189
+ filters.forEach((filter, index) => {
1190
+ if (!filter.field) {
1191
+ throw new Error(`Filter at index ${index} missing required field`);
1192
+ }
1193
+ if (!filter.operator) {
1194
+ throw new Error(`Filter at index ${index} missing required operator`);
1195
+ }
1196
+ if (!Array.isArray(filter.values)) {
1197
+ throw new Error(`Filter at index ${index} values must be an array`);
1198
+ }
1199
+ });
1200
+ return {
1201
+ filters,
1202
+ whereOperator
1203
+ };
1204
+ }
1205
+ function mapFiltersToWhere(filters) {
1206
+ const where = {};
1207
+ filters.forEach((filter) => {
1208
+ const reverseMapping = {};
1209
+ Object.entries(OPERATOR_MAPPING).forEach(([sdkOp, apiOp]) => {
1210
+ reverseMapping[apiOp] = sdkOp;
1211
+ });
1212
+ const sdkOperator = reverseMapping[filter.operator];
1213
+ if (!sdkOperator) {
1214
+ throw new Error(`Unsupported API operator: ${filter.operator}`);
1215
+ }
1216
+ if (!where[filter.field]) {
1217
+ where[filter.field] = {};
1218
+ }
1219
+ const fieldCondition = where[filter.field];
1220
+ if (sdkOperator === "$between" && filter.values.length === 2) {
1221
+ fieldCondition[sdkOperator] = filter.values;
1222
+ } else if (sdkOperator === "$in" || sdkOperator === "$notIn" || sdkOperator === "$isOneOfArray") {
1223
+ fieldCondition[sdkOperator] = filter.values;
1224
+ } else if (sdkOperator === "$isNull" || sdkOperator === "$isNotNull" || sdkOperator === "$isEmpty") {
1225
+ fieldCondition[sdkOperator] = true;
1226
+ } else {
1227
+ fieldCondition[sdkOperator] = filter.values[0];
1228
+ }
1229
+ });
1230
+ return where;
1231
+ }
1232
+ class FilterBuilder {
1233
+ constructor() {
1234
+ this.filters = [];
1235
+ }
1236
+ equals(field, value) {
1237
+ this.filters.push({
1238
+ field,
1239
+ operator: FILTER_OPERATORS.EQUALS,
1240
+ values: [value]
1241
+ });
1242
+ return this;
1243
+ }
1244
+ notEquals(field, value) {
1245
+ this.filters.push({
1246
+ field,
1247
+ operator: FILTER_OPERATORS.NOT_EQUALS,
1248
+ values: [value]
1249
+ });
1250
+ return this;
1251
+ }
1252
+ greaterThan(field, value) {
1253
+ this.filters.push({
1254
+ field,
1255
+ operator: FILTER_OPERATORS.GREATER_THAN,
1256
+ values: [value]
1257
+ });
1258
+ return this;
1259
+ }
1260
+ lessThan(field, value) {
1261
+ this.filters.push({
1262
+ field,
1263
+ operator: FILTER_OPERATORS.LESS_THAN,
1264
+ values: [value]
1265
+ });
1266
+ return this;
1267
+ }
1268
+ between(field, start, end) {
1269
+ this.filters.push({
1270
+ field,
1271
+ operator: FILTER_OPERATORS.BETWEEN,
1272
+ values: [start, end]
1273
+ });
1274
+ return this;
1275
+ }
1276
+ in(field, values) {
1277
+ this.filters.push({
1278
+ field,
1279
+ operator: FILTER_OPERATORS.IN,
1280
+ values
1281
+ });
1282
+ return this;
1283
+ }
1284
+ like(field, value) {
1285
+ this.filters.push({
1286
+ field,
1287
+ operator: FILTER_OPERATORS.LIKE,
1288
+ values: [value]
1289
+ });
1290
+ return this;
1291
+ }
1292
+ startsWith(field, value) {
1293
+ this.filters.push({
1294
+ field,
1295
+ operator: FILTER_OPERATORS.STARTS_WITH,
1296
+ values: [value]
1297
+ });
1298
+ return this;
1299
+ }
1300
+ isEmpty(field) {
1301
+ this.filters.push({
1302
+ field,
1303
+ operator: FILTER_OPERATORS.IS_EMPTY,
1304
+ values: []
1305
+ });
1306
+ return this;
1307
+ }
1308
+ isNull(field) {
1309
+ this.filters.push({
1310
+ field,
1311
+ operator: FILTER_OPERATORS.IS_NULL,
1312
+ values: []
1313
+ });
1314
+ return this;
1315
+ }
1316
+ arrayContains(field, value) {
1317
+ this.filters.push({
1318
+ field,
1319
+ operator: FILTER_OPERATORS.ARRAY_CONTAINS,
1320
+ values: [value]
1321
+ });
1322
+ return this;
1323
+ }
1324
+ build() {
1325
+ return [...this.filters];
1326
+ }
1327
+ clear() {
1328
+ this.filters = [];
1329
+ return this;
1330
+ }
1331
+ }
1332
+ function createFilter() {
1333
+ return new FilterBuilder();
1334
+ }
1335
+ function transformTableCreateRequest(request, options = {}) {
1336
+ return {
1337
+ name: request.name,
1338
+ description: request.description,
1339
+ fields: request.fields.map(transformFieldDefinition),
1340
+ is_ai_generated_schema: options.is_ai_generated_schema || false,
1341
+ is_template: options.is_template || false
1342
+ };
1343
+ }
1344
+ function transformFieldDefinition(field) {
1345
+ return {
1346
+ name: field.name,
1347
+ type: field.type,
1348
+ is_nullable: field.is_nullable ?? true,
1349
+ is_primary_key: field.is_primary_key ?? false,
1350
+ is_unique: field.is_unique ?? false,
1351
+ is_indexed: field.is_indexed ?? false,
1352
+ is_visible: field.is_visible ?? true,
1353
+ is_readonly: field.is_readonly ?? false,
1354
+ field_order: field.field_order ?? 1,
1355
+ alignment: field.alignment ?? "left",
1356
+ timezone: field.timezone ?? void 0,
1357
+ date_format: field.date_format ?? void 0,
1358
+ time_format: field.time_format ?? void 0,
1359
+ decimals: field.decimals ?? void 0,
1360
+ currency_format: field.currency_format ?? void 0,
1361
+ selection_source: field.type === "dropdown" && !field.selection_source ? "provide-static-list" : field.selection_source ?? void 0,
1362
+ selectable_items: field.selectable_items ?? void 0,
1363
+ multiple_selections: field.multiple_selections ?? false,
1364
+ phone_format: field.phone_format ?? void 0,
1365
+ vector_dimension: field.vector_dimension ?? void 0,
1366
+ description: field.description,
1367
+ default_value: field.default_value
1368
+ };
1369
+ }
1370
+ class TablesApiClient {
1371
+ constructor(apiKey, config = {}) {
1372
+ this.config = { apiKey, ...config };
1373
+ this.httpAdapter = createHttpAdapter();
1374
+ const environment = config.environment || "prod";
1375
+ const region = config.region || "asia-south1";
1376
+ this.baseURL = this.getBaseURL(environment, region);
1377
+ }
1378
+ getBaseURL(environment, region) {
1379
+ const regionConfig = REGION_CONFIGS[region];
1380
+ if (!regionConfig) {
1381
+ throw new Error(`Unsupported region: ${region}`);
1382
+ }
1383
+ const envConfig = regionConfig[environment];
1384
+ if (!envConfig) {
1385
+ throw new Error(
1386
+ `Unsupported environment: ${environment} for region: ${region}`
1387
+ );
1388
+ }
1389
+ return `${envConfig.baseURL}/v1`;
1390
+ }
1391
+ /**
1392
+ * Create a new table
1393
+ */
1394
+ async createTable(request, options = {}) {
1395
+ try {
1396
+ const endpoint = TABLE_ENDPOINTS.create;
1397
+ const url = `${this.baseURL}${endpoint.path}`;
1398
+ const transformedRequest = transformTableCreateRequest(request, options);
1399
+ const response = await this.httpAdapter.request({
1400
+ url,
1401
+ method: endpoint.method,
1402
+ headers: this.buildHeaders(),
1403
+ data: transformedRequest,
1404
+ timeout: this.config.timeout
1405
+ });
1406
+ return response.data;
1407
+ } catch (error) {
1408
+ return this.formatErrorResponse(error);
1409
+ }
1410
+ }
1411
+ /**
1412
+ * List tables with filtering and pagination
1413
+ */
1414
+ async listTables(options = {}) {
1415
+ try {
1416
+ const endpoint = TABLE_ENDPOINTS.list;
1417
+ const url = `${this.baseURL}${endpoint.path}`;
1418
+ const response = await this.httpAdapter.request({
1419
+ url,
1420
+ method: endpoint.method,
1421
+ headers: this.buildHeaders(),
1422
+ data: options,
1423
+ timeout: this.config.timeout
1424
+ });
1425
+ const responseData = response.data;
1426
+ if (options.fields && responseData.data) {
1427
+ responseData.data = filterArrayFields(
1428
+ responseData.data,
1429
+ options.fields
1430
+ );
1431
+ }
1432
+ return responseData;
1433
+ } catch (error) {
1434
+ return this.formatErrorResponse(error);
1435
+ }
1436
+ }
1437
+ /**
1438
+ * Get a specific table by ID
1439
+ */
1440
+ async getTable(tableId, options = {}) {
1441
+ try {
1442
+ const endpoint = TABLE_ENDPOINTS.get;
1443
+ const url = `${this.baseURL}${buildEndpointPath(endpoint, { table_id: tableId })}`;
1444
+ const response = await this.httpAdapter.request({
1445
+ url,
1446
+ method: endpoint.method,
1447
+ headers: this.buildHeaders(),
1448
+ timeout: this.config.timeout
1449
+ });
1450
+ const responseData = response.data;
1451
+ if (options.fields && responseData.data) {
1452
+ responseData.data = filterObjectFields(
1453
+ responseData.data,
1454
+ options.fields
1455
+ );
1456
+ }
1457
+ return responseData;
1458
+ } catch (error) {
1459
+ return this.formatErrorResponse(error);
1460
+ }
1461
+ }
1462
+ /**
1463
+ * Update an existing table
1464
+ */
1465
+ async updateTable(tableId, updates) {
1466
+ try {
1467
+ const { fields, ...updateData } = updates;
1468
+ const endpoint = TABLE_ENDPOINTS.update;
1469
+ const url = `${this.baseURL}${buildEndpointPath(endpoint, { table_id: tableId })}`;
1470
+ const response = await this.httpAdapter.request({
1471
+ url,
1472
+ method: endpoint.method,
1473
+ headers: this.buildHeaders(),
1474
+ data: updateData,
1475
+ timeout: this.config.timeout
1476
+ });
1477
+ const responseData = response.data;
1478
+ if (fields && responseData.data) {
1479
+ responseData.data = filterObjectFields(
1480
+ responseData.data,
1481
+ fields
1482
+ );
1483
+ }
1484
+ return responseData;
1485
+ } catch (error) {
1486
+ return this.formatErrorResponse(error);
1487
+ }
1488
+ }
1489
+ /**
1490
+ * Delete a table
1491
+ */
1492
+ async deleteTable(tableId) {
1493
+ try {
1494
+ const endpoint = TABLE_ENDPOINTS.delete;
1495
+ const url = `${this.baseURL}${buildEndpointPath(endpoint, { table_id: tableId })}`;
1496
+ const response = await this.httpAdapter.request({
1497
+ url,
1498
+ method: endpoint.method,
1499
+ headers: this.buildHeaders(),
1500
+ timeout: this.config.timeout
1501
+ });
1502
+ return response.data;
1503
+ } catch (error) {
1504
+ return this.formatErrorResponse(error);
1505
+ }
1506
+ }
1507
+ // Private helper methods
1508
+ buildHeaders() {
1509
+ return {
1510
+ "Content-Type": "application/json",
1511
+ Accept: "application/json",
1512
+ "x-boltic-token": this.config.apiKey
1513
+ };
1514
+ }
1515
+ formatErrorResponse(error) {
1516
+ var _a, _b, _c;
1517
+ if (this.config.debug) {
1518
+ console.error("Tables API Error:", error);
1519
+ }
1520
+ if (error && typeof error === "object" && "response" in error) {
1521
+ const apiError = error;
1522
+ if ((_b = (_a = apiError.response) == null ? void 0 : _a.data) == null ? void 0 : _b.error) {
1523
+ return apiError.response.data;
1524
+ }
1525
+ return {
1526
+ data: {},
1527
+ error: {
1528
+ code: "API_ERROR",
1529
+ message: error.message || "Unknown API error",
1530
+ meta: [`Status: ${((_c = apiError.response) == null ? void 0 : _c.status) || "unknown"}`]
1531
+ }
1532
+ };
1533
+ }
1534
+ if (error && typeof error === "object" && "message" in error) {
1535
+ return {
1536
+ data: {},
1537
+ error: {
1538
+ code: "CLIENT_ERROR",
1539
+ message: error.message,
1540
+ meta: ["Client-side error occurred"]
1541
+ }
1542
+ };
1543
+ }
1544
+ return {
1545
+ data: {},
1546
+ error: {
1547
+ code: "UNKNOWN_ERROR",
1548
+ message: "An unexpected error occurred",
1549
+ meta: ["Unknown error type"]
1550
+ }
1551
+ };
1552
+ }
1553
+ }
1554
+ function isErrorResponse(response) {
1555
+ return "error" in response && response.error !== void 0;
1556
+ }
1557
+ function isListResponse(response) {
1558
+ return "pagination" in response;
1559
+ }
1560
+ class BaseResource {
1561
+ constructor(client, basePath) {
1562
+ this.client = client;
1563
+ this.basePath = basePath;
1564
+ }
1565
+ // Public getter for basePath
1566
+ getBasePath() {
1567
+ return this.basePath;
1568
+ }
1569
+ async makeRequest(method, path, data, options) {
1570
+ const url = `${this.basePath}${path}`;
1571
+ try {
1572
+ let response;
1573
+ switch (method) {
1574
+ case "GET":
1575
+ response = await this.client.get(url, {
1576
+ params: options == null ? void 0 : options.params
1577
+ });
1578
+ break;
1579
+ case "POST":
1580
+ response = await this.client.post(url, data, {
1581
+ params: options == null ? void 0 : options.params
1582
+ });
1583
+ break;
1584
+ case "PUT":
1585
+ response = await this.client.put(url, data, {
1586
+ params: options == null ? void 0 : options.params
1587
+ });
1588
+ break;
1589
+ case "PATCH":
1590
+ response = await this.client.patch(url, data, {
1591
+ params: options == null ? void 0 : options.params
1592
+ });
1593
+ break;
1594
+ case "DELETE":
1595
+ response = await this.client.delete(url, {
1596
+ params: options == null ? void 0 : options.params
1597
+ });
1598
+ break;
1599
+ }
1600
+ return response.data;
1601
+ } catch (error) {
1602
+ return {
1603
+ data: {},
1604
+ error: {
1605
+ code: "CLIENT_ERROR",
1606
+ message: formatError(error),
1607
+ meta: ["Request failed"]
1608
+ }
1609
+ };
1610
+ }
1611
+ }
1612
+ buildQueryParams(options = {}) {
1613
+ var _a, _b;
1614
+ const params = {};
1615
+ if ((_a = options.fields) == null ? void 0 : _a.length) {
1616
+ params.fields = options.fields.join(",");
1617
+ }
1618
+ if ((_b = options.sort) == null ? void 0 : _b.length) {
1619
+ params.sort = options.sort.map((s) => `${s.field}:${s.order}`).join(",");
1620
+ }
1621
+ if (options.limit !== void 0) {
1622
+ params.limit = options.limit;
1623
+ }
1624
+ if (options.offset !== void 0) {
1625
+ params.offset = options.offset;
1626
+ }
1627
+ if (options.where) {
1628
+ Object.entries(options.where).forEach(([key, value]) => {
1629
+ if (value !== void 0 && value !== null) {
1630
+ params[`where[${key}]`] = typeof value === "object" ? JSON.stringify(value) : value;
1631
+ }
1632
+ });
1633
+ }
1634
+ return params;
1635
+ }
1636
+ handleResponse(response) {
1637
+ if ("error" in response) {
1638
+ if (this.client.getConfig().debug) {
1639
+ console.error("API Error:", response.error);
1640
+ }
1641
+ }
1642
+ return response;
1643
+ }
1644
+ }
1645
+ class TableResource extends BaseResource {
1646
+ constructor(client) {
1647
+ super(client, "/v1/tables");
1648
+ const config = client.getConfig();
1649
+ this.tablesApiClient = new TablesApiClient(config.apiKey, {
1650
+ environment: config.environment,
1651
+ timeout: config.timeout,
1652
+ debug: config.debug,
1653
+ retryAttempts: config.retryAttempts,
1654
+ retryDelay: config.retryDelay,
1655
+ headers: config.headers
1656
+ });
1657
+ }
1658
+ /**
1659
+ * Get the TablesApiClient instance
1660
+ */
1661
+ getTablesApiClient() {
1662
+ return this.tablesApiClient;
1663
+ }
1664
+ /**
1665
+ * Create a new table
1666
+ */
1667
+ async create(data) {
1668
+ try {
1669
+ const processedData = { ...data };
1670
+ if (data.fields && data.fields.length > 0) {
1671
+ processedData.fields = await this.processFieldsDefaults(data.fields);
1672
+ }
1673
+ const result = await this.tablesApiClient.createTable(processedData);
1674
+ if (isErrorResponse(result)) {
1675
+ throw new ApiError(
1676
+ result.error.message || "Create table failed",
1677
+ 400,
1678
+ result.error
1679
+ );
1680
+ }
1681
+ return result;
1682
+ } catch (error) {
1683
+ throw error instanceof ApiError ? error : new ApiError(this.formatError(error), 500);
1684
+ }
1685
+ }
1686
+ /**
1687
+ * Process fields with defaults for table creation
1688
+ */
1689
+ async processFieldsDefaults(fields) {
1690
+ const processedFields = [];
1691
+ for (let i = 0; i < fields.length; i++) {
1692
+ const field = fields[i];
1693
+ const processedField = { ...field };
1694
+ if (processedField.is_primary_key === void 0) {
1695
+ processedField.is_primary_key = false;
1696
+ }
1697
+ if (processedField.is_unique === void 0) {
1698
+ processedField.is_unique = false;
1699
+ }
1700
+ if (processedField.is_nullable === void 0) {
1701
+ processedField.is_nullable = true;
1702
+ }
1703
+ if (processedField.is_indexed === void 0) {
1704
+ processedField.is_indexed = false;
1705
+ }
1706
+ if (processedField.field_order === void 0) {
1707
+ processedField.field_order = i + 1;
1708
+ }
1709
+ if (processedField.field_order <= 0 || processedField.field_order >= 2147483647) {
1710
+ throw new Error(
1711
+ "Field order must be a number greater than 0 and less than 2147483647"
1712
+ );
1713
+ }
1714
+ processedFields.push(processedField);
1715
+ }
1716
+ return processedFields;
1717
+ }
1718
+ /**
1719
+ * Transform SDK TableQueryOptions to API request format
1720
+ */
1721
+ transformTableQueryToApiRequest(options) {
1722
+ const apiRequest = {
1723
+ page: {
1724
+ page_no: 1,
1725
+ page_size: options.limit || 100
1726
+ },
1727
+ filters: [],
1728
+ sort: []
1729
+ };
1730
+ if (options.offset && options.limit) {
1731
+ const pageNo = Math.floor(options.offset / options.limit) + 1;
1732
+ apiRequest.page.page_no = pageNo;
1733
+ }
1734
+ if (options.where) {
1735
+ Object.entries(options.where).forEach(([field, value]) => {
1736
+ if (value !== void 0 && value !== null) {
1737
+ apiRequest.filters.push({
1738
+ field,
1739
+ operator: "=",
1740
+ values: [value]
1741
+ });
1742
+ }
1743
+ });
1744
+ }
1745
+ if (options.sort) {
1746
+ apiRequest.sort = options.sort.map((s) => ({
1747
+ field: s.field,
1748
+ direction: s.order
1749
+ }));
1750
+ }
1751
+ return apiRequest;
1752
+ }
1753
+ /**
1754
+ * Find all tables with optional filtering
1755
+ */
1756
+ async findAll(options = {}) {
1757
+ try {
1758
+ const apiRequest = this.transformTableQueryToApiRequest(options);
1759
+ const result = await this.tablesApiClient.listTables(
1760
+ apiRequest
1761
+ );
1762
+ if (isErrorResponse(result)) {
1763
+ throw new ApiError(
1764
+ result.error.message || "List tables failed",
1765
+ 400,
1766
+ result.error
1767
+ );
1768
+ }
1769
+ return result;
1770
+ } catch (error) {
1771
+ throw error instanceof ApiError ? error : new ApiError(this.formatError(error), 500);
1772
+ }
1773
+ }
1774
+ /**
1775
+ * Find a single table by ID or name
1776
+ */
1777
+ async findOne(options) {
1778
+ var _a, _b, _c;
1779
+ try {
1780
+ if (!((_a = options.where) == null ? void 0 : _a.id) && !((_b = options.where) == null ? void 0 : _b.name)) {
1781
+ throw new ValidationError(
1782
+ "Either id or name must be provided in where clause"
1783
+ );
1784
+ }
1785
+ if ((_c = options.where) == null ? void 0 : _c.id) {
1786
+ const result = await this.tablesApiClient.getTable(
1787
+ options.where.id
1788
+ );
1789
+ if (isErrorResponse(result)) {
1790
+ if (result.error.code === "TABLE_NOT_FOUND") {
1791
+ return {
1792
+ data: null,
1793
+ message: "Table not found"
1794
+ };
1795
+ }
1796
+ throw new ApiError(
1797
+ result.error.message || "Get table failed",
1798
+ 400,
1799
+ result.error
1800
+ );
1801
+ }
1802
+ return result;
1803
+ } else {
1804
+ const apiRequest = {
1805
+ page: { page_no: 1, page_size: 1 },
1806
+ filters: [
1807
+ {
1808
+ field: "name",
1809
+ operator: "=",
1810
+ values: [options.where.name]
1811
+ }
1812
+ ],
1813
+ sort: []
1814
+ };
1815
+ const listResult = await this.tablesApiClient.listTables(
1816
+ apiRequest
1817
+ );
1818
+ if (isErrorResponse(listResult)) {
1819
+ throw new ApiError(
1820
+ listResult.error.message || "Find table by name failed",
1821
+ 400,
1822
+ listResult.error
1823
+ );
1824
+ }
1825
+ const table = isListResponse(listResult) ? listResult.data[0] : null;
1826
+ return {
1827
+ data: table || null,
1828
+ message: table ? "Table found" : "Table not found"
1829
+ };
1830
+ }
1831
+ } catch (error) {
1832
+ throw error instanceof ApiError || error instanceof ValidationError ? error : new ApiError(this.formatError(error), 500);
1833
+ }
1834
+ }
1835
+ /**
1836
+ * Find a single table by name
1837
+ */
1838
+ async findByName(name) {
1839
+ return this.findOne({ where: { name } });
1840
+ }
1841
+ /**
1842
+ * Find a single table by ID
1843
+ */
1844
+ async findById(id) {
1845
+ return this.findOne({ where: { id } });
1846
+ }
1847
+ /**
1848
+ * Update a table by name
1849
+ */
1850
+ async update(name, data) {
1851
+ try {
1852
+ const tableResult = await this.findByName(name);
1853
+ if (!tableResult.data) {
1854
+ throw new ApiError(`Table '${name}' not found`, 404);
1855
+ }
1856
+ if (tableResult.data.snapshot_url) {
1857
+ throw new ApiError(
1858
+ `Cannot update snapshot table '${name}'. Snapshots are read-only and cannot be modified.`,
1859
+ 400
1860
+ );
1861
+ }
1862
+ const result = await this.tablesApiClient.updateTable(
1863
+ tableResult.data.id,
1864
+ data
1865
+ );
1866
+ if (isErrorResponse(result)) {
1867
+ throw new ApiError(
1868
+ result.error.message || "Update table failed",
1869
+ 400,
1870
+ result.error
1871
+ );
1872
+ }
1873
+ return result;
1874
+ } catch (error) {
1875
+ throw error instanceof ApiError ? error : new ApiError(this.formatError(error), 500);
1876
+ }
1877
+ }
1878
+ /**
1879
+ * Delete a table by name
1880
+ */
1881
+ async delete(name) {
1882
+ try {
1883
+ const tableResult = await this.findByName(name);
1884
+ if (!tableResult.data) {
1885
+ throw new ApiError(`Table '${name}' not found`, 404);
1886
+ }
1887
+ if (tableResult.data.snapshot_url) {
1888
+ throw new ApiError(
1889
+ `Cannot delete snapshot table '${name}'. Snapshots are read-only and cannot be deleted.`,
1890
+ 400
1891
+ );
1892
+ }
1893
+ const result = await this.tablesApiClient.deleteTable(
1894
+ tableResult.data.id
1895
+ );
1896
+ if (isErrorResponse(result)) {
1897
+ throw new ApiError(
1898
+ result.error.message || "Delete table failed",
1899
+ 400,
1900
+ result.error
1901
+ );
1902
+ }
1903
+ return result;
1904
+ } catch (error) {
1905
+ throw error instanceof ApiError ? error : new ApiError(this.formatError(error), 500);
1906
+ }
1907
+ }
1908
+ /**
1909
+ * Rename a table
1910
+ */
1911
+ async rename(oldName, newName) {
1912
+ try {
1913
+ return await this.update(oldName, {
1914
+ name: newName
1915
+ });
1916
+ } catch (error) {
1917
+ throw error instanceof ApiError ? error : new ApiError(this.formatError(error), 500);
1918
+ }
1919
+ }
1920
+ /**
1921
+ * Set table access permissions
1922
+ */
1923
+ async setAccess(request) {
1924
+ try {
1925
+ return await this.update(request.table_name, {
1926
+ is_shared: request.is_shared
1927
+ });
1928
+ } catch (error) {
1929
+ throw error instanceof ApiError ? error : new ApiError(this.formatError(error), 500);
1930
+ }
1931
+ }
1932
+ // Helper method to format generic errors
1933
+ formatError(error) {
1934
+ if (error instanceof Error) {
1935
+ return error.message;
1936
+ }
1937
+ if (typeof error === "string") {
1938
+ return error;
1939
+ }
1940
+ return "An unexpected error occurred";
1941
+ }
1942
+ }
1943
+ class ColumnResource extends BaseResource {
1944
+ constructor(client) {
1945
+ super(client, "/v1/tables");
1946
+ const config = client.getConfig();
1947
+ this.columnsApiClient = new ColumnsApiClient(config.apiKey, {
1948
+ environment: config.environment,
1949
+ timeout: config.timeout,
1950
+ debug: config.debug,
1951
+ retryAttempts: config.retryAttempts,
1952
+ retryDelay: config.retryDelay,
1953
+ headers: config.headers
1954
+ });
1955
+ this.tablesApiClient = new TablesApiClient(config.apiKey, {
1956
+ environment: config.environment,
1957
+ timeout: config.timeout,
1958
+ debug: config.debug,
1959
+ retryAttempts: config.retryAttempts,
1960
+ retryDelay: config.retryDelay,
1961
+ headers: config.headers
1962
+ });
1963
+ }
1964
+ /**
1965
+ * Create a single column in a table
1966
+ */
1967
+ async create(tableName, column) {
1968
+ try {
1969
+ const tableInfo = await this.getTableInfo(tableName);
1970
+ if (!tableInfo) {
1971
+ return {
1972
+ data: {},
1973
+ error: {
1974
+ code: "TABLE_NOT_FOUND",
1975
+ message: `Table '${tableName}' not found`
1976
+ }
1977
+ };
1978
+ }
1979
+ if (tableInfo.snapshot_url) {
1980
+ return {
1981
+ data: {},
1982
+ error: {
1983
+ code: "SNAPSHOT_PROTECTION",
1984
+ message: `Cannot create column in snapshot table '${tableName}'. Snapshots are read-only and cannot be modified.`
1985
+ }
1986
+ };
1987
+ }
1988
+ const processedColumn = await this.processColumnDefaults(
1989
+ tableInfo.id,
1990
+ column
1991
+ );
1992
+ const result = await this.columnsApiClient.createColumn(
1993
+ tableInfo.id,
1994
+ processedColumn
1995
+ );
1996
+ if (isErrorResponse(result)) {
1997
+ return result;
1998
+ }
1999
+ return result;
2000
+ } catch (error) {
2001
+ return {
2002
+ data: {},
2003
+ error: {
2004
+ code: "CREATE_COLUMN_ERROR",
2005
+ message: error instanceof Error ? error.message : "Unknown error occurred"
2006
+ }
2007
+ };
2008
+ }
2009
+ }
2010
+ /**
2011
+ * Process column defaults and auto-generate field_order
2012
+ */
2013
+ async processColumnDefaults(tableId, column) {
2014
+ const processedColumn = { ...column };
2015
+ if (processedColumn.is_primary_key === void 0) {
2016
+ processedColumn.is_primary_key = false;
2017
+ }
2018
+ if (processedColumn.is_unique === void 0) {
2019
+ processedColumn.is_unique = false;
2020
+ }
2021
+ if (processedColumn.is_nullable === void 0) {
2022
+ processedColumn.is_nullable = true;
2023
+ }
2024
+ if (processedColumn.is_indexed === void 0) {
2025
+ processedColumn.is_indexed = false;
2026
+ }
2027
+ if (processedColumn.field_order === void 0) {
2028
+ processedColumn.field_order = await this.generateFieldOrder(tableId);
2029
+ }
2030
+ if (processedColumn.field_order <= 0 || processedColumn.field_order >= 2147483647) {
2031
+ throw new Error(
2032
+ "Field order must be a number greater than 0 and less than 2147483647"
2033
+ );
2034
+ }
2035
+ return processedColumn;
2036
+ }
2037
+ /**
2038
+ * Generate the next available field_order for a table
2039
+ */
2040
+ async generateFieldOrder(tableId) {
2041
+ try {
2042
+ const existingColumns = await this.columnsApiClient.listColumns(tableId);
2043
+ let maxOrder = 0;
2044
+ if (!isErrorResponse(existingColumns) && existingColumns.data && Array.isArray(existingColumns.data)) {
2045
+ for (const col of existingColumns.data) {
2046
+ if (col.field_order && col.field_order > maxOrder) {
2047
+ maxOrder = col.field_order;
2048
+ }
2049
+ }
2050
+ }
2051
+ return maxOrder + 1;
2052
+ } catch (error) {
2053
+ return Math.floor(Date.now() / 1e3) % 2147483647;
2054
+ }
2055
+ }
2056
+ /**
2057
+ * Transform SDK ColumnQueryOptions to API request format
2058
+ */
2059
+ transformColumnQueryToApiRequest(options) {
2060
+ const apiRequest = {
2061
+ page: {
2062
+ page_no: 1,
2063
+ page_size: options.limit || 100
2064
+ },
2065
+ filters: [],
2066
+ sort: []
2067
+ };
2068
+ if (options.offset && options.limit) {
2069
+ const pageNo = Math.floor(options.offset / options.limit) + 1;
2070
+ apiRequest.page.page_no = pageNo;
2071
+ }
2072
+ if (options.where) {
2073
+ Object.entries(options.where).forEach(([field, value]) => {
2074
+ if (value !== void 0 && value !== null) {
2075
+ apiRequest.filters.push({
2076
+ field,
2077
+ operator: "=",
2078
+ values: [value]
2079
+ });
2080
+ }
2081
+ });
2082
+ }
2083
+ if (options.sort) {
2084
+ apiRequest.sort = options.sort.map((s) => ({
2085
+ field: s.field,
2086
+ direction: s.order
2087
+ }));
2088
+ }
2089
+ return apiRequest;
2090
+ }
2091
+ /**
2092
+ * Add multiple columns to existing table
2093
+ */
2094
+ async createMany(tableName, columns) {
2095
+ try {
2096
+ const tableInfo = await this.getTableInfo(tableName);
2097
+ if (!tableInfo) {
2098
+ return {
2099
+ data: {},
2100
+ error: {
2101
+ code: "TABLE_NOT_FOUND",
2102
+ message: `Table '${tableName}' not found`
2103
+ }
2104
+ };
2105
+ }
2106
+ if (tableInfo.snapshot_url) {
2107
+ return {
2108
+ data: {},
2109
+ error: {
2110
+ code: "SNAPSHOT_PROTECTION",
2111
+ message: `Cannot create columns in snapshot table '${tableName}'. Snapshots are read-only and cannot be modified.`
2112
+ }
2113
+ };
2114
+ }
2115
+ const processedColumns = [];
2116
+ for (const column of columns) {
2117
+ const processedColumn = await this.processColumnDefaults(
2118
+ tableInfo.id,
2119
+ column
2120
+ );
2121
+ processedColumns.push(processedColumn);
2122
+ }
2123
+ const result = await this.columnsApiClient.createColumns(tableInfo.id, {
2124
+ columns: processedColumns
2125
+ });
2126
+ if (isErrorResponse(result)) {
2127
+ return result;
2128
+ }
2129
+ return result;
2130
+ } catch (error) {
2131
+ return {
2132
+ data: {},
2133
+ error: {
2134
+ code: "CREATE_COLUMNS_ERROR",
2135
+ message: error instanceof Error ? error.message : "Unknown error occurred"
2136
+ }
2137
+ };
2138
+ }
2139
+ }
2140
+ /**
2141
+ * Find all columns in a table (replaces list functionality)
2142
+ */
2143
+ async findAll(tableName, options = {}) {
2144
+ try {
2145
+ const tableInfo = await this.getTableInfo(tableName);
2146
+ if (!tableInfo) {
2147
+ return {
2148
+ data: {},
2149
+ error: {
2150
+ code: "TABLE_NOT_FOUND",
2151
+ message: `Table '${tableName}' not found`
2152
+ }
2153
+ };
2154
+ }
2155
+ const apiRequest = this.transformColumnQueryToApiRequest(options);
2156
+ const result = await this.columnsApiClient.listColumns(
2157
+ tableInfo.id,
2158
+ apiRequest
2159
+ );
2160
+ if (isErrorResponse(result)) {
2161
+ return result;
2162
+ }
2163
+ return result;
2164
+ } catch (error) {
2165
+ return {
2166
+ data: {},
2167
+ error: {
2168
+ code: "LIST_COLUMNS_ERROR",
2169
+ message: error instanceof Error ? error.message : "Unknown error occurred"
2170
+ }
2171
+ };
2172
+ }
2173
+ }
2174
+ /**
2175
+ * Get a single column by name
2176
+ */
2177
+ async get(tableName, columnName) {
2178
+ try {
2179
+ const tableInfo = await this.getTableInfo(tableName);
2180
+ if (!tableInfo) {
2181
+ return {
2182
+ data: {},
2183
+ error: {
2184
+ code: "TABLE_NOT_FOUND",
2185
+ message: `Table '${tableName}' not found`
2186
+ }
2187
+ };
2188
+ }
2189
+ const result = await this.columnsApiClient.findColumnByName(
2190
+ tableInfo.id,
2191
+ columnName
2192
+ );
2193
+ if (isErrorResponse(result)) {
2194
+ return result;
2195
+ }
2196
+ if (!result.data) {
2197
+ return {
2198
+ data: {},
2199
+ error: {
2200
+ code: "COLUMN_NOT_FOUND",
2201
+ message: `Column '${columnName}' not found in table '${tableName}'`
2202
+ }
2203
+ };
2204
+ }
2205
+ return {
2206
+ data: result.data,
2207
+ message: "Column found successfully"
2208
+ };
2209
+ } catch (error) {
2210
+ return {
2211
+ data: {},
2212
+ error: {
2213
+ code: "GET_COLUMN_ERROR",
2214
+ message: error instanceof Error ? error.message : "Unknown error occurred"
2215
+ }
2216
+ };
2217
+ }
2218
+ }
2219
+ async findById(tableName, columnId) {
2220
+ try {
2221
+ const tableInfo = await this.getTableInfo(tableName);
2222
+ if (!tableInfo) {
2223
+ return {
2224
+ data: {},
2225
+ error: {
2226
+ code: "TABLE_NOT_FOUND",
2227
+ message: `Table '${tableName}' not found`
2228
+ }
2229
+ };
2230
+ }
2231
+ const result = await this.columnsApiClient.getColumn(
2232
+ tableInfo.id,
2233
+ columnId
2234
+ );
2235
+ if (isErrorResponse(result)) {
2236
+ return result;
2237
+ }
2238
+ return result;
2239
+ } catch (error) {
2240
+ return {
2241
+ data: {},
2242
+ error: {
2243
+ code: "FIND_COLUMN_BY_ID_ERROR",
2244
+ message: error instanceof Error ? error.message : "Unknown error occurred"
2245
+ }
2246
+ };
2247
+ }
2248
+ }
2249
+ /**
2250
+ * Update a column by name
2251
+ */
2252
+ async update(tableName, columnName, updates) {
2253
+ try {
2254
+ const tableInfo = await this.getTableInfo(tableName);
2255
+ if (!tableInfo) {
2256
+ return {
2257
+ data: {},
2258
+ error: {
2259
+ code: "TABLE_NOT_FOUND",
2260
+ message: `Table '${tableName}' not found`
2261
+ }
2262
+ };
2263
+ }
2264
+ if (tableInfo.snapshot_url) {
2265
+ return {
2266
+ data: {},
2267
+ error: {
2268
+ code: "SNAPSHOT_PROTECTION",
2269
+ message: `Cannot update column '${columnName}' in snapshot table '${tableName}'. Snapshots are read-only and cannot be modified.`
2270
+ }
2271
+ };
2272
+ }
2273
+ const result = await this.columnsApiClient.updateColumnByName(
2274
+ tableInfo.id,
2275
+ columnName,
2276
+ updates
2277
+ );
2278
+ if (isErrorResponse(result)) {
2279
+ return result;
2280
+ }
2281
+ return result;
2282
+ } catch (error) {
2283
+ return {
2284
+ data: {},
2285
+ error: {
2286
+ code: "UPDATE_COLUMN_ERROR",
2287
+ message: error instanceof Error ? error.message : "Unknown error occurred"
2288
+ }
2289
+ };
2290
+ }
2291
+ }
2292
+ /**
2293
+ * Delete a column by name
2294
+ */
2295
+ async delete(tableName, columnName) {
2296
+ try {
2297
+ const tableInfo = await this.getTableInfo(tableName);
2298
+ if (!tableInfo) {
2299
+ return {
2300
+ data: {},
2301
+ error: {
2302
+ code: "TABLE_NOT_FOUND",
2303
+ message: `Table '${tableName}' not found`
2304
+ }
2305
+ };
2306
+ }
2307
+ if (tableInfo.snapshot_url) {
2308
+ return {
2309
+ data: {},
2310
+ error: {
2311
+ code: "SNAPSHOT_PROTECTION",
2312
+ message: `Cannot delete column '${columnName}' from snapshot table '${tableName}'. Snapshots are read-only and cannot be modified.`
2313
+ }
2314
+ };
2315
+ }
2316
+ const result = await this.columnsApiClient.deleteColumnByName(
2317
+ tableInfo.id,
2318
+ columnName
2319
+ );
2320
+ if (isErrorResponse(result)) {
2321
+ return result;
2322
+ }
2323
+ return {
2324
+ data: {
2325
+ success: true,
2326
+ message: "Column deleted successfully"
2327
+ }
2328
+ };
2329
+ } catch (error) {
2330
+ return {
2331
+ data: {},
2332
+ error: {
2333
+ code: "DELETE_COLUMN_ERROR",
2334
+ message: error instanceof Error ? error.message : "Unknown error occurred"
2335
+ }
2336
+ };
2337
+ }
2338
+ }
2339
+ /**
2340
+ * Helper method to get table information by name
2341
+ */
2342
+ async getTableInfo(tableName) {
2343
+ try {
2344
+ const tableResource = new TableResource(this.client);
2345
+ const tableResult = await tableResource.findByName(tableName);
2346
+ if (tableResult.data) {
2347
+ return {
2348
+ id: tableResult.data.id,
2349
+ snapshot_url: tableResult.data.snapshot_url
2350
+ };
2351
+ }
2352
+ return null;
2353
+ } catch (error) {
2354
+ console.error("Error getting table info:", error);
2355
+ return null;
2356
+ }
2357
+ }
2358
+ /**
2359
+ * Helper method to get table ID by name (deprecated, use getTableInfo instead)
2360
+ */
2361
+ async getTableId(tableName) {
2362
+ const tableInfo = await this.getTableInfo(tableName);
2363
+ return (tableInfo == null ? void 0 : tableInfo.id) || null;
2364
+ }
2365
+ }
2366
+ const RECORD_ENDPOINTS = {
2367
+ insert: {
2368
+ path: "/tables/{table_id}/records",
2369
+ method: "POST",
2370
+ authenticated: true
2371
+ },
2372
+ list: {
2373
+ path: "/tables/{table_id}/records/list",
2374
+ method: "POST",
2375
+ authenticated: true,
2376
+ rateLimit: { requests: 200, window: 6e4 }
2377
+ },
2378
+ get: {
2379
+ path: "/tables/{table_id}/records/{record_id}",
2380
+ method: "GET",
2381
+ authenticated: true,
2382
+ rateLimit: { requests: 200, window: 6e4 }
2383
+ },
2384
+ update: {
2385
+ path: "/tables/{table_id}/records",
2386
+ method: "PATCH",
2387
+ authenticated: true
2388
+ },
2389
+ updateById: {
2390
+ path: "/tables/{table_id}/records/{record_id}",
2391
+ method: "PATCH",
2392
+ authenticated: true
2393
+ },
2394
+ delete: {
2395
+ path: "/tables/{table_id}/records/list",
2396
+ method: "DELETE",
2397
+ authenticated: true
2398
+ }
2399
+ };
2400
+ const buildRecordEndpointPath = (endpoint, params = {}) => {
2401
+ let path = endpoint.path;
2402
+ Object.entries(params).forEach(([key, value]) => {
2403
+ path = path.replace(`{${key}}`, encodeURIComponent(value));
2404
+ });
2405
+ const unreplacedParams = path.match(/\{([^}]+)\}/g);
2406
+ if (unreplacedParams) {
2407
+ throw new Error(`Missing path parameters: ${unreplacedParams.join(", ")}`);
2408
+ }
2409
+ return path;
2410
+ };
2411
+ function transformDeleteRequest(sdkRequest) {
2412
+ const result = {};
2413
+ if (sdkRequest.record_ids && sdkRequest.record_ids.length > 0) {
2414
+ result.record_ids = sdkRequest.record_ids;
2415
+ }
2416
+ if (sdkRequest.filters) {
2417
+ if (Array.isArray(sdkRequest.filters)) {
2418
+ if (sdkRequest.filters.length > 0 && typeof sdkRequest.filters[0] === "object" && "field" in sdkRequest.filters[0] && "operator" in sdkRequest.filters[0] && "values" in sdkRequest.filters[0]) {
2419
+ result.filters = sdkRequest.filters;
2420
+ } else {
2421
+ console.warn(
2422
+ "Legacy Record<string, unknown>[] filter format detected. Please migrate to the new filter format."
2423
+ );
2424
+ result.filters = sdkRequest.filters;
2425
+ }
2426
+ } else {
2427
+ result.filters = mapWhereToFilters(sdkRequest.filters);
2428
+ }
2429
+ }
2430
+ return result;
2431
+ }
2432
+ class RecordsApiClient {
2433
+ constructor(apiKey, config = {}) {
2434
+ this.config = { apiKey, ...config };
2435
+ this.httpAdapter = createHttpAdapter();
2436
+ const environment = config.environment || "prod";
2437
+ const region = config.region || "asia-south1";
2438
+ this.baseURL = this.getBaseURL(environment, region);
2439
+ }
2440
+ getBaseURL(environment, region) {
2441
+ const regionConfig = REGION_CONFIGS[region];
2442
+ if (!regionConfig) {
2443
+ throw new Error(`Unsupported region: ${region}`);
2444
+ }
2445
+ const envConfig = regionConfig[environment];
2446
+ if (!envConfig) {
2447
+ throw new Error(
2448
+ `Unsupported environment: ${environment} for region: ${region}`
2449
+ );
2450
+ }
2451
+ return `${envConfig.baseURL}/v1`;
2452
+ }
2453
+ /**
2454
+ * Insert a single record
2455
+ */
2456
+ async insertRecord(request) {
2457
+ try {
2458
+ const { table_id, fields, ...recordData } = request;
2459
+ if (!table_id) {
2460
+ return this.formatErrorResponse(
2461
+ new Error("table_id is required for insert operation")
2462
+ );
2463
+ }
2464
+ const endpoint = RECORD_ENDPOINTS.insert;
2465
+ const url = `${this.baseURL}${buildRecordEndpointPath(endpoint, { table_id })}`;
2466
+ const response = await this.httpAdapter.request({
2467
+ url,
2468
+ method: endpoint.method,
2469
+ headers: this.buildHeaders(),
2470
+ data: recordData,
2471
+ timeout: this.config.timeout
2472
+ });
2473
+ const responseData = response.data;
2474
+ if (fields && responseData.data) {
2475
+ responseData.data = filterObjectFields(
2476
+ responseData.data,
2477
+ fields
2478
+ );
2479
+ }
2480
+ return responseData;
2481
+ } catch (error) {
2482
+ return this.formatErrorResponse(error);
2483
+ }
2484
+ }
2485
+ /**
2486
+ * Get a single record by ID
2487
+ */
2488
+ async getRecord(recordId, tableId, options = {}) {
2489
+ try {
2490
+ if (!tableId) {
2491
+ return this.formatErrorResponse(
2492
+ new Error("table_id is required for get operation")
2493
+ );
2494
+ }
2495
+ const endpoint = RECORD_ENDPOINTS.get;
2496
+ const url = `${this.baseURL}${buildRecordEndpointPath(endpoint, {
2497
+ table_id: tableId,
2498
+ record_id: recordId
2499
+ })}`;
2500
+ const response = await this.httpAdapter.request({
2501
+ url,
2502
+ method: endpoint.method,
2503
+ headers: this.buildHeaders(),
2504
+ timeout: this.config.timeout
2505
+ });
2506
+ const responseData = response.data;
2507
+ if (options.fields && responseData.data) {
2508
+ responseData.data = filterObjectFields(
2509
+ responseData.data,
2510
+ options.fields
2511
+ );
2512
+ }
2513
+ return responseData;
2514
+ } catch (error) {
2515
+ return this.formatErrorResponse(error);
2516
+ }
2517
+ }
2518
+ /**
2519
+ * List records with filtering and pagination
2520
+ */
2521
+ async listRecords(options = {}) {
2522
+ try {
2523
+ const { table_id, ...queryOptions } = options;
2524
+ if (!table_id) {
2525
+ return this.formatErrorResponse(
2526
+ new Error("table_id is required for list operation")
2527
+ );
2528
+ }
2529
+ const endpoint = RECORD_ENDPOINTS.list;
2530
+ const url = `${this.baseURL}${buildRecordEndpointPath(endpoint, { table_id })}`;
2531
+ const response = await this.httpAdapter.request({
2532
+ url,
2533
+ method: endpoint.method,
2534
+ headers: this.buildHeaders(),
2535
+ data: queryOptions,
2536
+ timeout: this.config.timeout
2537
+ });
2538
+ const responseData = response.data;
2539
+ if (queryOptions.fields && responseData.data) {
2540
+ responseData.data = filterArrayFields(
2541
+ responseData.data,
2542
+ queryOptions.fields
2543
+ );
2544
+ }
2545
+ return responseData;
2546
+ } catch (error) {
2547
+ return this.formatErrorResponse(error);
2548
+ }
2549
+ }
2550
+ /**
2551
+ * Update records by filters
2552
+ */
2553
+ async updateRecords(request) {
2554
+ try {
2555
+ const { table_id, ...updateOptions } = request;
2556
+ if (!table_id) {
2557
+ return this.formatErrorResponse(
2558
+ new Error("table_id is required for update operation")
2559
+ );
2560
+ }
2561
+ const endpoint = RECORD_ENDPOINTS.update;
2562
+ const url = `${this.baseURL}${buildRecordEndpointPath(endpoint, { table_id })}`;
2563
+ const response = await this.httpAdapter.request({
2564
+ url,
2565
+ method: endpoint.method,
2566
+ headers: this.buildHeaders(),
2567
+ data: updateOptions,
2568
+ timeout: this.config.timeout
2569
+ });
2570
+ const responseData = response.data;
2571
+ if (updateOptions.fields && responseData.data) {
2572
+ responseData.data = filterArrayFields(
2573
+ responseData.data,
2574
+ updateOptions.fields
2575
+ );
2576
+ }
2577
+ return responseData;
2578
+ } catch (error) {
2579
+ return this.formatErrorResponse(error);
2580
+ }
2581
+ }
2582
+ /**
2583
+ * Update a single record by ID
2584
+ */
2585
+ async updateRecordById(recordId, request) {
2586
+ try {
2587
+ const { table_id, ...updateOptions } = request;
2588
+ if (!table_id) {
2589
+ return this.formatErrorResponse(
2590
+ new Error("table_id is required for updateById operation")
2591
+ );
2592
+ }
2593
+ const endpoint = RECORD_ENDPOINTS.updateById;
2594
+ const url = `${this.baseURL}${buildRecordEndpointPath(endpoint, {
2595
+ record_id: recordId,
2596
+ table_id
2597
+ })}`;
2598
+ const response = await this.httpAdapter.request({
2599
+ url,
2600
+ method: endpoint.method,
2601
+ headers: this.buildHeaders(),
2602
+ data: updateOptions.set,
2603
+ timeout: this.config.timeout
2604
+ });
2605
+ const responseData = response.data;
2606
+ if (updateOptions.fields && responseData.data) {
2607
+ responseData.data = filterObjectFields(
2608
+ responseData.data,
2609
+ updateOptions.fields
2610
+ );
2611
+ }
2612
+ return responseData;
2613
+ } catch (error) {
2614
+ return this.formatErrorResponse(error);
2615
+ }
2616
+ }
2617
+ /**
2618
+ * Unified delete records method that supports both record_ids and filters
2619
+ */
2620
+ async deleteRecords(request) {
2621
+ try {
2622
+ const { table_id } = request;
2623
+ if (!table_id) {
2624
+ return this.formatErrorResponse(
2625
+ new Error("table_id is required for delete operation")
2626
+ );
2627
+ }
2628
+ const transformedRequest = transformDeleteRequest(request);
2629
+ const endpoint = RECORD_ENDPOINTS.delete;
2630
+ const url = `${this.baseURL}${buildRecordEndpointPath(endpoint, { table_id })}`;
2631
+ const response = await this.httpAdapter.request({
2632
+ url,
2633
+ method: endpoint.method,
2634
+ headers: this.buildHeaders(),
2635
+ data: transformedRequest,
2636
+ timeout: this.config.timeout
2637
+ });
2638
+ return response.data;
2639
+ } catch (error) {
2640
+ return this.formatErrorResponse(error);
2641
+ }
2642
+ }
2643
+ /**
2644
+ * Delete a single record by ID
2645
+ */
2646
+ async deleteRecordById(recordId, request) {
2647
+ return this.deleteRecords({
2648
+ record_ids: [recordId],
2649
+ table_id: request.table_id
2650
+ });
2651
+ }
2652
+ buildHeaders() {
2653
+ return {
2654
+ "Content-Type": "application/json",
2655
+ Accept: "application/json",
2656
+ "x-boltic-token": this.config.apiKey
2657
+ };
2658
+ }
2659
+ formatErrorResponse(error) {
2660
+ var _a, _b, _c;
2661
+ if (this.config.debug) {
2662
+ console.error("Records API Error:", error);
2663
+ }
2664
+ if (error && typeof error === "object" && "response" in error) {
2665
+ const apiError = error;
2666
+ if ((_b = (_a = apiError.response) == null ? void 0 : _a.data) == null ? void 0 : _b.error) {
2667
+ return apiError.response.data;
2668
+ }
2669
+ return {
2670
+ data: {},
2671
+ error: {
2672
+ code: "API_ERROR",
2673
+ message: error.message || "Unknown API error",
2674
+ meta: [`Status: ${((_c = apiError.response) == null ? void 0 : _c.status) || "unknown"}`]
2675
+ }
2676
+ };
2677
+ }
2678
+ if (error && typeof error === "object" && "message" in error) {
2679
+ return {
2680
+ data: {},
2681
+ error: {
2682
+ code: "CLIENT_ERROR",
2683
+ message: error.message,
2684
+ meta: ["Client-side error occurred"]
2685
+ }
2686
+ };
2687
+ }
2688
+ return {
2689
+ data: {},
2690
+ error: {
2691
+ code: "UNKNOWN_ERROR",
2692
+ message: "An unexpected error occurred",
2693
+ meta: ["Unknown error type"]
2694
+ }
2695
+ };
2696
+ }
2697
+ }
2698
+ class RecordResource {
2699
+ constructor(client) {
2700
+ this.client = client;
2701
+ this.apiClient = new RecordsApiClient(client.getConfig().apiKey, {
2702
+ environment: client.getConfig().environment,
2703
+ timeout: client.getConfig().timeout,
2704
+ debug: client.getConfig().debug
2705
+ });
2706
+ this.tablesApiClient = new TablesApiClient(client.getConfig().apiKey, {
2707
+ environment: client.getConfig().environment,
2708
+ timeout: client.getConfig().timeout,
2709
+ debug: client.getConfig().debug
2710
+ });
2711
+ }
2712
+ /**
2713
+ * Insert a single record
2714
+ */
2715
+ async insert(tableName, data) {
2716
+ try {
2717
+ const tableInfo = await this.getTableInfo(tableName);
2718
+ if (!tableInfo) {
2719
+ return {
2720
+ data: {},
2721
+ error: {
2722
+ code: "TABLE_NOT_FOUND",
2723
+ message: `Table '${tableName}' not found`
2724
+ }
2725
+ };
2726
+ }
2727
+ if (tableInfo.snapshot_url) {
2728
+ return {
2729
+ data: {},
2730
+ error: {
2731
+ code: "SNAPSHOT_PROTECTION",
2732
+ message: `Cannot insert record into snapshot table '${tableName}'. Snapshots are read-only and cannot be modified.`
2733
+ }
2734
+ };
2735
+ }
2736
+ const completeDataResult = await this.ensureCompleteRecordData(
2737
+ tableName,
2738
+ data
2739
+ );
2740
+ if ("error" in completeDataResult && completeDataResult.error) {
2741
+ return completeDataResult;
2742
+ }
2743
+ const requestData = {
2744
+ ...completeDataResult,
2745
+ table_id: tableInfo.id
2746
+ };
2747
+ const result = await this.apiClient.insertRecord(requestData);
2748
+ if (isErrorResponse(result)) {
2749
+ return result;
2750
+ }
2751
+ return result;
2752
+ } catch (error) {
2753
+ return {
2754
+ data: {},
2755
+ error: {
2756
+ code: "INSERT_ERROR",
2757
+ message: error instanceof Error ? error.message : "Unknown error occurred"
2758
+ }
2759
+ };
2760
+ }
2761
+ }
2762
+ /**
2763
+ * Get a single record by ID
2764
+ */
2765
+ async get(tableName, recordId) {
2766
+ try {
2767
+ const tableInfo = await this.getTableInfo(tableName);
2768
+ if (!tableInfo) {
2769
+ return {
2770
+ data: {},
2771
+ error: {
2772
+ code: "TABLE_NOT_FOUND",
2773
+ message: `Table '${tableName}' not found`
2774
+ }
2775
+ };
2776
+ }
2777
+ const result = await this.apiClient.getRecord(recordId, tableInfo.id);
2778
+ if (isErrorResponse(result)) {
2779
+ return result;
2780
+ }
2781
+ return result;
2782
+ } catch (error) {
2783
+ return {
2784
+ data: {},
2785
+ error: {
2786
+ code: "GET_ERROR",
2787
+ message: error instanceof Error ? error.message : "Unknown error occurred"
2788
+ }
2789
+ };
2790
+ }
2791
+ }
2792
+ /**
2793
+ * List records with filtering and pagination
2794
+ */
2795
+ async list(tableName, options = {}) {
2796
+ try {
2797
+ const tableInfo = await this.getTableInfo(tableName);
2798
+ if (!tableInfo) {
2799
+ return {
2800
+ data: {},
2801
+ error: {
2802
+ code: "TABLE_NOT_FOUND",
2803
+ message: `Table '${tableName}' not found`
2804
+ }
2805
+ };
2806
+ }
2807
+ const requestOptions = { ...options, table_id: tableInfo.id };
2808
+ const result = await this.apiClient.listRecords(requestOptions);
2809
+ if (isErrorResponse(result)) {
2810
+ return result;
2811
+ }
2812
+ return result;
2813
+ } catch (error) {
2814
+ return {
2815
+ data: {},
2816
+ error: {
2817
+ code: "LIST_ERROR",
2818
+ message: error instanceof Error ? error.message : "Unknown error occurred"
2819
+ }
2820
+ };
2821
+ }
2822
+ }
2823
+ /**
2824
+ * Update records by filters
2825
+ */
2826
+ async update(tableName, options) {
2827
+ try {
2828
+ const tableInfo = await this.getTableInfo(tableName);
2829
+ if (!tableInfo) {
2830
+ return {
2831
+ data: {},
2832
+ error: {
2833
+ code: "TABLE_NOT_FOUND",
2834
+ message: `Table '${tableName}' not found`
2835
+ }
2836
+ };
2837
+ }
2838
+ if (tableInfo.snapshot_url) {
2839
+ return {
2840
+ data: {},
2841
+ error: {
2842
+ code: "SNAPSHOT_PROTECTION",
2843
+ message: `Cannot update records in snapshot table '${tableName}'. Snapshots are read-only and cannot be modified.`
2844
+ }
2845
+ };
2846
+ }
2847
+ const requestOptions = { ...options, table_id: tableInfo.id };
2848
+ const result = await this.apiClient.updateRecords(requestOptions);
2849
+ if (isErrorResponse(result)) {
2850
+ return result;
2851
+ }
2852
+ return result;
2853
+ } catch (error) {
2854
+ return {
2855
+ data: {},
2856
+ error: {
2857
+ code: "UPDATE_ERROR",
2858
+ message: error instanceof Error ? error.message : "Unknown error occurred"
2859
+ }
2860
+ };
2861
+ }
2862
+ }
2863
+ /**
2864
+ * Update a single record by ID
2865
+ */
2866
+ async updateById(tableName, recordId, data) {
2867
+ try {
2868
+ const tableInfo = await this.getTableInfo(tableName);
2869
+ if (!tableInfo) {
2870
+ return {
2871
+ data: {},
2872
+ error: {
2873
+ code: "TABLE_NOT_FOUND",
2874
+ message: `Table '${tableName}' not found`
2875
+ }
2876
+ };
2877
+ }
2878
+ if (tableInfo.snapshot_url) {
2879
+ return {
2880
+ data: {},
2881
+ error: {
2882
+ code: "SNAPSHOT_PROTECTION",
2883
+ message: `Cannot update record in snapshot table '${tableName}'. Snapshots are read-only and cannot be modified.`
2884
+ }
2885
+ };
2886
+ }
2887
+ const requestOptions = {
2888
+ id: recordId,
2889
+ set: data,
2890
+ table_id: tableInfo.id
2891
+ };
2892
+ const result = await this.apiClient.updateRecordById(
2893
+ recordId,
2894
+ requestOptions
2895
+ );
2896
+ if (isErrorResponse(result)) {
2897
+ return result;
2898
+ }
2899
+ return result;
2900
+ } catch (error) {
2901
+ return {
2902
+ data: {},
2903
+ error: {
2904
+ code: "UPDATE_BY_ID_ERROR",
2905
+ message: error instanceof Error ? error.message : "Unknown error occurred"
2906
+ }
2907
+ };
2908
+ }
2909
+ }
2910
+ /**
2911
+ * Unified delete method that supports both record IDs and filters
2912
+ */
2913
+ async delete(tableName, options) {
2914
+ try {
2915
+ const tableInfo = await this.getTableInfo(tableName);
2916
+ if (!tableInfo) {
2917
+ return {
2918
+ data: {},
2919
+ error: {
2920
+ code: "TABLE_NOT_FOUND",
2921
+ message: `Table '${tableName}' not found`
2922
+ }
2923
+ };
2924
+ }
2925
+ if (tableInfo.snapshot_url) {
2926
+ return {
2927
+ data: {},
2928
+ error: {
2929
+ code: "SNAPSHOT_PROTECTION",
2930
+ message: `Cannot delete records from snapshot table '${tableName}'. Snapshots are read-only and cannot be modified.`
2931
+ }
2932
+ };
2933
+ }
2934
+ const requestOptions = { ...options, table_id: tableInfo.id };
2935
+ const result = await this.apiClient.deleteRecords(requestOptions);
2936
+ if (isErrorResponse(result)) {
2937
+ return result;
2938
+ }
2939
+ return result;
2940
+ } catch (error) {
2941
+ return {
2942
+ data: {},
2943
+ error: {
2944
+ code: "DELETE_ERROR",
2945
+ message: error instanceof Error ? error.message : "Unknown error occurred"
2946
+ }
2947
+ };
2948
+ }
2949
+ }
2950
+ /**
2951
+ * Delete a single record by ID
2952
+ */
2953
+ async deleteById(tableName, recordId) {
2954
+ try {
2955
+ const tableInfo = await this.getTableInfo(tableName);
2956
+ if (!tableInfo) {
2957
+ return {
2958
+ data: {},
2959
+ error: {
2960
+ code: "TABLE_NOT_FOUND",
2961
+ message: `Table '${tableName}' not found`
2962
+ }
2963
+ };
2964
+ }
2965
+ if (tableInfo.snapshot_url) {
2966
+ return {
2967
+ data: {},
2968
+ error: {
2969
+ code: "SNAPSHOT_PROTECTION",
2970
+ message: `Cannot delete record from snapshot table '${tableName}'. Snapshots are read-only and cannot be modified.`
2971
+ }
2972
+ };
2973
+ }
2974
+ const result = await this.apiClient.deleteRecordById(recordId, {
2975
+ table_id: tableInfo.id
2976
+ });
2977
+ if (isErrorResponse(result)) {
2978
+ return result;
2979
+ }
2980
+ return result;
2981
+ } catch (error) {
2982
+ return {
2983
+ data: {},
2984
+ error: {
2985
+ code: "DELETE_BY_ID_ERROR",
2986
+ message: error instanceof Error ? error.message : "Unknown error occurred"
2987
+ }
2988
+ };
2989
+ }
2990
+ }
2991
+ /**
2992
+ * Helper method to get table information by name
2993
+ */
2994
+ async getTableInfo(tableName) {
2995
+ try {
2996
+ const tableResource = new TableResource(this.client);
2997
+ const tableResult = await tableResource.findByName(tableName);
2998
+ if (tableResult.data) {
2999
+ return {
3000
+ id: tableResult.data.id,
3001
+ snapshot_url: tableResult.data.snapshot_url
3002
+ };
3003
+ }
3004
+ return null;
3005
+ } catch (error) {
3006
+ console.error("Error getting table info:", error);
3007
+ return null;
3008
+ }
3009
+ }
3010
+ /**
3011
+ * Helper method to ensure all required fields for a record are present,
3012
+ * filling missing ones with null.
3013
+ */
3014
+ async ensureCompleteRecordData(tableName, data) {
3015
+ try {
3016
+ const columnResource = new ColumnResource(this.client);
3017
+ const columnsResult = await columnResource.findAll(tableName);
3018
+ if (isErrorResponse(columnsResult)) {
3019
+ return columnsResult;
3020
+ }
3021
+ const columns = Array.isArray(columnsResult.data) ? columnsResult.data : [];
3022
+ const completeData = { ...data };
3023
+ for (const column of columns) {
3024
+ if (column.name === "id" || column.name === "created_at" || column.name === "updated_at") {
3025
+ continue;
3026
+ }
3027
+ if (!(column.name in data)) {
3028
+ completeData[column.name] = null;
3029
+ }
3030
+ }
3031
+ return completeData;
3032
+ } catch (error) {
3033
+ return {
3034
+ data: {},
3035
+ error: {
3036
+ code: "COMPLETE_DATA_ERROR",
3037
+ message: error instanceof Error ? error.message : "Unknown error occurred"
3038
+ }
3039
+ };
3040
+ }
3041
+ }
3042
+ }
3043
+ class RecordBuilder {
3044
+ constructor(options) {
3045
+ this.queryOptions = {};
3046
+ this.updateData = {};
3047
+ this.tableName = options.tableName;
3048
+ this.recordResource = options.recordResource;
3049
+ }
3050
+ /**
3051
+ * Add filter conditions
3052
+ */
3053
+ where(conditions) {
3054
+ if (!this.queryOptions.filters) {
3055
+ this.queryOptions.filters = [];
3056
+ }
3057
+ Object.entries(conditions).forEach(([field, value]) => {
3058
+ this.queryOptions.filters.push({
3059
+ field,
3060
+ operator: "equals",
3061
+ values: [value]
3062
+ });
3063
+ });
3064
+ return this;
3065
+ }
3066
+ /**
3067
+ * Set sorting
3068
+ */
3069
+ orderBy(field, direction = "asc") {
3070
+ if (!this.queryOptions.sort) {
3071
+ this.queryOptions.sort = [];
3072
+ }
3073
+ this.queryOptions.sort.push({ field, order: direction });
3074
+ return this;
3075
+ }
3076
+ /**
3077
+ * Set limit (using page)
3078
+ */
3079
+ limit(count) {
3080
+ if (!this.queryOptions.page) {
3081
+ this.queryOptions.page = { page_no: 1, page_size: count };
3082
+ } else {
3083
+ this.queryOptions.page.page_size = count;
3084
+ }
3085
+ return this;
3086
+ }
3087
+ /**
3088
+ * Set offset (using page)
3089
+ */
3090
+ offset(count) {
3091
+ if (!this.queryOptions.page) {
3092
+ this.queryOptions.page = {
3093
+ page_no: Math.floor(count / 50) + 1,
3094
+ page_size: 50
3095
+ };
3096
+ } else {
3097
+ const pageSize = this.queryOptions.page.page_size || 50;
3098
+ this.queryOptions.page.page_no = Math.floor(count / pageSize) + 1;
3099
+ }
3100
+ return this;
3101
+ }
3102
+ /**
3103
+ * Set fields to select
3104
+ */
3105
+ select(fields) {
3106
+ this.queryOptions.fields = fields;
3107
+ return this;
3108
+ }
3109
+ /**
3110
+ * Set data for update operations
3111
+ */
3112
+ set(data) {
3113
+ this.updateData = { ...this.updateData, ...data };
3114
+ return this;
3115
+ }
3116
+ /**
3117
+ * Set pagination
3118
+ */
3119
+ page(pageNo, pageSize = 50) {
3120
+ this.queryOptions.page = {
3121
+ page_no: pageNo,
3122
+ page_size: pageSize
3123
+ };
3124
+ return this;
3125
+ }
3126
+ /**
3127
+ * Execute list operation (was findAll)
3128
+ */
3129
+ async list() {
3130
+ return this.recordResource.list(this.tableName, this.queryOptions);
3131
+ }
3132
+ /**
3133
+ * Execute findAll operation (alias for list)
3134
+ */
3135
+ async findAll() {
3136
+ return this.recordResource.list(this.tableName, this.queryOptions);
3137
+ }
3138
+ /**
3139
+ * Execute findOne operation by getting first result from list
3140
+ */
3141
+ async findOne() {
3142
+ const queryOptions = { ...this.queryOptions, limit: 1 };
3143
+ const result = await this.recordResource.list(this.tableName, queryOptions);
3144
+ if ("error" in result) {
3145
+ return result;
3146
+ }
3147
+ const record = result.data.length > 0 ? result.data[0] : null;
3148
+ return {
3149
+ data: record,
3150
+ message: record ? "Record found" : "No record found"
3151
+ };
3152
+ }
3153
+ /**
3154
+ * Build where conditions from filters for API consumption
3155
+ */
3156
+ buildWhereConditions() {
3157
+ const where = {};
3158
+ if (this.queryOptions.filters) {
3159
+ this.queryOptions.filters.forEach((filter) => {
3160
+ if ("field" in filter && "values" in filter) {
3161
+ const apiFilter = filter;
3162
+ const fieldName = String(apiFilter.field);
3163
+ if (apiFilter.operator === "equals") {
3164
+ where[fieldName] = apiFilter.values[0];
3165
+ } else if (apiFilter.operator === "contains") {
3166
+ where[fieldName] = { $like: `%${String(apiFilter.values[0])}%` };
3167
+ } else {
3168
+ where[fieldName] = apiFilter.values[0];
3169
+ }
3170
+ } else {
3171
+ Object.assign(where, filter);
3172
+ }
3173
+ });
3174
+ }
3175
+ return where;
3176
+ }
3177
+ /**
3178
+ * Execute update operation - requires filters or record IDs
3179
+ */
3180
+ async update() {
3181
+ if (!this.updateData) {
3182
+ return {
3183
+ data: [],
3184
+ error: {
3185
+ code: "MISSING_UPDATE_DATA",
3186
+ message: "Update data is required for update operation"
3187
+ }
3188
+ };
3189
+ }
3190
+ const updateOptions = {
3191
+ set: this.updateData,
3192
+ filters: this.queryOptions.filters || []
3193
+ };
3194
+ return this.recordResource.update(this.tableName, updateOptions);
3195
+ }
3196
+ /**
3197
+ * Execute update by ID operation
3198
+ */
3199
+ async updateById(id) {
3200
+ return this.recordResource.updateById(this.tableName, id, this.updateData);
3201
+ }
3202
+ /**
3203
+ * Execute delete by single ID operation
3204
+ */
3205
+ async deleteById(id) {
3206
+ return this.recordResource.deleteById(this.tableName, id);
3207
+ }
3208
+ /**
3209
+ * Execute delete by IDs operation
3210
+ */
3211
+ async deleteByIds(ids) {
3212
+ return this.recordResource.delete(this.tableName, { record_ids: ids });
3213
+ }
3214
+ /**
3215
+ * Execute delete operation using filters
3216
+ */
3217
+ async delete() {
3218
+ if (!this.queryOptions.filters || this.queryOptions.filters.length === 0) {
3219
+ return {
3220
+ data: {},
3221
+ error: {
3222
+ code: "MISSING_DELETE_CONDITIONS",
3223
+ message: "Filter conditions are required for delete operation. Use where() to specify conditions."
3224
+ }
3225
+ };
3226
+ }
3227
+ const deleteOptions = {
3228
+ filters: this.buildWhereConditions()
3229
+ };
3230
+ return this.recordResource.delete(this.tableName, deleteOptions);
3231
+ }
3232
+ /**
3233
+ * Get the built query options (for debugging)
3234
+ */
3235
+ getQueryOptions() {
3236
+ return { ...this.queryOptions };
3237
+ }
3238
+ /**
3239
+ * Get the update data (for debugging)
3240
+ */
3241
+ getUpdateData() {
3242
+ return { ...this.updateData };
3243
+ }
3244
+ /**
3245
+ * Execute insert operation
3246
+ */
3247
+ async insert(data) {
3248
+ return this.recordResource.insert(this.tableName, data);
3249
+ }
3250
+ }
3251
+ function createRecordBuilder(options) {
3252
+ return new RecordBuilder(options);
3253
+ }
3254
+ const SQL_ENDPOINTS = {
3255
+ textToSQL: {
3256
+ path: "/tables/query/text-to-sql",
3257
+ method: "POST",
3258
+ authenticated: true,
3259
+ rateLimit: { requests: 100, window: 6e4 }
3260
+ // Limited due to AI processing
3261
+ },
3262
+ executeSQL: {
3263
+ path: "/tables/query/execute",
3264
+ method: "POST",
3265
+ authenticated: true,
3266
+ rateLimit: { requests: 200, window: 6e4 }
3267
+ }
3268
+ };
3269
+ const buildSqlEndpointPath = (endpoint, params = {}) => {
3270
+ let path = endpoint.path;
3271
+ Object.entries(params).forEach(([key, value]) => {
3272
+ path = path.replace(`{${key}}`, encodeURIComponent(value));
3273
+ });
3274
+ return path;
3275
+ };
3276
+ class BaseApiClient {
3277
+ constructor(apiKey, config = {}) {
3278
+ this.config = { apiKey, ...config };
3279
+ this.httpAdapter = createHttpAdapter();
3280
+ const environment = config.environment || "prod";
3281
+ const region = config.region || "asia-south1";
3282
+ this.baseURL = this.getBaseURL(environment, region);
3283
+ }
3284
+ getBaseURL(environment, region) {
3285
+ const regionConfig = REGION_CONFIGS[region];
3286
+ if (!regionConfig) {
3287
+ throw new Error(`Unsupported region: ${region}`);
3288
+ }
3289
+ const envConfig = regionConfig[environment];
3290
+ if (!envConfig) {
3291
+ throw new Error(
3292
+ `Unsupported environment: ${environment} for region: ${region}`
3293
+ );
3294
+ }
3295
+ return `${envConfig.baseURL}/v1`;
3296
+ }
3297
+ buildHeaders() {
3298
+ return {
3299
+ "Content-Type": "application/json",
3300
+ Accept: "application/json",
3301
+ "x-boltic-token": this.config.apiKey,
3302
+ ...this.config.headers
3303
+ };
3304
+ }
3305
+ formatErrorResponse(error, prefix = "API") {
3306
+ var _a, _b, _c;
3307
+ if (this.config.debug) {
3308
+ console.error(`${prefix} Error:`, error);
3309
+ }
3310
+ if (error && typeof error === "object" && "response" in error) {
3311
+ const apiError = error;
3312
+ if ((_b = (_a = apiError.response) == null ? void 0 : _a.data) == null ? void 0 : _b.error) {
3313
+ return apiError.response.data;
3314
+ }
3315
+ return {
3316
+ data: {},
3317
+ error: {
3318
+ code: `${prefix}_ERROR`,
3319
+ message: error.message || `Unknown ${prefix} error`,
3320
+ meta: [`Status: ${((_c = apiError.response) == null ? void 0 : _c.status) || "unknown"}`]
3321
+ }
3322
+ };
3323
+ }
3324
+ if (error && typeof error === "object" && "message" in error) {
3325
+ return {
3326
+ data: {},
3327
+ error: {
3328
+ code: `${prefix}_CLIENT_ERROR`,
3329
+ message: error.message,
3330
+ meta: [`${prefix} client-side error occurred`]
3331
+ }
3332
+ };
3333
+ }
3334
+ return {
3335
+ data: {},
3336
+ error: {
3337
+ code: `${prefix}_UNKNOWN_ERROR`,
3338
+ message: `An unexpected ${prefix} error occurred`,
3339
+ meta: [`Unknown ${prefix} error type`]
3340
+ }
3341
+ };
3342
+ }
3343
+ }
3344
+ class SqlApiClient extends BaseApiClient {
3345
+ constructor(apiKey, config = {}) {
3346
+ super(apiKey, config);
3347
+ }
3348
+ /**
3349
+ * Convert natural language to SQL query (streaming)
3350
+ */
3351
+ async textToSQL(request) {
3352
+ try {
3353
+ const endpoint = SQL_ENDPOINTS.textToSQL;
3354
+ const url = `${this.baseURL}${buildSqlEndpointPath(endpoint)}`;
3355
+ const response = await this.httpAdapter.request({
3356
+ url,
3357
+ method: endpoint.method,
3358
+ headers: this.buildHeaders(),
3359
+ data: request,
3360
+ timeout: this.config.timeout
3361
+ });
3362
+ if (response.status >= 400) {
3363
+ return this.formatErrorResponse(
3364
+ {
3365
+ response: { data: response.data, status: response.status }
3366
+ },
3367
+ "SQL"
3368
+ );
3369
+ }
3370
+ const sqlResponse = response.data;
3371
+ return this.createAsyncIterable(sqlResponse.data);
3372
+ } catch (error) {
3373
+ return this.formatErrorResponse(error, "SQL");
3374
+ }
3375
+ }
3376
+ /**
3377
+ * Execute SQL query
3378
+ */
3379
+ async executeSQL(request) {
3380
+ try {
3381
+ const endpoint = SQL_ENDPOINTS.executeSQL;
3382
+ const url = `${this.baseURL}${buildSqlEndpointPath(endpoint)}`;
3383
+ const response = await this.httpAdapter.request({
3384
+ url,
3385
+ method: endpoint.method,
3386
+ headers: this.buildHeaders(),
3387
+ data: request,
3388
+ timeout: this.config.timeout
3389
+ });
3390
+ if (response.status >= 400) {
3391
+ return this.formatErrorResponse(
3392
+ {
3393
+ response: { data: response.data, status: response.status }
3394
+ },
3395
+ "SQL"
3396
+ );
3397
+ }
3398
+ return response.data;
3399
+ } catch (error) {
3400
+ return this.formatErrorResponse(error, "SQL");
3401
+ }
3402
+ }
3403
+ /**
3404
+ * Helper method to create AsyncIterable from string data
3405
+ * TODO: Replace with proper streaming implementation when backend supports it
3406
+ */
3407
+ async *createAsyncIterable(data) {
3408
+ yield data;
3409
+ }
3410
+ }
3411
+ function transformTextToSQLRequest(prompt, options = {}) {
3412
+ return {
3413
+ prompt,
3414
+ current_query: options.currentQuery
3415
+ };
3416
+ }
3417
+ class SqlResource {
3418
+ constructor(client) {
3419
+ const config = client.getConfig();
3420
+ this.sqlApiClient = new SqlApiClient(config.apiKey, {
3421
+ environment: config.environment,
3422
+ region: config.region,
3423
+ timeout: config.timeout,
3424
+ debug: config.debug,
3425
+ retryAttempts: config.retryAttempts,
3426
+ retryDelay: config.retryDelay,
3427
+ headers: config.headers
3428
+ });
3429
+ }
3430
+ /**
3431
+ * Convert natural language to SQL query
3432
+ * Returns streaming results for real-time query generation
3433
+ *
3434
+ * @param prompt - Natural language description of the desired query
3435
+ * @param options - Optional parameters including currentQuery for refinement
3436
+ * @returns AsyncIterable<string> for streaming SQL generation
3437
+ *
3438
+ */
3439
+ async textToSQL(prompt, options = {}) {
3440
+ const request = transformTextToSQLRequest(prompt, options);
3441
+ const response = await this.sqlApiClient.textToSQL(request);
3442
+ if ("error" in response && response.error !== void 0) {
3443
+ throw response;
3444
+ }
3445
+ return response;
3446
+ }
3447
+ /**
3448
+ * Execute SQL query with built-in safety measures and performance optimization
3449
+ *
3450
+ * @param query - SQL query string to execute
3451
+ * @returns Promise<ExecuteSQLApiResponse> with raw API response following Boltic API Response Structure
3452
+ *
3453
+ */
3454
+ async executeSQL(query) {
3455
+ const response = await this.sqlApiClient.executeSQL({ query });
3456
+ if (isErrorResponse(response)) {
3457
+ throw response;
3458
+ }
3459
+ return response;
3460
+ }
3461
+ }
3462
+ class TableBuilder {
3463
+ constructor(options, tablesApiClient) {
3464
+ this.isPublic = false;
3465
+ this.fields = [];
3466
+ this.tableName = options.name;
3467
+ this.description = options.description;
3468
+ this.tablesApiClient = tablesApiClient;
3469
+ }
3470
+ /**
3471
+ * Set table name
3472
+ */
3473
+ name(name) {
3474
+ this.tableName = name;
3475
+ return this;
3476
+ }
3477
+ /**
3478
+ * Set table description
3479
+ */
3480
+ describe(description) {
3481
+ this.description = description;
3482
+ return this;
3483
+ }
3484
+ /**
3485
+ * Set if table is public
3486
+ */
3487
+ public(isPublic = true) {
3488
+ this.isPublic = isPublic;
3489
+ return this;
3490
+ }
3491
+ /**
3492
+ * Add a text field
3493
+ */
3494
+ text(name, options = {}) {
3495
+ this.fields.push({
3496
+ name,
3497
+ type: "text",
3498
+ is_nullable: options.nullable ?? true,
3499
+ is_unique: options.unique ?? false,
3500
+ is_indexed: options.indexed ?? false,
3501
+ is_primary_key: false,
3502
+ default_value: options.defaultValue,
3503
+ description: options.description,
3504
+ alignment: options.alignment || "left",
3505
+ field_order: this.fields.length + 1
3506
+ });
3507
+ return this;
3508
+ }
3509
+ /**
3510
+ * Add a long text field
3511
+ */
3512
+ longText(name, options = {}) {
3513
+ this.fields.push({
3514
+ name,
3515
+ type: "long-text",
3516
+ is_nullable: options.nullable ?? true,
3517
+ is_unique: false,
3518
+ is_indexed: false,
3519
+ is_primary_key: false,
3520
+ description: options.description,
3521
+ alignment: options.alignment || "left",
3522
+ field_order: this.fields.length + 1
3523
+ });
3524
+ return this;
3525
+ }
3526
+ /**
3527
+ * Add a number field
3528
+ */
3529
+ number(name, options = {}) {
3530
+ this.fields.push({
3531
+ name,
3532
+ type: "number",
3533
+ is_nullable: options.nullable ?? true,
3534
+ is_unique: options.unique ?? false,
3535
+ is_indexed: options.indexed ?? false,
3536
+ is_primary_key: false,
3537
+ default_value: options.defaultValue,
3538
+ description: options.description,
3539
+ decimals: options.decimals,
3540
+ alignment: options.alignment || "right",
3541
+ field_order: this.fields.length + 1
3542
+ });
3543
+ return this;
3544
+ }
3545
+ /**
3546
+ * Add a currency field
3547
+ */
3548
+ currency(name, options = {}) {
3549
+ this.fields.push({
3550
+ name,
3551
+ type: "currency",
3552
+ is_nullable: options.nullable ?? true,
3553
+ is_unique: false,
3554
+ is_indexed: false,
3555
+ is_primary_key: false,
3556
+ default_value: options.defaultValue,
3557
+ description: options.description,
3558
+ currency_format: options.currencyFormat,
3559
+ decimals: options.decimals,
3560
+ alignment: "right",
3561
+ field_order: this.fields.length + 1
3562
+ });
3563
+ return this;
3564
+ }
3565
+ /**
3566
+ * Add a checkbox field
3567
+ */
3568
+ checkbox(name, options = {}) {
3569
+ this.fields.push({
3570
+ name,
3571
+ type: "checkbox",
3572
+ is_nullable: options.nullable ?? true,
3573
+ is_unique: false,
3574
+ is_indexed: false,
3575
+ is_primary_key: false,
3576
+ default_value: options.defaultValue,
3577
+ description: options.description,
3578
+ alignment: "center",
3579
+ field_order: this.fields.length + 1
3580
+ });
3581
+ return this;
3582
+ }
3583
+ /**
3584
+ * Add a dropdown field
3585
+ */
3586
+ dropdown(name, items, options = {}) {
3587
+ this.fields.push({
3588
+ name,
3589
+ type: "dropdown",
3590
+ is_nullable: options.nullable ?? true,
3591
+ is_unique: false,
3592
+ is_indexed: false,
3593
+ is_primary_key: false,
3594
+ default_value: options.defaultValue,
3595
+ description: options.description,
3596
+ selection_source: "provide-static-list",
3597
+ selectable_items: items,
3598
+ multiple_selections: options.multiple ?? false,
3599
+ alignment: "left",
3600
+ field_order: this.fields.length + 1
3601
+ });
3602
+ return this;
3603
+ }
3604
+ /**
3605
+ * Add an email field
3606
+ */
3607
+ email(name, options = {}) {
3608
+ this.fields.push({
3609
+ name,
3610
+ type: "email",
3611
+ is_nullable: options.nullable ?? true,
3612
+ is_unique: options.unique ?? false,
3613
+ is_indexed: options.indexed ?? false,
3614
+ is_primary_key: false,
3615
+ description: options.description,
3616
+ alignment: "left",
3617
+ field_order: this.fields.length + 1
3618
+ });
3619
+ return this;
3620
+ }
3621
+ /**
3622
+ * Add a phone number field
3623
+ */
3624
+ phone(name, options = {}) {
3625
+ this.fields.push({
3626
+ name,
3627
+ type: "phone-number",
3628
+ is_nullable: options.nullable ?? true,
3629
+ is_unique: false,
3630
+ is_indexed: false,
3631
+ is_primary_key: false,
3632
+ description: options.description,
3633
+ phone_format: options.format,
3634
+ alignment: "left",
3635
+ field_order: this.fields.length + 1
3636
+ });
3637
+ return this;
3638
+ }
3639
+ /**
3640
+ * Add a link field
3641
+ */
3642
+ link(name, options = {}) {
3643
+ this.fields.push({
3644
+ name,
3645
+ type: "link",
3646
+ is_nullable: options.nullable ?? true,
3647
+ is_unique: false,
3648
+ is_indexed: false,
3649
+ is_primary_key: false,
3650
+ description: options.description,
3651
+ alignment: "left",
3652
+ field_order: this.fields.length + 1
3653
+ });
3654
+ return this;
3655
+ }
3656
+ /**
3657
+ * Add a JSON field
3658
+ */
3659
+ json(name, options = {}) {
3660
+ this.fields.push({
3661
+ name,
3662
+ type: "json",
3663
+ is_nullable: options.nullable ?? true,
3664
+ is_unique: false,
3665
+ is_indexed: false,
3666
+ is_primary_key: false,
3667
+ description: options.description,
3668
+ alignment: "left",
3669
+ field_order: this.fields.length + 1
3670
+ });
3671
+ return this;
3672
+ }
3673
+ /**
3674
+ * Add a date-time field
3675
+ */
3676
+ dateTime(name, options = {}) {
3677
+ this.fields.push({
3678
+ name,
3679
+ type: "date-time",
3680
+ is_nullable: options.nullable ?? true,
3681
+ is_unique: false,
3682
+ is_indexed: false,
3683
+ is_primary_key: false,
3684
+ description: options.description,
3685
+ date_format: options.dateFormat,
3686
+ time_format: options.timeFormat,
3687
+ timezone: options.timezone,
3688
+ alignment: "left",
3689
+ field_order: this.fields.length + 1
3690
+ });
3691
+ return this;
3692
+ }
3693
+ /**
3694
+ * Add a vector field
3695
+ */
3696
+ vector(name, dimension, options = {}) {
3697
+ this.fields.push({
3698
+ name,
3699
+ type: "vector",
3700
+ is_nullable: options.nullable ?? true,
3701
+ is_unique: false,
3702
+ is_indexed: false,
3703
+ is_primary_key: false,
3704
+ description: options.description,
3705
+ vector_dimension: dimension,
3706
+ alignment: "left",
3707
+ field_order: this.fields.length + 1
3708
+ });
3709
+ return this;
3710
+ }
3711
+ /**
3712
+ /**
3713
+ * Add a half-precision vector field
3714
+ */
3715
+ halfVector(name, dimension, options = {}) {
3716
+ this.fields.push({
3717
+ name,
3718
+ type: "halfvec",
3719
+ is_nullable: options.nullable ?? true,
3720
+ is_unique: false,
3721
+ is_indexed: false,
3722
+ is_primary_key: false,
3723
+ description: options.description,
3724
+ vector_dimension: dimension,
3725
+ alignment: "left",
3726
+ field_order: this.fields.length + 1
3727
+ });
3728
+ return this;
3729
+ }
3730
+ /**
3731
+ * Add a sparse vector field
3732
+ */
3733
+ sparseVector(name, dimension, options = {}) {
3734
+ this.fields.push({
3735
+ name,
3736
+ type: "sparsevec",
3737
+ is_nullable: options.nullable ?? true,
3738
+ is_unique: false,
3739
+ is_indexed: false,
3740
+ is_primary_key: false,
3741
+ description: options.description,
3742
+ vector_dimension: dimension,
3743
+ alignment: "left",
3744
+ field_order: this.fields.length + 1
3745
+ });
3746
+ return this;
3747
+ }
3748
+ /**
3749
+ * Add a custom field
3750
+ */
3751
+ addField(field) {
3752
+ this.fields.push({
3753
+ ...field,
3754
+ field_order: field.field_order || this.fields.length + 1
3755
+ });
3756
+ return this;
3757
+ }
3758
+ /**
3759
+ * Remove a field by name
3760
+ */
3761
+ removeField(name) {
3762
+ this.fields = this.fields.filter((field) => field.name !== name);
3763
+ this.fields.forEach((field, index) => {
3764
+ field.field_order = index + 1;
3765
+ });
3766
+ return this;
3767
+ }
3768
+ /**
3769
+ * Get current fields
3770
+ */
3771
+ getFields() {
3772
+ return [...this.fields];
3773
+ }
3774
+ /**
3775
+ * Get current table name
3776
+ */
3777
+ getName() {
3778
+ return this.tableName;
3779
+ }
3780
+ /**
3781
+ * Get current description
3782
+ */
3783
+ getDescription() {
3784
+ return this.description;
3785
+ }
3786
+ /**
3787
+ * Build the table request object
3788
+ */
3789
+ build() {
3790
+ if (!this.tableName) {
3791
+ throw new ValidationError("Table name is required", [
3792
+ { field: "name", message: "Table name cannot be empty" }
3793
+ ]);
3794
+ }
3795
+ if (this.fields.length === 0) {
3796
+ throw new ValidationError("At least one field is required", [
3797
+ { field: "fields", message: "Table must have at least one field" }
3798
+ ]);
3799
+ }
3800
+ return {
3801
+ name: this.tableName,
3802
+ description: this.description,
3803
+ fields: this.fields
3804
+ };
3805
+ }
3806
+ /**
3807
+ * Build and create the table (requires API client)
3808
+ */
3809
+ async create(options = {}) {
3810
+ if (!this.tablesApiClient) {
3811
+ throw new Error("TablesApiClient is required for table creation");
3812
+ }
3813
+ const request = this.build();
3814
+ return this.tablesApiClient.createTable(request, options);
3815
+ }
3816
+ }
3817
+ function createTableBuilder(options, tablesApiClient) {
3818
+ return new TableBuilder(options, tablesApiClient);
3819
+ }
3820
+ class BolticClient {
3821
+ constructor(apiKey, options = {}) {
3822
+ this.currentDatabase = null;
3823
+ this.clientOptions = options;
3824
+ this.configManager = new ConfigManager(
3825
+ apiKey,
3826
+ options.environment || "prod",
3827
+ options.region || "asia-south1",
3828
+ options
3829
+ );
3830
+ const config = this.configManager.getConfig();
3831
+ this.authManager = new AuthManager({
3832
+ apiKey: config.apiKey,
3833
+ maxRetries: config.maxRetries
3834
+ });
3835
+ this.baseClient = new BaseClient(config, this.authManager);
3836
+ this.tableResource = new TableResource(this.baseClient);
3837
+ this.columnResource = new ColumnResource(this.baseClient);
3838
+ this.recordResource = new RecordResource(this.baseClient);
3839
+ this.sqlResource = new SqlResource(this.baseClient);
3840
+ this.currentDatabase = {
3841
+ databaseName: "Default"
3842
+ };
3843
+ }
3844
+ getCurrentDatabase() {
3845
+ return this.currentDatabase;
3846
+ }
3847
+ // Direct table operations
3848
+ get tables() {
3849
+ return {
3850
+ create: (data) => this.tableResource.create(data),
3851
+ findAll: (options) => this.tableResource.findAll(options),
3852
+ findById: (id) => this.tableResource.findById(id),
3853
+ findByName: (name) => this.tableResource.findByName(name),
3854
+ findOne: (options) => this.tableResource.findOne(options),
3855
+ update: (name, data) => this.tableResource.update(name, data),
3856
+ delete: (name) => this.tableResource.delete(name),
3857
+ rename: (oldName, newName) => this.tableResource.rename(oldName, newName),
3858
+ setAccess: (request) => this.tableResource.setAccess(request)
3859
+ };
3860
+ }
3861
+ // Direct column operations
3862
+ get columns() {
3863
+ return {
3864
+ create: (tableName, column) => this.columnResource.create(tableName, column),
3865
+ createMany: (tableName, columns) => this.columnResource.createMany(tableName, columns),
3866
+ findAll: (tableName, options) => this.columnResource.findAll(tableName, options),
3867
+ findOne: (tableName, columnName) => this.columnResource.get(tableName, columnName),
3868
+ findById: (tableName, columnId) => this.columnResource.findById(tableName, columnId),
3869
+ update: (tableName, columnName, updates) => this.columnResource.update(tableName, columnName, updates),
3870
+ delete: (tableName, columnName) => this.columnResource.delete(tableName, columnName)
3871
+ };
3872
+ }
3873
+ // Fluent table operations
3874
+ table(name) {
3875
+ const tableBuilder = createTableBuilder(
3876
+ { name },
3877
+ this.tableResource.getTablesApiClient()
3878
+ );
3879
+ return tableBuilder;
3880
+ }
3881
+ // Method 3: Table-scoped operations
3882
+ from(tableName) {
3883
+ return {
3884
+ // Column operations for this table
3885
+ columns: () => ({
3886
+ create: (column) => this.columnResource.create(tableName, column),
3887
+ findAll: (options) => this.columnResource.findAll(tableName, options),
3888
+ get: (columnName) => this.columnResource.get(tableName, columnName),
3889
+ update: (columnName, updates) => this.columnResource.update(tableName, columnName, updates),
3890
+ delete: (columnName) => this.columnResource.delete(tableName, columnName)
3891
+ }),
3892
+ // Record operations for this table
3893
+ records: () => ({
3894
+ insert: (data) => this.recordResource.insert(tableName, data),
3895
+ findOne: (recordId) => this.recordResource.get(tableName, recordId),
3896
+ update: (options) => this.recordResource.update(tableName, options),
3897
+ updateById: (recordId, data) => this.recordResource.updateById(tableName, recordId, data),
3898
+ // Unified delete method
3899
+ delete: (options) => this.recordResource.delete(tableName, options),
3900
+ // Single record delete method
3901
+ deleteById: (recordId) => this.recordResource.deleteById(tableName, recordId)
3902
+ }),
3903
+ // Fluent record builder for this table
3904
+ record: () => createRecordBuilder({
3905
+ tableName,
3906
+ recordResource: this.recordResource
3907
+ })
3908
+ };
3909
+ }
3910
+ // Direct record operations
3911
+ get records() {
3912
+ return {
3913
+ insert: (tableName, data) => this.recordResource.insert(tableName, data),
3914
+ findAll: (tableName, options) => this.recordResource.list(tableName, options),
3915
+ findOne: (tableName, recordId) => this.recordResource.get(tableName, recordId),
3916
+ update: (tableName, options) => this.recordResource.update(tableName, options),
3917
+ updateById: (tableName, recordId, data) => this.recordResource.updateById(tableName, recordId, data),
3918
+ delete: (tableName, options) => this.recordResource.delete(tableName, options),
3919
+ deleteById: (tableName, recordId) => this.recordResource.deleteById(tableName, recordId)
3920
+ };
3921
+ }
3922
+ // Method 4: Create fluent record builder
3923
+ record(tableName) {
3924
+ return createRecordBuilder({
3925
+ tableName,
3926
+ recordResource: this.recordResource
3927
+ });
3928
+ }
3929
+ // Direct SQL operations
3930
+ get sql() {
3931
+ return {
3932
+ textToSQL: (prompt, options) => this.sqlResource.textToSQL(prompt, options),
3933
+ executeSQL: (query) => this.sqlResource.executeSQL(query)
3934
+ };
3935
+ }
3936
+ // SQL resource access for testing
3937
+ getSqlResource() {
3938
+ return this.sqlResource;
3939
+ }
3940
+ // Configuration management
3941
+ updateApiKey(newApiKey) {
3942
+ this.configManager.updateConfig({ apiKey: newApiKey });
3943
+ this.authManager.updateApiKey(newApiKey);
3944
+ }
3945
+ updateConfig(updates) {
3946
+ this.configManager.updateConfig(updates);
3947
+ this.baseClient.updateConfig(this.configManager.getConfig());
3948
+ }
3949
+ getConfig() {
3950
+ return this.configManager.getConfig();
3951
+ }
3952
+ // Authentication management
3953
+ async validateApiKey() {
3954
+ return this.authManager.validateApiKeyAsync();
3955
+ }
3956
+ isAuthenticated() {
3957
+ return this.authManager.isAuthenticated();
3958
+ }
3959
+ // HTTP client access
3960
+ getHttpClient() {
3961
+ return this.baseClient;
3962
+ }
3963
+ // Interceptor management
3964
+ addRequestInterceptor(interceptor) {
3965
+ return this.baseClient.getInterceptors().request.use(interceptor);
3966
+ }
3967
+ addResponseInterceptor(onFulfilled, onRejected) {
3968
+ return this.baseClient.getInterceptors().response.use(onFulfilled, onRejected);
3969
+ }
3970
+ ejectRequestInterceptor(id) {
3971
+ this.baseClient.getInterceptors().request.eject(id);
3972
+ }
3973
+ ejectResponseInterceptor(id) {
3974
+ this.baseClient.getInterceptors().response.eject(id);
3975
+ }
3976
+ // Connection testing
3977
+ async testConnection() {
3978
+ try {
3979
+ return await this.authManager.validateApiKeyAsync();
3980
+ } catch (error) {
3981
+ return false;
3982
+ }
3983
+ }
3984
+ // Get client version
3985
+ getVersion() {
3986
+ return "1.0.0";
3987
+ }
3988
+ // Environment helpers
3989
+ getEnvironment() {
3990
+ return this.configManager.getConfig().environment;
3991
+ }
3992
+ getRegion() {
3993
+ return this.configManager.getConfig().region;
3994
+ }
3995
+ // Debug helpers
3996
+ enableDebug() {
3997
+ this.configManager.updateConfig({ debug: true });
3998
+ }
3999
+ disableDebug() {
4000
+ this.configManager.updateConfig({ debug: false });
4001
+ }
4002
+ isDebugEnabled() {
4003
+ return this.configManager.getConfig().debug || false;
4004
+ }
4005
+ }
4006
+ function createTestClient(options = {}) {
4007
+ return new BolticClient(options.apiKey || "test-api-key-12345", {
4008
+ environment: "local",
4009
+ region: "asia-south1",
4010
+ debug: options.debug ?? true,
4011
+ timeout: 3e4,
4012
+ ...options
4013
+ });
4014
+ }
4015
+ function createMockResponse(data, pagination) {
4016
+ return {
4017
+ data,
4018
+ pagination
4019
+ };
4020
+ }
4021
+ function createErrorResponse(error, details) {
4022
+ return {
4023
+ error,
4024
+ details
4025
+ };
4026
+ }
4027
+ export {
4028
+ ApiError as A,
4029
+ BolticClient as B,
4030
+ ENV_CONFIGS as E,
4031
+ FILTER_OPERATORS as F,
4032
+ REGION_CONFIGS as R,
4033
+ SqlResource as S,
4034
+ ValidationError as V,
4035
+ isListResponse as a,
4036
+ buildApiFilters as b,
4037
+ createFilter as c,
4038
+ FilterBuilder as d,
4039
+ mapWhereToFilters as e,
4040
+ createRecordBuilder as f,
4041
+ createTableBuilder as g,
4042
+ createErrorWithContext as h,
4043
+ isErrorResponse as i,
4044
+ formatError as j,
4045
+ getHttpStatusCode as k,
4046
+ isNetworkError as l,
4047
+ mapFiltersToWhere as m,
4048
+ normalizeFilters as n,
4049
+ createErrorResponse as o,
4050
+ createMockResponse as p,
4051
+ createTestClient as q
4052
+ };
4053
+ //# sourceMappingURL=test-client-BM9X5DH9.mjs.map