@boltic/sdk 0.0.4 → 0.0.6

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.
@@ -1,3 +1,17 @@
1
+ declare interface AddIndexRequest {
2
+ field_names: string[];
3
+ method: 'btree' | 'hash' | 'spgist' | 'gin' | 'brin';
4
+ }
5
+
6
+ declare interface AddIndexResponse {
7
+ index_name: string;
8
+ method: string;
9
+ fields: string[];
10
+ field_ids?: string[];
11
+ created_at?: string;
12
+ created_by?: string;
13
+ }
14
+
1
15
  declare type AlignmentType = 'left' | 'center' | 'right';
2
16
 
3
17
  /**
@@ -64,6 +78,7 @@ declare class BolticClient {
64
78
  private columnResource;
65
79
  private recordResource;
66
80
  private sqlResource;
81
+ private indexResource;
67
82
  private currentDatabase;
68
83
  private clientOptions;
69
84
  constructor(apiKey: string, options?: ClientOptions);
@@ -96,6 +111,11 @@ declare class BolticClient {
96
111
  message?: string | undefined;
97
112
  }>>;
98
113
  };
114
+ get indexes(): {
115
+ addIndex: (tableName: string, payload: AddIndexRequest) => Promise<BolticErrorResponse_2 | BolticSuccessResponse<AddIndexResponse>>;
116
+ listIndexes: (tableName: string, query: ListIndexesQuery) => Promise<BolticErrorResponse_2 | BolticSuccessResponse<ListIndexesResponse>>;
117
+ deleteIndex: (tableName: string, indexName: string) => Promise<BolticErrorResponse_2 | BolticSuccessResponse<DeleteIndexResponse>>;
118
+ };
99
119
  table(name: string): TableBuilder;
100
120
  from(tableName: string): {
101
121
  columns: () => {
@@ -124,6 +144,11 @@ declare class BolticClient {
124
144
  }>>;
125
145
  };
126
146
  record: () => RecordBuilder;
147
+ indexes: () => {
148
+ addIndex: (payload: AddIndexRequest) => Promise<BolticErrorResponse_2 | BolticSuccessResponse<AddIndexResponse>>;
149
+ listIndexes: (query: ListIndexesQuery) => Promise<BolticErrorResponse_2 | BolticSuccessResponse<ListIndexesResponse>>;
150
+ deleteIndex: (indexName: string) => Promise<BolticErrorResponse_2 | BolticSuccessResponse<DeleteIndexResponse>>;
151
+ };
127
152
  };
128
153
  get records(): {
129
154
  insert: (tableName: string, data: RecordData) => Promise<BolticErrorResponse_2 | BolticSuccessResponse<RecordWithId>>;
@@ -397,6 +422,10 @@ declare const DateFormatEnum: Readonly<{
397
422
 
398
423
  declare type DecimalType = '00' | '0.0' | '0.00' | '0.000' | '0.0000' | '0.00000' | '0.000000';
399
424
 
425
+ declare interface DeleteIndexResponse {
426
+ message?: string;
427
+ }
428
+
400
429
  declare type Environment = 'local' | 'sit' | 'uat' | 'prod';
401
430
 
402
431
  declare interface EnvironmentConfig {
@@ -492,6 +521,20 @@ declare interface HttpResponse<T = unknown> {
492
521
  headers: Record<string, string>;
493
522
  }
494
523
 
524
+ declare interface IndexListItem {
525
+ schemaname?: string;
526
+ relname?: string;
527
+ indexrelname: string;
528
+ method?: string;
529
+ idx_scan?: number;
530
+ idx_tup_read?: number;
531
+ idx_tup_fetch?: number;
532
+ field_ids?: string[];
533
+ fields?: string[];
534
+ created_at?: string;
535
+ created_by?: string;
536
+ }
537
+
495
538
  declare interface InterceptorManager {
496
539
  request: {
497
540
  use(interceptor: RequestInterceptor): number;
@@ -520,6 +563,31 @@ declare class InterceptorManagerImpl implements InterceptorManager {
520
563
  executeErrorInterceptors(error: unknown): Promise<unknown>;
521
564
  }
522
565
 
566
+ declare interface ListIndexesQuery {
567
+ page?: {
568
+ page_no: number;
569
+ page_size: number;
570
+ };
571
+ filters?: Array<{
572
+ field: string;
573
+ operator: string;
574
+ values: unknown[];
575
+ }>;
576
+ sort?: Array<{
577
+ field: string;
578
+ direction: 'asc' | 'desc';
579
+ }>;
580
+ }
581
+
582
+ declare interface ListIndexesResponse {
583
+ items: IndexListItem[];
584
+ page?: {
585
+ page_no: number;
586
+ page_size: number;
587
+ total?: number;
588
+ };
589
+ }
590
+
523
591
  export declare interface MockClientOptions {
524
592
  apiKey?: string;
525
593
  environment?: 'local' | 'sit' | 'uat' | 'prod';
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./test-client-BI3VkYA6.js");class t{static async*fromSSE(e){if(!e.body)throw new Error("Response body is null");const t=e.body.getReader(),s=new TextDecoder;try{for(;;){const{done:e,value:o}=await t.read();if(e)break;const r=s.decode(o,{stream:!0}).split("\n");for(const t of r)if(t.startsWith("data: ")){const e=t.slice(6);"[DONE]"!==e&&(yield e)}}}finally{t.releaseLock()}}static async*fromChunked(e){if(!e.body)throw new Error("Response body is null");const t=e.body.getReader(),s=new TextDecoder;try{for(;;){const{done:e,value:o}=await t.read();if(e)break;const r=s.decode(o,{stream:!0});yield r}}finally{t.releaseLock()}}static async collectAll(e){let t="";for await(const s of e)t+=s;return t}static async*fromString(e,t=10){for(let s=0;s<e.length;s+=t)yield e.slice(s,s+t),await new Promise(e=>setTimeout(e,50))}static async*map(e,t){for await(const s of e)yield await t(s)}static async*filter(e,t){for await(const s of e)await t(s)&&(yield s)}static async*take(e,t){let s=0;for await(const o of e){if(s>=t)break;yield o,s++}}}exports.createErrorResponse=e.createErrorResponse,exports.createMockResponse=e.createMockResponse,exports.createTestClient=e.createTestClient,exports.SqlTestClient=class{constructor(e){this.sql=e}async generateSQL(e,s){const o=await this.sql.textToSQL(e,s);return t.collectAll(o)}async executeSQL(e){return this.sql.executeSQL(e)}async*simulateStreamingSQL(e,t=10,s=50){for(let o=0;o<e.length;o+=t)yield e.slice(o,o+t),await new Promise(e=>setTimeout(e,s))}},exports.TEST_UTILS_VERSION="1.0.0";
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./test-client-DfOmma3t.js");class t{static async*fromSSE(e){if(!e.body)throw new Error("Response body is null");const t=e.body.getReader(),s=new TextDecoder;try{for(;;){const{done:e,value:o}=await t.read();if(e)break;const r=s.decode(o,{stream:!0}).split("\n");for(const t of r)if(t.startsWith("data: ")){const e=t.slice(6);"[DONE]"!==e&&(yield e)}}}finally{t.releaseLock()}}static async*fromChunked(e){if(!e.body)throw new Error("Response body is null");const t=e.body.getReader(),s=new TextDecoder;try{for(;;){const{done:e,value:o}=await t.read();if(e)break;const r=s.decode(o,{stream:!0});yield r}}finally{t.releaseLock()}}static async collectAll(e){let t="";for await(const s of e)t+=s;return t}static async*fromString(e,t=10){for(let s=0;s<e.length;s+=t)yield e.slice(s,s+t),await new Promise(e=>setTimeout(e,50))}static async*map(e,t){for await(const s of e)yield await t(s)}static async*filter(e,t){for await(const s of e)await t(s)&&(yield s)}static async*take(e,t){let s=0;for await(const o of e){if(s>=t)break;yield o,s++}}}exports.createErrorResponse=e.createErrorResponse,exports.createMockResponse=e.createMockResponse,exports.createTestClient=e.createTestClient,exports.SqlTestClient=class{constructor(e){this.sql=e}async generateSQL(e,s){const o=await this.sql.textToSQL(e,s);return t.collectAll(o)}async executeSQL(e){return this.sql.executeSQL(e)}async*simulateStreamingSQL(e,t=10,s=50){for(let o=0;o<e.length;o+=t)yield e.slice(o,o+t),await new Promise(e=>setTimeout(e,s))}},exports.TEST_UTILS_VERSION="1.0.0";
2
2
  //# sourceMappingURL=testing.js.map
@@ -1,4 +1,4 @@
1
- import { o, p, q } from "./test-client-BffJwqJq.mjs";
1
+ import { o, p, q } from "./test-client-rQ1AmTo6.mjs";
2
2
  class StreamingUtils {
3
3
  /**
4
4
  * Convert Server-Sent Events to AsyncIterable
package/dist/sdk.js CHANGED
@@ -259,6 +259,39 @@ class AxiosAdapter {
259
259
  // Don't throw on non-2xx status codes
260
260
  };
261
261
  const response = await this.axios(axiosConfig);
262
+ if (response.status < 200 || response.status >= 300) {
263
+ const isHtmlError = typeof response.data === "string" && response.data.trim().startsWith("<!DOCTYPE") || typeof response.data === "string" && response.data.includes("<html");
264
+ if (isHtmlError) {
265
+ const htmlContent = response.data;
266
+ const preMatch = htmlContent.match(/<pre>(.*?)<\/pre>/s);
267
+ const errorMessage = preMatch ? preMatch[1].trim() : `HTTP ${response.status}: ${response.statusText}`;
268
+ throw createErrorWithContext(errorMessage, {
269
+ url: config.url,
270
+ method: config.method,
271
+ status: response.status,
272
+ statusText: response.statusText,
273
+ isHtmlError: true
274
+ });
275
+ }
276
+ if (response.data && typeof response.data === "object" && "error" in response.data) {
277
+ return {
278
+ data: response.data,
279
+ status: response.status,
280
+ statusText: response.statusText,
281
+ headers: response.headers || {}
282
+ };
283
+ }
284
+ throw createErrorWithContext(
285
+ `HTTP ${response.status}: ${response.statusText}`,
286
+ {
287
+ url: config.url,
288
+ method: config.method,
289
+ status: response.status,
290
+ statusText: response.statusText,
291
+ responseData: response.data
292
+ }
293
+ );
294
+ }
262
295
  return {
263
296
  data: response.data,
264
297
  status: response.status,
@@ -357,6 +390,39 @@ class FetchAdapter {
357
390
  response.headers.forEach((value, key) => {
358
391
  headers[key] = value;
359
392
  });
393
+ if (response.status < 200 || response.status >= 300) {
394
+ const isHtmlError = typeof data === "string" && (data.trim().startsWith("<!DOCTYPE") || data.includes("<html"));
395
+ if (isHtmlError) {
396
+ const htmlContent = data;
397
+ const preMatch = htmlContent.match(/<pre>(.*?)<\/pre>/s);
398
+ const errorMessage = preMatch ? preMatch[1].trim() : `HTTP ${response.status}: ${response.statusText}`;
399
+ throw createErrorWithContext(errorMessage, {
400
+ url: config.url,
401
+ method: config.method,
402
+ status: response.status,
403
+ statusText: response.statusText,
404
+ isHtmlError: true
405
+ });
406
+ }
407
+ if (data && typeof data === "object" && "error" in data) {
408
+ return {
409
+ data,
410
+ status: response.status,
411
+ statusText: response.statusText,
412
+ headers
413
+ };
414
+ }
415
+ throw createErrorWithContext(
416
+ `HTTP ${response.status}: ${response.statusText}`,
417
+ {
418
+ url: config.url,
419
+ method: config.method,
420
+ status: response.status,
421
+ statusText: response.statusText,
422
+ responseData: data
423
+ }
424
+ );
425
+ }
360
426
  const httpResponse = {
361
427
  data,
362
428
  status: response.status,
@@ -2298,6 +2364,209 @@ class ColumnResource extends BaseResource {
2298
2364
  return tableInfo?.id || null;
2299
2365
  }
2300
2366
  }
2367
+ const INDEX_ENDPOINTS = {
2368
+ create: {
2369
+ path: "/tables/indexes/{table_id}",
2370
+ method: "POST",
2371
+ authenticated: true
2372
+ },
2373
+ list: {
2374
+ path: "/tables/indexes/{table_id}/list",
2375
+ method: "POST",
2376
+ authenticated: true
2377
+ },
2378
+ delete: {
2379
+ path: "/tables/indexes/{table_id}",
2380
+ method: "DELETE",
2381
+ authenticated: true
2382
+ }
2383
+ };
2384
+ const buildIndexEndpointPath = (endpoint, params = {}) => {
2385
+ let path = endpoint.path;
2386
+ Object.entries(params).forEach(([key, value]) => {
2387
+ path = path.replace(`{${key}}`, encodeURIComponent(value));
2388
+ });
2389
+ const unreplacedParams = path.match(/\{([^}]+)\}/g);
2390
+ if (unreplacedParams) {
2391
+ throw new Error(`Missing path parameters: ${unreplacedParams.join(", ")}`);
2392
+ }
2393
+ return path;
2394
+ };
2395
+ class IndexesApiClient {
2396
+ constructor(apiKey, config = {}) {
2397
+ this.config = { apiKey, ...config };
2398
+ this.httpAdapter = createHttpAdapter();
2399
+ const environment = config.environment || "prod";
2400
+ const region = config.region || "asia-south1";
2401
+ this.baseURL = this.getBaseURL(environment, region);
2402
+ }
2403
+ getBaseURL(environment, region) {
2404
+ const regionConfig = REGION_CONFIGS[region];
2405
+ if (!regionConfig) {
2406
+ throw new Error(`Unsupported region: ${region}`);
2407
+ }
2408
+ const envConfig = regionConfig[environment];
2409
+ if (!envConfig) {
2410
+ throw new Error(
2411
+ `Unsupported environment: ${environment} for region: ${region}`
2412
+ );
2413
+ }
2414
+ return `${envConfig.baseURL}/v1`;
2415
+ }
2416
+ async addIndex(tableId, request) {
2417
+ try {
2418
+ const endpoint = INDEX_ENDPOINTS.create;
2419
+ const url = `${this.baseURL}${buildIndexEndpointPath(endpoint, { table_id: tableId })}`;
2420
+ const response = await this.httpAdapter.request({
2421
+ url,
2422
+ method: endpoint.method,
2423
+ headers: this.buildHeaders(),
2424
+ data: request,
2425
+ timeout: this.config.timeout
2426
+ });
2427
+ return response.data;
2428
+ } catch (error) {
2429
+ return this.formatErrorResponse(error);
2430
+ }
2431
+ }
2432
+ async listIndexes(tableId, query) {
2433
+ try {
2434
+ const endpoint = INDEX_ENDPOINTS.list;
2435
+ const url = `${this.baseURL}${buildIndexEndpointPath(endpoint, { table_id: tableId })}`;
2436
+ const response = await this.httpAdapter.request({
2437
+ url,
2438
+ method: endpoint.method,
2439
+ headers: this.buildHeaders(),
2440
+ data: query,
2441
+ timeout: this.config.timeout
2442
+ });
2443
+ return response.data;
2444
+ } catch (error) {
2445
+ return this.formatErrorResponse(error);
2446
+ }
2447
+ }
2448
+ async deleteIndex(tableId, request) {
2449
+ try {
2450
+ const endpoint = INDEX_ENDPOINTS.delete;
2451
+ const url = `${this.baseURL}${buildIndexEndpointPath(endpoint, { table_id: tableId })}`;
2452
+ const response = await this.httpAdapter.request({
2453
+ url,
2454
+ method: endpoint.method,
2455
+ headers: this.buildHeaders(),
2456
+ data: request,
2457
+ timeout: this.config.timeout
2458
+ });
2459
+ return response.data;
2460
+ } catch (error) {
2461
+ return this.formatErrorResponse(error);
2462
+ }
2463
+ }
2464
+ buildHeaders() {
2465
+ return {
2466
+ "Content-Type": "application/json",
2467
+ Accept: "application/json",
2468
+ "x-boltic-token": this.config.apiKey
2469
+ };
2470
+ }
2471
+ formatErrorResponse(error) {
2472
+ if (this.config.debug) {
2473
+ console.error("Indexes API Error:", error);
2474
+ }
2475
+ if (error && typeof error === "object" && "response" in error) {
2476
+ const apiError = error;
2477
+ if (apiError.response?.data?.error) {
2478
+ return apiError.response.data;
2479
+ }
2480
+ return {
2481
+ error: {
2482
+ code: "API_ERROR",
2483
+ message: error.message || "Unknown API error",
2484
+ meta: [`Status: ${apiError.response?.status || "unknown"}`]
2485
+ }
2486
+ };
2487
+ }
2488
+ if (error && typeof error === "object" && "message" in error) {
2489
+ return {
2490
+ error: {
2491
+ code: "CLIENT_ERROR",
2492
+ message: error.message,
2493
+ meta: ["Client-side error occurred"]
2494
+ }
2495
+ };
2496
+ }
2497
+ return {
2498
+ error: {
2499
+ code: "UNKNOWN_ERROR",
2500
+ message: "An unexpected error occurred",
2501
+ meta: ["Unknown error type"]
2502
+ }
2503
+ };
2504
+ }
2505
+ }
2506
+ class IndexResource {
2507
+ constructor(client) {
2508
+ this.client = client;
2509
+ const config = client.getConfig();
2510
+ this.apiClient = new IndexesApiClient(config.apiKey, {
2511
+ environment: config.environment,
2512
+ region: config.region,
2513
+ timeout: config.timeout,
2514
+ debug: config.debug,
2515
+ retryAttempts: config.retryAttempts,
2516
+ retryDelay: config.retryDelay,
2517
+ headers: config.headers
2518
+ });
2519
+ this.tableResource = new TableResource(client);
2520
+ }
2521
+ async resolveTableId(tableName) {
2522
+ const tableResult = await this.tableResource.findByName(tableName);
2523
+ if (!tableResult.data) throw new Error(`Table not found: ${tableName}`);
2524
+ return tableResult.data.id;
2525
+ }
2526
+ async addIndex(tableName, request) {
2527
+ try {
2528
+ const tableId = await this.resolveTableId(tableName);
2529
+ return await this.apiClient.addIndex(tableId, request);
2530
+ } catch (error) {
2531
+ return {
2532
+ error: {
2533
+ code: "CLIENT_ERROR",
2534
+ message: error?.message || "Failed to add index",
2535
+ meta: ["IndexResource.addIndex"]
2536
+ }
2537
+ };
2538
+ }
2539
+ }
2540
+ async listIndexes(tableName, query) {
2541
+ try {
2542
+ const tableId = await this.resolveTableId(tableName);
2543
+ return await this.apiClient.listIndexes(tableId, query);
2544
+ } catch (error) {
2545
+ return {
2546
+ error: {
2547
+ code: "CLIENT_ERROR",
2548
+ message: error?.message || "Failed to list indexes",
2549
+ meta: ["IndexResource.listIndexes"]
2550
+ }
2551
+ };
2552
+ }
2553
+ }
2554
+ async deleteIndex(tableName, indexName) {
2555
+ try {
2556
+ const tableId = await this.resolveTableId(tableName);
2557
+ const request = { index_name: indexName };
2558
+ return await this.apiClient.deleteIndex(tableId, request);
2559
+ } catch (error) {
2560
+ return {
2561
+ error: {
2562
+ code: "CLIENT_ERROR",
2563
+ message: error?.message || "Failed to delete index",
2564
+ meta: ["IndexResource.deleteIndex"]
2565
+ }
2566
+ };
2567
+ }
2568
+ }
2569
+ }
2301
2570
  const RECORD_ENDPOINTS = {
2302
2571
  insert: {
2303
2572
  path: "/tables/{table_id}/records",
@@ -2322,8 +2591,8 @@ const RECORD_ENDPOINTS = {
2322
2591
  rateLimit: { requests: 200, window: 6e4 }
2323
2592
  },
2324
2593
  update: {
2325
- path: "/tables/{table_id}/records",
2326
- method: "PATCH",
2594
+ path: "/tables/{table_id}/records/bulk-update",
2595
+ method: "PUT",
2327
2596
  authenticated: true
2328
2597
  },
2329
2598
  updateById: {
@@ -2528,26 +2797,34 @@ class RecordsApiClient {
2528
2797
  */
2529
2798
  async updateRecords(request) {
2530
2799
  try {
2531
- const { table_id, ...updateOptions } = request;
2800
+ const { table_id, set, filters, fields, ...rest } = request;
2532
2801
  if (!table_id) {
2533
2802
  return this.formatErrorResponse(
2534
2803
  new Error("table_id is required for update operation")
2535
2804
  );
2536
2805
  }
2806
+ const apiPayload = {
2807
+ updates: set,
2808
+ filters,
2809
+ ...rest
2810
+ };
2811
+ if (fields) {
2812
+ apiPayload.fields = fields;
2813
+ }
2537
2814
  const endpoint = RECORD_ENDPOINTS.update;
2538
2815
  const url = `${this.baseURL}${buildRecordEndpointPath(endpoint, { table_id })}`;
2539
2816
  const response = await this.httpAdapter.request({
2540
2817
  url,
2541
2818
  method: endpoint.method,
2542
2819
  headers: this.buildHeaders(),
2543
- data: updateOptions,
2820
+ data: apiPayload,
2544
2821
  timeout: this.config.timeout
2545
2822
  });
2546
2823
  const responseData = response.data;
2547
- if (updateOptions.fields && responseData.data) {
2824
+ if (fields && responseData.data) {
2548
2825
  responseData.data = filterArrayFields(
2549
2826
  responseData.data,
2550
- updateOptions.fields
2827
+ fields
2551
2828
  );
2552
2829
  }
2553
2830
  return responseData;
@@ -3764,6 +4041,7 @@ class BolticClient {
3764
4041
  this.columnResource = new ColumnResource(this.baseClient);
3765
4042
  this.recordResource = new RecordResource(this.baseClient);
3766
4043
  this.sqlResource = new SqlResource(this.baseClient);
4044
+ this.indexResource = new IndexResource(this.baseClient);
3767
4045
  this.currentDatabase = {
3768
4046
  databaseName: "Default"
3769
4047
  };
@@ -3797,6 +4075,14 @@ class BolticClient {
3797
4075
  delete: (tableName, columnName) => this.columnResource.delete(tableName, columnName)
3798
4076
  };
3799
4077
  }
4078
+ // Direct index operations
4079
+ get indexes() {
4080
+ return {
4081
+ addIndex: (tableName, payload) => this.indexResource.addIndex(tableName, payload),
4082
+ listIndexes: (tableName, query) => this.indexResource.listIndexes(tableName, query),
4083
+ deleteIndex: (tableName, indexName) => this.indexResource.deleteIndex(tableName, indexName)
4084
+ };
4085
+ }
3800
4086
  // Fluent table operations
3801
4087
  table(name) {
3802
4088
  const tableBuilder = createTableBuilder({ name });
@@ -3829,6 +4115,12 @@ class BolticClient {
3829
4115
  record: () => createRecordBuilder({
3830
4116
  tableName,
3831
4117
  recordResource: this.recordResource
4118
+ }),
4119
+ // Indexes - Method 2: Function chaining under from(tableName)
4120
+ indexes: () => ({
4121
+ addIndex: (payload) => this.indexResource.addIndex(tableName, payload),
4122
+ listIndexes: (query) => this.indexResource.listIndexes(tableName, query),
4123
+ deleteIndex: (indexName) => this.indexResource.deleteIndex(tableName, indexName)
3832
4124
  })
3833
4125
  };
3834
4126
  }
@@ -3939,6 +4231,7 @@ class BolticClient {
3939
4231
  this.columnResource = new ColumnResource(this.baseClient);
3940
4232
  this.recordResource = new RecordResource(this.baseClient);
3941
4233
  this.sqlResource = new SqlResource(this.baseClient);
4234
+ this.indexResource = new IndexResource(this.baseClient);
3942
4235
  }
3943
4236
  // Security methods to prevent API key exposure
3944
4237
  toString() {