@boltic/sdk 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +191 -146
- package/dist/databases/index.d.ts +214 -93
- package/dist/databases/index.js +1 -1
- package/dist/databases/index.js.map +1 -1
- package/dist/databases/index.mjs +1 -1
- package/dist/databases/index.mjs.map +1 -1
- package/dist/databases/test-client-BEAX5vfC.mjs +2 -0
- package/dist/databases/test-client-BEAX5vfC.mjs.map +1 -0
- package/dist/databases/test-client-BgkvBtst.js +2 -0
- package/dist/databases/test-client-BgkvBtst.js.map +1 -0
- package/dist/databases/testing.d.ts +204 -94
- package/dist/databases/testing.js +1 -1
- package/dist/databases/testing.mjs +1 -1
- package/dist/sdk.js +1531 -765
- package/dist/sdk.js.map +1 -1
- package/dist/sdk.mjs +1532 -766
- package/dist/sdk.mjs.map +1 -1
- package/dist/types/index.d.ts +916 -70
- package/package.json +2 -1
- package/dist/databases/test-client-Bo_BCApL.js +0 -2
- package/dist/databases/test-client-Bo_BCApL.js.map +0 -1
- package/dist/databases/test-client-C9T839dW.mjs +0 -2
- package/dist/databases/test-client-C9T839dW.mjs.map +0 -1
package/dist/sdk.js
CHANGED
|
@@ -111,6 +111,73 @@ let AuthManager$1 = class AuthManager {
|
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
};
|
|
114
|
+
const REGION_CONFIGS = {
|
|
115
|
+
"asia-south1": {
|
|
116
|
+
local: {
|
|
117
|
+
baseURL: "http://localhost:8000",
|
|
118
|
+
timeout: 3e4,
|
|
119
|
+
debug: true
|
|
120
|
+
},
|
|
121
|
+
sit: {
|
|
122
|
+
baseURL: "https://asia-south1.api.fcz0.de/service/sdk/boltic-tables",
|
|
123
|
+
timeout: 15e3
|
|
124
|
+
},
|
|
125
|
+
uat: {
|
|
126
|
+
baseURL: "https://asia-south1.api.uat.fcz0.de/service/sdk/boltic-tables",
|
|
127
|
+
timeout: 15e3
|
|
128
|
+
},
|
|
129
|
+
prod: {
|
|
130
|
+
baseURL: "https://asia-south1.api.boltic.io/service/sdk/boltic-tables",
|
|
131
|
+
timeout: 1e4
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"us-central1": {
|
|
135
|
+
local: {
|
|
136
|
+
baseURL: "http://localhost:8000",
|
|
137
|
+
timeout: 3e4,
|
|
138
|
+
debug: true
|
|
139
|
+
},
|
|
140
|
+
sit: {
|
|
141
|
+
baseURL: "https://us-central1.api.fcz0.de/service/sdk/boltic-tables",
|
|
142
|
+
timeout: 15e3
|
|
143
|
+
},
|
|
144
|
+
uat: {
|
|
145
|
+
baseURL: "https://us-central1.api.uat.fcz0.de/service/sdk/boltic-tables",
|
|
146
|
+
timeout: 15e3
|
|
147
|
+
},
|
|
148
|
+
prod: {
|
|
149
|
+
baseURL: "https://us-central1.api.boltic.io/service/sdk/boltic-tables",
|
|
150
|
+
timeout: 1e4
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
const REGION_BASE_HOSTS = {
|
|
155
|
+
"asia-south1": {
|
|
156
|
+
local: { host: "http://localhost:8000", timeout: 3e4, debug: true },
|
|
157
|
+
sit: { host: "https://asia-south1.api.fcz0.de", timeout: 15e3 },
|
|
158
|
+
uat: { host: "https://asia-south1.api.uat.fcz0.de", timeout: 15e3 },
|
|
159
|
+
prod: { host: "https://asia-south1.api.boltic.io", timeout: 1e4 }
|
|
160
|
+
},
|
|
161
|
+
"us-central1": {
|
|
162
|
+
local: { host: "http://localhost:8000", timeout: 3e4, debug: true },
|
|
163
|
+
sit: { host: "https://us-central1.api.fcz0.de", timeout: 15e3 },
|
|
164
|
+
uat: { host: "https://us-central1.api.uat.fcz0.de", timeout: 15e3 },
|
|
165
|
+
prod: { host: "https://us-central1.api.boltic.io", timeout: 1e4 }
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
function resolveServiceURL(region, environment, servicePath) {
|
|
169
|
+
const regionConfig = REGION_BASE_HOSTS[region];
|
|
170
|
+
if (!regionConfig) {
|
|
171
|
+
throw new Error(`Unsupported region: ${region}`);
|
|
172
|
+
}
|
|
173
|
+
const envConfig = regionConfig[environment];
|
|
174
|
+
if (!envConfig) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
`Unsupported environment: ${environment} for region: ${region}`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
return `${envConfig.host}${servicePath}`;
|
|
180
|
+
}
|
|
114
181
|
function isErrorResponse(response) {
|
|
115
182
|
return "error" in response && response.error !== void 0;
|
|
116
183
|
}
|
|
@@ -169,77 +236,6 @@ Context: ${JSON.stringify(context, null, 2)}`;
|
|
|
169
236
|
}
|
|
170
237
|
return String(error);
|
|
171
238
|
}
|
|
172
|
-
class AuthManager2 {
|
|
173
|
-
constructor(config) {
|
|
174
|
-
this.tokenInfo = null;
|
|
175
|
-
this.config = {
|
|
176
|
-
maxRetries: 3,
|
|
177
|
-
...config
|
|
178
|
-
};
|
|
179
|
-
this.validateApiKey(config.apiKey);
|
|
180
|
-
}
|
|
181
|
-
validateApiKey(apiKey) {
|
|
182
|
-
if (!apiKey || typeof apiKey !== "string" || apiKey.trim().length === 0) {
|
|
183
|
-
throw createErrorWithContext(
|
|
184
|
-
"API key is required and must be a non-empty string",
|
|
185
|
-
{
|
|
186
|
-
name: "AuthenticationError",
|
|
187
|
-
code: "INVALID_API_KEY"
|
|
188
|
-
}
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
if (apiKey.length < 10) {
|
|
192
|
-
throw createErrorWithContext(
|
|
193
|
-
"API key appears to be invalid (too short)",
|
|
194
|
-
{
|
|
195
|
-
name: "AuthenticationError",
|
|
196
|
-
code: "INVALID_API_KEY_FORMAT"
|
|
197
|
-
}
|
|
198
|
-
);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
getAuthHeaders() {
|
|
202
|
-
return {
|
|
203
|
-
"x-boltic-token": this.config.apiKey
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
updateApiKey(newApiKey) {
|
|
207
|
-
this.validateApiKey(newApiKey);
|
|
208
|
-
this.config.apiKey = newApiKey;
|
|
209
|
-
this.tokenInfo = null;
|
|
210
|
-
}
|
|
211
|
-
isAuthenticated() {
|
|
212
|
-
return !!this.config.apiKey;
|
|
213
|
-
}
|
|
214
|
-
async validateApiKeyAsync() {
|
|
215
|
-
try {
|
|
216
|
-
this.validateApiKey(this.config.apiKey);
|
|
217
|
-
return true;
|
|
218
|
-
} catch {
|
|
219
|
-
return false;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
getTokenInfo() {
|
|
223
|
-
return this.tokenInfo ? { ...this.tokenInfo } : null;
|
|
224
|
-
}
|
|
225
|
-
getMaxRetries() {
|
|
226
|
-
return this.config.maxRetries || 3;
|
|
227
|
-
}
|
|
228
|
-
// Security methods to prevent API key exposure
|
|
229
|
-
toString() {
|
|
230
|
-
return `AuthManager { authenticated: ${this.isAuthenticated()}, maxRetries: ${this.getMaxRetries()} }`;
|
|
231
|
-
}
|
|
232
|
-
toJSON() {
|
|
233
|
-
return {
|
|
234
|
-
authenticated: this.isAuthenticated(),
|
|
235
|
-
maxRetries: this.getMaxRetries()
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
// Custom inspect method for Node.js console logging
|
|
239
|
-
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
240
|
-
return this.toString();
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
239
|
class AxiosAdapter {
|
|
244
240
|
constructor() {
|
|
245
241
|
try {
|
|
@@ -262,7 +258,6 @@ class AxiosAdapter {
|
|
|
262
258
|
timeout: config.timeout,
|
|
263
259
|
signal: config.signal,
|
|
264
260
|
validateStatus: () => true
|
|
265
|
-
// Don't throw on non-2xx status codes
|
|
266
261
|
};
|
|
267
262
|
const response = await this.axios(axiosConfig);
|
|
268
263
|
if (response.status < 200 || response.status >= 300) {
|
|
@@ -482,6 +477,157 @@ function createHttpAdapter() {
|
|
|
482
477
|
);
|
|
483
478
|
}
|
|
484
479
|
}
|
|
480
|
+
class AuthManager2 {
|
|
481
|
+
constructor(config) {
|
|
482
|
+
this.tokenInfo = null;
|
|
483
|
+
this.config = {
|
|
484
|
+
maxRetries: 3,
|
|
485
|
+
...config
|
|
486
|
+
};
|
|
487
|
+
this.validateApiKey(config.apiKey);
|
|
488
|
+
}
|
|
489
|
+
validateApiKey(apiKey) {
|
|
490
|
+
if (!apiKey || typeof apiKey !== "string" || apiKey.trim().length === 0) {
|
|
491
|
+
throw createErrorWithContext(
|
|
492
|
+
"API key is required and must be a non-empty string",
|
|
493
|
+
{
|
|
494
|
+
name: "AuthenticationError",
|
|
495
|
+
code: "INVALID_API_KEY"
|
|
496
|
+
}
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
if (apiKey.length < 10) {
|
|
500
|
+
throw createErrorWithContext(
|
|
501
|
+
"API key appears to be invalid (too short)",
|
|
502
|
+
{
|
|
503
|
+
name: "AuthenticationError",
|
|
504
|
+
code: "INVALID_API_KEY_FORMAT"
|
|
505
|
+
}
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
getAuthHeaders() {
|
|
510
|
+
return {
|
|
511
|
+
"x-boltic-token": this.config.apiKey
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
updateApiKey(newApiKey) {
|
|
515
|
+
this.validateApiKey(newApiKey);
|
|
516
|
+
this.config.apiKey = newApiKey;
|
|
517
|
+
this.tokenInfo = null;
|
|
518
|
+
}
|
|
519
|
+
isAuthenticated() {
|
|
520
|
+
return !!this.config.apiKey;
|
|
521
|
+
}
|
|
522
|
+
async validateApiKeyAsync() {
|
|
523
|
+
try {
|
|
524
|
+
this.validateApiKey(this.config.apiKey);
|
|
525
|
+
return true;
|
|
526
|
+
} catch {
|
|
527
|
+
return false;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
getTokenInfo() {
|
|
531
|
+
return this.tokenInfo ? { ...this.tokenInfo } : null;
|
|
532
|
+
}
|
|
533
|
+
getMaxRetries() {
|
|
534
|
+
return this.config.maxRetries || 3;
|
|
535
|
+
}
|
|
536
|
+
toString() {
|
|
537
|
+
return `AuthManager { authenticated: ${this.isAuthenticated()}, maxRetries: ${this.getMaxRetries()} }`;
|
|
538
|
+
}
|
|
539
|
+
toJSON() {
|
|
540
|
+
return {
|
|
541
|
+
authenticated: this.isAuthenticated(),
|
|
542
|
+
maxRetries: this.getMaxRetries()
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
546
|
+
return this.toString();
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
const SERVICE_PATHS = {
|
|
550
|
+
DATABASES: "/service/sdk/boltic-tables/v1",
|
|
551
|
+
WORKFLOW_TEMPORAL: "/service/panel/temporal/v1.0",
|
|
552
|
+
INTEGRATION: "/service/panel/integration/v1",
|
|
553
|
+
SERVERLESS: "/service/panel/serverless/v1.0"
|
|
554
|
+
};
|
|
555
|
+
class BaseApiClient {
|
|
556
|
+
constructor(apiKey, config = {}, servicePath = SERVICE_PATHS.DATABASES) {
|
|
557
|
+
this.config = { apiKey, ...config };
|
|
558
|
+
this.httpAdapter = createHttpAdapter();
|
|
559
|
+
this.environment = config.environment || "prod";
|
|
560
|
+
this.region = config.region || "asia-south1";
|
|
561
|
+
this.baseURL = resolveServiceURL(
|
|
562
|
+
this.region,
|
|
563
|
+
this.environment,
|
|
564
|
+
servicePath
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Resolve a secondary service URL using the same region/environment
|
|
569
|
+
* but a different service path.
|
|
570
|
+
*/
|
|
571
|
+
resolveAdditionalServiceURL(servicePath) {
|
|
572
|
+
return resolveServiceURL(this.region, this.environment, servicePath);
|
|
573
|
+
}
|
|
574
|
+
buildHeaders() {
|
|
575
|
+
return {
|
|
576
|
+
"Content-Type": "application/json",
|
|
577
|
+
Accept: "application/json",
|
|
578
|
+
"x-boltic-token": this.config.apiKey,
|
|
579
|
+
...this.config.headers
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
formatErrorResponse(error, prefix = "API") {
|
|
583
|
+
if (this.config.debug) {
|
|
584
|
+
console.error(`[${this.constructor.name}] ${prefix} Error:`, error);
|
|
585
|
+
}
|
|
586
|
+
if (error && typeof error === "object" && "response" in error) {
|
|
587
|
+
const apiError = error;
|
|
588
|
+
if (apiError.response?.data?.error) {
|
|
589
|
+
return apiError.response.data;
|
|
590
|
+
}
|
|
591
|
+
return {
|
|
592
|
+
error: {
|
|
593
|
+
code: `${prefix}_ERROR`,
|
|
594
|
+
message: error instanceof Error ? error.message : `Unknown ${prefix} error`,
|
|
595
|
+
meta: [`Status: ${apiError.response?.status || "unknown"}`]
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
if (error instanceof Error) {
|
|
600
|
+
return {
|
|
601
|
+
error: {
|
|
602
|
+
code: `${prefix}_CLIENT_ERROR`,
|
|
603
|
+
message: error.message,
|
|
604
|
+
meta: []
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
return {
|
|
609
|
+
error: {
|
|
610
|
+
code: `${prefix}_UNKNOWN_ERROR`,
|
|
611
|
+
message: `An unexpected ${prefix} error occurred`,
|
|
612
|
+
meta: []
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
toString() {
|
|
617
|
+
return `${this.constructor.name} { environment: "${this.config.environment || "prod"}", debug: ${this.config.debug || false} }`;
|
|
618
|
+
}
|
|
619
|
+
toJSON() {
|
|
620
|
+
const safeConfig = { ...this.config };
|
|
621
|
+
delete safeConfig.apiKey;
|
|
622
|
+
return {
|
|
623
|
+
client: this.constructor.name,
|
|
624
|
+
config: safeConfig
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
628
|
+
return this.toString();
|
|
629
|
+
}
|
|
630
|
+
}
|
|
485
631
|
class InterceptorManagerImpl {
|
|
486
632
|
constructor() {
|
|
487
633
|
this.requestInterceptors = /* @__PURE__ */ new Map();
|
|
@@ -666,46 +812,88 @@ class BaseClient {
|
|
|
666
812
|
return { ...this.config };
|
|
667
813
|
}
|
|
668
814
|
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
815
|
+
class BaseResource {
|
|
816
|
+
constructor(client, basePath) {
|
|
817
|
+
this.client = client;
|
|
818
|
+
this.basePath = basePath;
|
|
819
|
+
}
|
|
820
|
+
getBasePath() {
|
|
821
|
+
return this.basePath;
|
|
822
|
+
}
|
|
823
|
+
async makeRequest(method, path, data, options) {
|
|
824
|
+
const url = `${this.basePath}${path}`;
|
|
825
|
+
try {
|
|
826
|
+
let response;
|
|
827
|
+
switch (method) {
|
|
828
|
+
case "GET":
|
|
829
|
+
response = await this.client.get(url, {
|
|
830
|
+
params: options?.params
|
|
831
|
+
});
|
|
832
|
+
break;
|
|
833
|
+
case "POST":
|
|
834
|
+
response = await this.client.post(url, data, {
|
|
835
|
+
params: options?.params
|
|
836
|
+
});
|
|
837
|
+
break;
|
|
838
|
+
case "PUT":
|
|
839
|
+
response = await this.client.put(url, data, {
|
|
840
|
+
params: options?.params
|
|
841
|
+
});
|
|
842
|
+
break;
|
|
843
|
+
case "PATCH":
|
|
844
|
+
response = await this.client.patch(url, data, {
|
|
845
|
+
params: options?.params
|
|
846
|
+
});
|
|
847
|
+
break;
|
|
848
|
+
case "DELETE":
|
|
849
|
+
response = await this.client.delete(url, {
|
|
850
|
+
params: options?.params
|
|
851
|
+
});
|
|
852
|
+
break;
|
|
853
|
+
}
|
|
854
|
+
return response.data;
|
|
855
|
+
} catch (error) {
|
|
856
|
+
return {
|
|
857
|
+
error: {
|
|
858
|
+
code: "CLIENT_ERROR",
|
|
859
|
+
message: formatError(error),
|
|
860
|
+
meta: ["Request failed"]
|
|
861
|
+
}
|
|
862
|
+
};
|
|
687
863
|
}
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
864
|
+
}
|
|
865
|
+
buildQueryParams(options = {}) {
|
|
866
|
+
const params = {};
|
|
867
|
+
if (options.fields?.length) {
|
|
868
|
+
params.fields = options.fields.join(",");
|
|
869
|
+
}
|
|
870
|
+
if (options.sort?.length) {
|
|
871
|
+
params.sort = options.sort.map((s) => `${s.field}:${s.order}`).join(",");
|
|
872
|
+
}
|
|
873
|
+
if (options.limit !== void 0) {
|
|
874
|
+
params.limit = options.limit;
|
|
875
|
+
}
|
|
876
|
+
if (options.offset !== void 0) {
|
|
877
|
+
params.offset = options.offset;
|
|
878
|
+
}
|
|
879
|
+
if (options.where) {
|
|
880
|
+
Object.entries(options.where).forEach(([key, value]) => {
|
|
881
|
+
if (value !== void 0 && value !== null) {
|
|
882
|
+
params[`where[${key}]`] = typeof value === "object" ? JSON.stringify(value) : value;
|
|
883
|
+
}
|
|
884
|
+
});
|
|
706
885
|
}
|
|
886
|
+
return params;
|
|
707
887
|
}
|
|
708
|
-
|
|
888
|
+
handleResponse(response) {
|
|
889
|
+
if ("error" in response) {
|
|
890
|
+
if (this.client.getConfig().debug) {
|
|
891
|
+
console.error("API Error:", response.error);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
return response;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
709
897
|
class ConfigManager {
|
|
710
898
|
constructor(apiKey, environment = "prod", region = "asia-south1", overrides) {
|
|
711
899
|
const envConfig = REGION_CONFIGS[region][environment];
|
|
@@ -728,7 +916,6 @@ class ConfigManager {
|
|
|
728
916
|
updateConfig(updates) {
|
|
729
917
|
this.config = { ...this.config, ...updates };
|
|
730
918
|
}
|
|
731
|
-
// Security methods to prevent API key exposure
|
|
732
919
|
toString() {
|
|
733
920
|
return `ConfigManager { environment: "${this.config.environment}", region: "${this.config.region}", debug: ${this.config.debug} }`;
|
|
734
921
|
}
|
|
@@ -737,7 +924,6 @@ class ConfigManager {
|
|
|
737
924
|
delete safeConfig.apiKey;
|
|
738
925
|
return safeConfig;
|
|
739
926
|
}
|
|
740
|
-
// Custom inspect method for Node.js console logging
|
|
741
927
|
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
742
928
|
return this.toString();
|
|
743
929
|
}
|
|
@@ -924,26 +1110,9 @@ function transformDateFormat(dateFormat) {
|
|
|
924
1110
|
function transformTimeFormat(timeFormat) {
|
|
925
1111
|
return TimeFormatEnum[timeFormat] || timeFormat;
|
|
926
1112
|
}
|
|
927
|
-
class ColumnsApiClient {
|
|
1113
|
+
class ColumnsApiClient extends BaseApiClient {
|
|
928
1114
|
constructor(apiKey, config = {}) {
|
|
929
|
-
|
|
930
|
-
this.httpAdapter = createHttpAdapter();
|
|
931
|
-
const environment = config.environment || "prod";
|
|
932
|
-
const region = config.region || "asia-south1";
|
|
933
|
-
this.baseURL = this.getBaseURL(environment, region);
|
|
934
|
-
}
|
|
935
|
-
getBaseURL(environment, region) {
|
|
936
|
-
const regionConfig = REGION_CONFIGS[region];
|
|
937
|
-
if (!regionConfig) {
|
|
938
|
-
throw new Error(`Unsupported region: ${region}`);
|
|
939
|
-
}
|
|
940
|
-
const envConfig = regionConfig[environment];
|
|
941
|
-
if (!envConfig) {
|
|
942
|
-
throw new Error(
|
|
943
|
-
`Unsupported environment: ${environment} for region: ${region}`
|
|
944
|
-
);
|
|
945
|
-
}
|
|
946
|
-
return `${envConfig.baseURL}/v1`;
|
|
1115
|
+
super(apiKey, config);
|
|
947
1116
|
}
|
|
948
1117
|
/**
|
|
949
1118
|
* Create a single column in a table
|
|
@@ -980,7 +1149,7 @@ class ColumnsApiClient {
|
|
|
980
1149
|
const createdColumns = [];
|
|
981
1150
|
for (const column of columns) {
|
|
982
1151
|
const result = await this.createColumn(tableId, column);
|
|
983
|
-
if (
|
|
1152
|
+
if (isErrorResponse(result)) {
|
|
984
1153
|
return result;
|
|
985
1154
|
}
|
|
986
1155
|
createdColumns.push(result.data);
|
|
@@ -1132,7 +1301,7 @@ class ColumnsApiClient {
|
|
|
1132
1301
|
tableId,
|
|
1133
1302
|
apiRequest
|
|
1134
1303
|
);
|
|
1135
|
-
if (
|
|
1304
|
+
if (isErrorResponse(listResult)) {
|
|
1136
1305
|
return listResult;
|
|
1137
1306
|
}
|
|
1138
1307
|
const column = listResult.data[0] || null;
|
|
@@ -1179,7 +1348,7 @@ class ColumnsApiClient {
|
|
|
1179
1348
|
async updateColumnByName(tableId, columnName, updates) {
|
|
1180
1349
|
try {
|
|
1181
1350
|
const findResult = await this.findColumnByName(tableId, columnName);
|
|
1182
|
-
if (
|
|
1351
|
+
if (isErrorResponse(findResult)) {
|
|
1183
1352
|
return findResult;
|
|
1184
1353
|
}
|
|
1185
1354
|
if (!findResult.data) {
|
|
@@ -1213,7 +1382,7 @@ class ColumnsApiClient {
|
|
|
1213
1382
|
async deleteColumnByName(tableId, columnName) {
|
|
1214
1383
|
try {
|
|
1215
1384
|
const findResult = await this.findColumnByName(tableId, columnName);
|
|
1216
|
-
if (
|
|
1385
|
+
if (isErrorResponse(findResult)) {
|
|
1217
1386
|
return findResult;
|
|
1218
1387
|
}
|
|
1219
1388
|
if (!findResult.data) {
|
|
@@ -1230,47 +1399,6 @@ class ColumnsApiClient {
|
|
|
1230
1399
|
return this.formatErrorResponse(error);
|
|
1231
1400
|
}
|
|
1232
1401
|
}
|
|
1233
|
-
buildHeaders() {
|
|
1234
|
-
return {
|
|
1235
|
-
"Content-Type": "application/json",
|
|
1236
|
-
Accept: "application/json",
|
|
1237
|
-
"x-boltic-token": this.config.apiKey
|
|
1238
|
-
};
|
|
1239
|
-
}
|
|
1240
|
-
formatErrorResponse(error) {
|
|
1241
|
-
if (this.config.debug) {
|
|
1242
|
-
console.error("Columns API Error:", error);
|
|
1243
|
-
}
|
|
1244
|
-
if (error && typeof error === "object" && "response" in error) {
|
|
1245
|
-
const apiError = error;
|
|
1246
|
-
if (apiError.response?.data?.error) {
|
|
1247
|
-
return apiError.response.data;
|
|
1248
|
-
}
|
|
1249
|
-
return {
|
|
1250
|
-
error: {
|
|
1251
|
-
code: "API_ERROR",
|
|
1252
|
-
message: error.message || "Unknown API error",
|
|
1253
|
-
meta: [`Status: ${apiError.response?.status || "unknown"}`]
|
|
1254
|
-
}
|
|
1255
|
-
};
|
|
1256
|
-
}
|
|
1257
|
-
if (error && typeof error === "object" && "message" in error) {
|
|
1258
|
-
return {
|
|
1259
|
-
error: {
|
|
1260
|
-
code: "CLIENT_ERROR",
|
|
1261
|
-
message: error.message,
|
|
1262
|
-
meta: ["Client-side error occurred"]
|
|
1263
|
-
}
|
|
1264
|
-
};
|
|
1265
|
-
}
|
|
1266
|
-
return {
|
|
1267
|
-
error: {
|
|
1268
|
-
code: "UNKNOWN_ERROR",
|
|
1269
|
-
message: "An unexpected error occurred",
|
|
1270
|
-
meta: ["Unknown error type"]
|
|
1271
|
-
}
|
|
1272
|
-
};
|
|
1273
|
-
}
|
|
1274
1402
|
}
|
|
1275
1403
|
const TABLE_ENDPOINTS = {
|
|
1276
1404
|
list: {
|
|
@@ -1449,26 +1577,9 @@ function transformFieldDefinition(field) {
|
|
|
1449
1577
|
default_value: field.default_value
|
|
1450
1578
|
};
|
|
1451
1579
|
}
|
|
1452
|
-
class TablesApiClient {
|
|
1580
|
+
class TablesApiClient extends BaseApiClient {
|
|
1453
1581
|
constructor(apiKey, config = {}) {
|
|
1454
|
-
|
|
1455
|
-
this.httpAdapter = createHttpAdapter();
|
|
1456
|
-
const environment = config.environment || "prod";
|
|
1457
|
-
const region = config.region || "asia-south1";
|
|
1458
|
-
this.baseURL = this.getBaseURL(environment, region);
|
|
1459
|
-
}
|
|
1460
|
-
getBaseURL(environment, region) {
|
|
1461
|
-
const regionConfig = REGION_CONFIGS[region];
|
|
1462
|
-
if (!regionConfig) {
|
|
1463
|
-
throw new Error(`Unsupported region: ${region}`);
|
|
1464
|
-
}
|
|
1465
|
-
const envConfig = regionConfig[environment];
|
|
1466
|
-
if (!envConfig) {
|
|
1467
|
-
throw new Error(
|
|
1468
|
-
`Unsupported environment: ${environment} for region: ${region}`
|
|
1469
|
-
);
|
|
1470
|
-
}
|
|
1471
|
-
return `${envConfig.baseURL}/v1`;
|
|
1582
|
+
super(apiKey, config);
|
|
1472
1583
|
}
|
|
1473
1584
|
/**
|
|
1474
1585
|
* Create a new table
|
|
@@ -1591,200 +1702,75 @@ class TablesApiClient {
|
|
|
1591
1702
|
return this.formatErrorResponse(error);
|
|
1592
1703
|
}
|
|
1593
1704
|
}
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1705
|
+
}
|
|
1706
|
+
class TableResource extends BaseResource {
|
|
1707
|
+
constructor(client) {
|
|
1708
|
+
super(client, "/v1/tables");
|
|
1709
|
+
const config = client.getConfig();
|
|
1710
|
+
this.tablesApiClient = new TablesApiClient(config.apiKey, {
|
|
1711
|
+
environment: config.environment,
|
|
1712
|
+
region: config.region,
|
|
1713
|
+
timeout: config.timeout,
|
|
1714
|
+
debug: config.debug,
|
|
1715
|
+
retryAttempts: config.retryAttempts,
|
|
1716
|
+
retryDelay: config.retryDelay,
|
|
1717
|
+
headers: config.headers
|
|
1718
|
+
});
|
|
1601
1719
|
}
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1720
|
+
/**
|
|
1721
|
+
* Create a new table
|
|
1722
|
+
*/
|
|
1723
|
+
async create(data, dbId) {
|
|
1724
|
+
try {
|
|
1725
|
+
const processedData = { ...data };
|
|
1726
|
+
if (data.fields && data.fields.length > 0) {
|
|
1727
|
+
processedData.fields = await this.processFieldsDefaults(data.fields);
|
|
1728
|
+
}
|
|
1729
|
+
const result = await this.tablesApiClient.createTable(
|
|
1730
|
+
processedData,
|
|
1731
|
+
dbId ? { db_id: dbId } : {}
|
|
1732
|
+
);
|
|
1733
|
+
if (isErrorResponse(result)) {
|
|
1734
|
+
throw new ApiError(
|
|
1735
|
+
result.error.message || "Create table failed",
|
|
1736
|
+
400,
|
|
1737
|
+
result.error
|
|
1738
|
+
);
|
|
1739
|
+
}
|
|
1740
|
+
return result;
|
|
1741
|
+
} catch (error) {
|
|
1742
|
+
throw error instanceof ApiError ? error : new ApiError(this.formatError(error), 500);
|
|
1605
1743
|
}
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1744
|
+
}
|
|
1745
|
+
/**
|
|
1746
|
+
* Process fields with defaults for table creation
|
|
1747
|
+
*/
|
|
1748
|
+
async processFieldsDefaults(fields) {
|
|
1749
|
+
const processedFields = [];
|
|
1750
|
+
for (let i = 0; i < fields.length; i++) {
|
|
1751
|
+
const field = fields[i];
|
|
1752
|
+
const processedField = { ...field };
|
|
1753
|
+
if (processedField.is_primary_key === void 0) {
|
|
1754
|
+
processedField.is_primary_key = false;
|
|
1610
1755
|
}
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1756
|
+
if (processedField.is_unique === void 0) {
|
|
1757
|
+
processedField.is_unique = false;
|
|
1758
|
+
}
|
|
1759
|
+
if (processedField.is_nullable === void 0) {
|
|
1760
|
+
processedField.is_nullable = true;
|
|
1761
|
+
}
|
|
1762
|
+
if (processedField.is_indexed === void 0) {
|
|
1763
|
+
processedField.is_indexed = false;
|
|
1764
|
+
}
|
|
1765
|
+
if (processedField.type === "encrypted") {
|
|
1766
|
+
if (processedField.show_decrypted === void 0) {
|
|
1767
|
+
processedField.show_decrypted = false;
|
|
1616
1768
|
}
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
code: "CLIENT_ERROR",
|
|
1623
|
-
message: error.message,
|
|
1624
|
-
meta: ["Client-side error occurred"]
|
|
1625
|
-
}
|
|
1626
|
-
};
|
|
1627
|
-
}
|
|
1628
|
-
return {
|
|
1629
|
-
error: {
|
|
1630
|
-
code: "UNKNOWN_ERROR",
|
|
1631
|
-
message: "An unexpected error occurred",
|
|
1632
|
-
meta: ["Unknown error type"]
|
|
1633
|
-
}
|
|
1634
|
-
};
|
|
1635
|
-
}
|
|
1636
|
-
}
|
|
1637
|
-
class BaseResource {
|
|
1638
|
-
constructor(client, basePath) {
|
|
1639
|
-
this.client = client;
|
|
1640
|
-
this.basePath = basePath;
|
|
1641
|
-
}
|
|
1642
|
-
// Public getter for basePath
|
|
1643
|
-
getBasePath() {
|
|
1644
|
-
return this.basePath;
|
|
1645
|
-
}
|
|
1646
|
-
async makeRequest(method, path, data, options) {
|
|
1647
|
-
const url = `${this.basePath}${path}`;
|
|
1648
|
-
try {
|
|
1649
|
-
let response;
|
|
1650
|
-
switch (method) {
|
|
1651
|
-
case "GET":
|
|
1652
|
-
response = await this.client.get(url, {
|
|
1653
|
-
params: options?.params
|
|
1654
|
-
});
|
|
1655
|
-
break;
|
|
1656
|
-
case "POST":
|
|
1657
|
-
response = await this.client.post(url, data, {
|
|
1658
|
-
params: options?.params
|
|
1659
|
-
});
|
|
1660
|
-
break;
|
|
1661
|
-
case "PUT":
|
|
1662
|
-
response = await this.client.put(url, data, {
|
|
1663
|
-
params: options?.params
|
|
1664
|
-
});
|
|
1665
|
-
break;
|
|
1666
|
-
case "PATCH":
|
|
1667
|
-
response = await this.client.patch(url, data, {
|
|
1668
|
-
params: options?.params
|
|
1669
|
-
});
|
|
1670
|
-
break;
|
|
1671
|
-
case "DELETE":
|
|
1672
|
-
response = await this.client.delete(url, {
|
|
1673
|
-
params: options?.params
|
|
1674
|
-
});
|
|
1675
|
-
break;
|
|
1676
|
-
}
|
|
1677
|
-
return response.data;
|
|
1678
|
-
} catch (error) {
|
|
1679
|
-
return {
|
|
1680
|
-
error: {
|
|
1681
|
-
code: "CLIENT_ERROR",
|
|
1682
|
-
message: formatError(error),
|
|
1683
|
-
meta: ["Request failed"]
|
|
1684
|
-
}
|
|
1685
|
-
};
|
|
1686
|
-
}
|
|
1687
|
-
}
|
|
1688
|
-
buildQueryParams(options = {}) {
|
|
1689
|
-
const params = {};
|
|
1690
|
-
if (options.fields?.length) {
|
|
1691
|
-
params.fields = options.fields.join(",");
|
|
1692
|
-
}
|
|
1693
|
-
if (options.sort?.length) {
|
|
1694
|
-
params.sort = options.sort.map((s) => `${s.field}:${s.order}`).join(",");
|
|
1695
|
-
}
|
|
1696
|
-
if (options.limit !== void 0) {
|
|
1697
|
-
params.limit = options.limit;
|
|
1698
|
-
}
|
|
1699
|
-
if (options.offset !== void 0) {
|
|
1700
|
-
params.offset = options.offset;
|
|
1701
|
-
}
|
|
1702
|
-
if (options.where) {
|
|
1703
|
-
Object.entries(options.where).forEach(([key, value]) => {
|
|
1704
|
-
if (value !== void 0 && value !== null) {
|
|
1705
|
-
params[`where[${key}]`] = typeof value === "object" ? JSON.stringify(value) : value;
|
|
1706
|
-
}
|
|
1707
|
-
});
|
|
1708
|
-
}
|
|
1709
|
-
return params;
|
|
1710
|
-
}
|
|
1711
|
-
handleResponse(response) {
|
|
1712
|
-
if ("error" in response) {
|
|
1713
|
-
if (this.client.getConfig().debug) {
|
|
1714
|
-
console.error("API Error:", response.error);
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
return response;
|
|
1718
|
-
}
|
|
1719
|
-
}
|
|
1720
|
-
class TableResource extends BaseResource {
|
|
1721
|
-
constructor(client) {
|
|
1722
|
-
super(client, "/v1/tables");
|
|
1723
|
-
const config = client.getConfig();
|
|
1724
|
-
this.tablesApiClient = new TablesApiClient(config.apiKey, {
|
|
1725
|
-
environment: config.environment,
|
|
1726
|
-
region: config.region,
|
|
1727
|
-
timeout: config.timeout,
|
|
1728
|
-
debug: config.debug,
|
|
1729
|
-
retryAttempts: config.retryAttempts,
|
|
1730
|
-
retryDelay: config.retryDelay,
|
|
1731
|
-
headers: config.headers
|
|
1732
|
-
});
|
|
1733
|
-
}
|
|
1734
|
-
/**
|
|
1735
|
-
* Create a new table
|
|
1736
|
-
*/
|
|
1737
|
-
async create(data, dbId) {
|
|
1738
|
-
try {
|
|
1739
|
-
const processedData = { ...data };
|
|
1740
|
-
if (data.fields && data.fields.length > 0) {
|
|
1741
|
-
processedData.fields = await this.processFieldsDefaults(data.fields);
|
|
1742
|
-
}
|
|
1743
|
-
const result = await this.tablesApiClient.createTable(
|
|
1744
|
-
processedData,
|
|
1745
|
-
dbId ? { db_id: dbId } : {}
|
|
1746
|
-
);
|
|
1747
|
-
if (isErrorResponse(result)) {
|
|
1748
|
-
throw new ApiError(
|
|
1749
|
-
result.error.message || "Create table failed",
|
|
1750
|
-
400,
|
|
1751
|
-
result.error
|
|
1752
|
-
);
|
|
1753
|
-
}
|
|
1754
|
-
return result;
|
|
1755
|
-
} catch (error) {
|
|
1756
|
-
throw error instanceof ApiError ? error : new ApiError(this.formatError(error), 500);
|
|
1757
|
-
}
|
|
1758
|
-
}
|
|
1759
|
-
/**
|
|
1760
|
-
* Process fields with defaults for table creation
|
|
1761
|
-
*/
|
|
1762
|
-
async processFieldsDefaults(fields) {
|
|
1763
|
-
const processedFields = [];
|
|
1764
|
-
for (let i = 0; i < fields.length; i++) {
|
|
1765
|
-
const field = fields[i];
|
|
1766
|
-
const processedField = { ...field };
|
|
1767
|
-
if (processedField.is_primary_key === void 0) {
|
|
1768
|
-
processedField.is_primary_key = false;
|
|
1769
|
-
}
|
|
1770
|
-
if (processedField.is_unique === void 0) {
|
|
1771
|
-
processedField.is_unique = false;
|
|
1772
|
-
}
|
|
1773
|
-
if (processedField.is_nullable === void 0) {
|
|
1774
|
-
processedField.is_nullable = true;
|
|
1775
|
-
}
|
|
1776
|
-
if (processedField.is_indexed === void 0) {
|
|
1777
|
-
processedField.is_indexed = false;
|
|
1778
|
-
}
|
|
1779
|
-
if (processedField.type === "encrypted") {
|
|
1780
|
-
if (processedField.show_decrypted === void 0) {
|
|
1781
|
-
processedField.show_decrypted = false;
|
|
1782
|
-
}
|
|
1783
|
-
if (processedField.is_deterministic === void 0) {
|
|
1784
|
-
processedField.is_deterministic = false;
|
|
1785
|
-
}
|
|
1786
|
-
if (processedField.default_value !== void 0 && processedField.default_value !== null) {
|
|
1787
|
-
throw new Error("Encrypted columns do not accept a default value");
|
|
1769
|
+
if (processedField.is_deterministic === void 0) {
|
|
1770
|
+
processedField.is_deterministic = false;
|
|
1771
|
+
}
|
|
1772
|
+
if (processedField.default_value !== void 0 && processedField.default_value !== null) {
|
|
1773
|
+
throw new Error("Encrypted columns do not accept a default value");
|
|
1788
1774
|
}
|
|
1789
1775
|
}
|
|
1790
1776
|
if (processedField.field_order === void 0) {
|
|
@@ -2466,26 +2452,9 @@ const buildDatabaseEndpointPath = (endpoint, params = {}) => {
|
|
|
2466
2452
|
});
|
|
2467
2453
|
return path;
|
|
2468
2454
|
};
|
|
2469
|
-
class DatabasesApiClient {
|
|
2455
|
+
class DatabasesApiClient extends BaseApiClient {
|
|
2470
2456
|
constructor(apiKey, config = {}) {
|
|
2471
|
-
|
|
2472
|
-
this.httpAdapter = createHttpAdapter();
|
|
2473
|
-
const environment = config.environment || "prod";
|
|
2474
|
-
const region = config.region || "asia-south1";
|
|
2475
|
-
this.baseURL = this.getBaseURL(environment, region);
|
|
2476
|
-
}
|
|
2477
|
-
getBaseURL(environment, region) {
|
|
2478
|
-
const regionConfig = REGION_CONFIGS[region];
|
|
2479
|
-
if (!regionConfig) {
|
|
2480
|
-
throw new Error(`Unsupported region: ${region}`);
|
|
2481
|
-
}
|
|
2482
|
-
const envConfig = regionConfig[environment];
|
|
2483
|
-
if (!envConfig) {
|
|
2484
|
-
throw new Error(
|
|
2485
|
-
`Unsupported environment: ${environment} for region: ${region}`
|
|
2486
|
-
);
|
|
2487
|
-
}
|
|
2488
|
-
return `${envConfig.baseURL}/v1`;
|
|
2457
|
+
super(apiKey, config);
|
|
2489
2458
|
}
|
|
2490
2459
|
/**
|
|
2491
2460
|
* Create a new database
|
|
@@ -2497,16 +2466,13 @@ class DatabasesApiClient {
|
|
|
2497
2466
|
const response = await this.httpAdapter.request({
|
|
2498
2467
|
url,
|
|
2499
2468
|
method: endpoint.method,
|
|
2500
|
-
headers:
|
|
2501
|
-
"Content-Type": "application/json",
|
|
2502
|
-
"x-boltic-token": this.config.apiKey
|
|
2503
|
-
},
|
|
2469
|
+
headers: this.buildHeaders(),
|
|
2504
2470
|
data: request,
|
|
2505
2471
|
timeout: this.config.timeout
|
|
2506
2472
|
});
|
|
2507
2473
|
return response.data;
|
|
2508
2474
|
} catch (error) {
|
|
2509
|
-
return this.
|
|
2475
|
+
return this.formatErrorResponse(error);
|
|
2510
2476
|
}
|
|
2511
2477
|
}
|
|
2512
2478
|
/**
|
|
@@ -2532,10 +2498,7 @@ class DatabasesApiClient {
|
|
|
2532
2498
|
const response = await this.httpAdapter.request({
|
|
2533
2499
|
url,
|
|
2534
2500
|
method: endpoint.method,
|
|
2535
|
-
headers:
|
|
2536
|
-
"Content-Type": "application/json",
|
|
2537
|
-
"x-boltic-token": this.config.apiKey
|
|
2538
|
-
},
|
|
2501
|
+
headers: this.buildHeaders(),
|
|
2539
2502
|
data: request,
|
|
2540
2503
|
timeout: this.config.timeout
|
|
2541
2504
|
});
|
|
@@ -2551,7 +2514,7 @@ class DatabasesApiClient {
|
|
|
2551
2514
|
}
|
|
2552
2515
|
return result;
|
|
2553
2516
|
} catch (error) {
|
|
2554
|
-
return this.
|
|
2517
|
+
return this.formatErrorResponse(error);
|
|
2555
2518
|
}
|
|
2556
2519
|
}
|
|
2557
2520
|
/**
|
|
@@ -2565,16 +2528,13 @@ class DatabasesApiClient {
|
|
|
2565
2528
|
const response = await this.httpAdapter.request({
|
|
2566
2529
|
url,
|
|
2567
2530
|
method: endpoint.method,
|
|
2568
|
-
headers:
|
|
2569
|
-
"Content-Type": "application/json",
|
|
2570
|
-
"x-boltic-token": this.config.apiKey
|
|
2571
|
-
},
|
|
2531
|
+
headers: this.buildHeaders(),
|
|
2572
2532
|
data: request,
|
|
2573
2533
|
timeout: this.config.timeout
|
|
2574
2534
|
});
|
|
2575
2535
|
return response.data;
|
|
2576
2536
|
} catch (error) {
|
|
2577
|
-
return this.
|
|
2537
|
+
return this.formatErrorResponse(error);
|
|
2578
2538
|
}
|
|
2579
2539
|
}
|
|
2580
2540
|
/**
|
|
@@ -2588,15 +2548,12 @@ class DatabasesApiClient {
|
|
|
2588
2548
|
const response = await this.httpAdapter.request({
|
|
2589
2549
|
url,
|
|
2590
2550
|
method: endpoint.method,
|
|
2591
|
-
headers:
|
|
2592
|
-
"Content-Type": "application/json",
|
|
2593
|
-
"x-boltic-token": this.config.apiKey
|
|
2594
|
-
},
|
|
2551
|
+
headers: this.buildHeaders(),
|
|
2595
2552
|
timeout: this.config.timeout
|
|
2596
2553
|
});
|
|
2597
2554
|
return response.data;
|
|
2598
2555
|
} catch (error) {
|
|
2599
|
-
return this.
|
|
2556
|
+
return this.formatErrorResponse(error);
|
|
2600
2557
|
}
|
|
2601
2558
|
}
|
|
2602
2559
|
/**
|
|
@@ -2609,10 +2566,7 @@ class DatabasesApiClient {
|
|
|
2609
2566
|
const response = await this.httpAdapter.request({
|
|
2610
2567
|
url,
|
|
2611
2568
|
method: endpoint.method,
|
|
2612
|
-
headers:
|
|
2613
|
-
"Content-Type": "application/json",
|
|
2614
|
-
"x-boltic-token": this.config.apiKey
|
|
2615
|
-
},
|
|
2569
|
+
headers: this.buildHeaders(),
|
|
2616
2570
|
data: request,
|
|
2617
2571
|
timeout: this.config.timeout
|
|
2618
2572
|
});
|
|
@@ -2628,7 +2582,7 @@ class DatabasesApiClient {
|
|
|
2628
2582
|
}
|
|
2629
2583
|
return result;
|
|
2630
2584
|
} catch (error) {
|
|
2631
|
-
return this.
|
|
2585
|
+
return this.formatErrorResponse(error);
|
|
2632
2586
|
}
|
|
2633
2587
|
}
|
|
2634
2588
|
/**
|
|
@@ -2642,70 +2596,13 @@ class DatabasesApiClient {
|
|
|
2642
2596
|
const response = await this.httpAdapter.request({
|
|
2643
2597
|
url,
|
|
2644
2598
|
method: endpoint.method,
|
|
2645
|
-
headers:
|
|
2646
|
-
"Content-Type": "application/json",
|
|
2647
|
-
"x-boltic-token": this.config.apiKey
|
|
2648
|
-
},
|
|
2599
|
+
headers: this.buildHeaders(),
|
|
2649
2600
|
timeout: this.config.timeout
|
|
2650
2601
|
});
|
|
2651
2602
|
return response.data;
|
|
2652
2603
|
} catch (error) {
|
|
2653
|
-
return this.
|
|
2654
|
-
}
|
|
2655
|
-
}
|
|
2656
|
-
/**
|
|
2657
|
-
* Handle API errors and convert to standard error format
|
|
2658
|
-
*/
|
|
2659
|
-
handleError(error) {
|
|
2660
|
-
if (this.config.debug) {
|
|
2661
|
-
console.error("[DatabasesApiClient] Error:", error);
|
|
2662
|
-
}
|
|
2663
|
-
const hasErrorProperty = (err) => {
|
|
2664
|
-
return typeof err === "object" && err !== null && "error" in err && typeof err.error === "object" && err.error !== null;
|
|
2665
|
-
};
|
|
2666
|
-
const hasResponseError = (err) => {
|
|
2667
|
-
return typeof err === "object" && err !== null && "response" in err && typeof err.response === "object" && err.response !== null && "data" in err.response && typeof err.response.data === "object" && err.response.data !== null && "error" in err.response.data;
|
|
2668
|
-
};
|
|
2669
|
-
const isStandardError = (err) => {
|
|
2670
|
-
return err instanceof Error;
|
|
2671
|
-
};
|
|
2672
|
-
if (hasErrorProperty(error)) {
|
|
2673
|
-
const errorWithError = error;
|
|
2674
|
-
return {
|
|
2675
|
-
error: {
|
|
2676
|
-
code: typeof errorWithError.error.code === "number" ? String(errorWithError.error.code) : errorWithError.error.code || "UNKNOWN_ERROR",
|
|
2677
|
-
message: errorWithError.error.message || "An error occurred",
|
|
2678
|
-
meta: errorWithError.error.meta || []
|
|
2679
|
-
}
|
|
2680
|
-
};
|
|
2681
|
-
}
|
|
2682
|
-
if (hasResponseError(error)) {
|
|
2683
|
-
const errorWithResponse = error;
|
|
2684
|
-
return {
|
|
2685
|
-
error: {
|
|
2686
|
-
code: typeof errorWithResponse.response.data.error.code === "number" ? String(errorWithResponse.response.data.error.code) : errorWithResponse.response.data.error.code || "UNKNOWN_ERROR",
|
|
2687
|
-
message: errorWithResponse.response.data.error.message || "An error occurred",
|
|
2688
|
-
meta: errorWithResponse.response.data.error.meta || []
|
|
2689
|
-
}
|
|
2690
|
-
};
|
|
2691
|
-
}
|
|
2692
|
-
if (isStandardError(error)) {
|
|
2693
|
-
const standardError = error;
|
|
2694
|
-
return {
|
|
2695
|
-
error: {
|
|
2696
|
-
code: standardError.code || "UNKNOWN_ERROR",
|
|
2697
|
-
message: standardError.message || "An unexpected error occurred",
|
|
2698
|
-
meta: []
|
|
2699
|
-
}
|
|
2700
|
-
};
|
|
2604
|
+
return this.formatErrorResponse(error);
|
|
2701
2605
|
}
|
|
2702
|
-
return {
|
|
2703
|
-
error: {
|
|
2704
|
-
code: "UNKNOWN_ERROR",
|
|
2705
|
-
message: "An unexpected error occurred",
|
|
2706
|
-
meta: []
|
|
2707
|
-
}
|
|
2708
|
-
};
|
|
2709
2606
|
}
|
|
2710
2607
|
}
|
|
2711
2608
|
class DatabaseResource extends BaseResource {
|
|
@@ -2735,7 +2632,7 @@ class DatabaseResource extends BaseResource {
|
|
|
2735
2632
|
*/
|
|
2736
2633
|
async create(request) {
|
|
2737
2634
|
const result = await this.apiClient.createDatabase(request);
|
|
2738
|
-
if (
|
|
2635
|
+
if (isErrorResponse(result)) {
|
|
2739
2636
|
return {
|
|
2740
2637
|
error: {
|
|
2741
2638
|
code: typeof result.error.code === "number" ? String(result.error.code) : result.error.code,
|
|
@@ -2802,7 +2699,7 @@ class DatabaseResource extends BaseResource {
|
|
|
2802
2699
|
queryParams,
|
|
2803
2700
|
options
|
|
2804
2701
|
);
|
|
2805
|
-
if (
|
|
2702
|
+
if (isErrorResponse(result)) {
|
|
2806
2703
|
return {
|
|
2807
2704
|
error: {
|
|
2808
2705
|
code: typeof result.error.code === "number" ? String(result.error.code) : result.error.code,
|
|
@@ -2930,7 +2827,7 @@ class DatabaseResource extends BaseResource {
|
|
|
2930
2827
|
db_name: request.db_name
|
|
2931
2828
|
};
|
|
2932
2829
|
const result = await this.apiClient.updateDatabase(dbId, updateRequest);
|
|
2933
|
-
if (
|
|
2830
|
+
if (isErrorResponse(result)) {
|
|
2934
2831
|
return {
|
|
2935
2832
|
error: {
|
|
2936
2833
|
code: typeof result.error.code === "number" ? String(result.error.code) : result.error.code,
|
|
@@ -2979,7 +2876,7 @@ class DatabaseResource extends BaseResource {
|
|
|
2979
2876
|
}
|
|
2980
2877
|
const dbId = dbInfo.data.id;
|
|
2981
2878
|
const result = await this.apiClient.deleteDatabase(dbId);
|
|
2982
|
-
if (
|
|
2879
|
+
if (isErrorResponse(result)) {
|
|
2983
2880
|
return {
|
|
2984
2881
|
error: {
|
|
2985
2882
|
code: typeof result.error.code === "number" ? String(result.error.code) : result.error.code,
|
|
@@ -3022,7 +2919,7 @@ class DatabaseResource extends BaseResource {
|
|
|
3022
2919
|
request.filters = options.filters;
|
|
3023
2920
|
}
|
|
3024
2921
|
const result = await this.apiClient.listDatabaseJobs(request, options);
|
|
3025
|
-
if (
|
|
2922
|
+
if (isErrorResponse(result)) {
|
|
3026
2923
|
return {
|
|
3027
2924
|
error: {
|
|
3028
2925
|
code: typeof result.error.code === "number" ? String(result.error.code) : result.error.code,
|
|
@@ -3067,7 +2964,7 @@ class DatabaseResource extends BaseResource {
|
|
|
3067
2964
|
*/
|
|
3068
2965
|
async pollDeleteStatus(jobId) {
|
|
3069
2966
|
const result = await this.apiClient.pollDeleteStatus(jobId);
|
|
3070
|
-
if (
|
|
2967
|
+
if (isErrorResponse(result)) {
|
|
3071
2968
|
return {
|
|
3072
2969
|
error: {
|
|
3073
2970
|
code: typeof result.error.code === "number" ? String(result.error.code) : result.error.code,
|
|
@@ -3107,26 +3004,9 @@ const buildIndexEndpointPath = (endpoint, params = {}) => {
|
|
|
3107
3004
|
}
|
|
3108
3005
|
return path;
|
|
3109
3006
|
};
|
|
3110
|
-
class IndexesApiClient {
|
|
3007
|
+
class IndexesApiClient extends BaseApiClient {
|
|
3111
3008
|
constructor(apiKey, config = {}) {
|
|
3112
|
-
|
|
3113
|
-
this.httpAdapter = createHttpAdapter();
|
|
3114
|
-
const environment = config.environment || "prod";
|
|
3115
|
-
const region = config.region || "asia-south1";
|
|
3116
|
-
this.baseURL = this.getBaseURL(environment, region);
|
|
3117
|
-
}
|
|
3118
|
-
getBaseURL(environment, region) {
|
|
3119
|
-
const regionConfig = REGION_CONFIGS[region];
|
|
3120
|
-
if (!regionConfig) {
|
|
3121
|
-
throw new Error(`Unsupported region: ${region}`);
|
|
3122
|
-
}
|
|
3123
|
-
const envConfig = regionConfig[environment];
|
|
3124
|
-
if (!envConfig) {
|
|
3125
|
-
throw new Error(
|
|
3126
|
-
`Unsupported environment: ${environment} for region: ${region}`
|
|
3127
|
-
);
|
|
3128
|
-
}
|
|
3129
|
-
return `${envConfig.baseURL}/v1`;
|
|
3009
|
+
super(apiKey, config);
|
|
3130
3010
|
}
|
|
3131
3011
|
async addIndex(tableId, request, dbId) {
|
|
3132
3012
|
try {
|
|
@@ -3179,62 +3059,21 @@ class IndexesApiClient {
|
|
|
3179
3059
|
return this.formatErrorResponse(error);
|
|
3180
3060
|
}
|
|
3181
3061
|
}
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
}
|
|
3198
|
-
return {
|
|
3199
|
-
error: {
|
|
3200
|
-
code: "API_ERROR",
|
|
3201
|
-
message: error.message || "Unknown API error",
|
|
3202
|
-
meta: [`Status: ${apiError.response?.status || "unknown"}`]
|
|
3203
|
-
}
|
|
3204
|
-
};
|
|
3205
|
-
}
|
|
3206
|
-
if (error && typeof error === "object" && "message" in error) {
|
|
3207
|
-
return {
|
|
3208
|
-
error: {
|
|
3209
|
-
code: "CLIENT_ERROR",
|
|
3210
|
-
message: error.message,
|
|
3211
|
-
meta: ["Client-side error occurred"]
|
|
3212
|
-
}
|
|
3213
|
-
};
|
|
3214
|
-
}
|
|
3215
|
-
return {
|
|
3216
|
-
error: {
|
|
3217
|
-
code: "UNKNOWN_ERROR",
|
|
3218
|
-
message: "An unexpected error occurred",
|
|
3219
|
-
meta: ["Unknown error type"]
|
|
3220
|
-
}
|
|
3221
|
-
};
|
|
3222
|
-
}
|
|
3223
|
-
}
|
|
3224
|
-
class IndexResource {
|
|
3225
|
-
constructor(client) {
|
|
3226
|
-
this.client = client;
|
|
3227
|
-
const config = client.getConfig();
|
|
3228
|
-
this.apiClient = new IndexesApiClient(config.apiKey, {
|
|
3229
|
-
environment: config.environment,
|
|
3230
|
-
region: config.region,
|
|
3231
|
-
timeout: config.timeout,
|
|
3232
|
-
debug: config.debug,
|
|
3233
|
-
retryAttempts: config.retryAttempts,
|
|
3234
|
-
retryDelay: config.retryDelay,
|
|
3235
|
-
headers: config.headers
|
|
3236
|
-
});
|
|
3237
|
-
this.tableResource = new TableResource(client);
|
|
3062
|
+
}
|
|
3063
|
+
class IndexResource {
|
|
3064
|
+
constructor(client) {
|
|
3065
|
+
this.client = client;
|
|
3066
|
+
const config = client.getConfig();
|
|
3067
|
+
this.apiClient = new IndexesApiClient(config.apiKey, {
|
|
3068
|
+
environment: config.environment,
|
|
3069
|
+
region: config.region,
|
|
3070
|
+
timeout: config.timeout,
|
|
3071
|
+
debug: config.debug,
|
|
3072
|
+
retryAttempts: config.retryAttempts,
|
|
3073
|
+
retryDelay: config.retryDelay,
|
|
3074
|
+
headers: config.headers
|
|
3075
|
+
});
|
|
3076
|
+
this.tableResource = new TableResource(client);
|
|
3238
3077
|
}
|
|
3239
3078
|
async resolveTableId(tableName, dbId) {
|
|
3240
3079
|
const tableResult = await this.tableResource.findByName(tableName, dbId);
|
|
@@ -3356,26 +3195,9 @@ function transformDeleteRequest(sdkRequest) {
|
|
|
3356
3195
|
}
|
|
3357
3196
|
return result;
|
|
3358
3197
|
}
|
|
3359
|
-
class RecordsApiClient {
|
|
3198
|
+
class RecordsApiClient extends BaseApiClient {
|
|
3360
3199
|
constructor(apiKey, config = {}) {
|
|
3361
|
-
|
|
3362
|
-
this.httpAdapter = createHttpAdapter();
|
|
3363
|
-
const environment = config.environment || "prod";
|
|
3364
|
-
const region = config.region || "asia-south1";
|
|
3365
|
-
this.baseURL = this.getBaseURL(environment, region);
|
|
3366
|
-
}
|
|
3367
|
-
getBaseURL(environment, region) {
|
|
3368
|
-
const regionConfig = REGION_CONFIGS[region];
|
|
3369
|
-
if (!regionConfig) {
|
|
3370
|
-
throw new Error(`Unsupported region: ${region}`);
|
|
3371
|
-
}
|
|
3372
|
-
const envConfig = regionConfig[environment];
|
|
3373
|
-
if (!envConfig) {
|
|
3374
|
-
throw new Error(
|
|
3375
|
-
`Unsupported environment: ${environment} for region: ${region}`
|
|
3376
|
-
);
|
|
3377
|
-
}
|
|
3378
|
-
return `${envConfig.baseURL}/v1`;
|
|
3200
|
+
super(apiKey, config);
|
|
3379
3201
|
}
|
|
3380
3202
|
/**
|
|
3381
3203
|
* Insert a single record
|
|
@@ -3651,47 +3473,6 @@ class RecordsApiClient {
|
|
|
3651
3473
|
dbId
|
|
3652
3474
|
);
|
|
3653
3475
|
}
|
|
3654
|
-
buildHeaders() {
|
|
3655
|
-
return {
|
|
3656
|
-
"Content-Type": "application/json",
|
|
3657
|
-
Accept: "application/json",
|
|
3658
|
-
"x-boltic-token": this.config.apiKey
|
|
3659
|
-
};
|
|
3660
|
-
}
|
|
3661
|
-
formatErrorResponse(error) {
|
|
3662
|
-
if (this.config.debug) {
|
|
3663
|
-
console.error("Records API Error:", error);
|
|
3664
|
-
}
|
|
3665
|
-
if (error && typeof error === "object" && "response" in error) {
|
|
3666
|
-
const apiError = error;
|
|
3667
|
-
if (apiError.response?.data?.error) {
|
|
3668
|
-
return apiError.response.data;
|
|
3669
|
-
}
|
|
3670
|
-
return {
|
|
3671
|
-
error: {
|
|
3672
|
-
code: "API_ERROR",
|
|
3673
|
-
message: error.message || "Unknown API error",
|
|
3674
|
-
meta: [`Status: ${apiError.response?.status || "unknown"}`]
|
|
3675
|
-
}
|
|
3676
|
-
};
|
|
3677
|
-
}
|
|
3678
|
-
if (error && typeof error === "object" && "message" in error) {
|
|
3679
|
-
return {
|
|
3680
|
-
error: {
|
|
3681
|
-
code: "CLIENT_ERROR",
|
|
3682
|
-
message: error.message,
|
|
3683
|
-
meta: ["Client-side error occurred"]
|
|
3684
|
-
}
|
|
3685
|
-
};
|
|
3686
|
-
}
|
|
3687
|
-
return {
|
|
3688
|
-
error: {
|
|
3689
|
-
code: "UNKNOWN_ERROR",
|
|
3690
|
-
message: "An unexpected error occurred",
|
|
3691
|
-
meta: ["Unknown error type"]
|
|
3692
|
-
}
|
|
3693
|
-
};
|
|
3694
|
-
}
|
|
3695
3476
|
}
|
|
3696
3477
|
class RecordResource {
|
|
3697
3478
|
constructor(client) {
|
|
@@ -4279,86 +4060,6 @@ const buildSqlEndpointPath = (endpoint, params = {}) => {
|
|
|
4279
4060
|
});
|
|
4280
4061
|
return path;
|
|
4281
4062
|
};
|
|
4282
|
-
class BaseApiClient {
|
|
4283
|
-
constructor(apiKey, config = {}) {
|
|
4284
|
-
this.config = { apiKey, ...config };
|
|
4285
|
-
this.httpAdapter = createHttpAdapter();
|
|
4286
|
-
const environment = config.environment || "prod";
|
|
4287
|
-
const region = config.region || "asia-south1";
|
|
4288
|
-
this.baseURL = this.getBaseURL(environment, region);
|
|
4289
|
-
}
|
|
4290
|
-
getBaseURL(environment, region) {
|
|
4291
|
-
const regionConfig = REGION_CONFIGS[region];
|
|
4292
|
-
if (!regionConfig) {
|
|
4293
|
-
throw new Error(`Unsupported region: ${region}`);
|
|
4294
|
-
}
|
|
4295
|
-
const envConfig = regionConfig[environment];
|
|
4296
|
-
if (!envConfig) {
|
|
4297
|
-
throw new Error(
|
|
4298
|
-
`Unsupported environment: ${environment} for region: ${region}`
|
|
4299
|
-
);
|
|
4300
|
-
}
|
|
4301
|
-
return `${envConfig.baseURL}/v1`;
|
|
4302
|
-
}
|
|
4303
|
-
buildHeaders() {
|
|
4304
|
-
return {
|
|
4305
|
-
"Content-Type": "application/json",
|
|
4306
|
-
Accept: "application/json",
|
|
4307
|
-
"x-boltic-token": this.config.apiKey,
|
|
4308
|
-
...this.config.headers
|
|
4309
|
-
};
|
|
4310
|
-
}
|
|
4311
|
-
formatErrorResponse(error, prefix = "API") {
|
|
4312
|
-
if (this.config.debug) {
|
|
4313
|
-
console.error(`${prefix} Error:`, error);
|
|
4314
|
-
}
|
|
4315
|
-
if (error && typeof error === "object" && "response" in error) {
|
|
4316
|
-
const apiError = error;
|
|
4317
|
-
if (apiError.response?.data?.error) {
|
|
4318
|
-
return apiError.response.data;
|
|
4319
|
-
}
|
|
4320
|
-
return {
|
|
4321
|
-
error: {
|
|
4322
|
-
code: `${prefix}_ERROR`,
|
|
4323
|
-
message: error.message || `Unknown ${prefix} error`,
|
|
4324
|
-
meta: [`Status: ${apiError.response?.status || "unknown"}`]
|
|
4325
|
-
}
|
|
4326
|
-
};
|
|
4327
|
-
}
|
|
4328
|
-
if (error && typeof error === "object" && "message" in error) {
|
|
4329
|
-
return {
|
|
4330
|
-
error: {
|
|
4331
|
-
code: `${prefix}_CLIENT_ERROR`,
|
|
4332
|
-
message: error.message,
|
|
4333
|
-
meta: [`${prefix} client-side error occurred`]
|
|
4334
|
-
}
|
|
4335
|
-
};
|
|
4336
|
-
}
|
|
4337
|
-
return {
|
|
4338
|
-
error: {
|
|
4339
|
-
code: `${prefix}_UNKNOWN_ERROR`,
|
|
4340
|
-
message: `An unexpected ${prefix} error occurred`,
|
|
4341
|
-
meta: [`Unknown ${prefix} error type`]
|
|
4342
|
-
}
|
|
4343
|
-
};
|
|
4344
|
-
}
|
|
4345
|
-
// Security methods to prevent API key exposure
|
|
4346
|
-
toString() {
|
|
4347
|
-
return `${this.constructor.name} { environment: "${this.config.environment || "prod"}", debug: ${this.config.debug || false} }`;
|
|
4348
|
-
}
|
|
4349
|
-
toJSON() {
|
|
4350
|
-
const safeConfig = { ...this.config };
|
|
4351
|
-
delete safeConfig.apiKey;
|
|
4352
|
-
return {
|
|
4353
|
-
client: this.constructor.name,
|
|
4354
|
-
config: safeConfig
|
|
4355
|
-
};
|
|
4356
|
-
}
|
|
4357
|
-
// Custom inspect method for Node.js console logging
|
|
4358
|
-
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
4359
|
-
return this.toString();
|
|
4360
|
-
}
|
|
4361
|
-
}
|
|
4362
4063
|
class SqlApiClient extends BaseApiClient {
|
|
4363
4064
|
constructor(apiKey, config = {}) {
|
|
4364
4065
|
super(apiKey, config);
|
|
@@ -4796,74 +4497,1057 @@ class TableBuilder {
|
|
|
4796
4497
|
function createTableBuilder(options, tablesApiClient) {
|
|
4797
4498
|
return new TableBuilder(options, tablesApiClient);
|
|
4798
4499
|
}
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4500
|
+
const POLLING_INTERVAL_MS = 1e3;
|
|
4501
|
+
const MAX_POLLING_ATTEMPTS = 30;
|
|
4502
|
+
const SCHEMA_TYPE_MAPPING = {
|
|
4503
|
+
string: { type: "string", fallback_value: "" },
|
|
4504
|
+
number: { type: "number", fallback_value: "" },
|
|
4505
|
+
boolean: { type: "boolean", secondary_type: "string", fallback_value: "" },
|
|
4506
|
+
int: { type: "number", fallback_value: "" },
|
|
4507
|
+
integer: { type: "number", fallback_value: "" },
|
|
4508
|
+
"date-time": { type: "date-time", secondary_type: "string", fallback_value: "" },
|
|
4509
|
+
date: { type: "date", secondary_type: "string", fallback_value: "" },
|
|
4510
|
+
json: { type: "object", fallback_value: {} },
|
|
4511
|
+
text: { type: "string", fallback_value: "" },
|
|
4512
|
+
email: { type: "string", fallback_value: "" },
|
|
4513
|
+
password: { type: "string", fallback_value: "" },
|
|
4514
|
+
url: { type: "string", fallback_value: "" },
|
|
4515
|
+
textarea: { type: "string", fallback_value: "" },
|
|
4516
|
+
select: { type: "string", fallback_value: "" },
|
|
4517
|
+
multiselect: { type: "string", fallback_value: "" },
|
|
4518
|
+
autocomplete: { type: "array", fallback_value: [] },
|
|
4519
|
+
radio: { type: "string", fallback_value: "" },
|
|
4520
|
+
radiobuttons: { type: "string", fallback_value: "" },
|
|
4521
|
+
checkbox: { type: "array", fallback_value: [] },
|
|
4522
|
+
toggle: { type: "boolean", fallback_value: "" },
|
|
4523
|
+
hidden: { type: "string", fallback_value: "" },
|
|
4524
|
+
slider: { type: "number", fallback_value: "" },
|
|
4525
|
+
datepicker: { type: "string", fallback_value: "" },
|
|
4526
|
+
phoneinput: { type: "string", fallback_value: "" },
|
|
4527
|
+
time: { type: "string", fallback_value: "" },
|
|
4528
|
+
datetime: { type: "string", fallback_value: "" },
|
|
4529
|
+
code: { type: "string", fallback_value: "" },
|
|
4530
|
+
multitext: { type: "array", fallback_value: [] },
|
|
4531
|
+
array: { type: "array", fallback_value: [] },
|
|
4532
|
+
keyvalue: { type: "object", fallback_value: {} },
|
|
4533
|
+
object: { type: "object", fallback_value: {} },
|
|
4534
|
+
phone: { type: "string", fallback_value: "" },
|
|
4535
|
+
"number[]": { type: "string", fallback_value: "" },
|
|
4536
|
+
"number []": { type: "string", fallback_value: "" },
|
|
4537
|
+
"object | any": { type: "string", fallback_value: "" }
|
|
4538
|
+
};
|
|
4539
|
+
const WORKFLOW_ENDPOINTS = {
|
|
4540
|
+
executeActivity: {
|
|
4541
|
+
path: "/workflows/execute/activity",
|
|
4542
|
+
method: "POST",
|
|
4543
|
+
authenticated: true
|
|
4544
|
+
},
|
|
4545
|
+
getExecutionById: {
|
|
4546
|
+
path: "/workflows/run/{run_id}",
|
|
4547
|
+
method: "GET",
|
|
4548
|
+
authenticated: true
|
|
4549
|
+
},
|
|
4550
|
+
getIntegrations: {
|
|
4551
|
+
path: "/integrations",
|
|
4552
|
+
method: "GET",
|
|
4553
|
+
authenticated: true
|
|
4554
|
+
},
|
|
4555
|
+
getCredentials: {
|
|
4556
|
+
path: "/integrations/entity/{entity}",
|
|
4557
|
+
method: "GET",
|
|
4558
|
+
authenticated: true
|
|
4559
|
+
},
|
|
4560
|
+
getIntegrationResource: {
|
|
4561
|
+
path: "/integrations/{integration_slug}/schema",
|
|
4562
|
+
method: "GET",
|
|
4563
|
+
authenticated: true
|
|
4564
|
+
},
|
|
4565
|
+
getIntegrationForm: {
|
|
4566
|
+
path: "/integrations/{integration_slug}/fields",
|
|
4567
|
+
method: "GET",
|
|
4568
|
+
authenticated: true
|
|
4569
|
+
}
|
|
4570
|
+
};
|
|
4571
|
+
function buildWorkflowEndpointPath(endpoint, params = {}) {
|
|
4572
|
+
let path = endpoint.path;
|
|
4573
|
+
for (const [key, value] of Object.entries(params)) {
|
|
4574
|
+
path = path.replace(`{${key}}`, value);
|
|
4575
|
+
}
|
|
4576
|
+
return path;
|
|
4577
|
+
}
|
|
4578
|
+
class WorkflowApiClient extends BaseApiClient {
|
|
4579
|
+
constructor(apiKey, config = {}) {
|
|
4580
|
+
super(apiKey, config, SERVICE_PATHS.WORKFLOW_TEMPORAL);
|
|
4581
|
+
this.integrationBaseURL = this.resolveAdditionalServiceURL(
|
|
4582
|
+
SERVICE_PATHS.INTEGRATION
|
|
4808
4583
|
);
|
|
4809
|
-
const config = this.configManager.getConfig();
|
|
4810
|
-
this.authManager = new AuthManager2({
|
|
4811
|
-
apiKey: config.apiKey,
|
|
4812
|
-
maxRetries: config.maxRetries
|
|
4813
|
-
});
|
|
4814
|
-
this.baseClient = new BaseClient(config, this.authManager);
|
|
4815
|
-
this.tableResource = new TableResource(this.baseClient);
|
|
4816
|
-
this.columnResource = new ColumnResource(this.baseClient);
|
|
4817
|
-
this.recordResource = new RecordResource(this.baseClient);
|
|
4818
|
-
this.sqlResource = new SqlResource(this.baseClient);
|
|
4819
|
-
this.indexResource = new IndexResource(this.baseClient);
|
|
4820
|
-
this.databaseResource = new DatabaseResource(this.baseClient);
|
|
4821
|
-
this.currentDatabase = null;
|
|
4822
4584
|
}
|
|
4823
4585
|
/**
|
|
4824
|
-
*
|
|
4586
|
+
* Execute a workflow activity.
|
|
4587
|
+
*
|
|
4588
|
+
* @param body - The execute-activity request body
|
|
4825
4589
|
*/
|
|
4826
|
-
|
|
4827
|
-
|
|
4590
|
+
async executeActivity(body) {
|
|
4591
|
+
try {
|
|
4592
|
+
const endpoint = WORKFLOW_ENDPOINTS.executeActivity;
|
|
4593
|
+
const url = `${this.baseURL}${endpoint.path}`;
|
|
4594
|
+
const response = await this.httpAdapter.request({
|
|
4595
|
+
url,
|
|
4596
|
+
method: endpoint.method,
|
|
4597
|
+
headers: this.buildHeaders(),
|
|
4598
|
+
data: body,
|
|
4599
|
+
timeout: this.config.timeout
|
|
4600
|
+
});
|
|
4601
|
+
return response.data;
|
|
4602
|
+
} catch (error) {
|
|
4603
|
+
return this.formatErrorResponse(error, "WORKFLOW");
|
|
4604
|
+
}
|
|
4828
4605
|
}
|
|
4829
4606
|
/**
|
|
4830
|
-
*
|
|
4831
|
-
* All subsequent operations will use this database.
|
|
4832
|
-
*
|
|
4833
|
-
* If no internal name is provided, the SDK will switch back to the default database.
|
|
4834
|
-
*
|
|
4835
|
-
* @param dbInternalName - Database internal name/slug to switch to. If omitted or empty, default DB is used.
|
|
4836
|
-
*
|
|
4837
|
-
* @example
|
|
4838
|
-
* ```typescript
|
|
4839
|
-
* // Switch to a specific database by slug
|
|
4840
|
-
* await client.useDatabase('my_database_slug');
|
|
4607
|
+
* Fetch the result of a workflow execution by its run ID.
|
|
4841
4608
|
*
|
|
4842
|
-
*
|
|
4843
|
-
* await client.useDatabase();
|
|
4844
|
-
* ```
|
|
4609
|
+
* @param runId - The execution run ID returned by `executeActivity`
|
|
4845
4610
|
*/
|
|
4846
|
-
async
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4611
|
+
async getExecutionById(runId) {
|
|
4612
|
+
try {
|
|
4613
|
+
const endpoint = WORKFLOW_ENDPOINTS.getExecutionById;
|
|
4614
|
+
const path = buildWorkflowEndpointPath(endpoint, { run_id: runId });
|
|
4615
|
+
const url = `${this.baseURL}${path}`;
|
|
4616
|
+
const response = await this.httpAdapter.request({
|
|
4617
|
+
url,
|
|
4618
|
+
method: endpoint.method,
|
|
4619
|
+
headers: this.buildHeaders(),
|
|
4620
|
+
timeout: this.config.timeout
|
|
4621
|
+
});
|
|
4622
|
+
return response.data;
|
|
4623
|
+
} catch (error) {
|
|
4624
|
+
return this.formatErrorResponse(error, "WORKFLOW");
|
|
4851
4625
|
}
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4626
|
+
}
|
|
4627
|
+
/**
|
|
4628
|
+
* Fetch the list of available integrations.
|
|
4629
|
+
*
|
|
4630
|
+
* @param params - Optional pagination parameters
|
|
4631
|
+
*/
|
|
4632
|
+
async getIntegrations(params = {}) {
|
|
4633
|
+
try {
|
|
4634
|
+
const endpoint = WORKFLOW_ENDPOINTS.getIntegrations;
|
|
4635
|
+
const query = new URLSearchParams({
|
|
4636
|
+
page: String(params.page ?? 1),
|
|
4637
|
+
per_page: String(params.per_page ?? 999)
|
|
4638
|
+
});
|
|
4639
|
+
const url = `${this.baseURL}${endpoint.path}?${query.toString()}`;
|
|
4640
|
+
const response = await this.httpAdapter.request({
|
|
4641
|
+
url,
|
|
4642
|
+
method: endpoint.method,
|
|
4643
|
+
headers: this.buildHeaders(),
|
|
4644
|
+
timeout: this.config.timeout
|
|
4645
|
+
});
|
|
4646
|
+
return response.data;
|
|
4647
|
+
} catch (error) {
|
|
4648
|
+
return this.formatErrorResponse(error, "WORKFLOW");
|
|
4859
4649
|
}
|
|
4860
|
-
const db = result.data;
|
|
4861
|
-
this.currentDatabase = {
|
|
4862
|
-
databaseId: db.id,
|
|
4863
|
-
dbInternalName: db.db_internal_name || dbInternalName
|
|
4864
|
-
};
|
|
4865
4650
|
}
|
|
4866
|
-
|
|
4651
|
+
/**
|
|
4652
|
+
* Fetch credentials for a given integration entity.
|
|
4653
|
+
*
|
|
4654
|
+
* @param params - Entity name (required) and optional pagination
|
|
4655
|
+
*/
|
|
4656
|
+
async getCredentials(params) {
|
|
4657
|
+
try {
|
|
4658
|
+
const endpoint = WORKFLOW_ENDPOINTS.getCredentials;
|
|
4659
|
+
const path = buildWorkflowEndpointPath(endpoint, {
|
|
4660
|
+
entity: params.entity.toUpperCase()
|
|
4661
|
+
});
|
|
4662
|
+
const query = new URLSearchParams({
|
|
4663
|
+
current_page: String(params.current_page ?? 1),
|
|
4664
|
+
page_size: String(params.page_size ?? 999)
|
|
4665
|
+
});
|
|
4666
|
+
const url = `${this.integrationBaseURL}${path}?${query.toString()}`;
|
|
4667
|
+
const response = await this.httpAdapter.request({
|
|
4668
|
+
url,
|
|
4669
|
+
method: endpoint.method,
|
|
4670
|
+
headers: this.buildHeaders(),
|
|
4671
|
+
timeout: this.config.timeout
|
|
4672
|
+
});
|
|
4673
|
+
return response.data;
|
|
4674
|
+
} catch (error) {
|
|
4675
|
+
return this.formatErrorResponse(error, "INTEGRATION");
|
|
4676
|
+
}
|
|
4677
|
+
}
|
|
4678
|
+
/**
|
|
4679
|
+
* Fetch the resource/operation schema for an integration.
|
|
4680
|
+
*
|
|
4681
|
+
* @param params - Integration slug identifier
|
|
4682
|
+
*/
|
|
4683
|
+
async getIntegrationResource(params) {
|
|
4684
|
+
try {
|
|
4685
|
+
const endpoint = WORKFLOW_ENDPOINTS.getIntegrationResource;
|
|
4686
|
+
const path = buildWorkflowEndpointPath(endpoint, {
|
|
4687
|
+
integration_slug: params.integration_slug
|
|
4688
|
+
});
|
|
4689
|
+
const url = `${this.baseURL}${path}`;
|
|
4690
|
+
const response = await this.httpAdapter.request({
|
|
4691
|
+
url,
|
|
4692
|
+
method: endpoint.method,
|
|
4693
|
+
headers: this.buildHeaders(),
|
|
4694
|
+
timeout: this.config.timeout
|
|
4695
|
+
});
|
|
4696
|
+
return response.data;
|
|
4697
|
+
} catch (error) {
|
|
4698
|
+
return this.formatErrorResponse(error, "WORKFLOW");
|
|
4699
|
+
}
|
|
4700
|
+
}
|
|
4701
|
+
/**
|
|
4702
|
+
* Fetch the form schema (fields) for a specific integration resource + operation.
|
|
4703
|
+
*
|
|
4704
|
+
* @param params - Integration slug, resource, operation, and credential secret
|
|
4705
|
+
*/
|
|
4706
|
+
async getIntegrationForm(params) {
|
|
4707
|
+
try {
|
|
4708
|
+
const endpoint = WORKFLOW_ENDPOINTS.getIntegrationForm;
|
|
4709
|
+
const path = buildWorkflowEndpointPath(endpoint, {
|
|
4710
|
+
integration_slug: params.integration_slug
|
|
4711
|
+
});
|
|
4712
|
+
const query = new URLSearchParams({
|
|
4713
|
+
resource: params.resource,
|
|
4714
|
+
operation: params.operation,
|
|
4715
|
+
// getFormOnly: String(params.getFormOnly ?? true),
|
|
4716
|
+
secret: params.secret
|
|
4717
|
+
});
|
|
4718
|
+
const url = `${this.baseURL}${path}?${query.toString()}`;
|
|
4719
|
+
const response = await this.httpAdapter.request({
|
|
4720
|
+
url,
|
|
4721
|
+
method: endpoint.method,
|
|
4722
|
+
headers: this.buildHeaders(),
|
|
4723
|
+
timeout: this.config.timeout
|
|
4724
|
+
});
|
|
4725
|
+
return response.data;
|
|
4726
|
+
} catch (error) {
|
|
4727
|
+
return this.formatErrorResponse(error, "WORKFLOW");
|
|
4728
|
+
}
|
|
4729
|
+
}
|
|
4730
|
+
}
|
|
4731
|
+
const FORM_META_FIELDS = /* @__PURE__ */ new Set(["resource", "operation"]);
|
|
4732
|
+
function getSchemaMapping(displayType) {
|
|
4733
|
+
return SCHEMA_TYPE_MAPPING[displayType] ?? {
|
|
4734
|
+
type: "string",
|
|
4735
|
+
fallback_value: ""
|
|
4736
|
+
};
|
|
4737
|
+
}
|
|
4738
|
+
function transformFormToDefaults(fields, skipFields = FORM_META_FIELDS) {
|
|
4739
|
+
const result = {};
|
|
4740
|
+
for (const field of fields) {
|
|
4741
|
+
if (skipFields.has(field.name)) continue;
|
|
4742
|
+
const displayType = field.meta?.displayType || "text";
|
|
4743
|
+
const mapping = getSchemaMapping(displayType);
|
|
4744
|
+
result[field.name] = field.meta?.value !== void 0 ? field.meta.value : mapping.fallback_value;
|
|
4745
|
+
}
|
|
4746
|
+
return result;
|
|
4747
|
+
}
|
|
4748
|
+
function transformFormToJsonSchema(fields, skipFields = FORM_META_FIELDS) {
|
|
4749
|
+
const properties = {};
|
|
4750
|
+
for (const field of fields) {
|
|
4751
|
+
if (skipFields.has(field.name)) continue;
|
|
4752
|
+
const displayType = field.meta?.displayType || "text";
|
|
4753
|
+
const mapping = getSchemaMapping(displayType);
|
|
4754
|
+
const isRequired = field.meta?.validation?.required ?? false;
|
|
4755
|
+
const defaultValue = field.meta?.value !== void 0 ? field.meta.value : mapping.fallback_value;
|
|
4756
|
+
const prop = {
|
|
4757
|
+
type: mapping.type,
|
|
4758
|
+
required: isRequired,
|
|
4759
|
+
default: defaultValue
|
|
4760
|
+
};
|
|
4761
|
+
if (field.meta?.description) {
|
|
4762
|
+
prop.description = field.meta.description;
|
|
4763
|
+
}
|
|
4764
|
+
if (field.meta?.options && Array.isArray(field.meta.options) && field.meta.options.length > 0) {
|
|
4765
|
+
prop.enum = field.meta.options.map((opt) => opt.value);
|
|
4766
|
+
}
|
|
4767
|
+
properties[field.name] = prop;
|
|
4768
|
+
}
|
|
4769
|
+
return { type: "object", properties };
|
|
4770
|
+
}
|
|
4771
|
+
function buildDefaultResultPayload() {
|
|
4772
|
+
return {
|
|
4773
|
+
payload: {},
|
|
4774
|
+
global_variables: {}
|
|
4775
|
+
};
|
|
4776
|
+
}
|
|
4777
|
+
function buildExecuteActivityBody(params) {
|
|
4778
|
+
const node = {
|
|
4779
|
+
data: {
|
|
4780
|
+
type: params.data.type,
|
|
4781
|
+
name: params.data.name,
|
|
4782
|
+
properties: params.data.properties
|
|
4783
|
+
}
|
|
4784
|
+
};
|
|
4785
|
+
return {
|
|
4786
|
+
nodes: [node],
|
|
4787
|
+
result: params.result ?? buildDefaultResultPayload()
|
|
4788
|
+
};
|
|
4789
|
+
}
|
|
4790
|
+
function sleep$1(ms) {
|
|
4791
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4792
|
+
}
|
|
4793
|
+
class WorkflowResource extends BaseResource {
|
|
4794
|
+
constructor(client) {
|
|
4795
|
+
super(client, "/workflows");
|
|
4796
|
+
const config = client.getConfig();
|
|
4797
|
+
this.apiClient = new WorkflowApiClient(config.apiKey, {
|
|
4798
|
+
environment: config.environment,
|
|
4799
|
+
region: config.region,
|
|
4800
|
+
timeout: config.timeout,
|
|
4801
|
+
debug: config.debug
|
|
4802
|
+
});
|
|
4803
|
+
}
|
|
4804
|
+
/**
|
|
4805
|
+
* Execute a workflow integration activity.
|
|
4806
|
+
*
|
|
4807
|
+
* When `executeOnly` is `true`, returns the immediate API response.
|
|
4808
|
+
* When `executeOnly` is `false` (default), polls until a terminal state
|
|
4809
|
+
* is reached and returns the final execution result.
|
|
4810
|
+
*
|
|
4811
|
+
* @param params - Execution parameters
|
|
4812
|
+
* @returns The execute response or the final polled result
|
|
4813
|
+
*
|
|
4814
|
+
* @example
|
|
4815
|
+
* ```typescript
|
|
4816
|
+
* const result = await client.workflow.executeIntegration({
|
|
4817
|
+
* data: { type: 'apiActivity', name: 'api1', properties: { method: 'get', endpoint: '...' } },
|
|
4818
|
+
* });
|
|
4819
|
+
*
|
|
4820
|
+
* const fire = await client.workflow.executeIntegration({
|
|
4821
|
+
* data: { type: 'apiActivity', name: 'api1', properties: { method: 'get', endpoint: '...' } },
|
|
4822
|
+
* executeOnly: true,
|
|
4823
|
+
* });
|
|
4824
|
+
* ```
|
|
4825
|
+
*/
|
|
4826
|
+
async executeIntegration(params) {
|
|
4827
|
+
const body = buildExecuteActivityBody(params);
|
|
4828
|
+
const executeResult = await this.apiClient.executeActivity(body);
|
|
4829
|
+
if (isErrorResponse(executeResult)) {
|
|
4830
|
+
return executeResult;
|
|
4831
|
+
}
|
|
4832
|
+
if (params.executeOnly) {
|
|
4833
|
+
return executeResult;
|
|
4834
|
+
}
|
|
4835
|
+
const executionId = executeResult.data?.execution_id;
|
|
4836
|
+
if (!executionId) {
|
|
4837
|
+
return {
|
|
4838
|
+
error: {
|
|
4839
|
+
code: "MISSING_EXECUTION_ID",
|
|
4840
|
+
message: "Execute API response did not contain an execution_id",
|
|
4841
|
+
meta: []
|
|
4842
|
+
}
|
|
4843
|
+
};
|
|
4844
|
+
}
|
|
4845
|
+
return this.pollExecution(executionId);
|
|
4846
|
+
}
|
|
4847
|
+
/**
|
|
4848
|
+
* Retrieve the result of a workflow execution by its run/execution ID.
|
|
4849
|
+
*
|
|
4850
|
+
* @param executionId - The execution run ID
|
|
4851
|
+
* @returns The execution data or an error response
|
|
4852
|
+
*
|
|
4853
|
+
* @example
|
|
4854
|
+
* ```typescript
|
|
4855
|
+
* const result = await client.workflow.getIntegrationExecuteById('run-uuid');
|
|
4856
|
+
* ```
|
|
4857
|
+
*/
|
|
4858
|
+
async getIntegrationExecuteById(executionId) {
|
|
4859
|
+
return this.apiClient.getExecutionById(executionId);
|
|
4860
|
+
}
|
|
4861
|
+
/**
|
|
4862
|
+
* Fetch the list of available integrations.
|
|
4863
|
+
*
|
|
4864
|
+
* @param params - Optional pagination parameters (`page`, `per_page`)
|
|
4865
|
+
* @returns The integrations list or an error response
|
|
4866
|
+
*
|
|
4867
|
+
* @example
|
|
4868
|
+
* ```typescript
|
|
4869
|
+
* const list = await client.workflow.getIntegrations();
|
|
4870
|
+
* ```
|
|
4871
|
+
*/
|
|
4872
|
+
async getIntegrations(params = {}) {
|
|
4873
|
+
return this.apiClient.getIntegrations(params);
|
|
4874
|
+
}
|
|
4875
|
+
/**
|
|
4876
|
+
* Fetch credentials for a given integration entity.
|
|
4877
|
+
*
|
|
4878
|
+
* @param params - Entity name (required), optional `current_page` and `page_size`
|
|
4879
|
+
* @returns The credentials list or an error response
|
|
4880
|
+
*
|
|
4881
|
+
* @example
|
|
4882
|
+
* ```typescript
|
|
4883
|
+
* const creds = await client.workflow.getCredentials({ entity: 'freshsales' });
|
|
4884
|
+
* ```
|
|
4885
|
+
*/
|
|
4886
|
+
async getCredentials(params) {
|
|
4887
|
+
return this.apiClient.getCredentials(params);
|
|
4888
|
+
}
|
|
4889
|
+
/**
|
|
4890
|
+
* Fetch the resource/operation schema for an integration.
|
|
4891
|
+
*
|
|
4892
|
+
* Returns the available resources and operations supported by the
|
|
4893
|
+
* specified integration (e.g. which resources like "task", "project"
|
|
4894
|
+
* are available and what operations can be performed on them).
|
|
4895
|
+
*
|
|
4896
|
+
* @param params - Integration slug identifier
|
|
4897
|
+
* @returns The integration resource schema or an error response
|
|
4898
|
+
*
|
|
4899
|
+
* @example
|
|
4900
|
+
* ```typescript
|
|
4901
|
+
* const schema = await client.workflow.getIntegrationResource({
|
|
4902
|
+
* integration_slug: 'blt-int.asana',
|
|
4903
|
+
* });
|
|
4904
|
+
* ```
|
|
4905
|
+
*/
|
|
4906
|
+
async getIntegrationResource(params) {
|
|
4907
|
+
return this.apiClient.getIntegrationResource(params);
|
|
4908
|
+
}
|
|
4909
|
+
/**
|
|
4910
|
+
* Fetch the form schema (fields) for a specific integration resource + operation.
|
|
4911
|
+
*
|
|
4912
|
+
* By default, returns a flat JSON object with default/fallback values
|
|
4913
|
+
* for each input field. Set `asJsonSchema: true` to get a JSON Schema
|
|
4914
|
+
* object describing the expected input shape instead.
|
|
4915
|
+
*
|
|
4916
|
+
* Fields like `resource` and `operation` are automatically excluded
|
|
4917
|
+
* since they are already handled by the SDK parameters. The `secret`
|
|
4918
|
+
* field is included and populated with the value from `params.secret`.
|
|
4919
|
+
*
|
|
4920
|
+
* @param params - Integration slug, resource, operation, credential secret, and format flag
|
|
4921
|
+
* @returns Transformed form data or an error response
|
|
4922
|
+
*
|
|
4923
|
+
* @example
|
|
4924
|
+
* ```typescript
|
|
4925
|
+
* // Get flat defaults: { name: '', workspace: [], team: '', ... }
|
|
4926
|
+
* const defaults = await client.workflow.getIntegrationForm({
|
|
4927
|
+
* integration_slug: 'blt-int.asana',
|
|
4928
|
+
* resource: 'project',
|
|
4929
|
+
* operation: 'create',
|
|
4930
|
+
* secret: 'credential-secret-here',
|
|
4931
|
+
* });
|
|
4932
|
+
*
|
|
4933
|
+
* // Get JSON Schema: { type: 'object', properties: { name: { type: 'string', ... } } }
|
|
4934
|
+
* const schema = await client.workflow.getIntegrationForm({
|
|
4935
|
+
* integration_slug: 'blt-int.asana',
|
|
4936
|
+
* resource: 'project',
|
|
4937
|
+
* operation: 'create',
|
|
4938
|
+
* secret: 'credential-secret-here',
|
|
4939
|
+
* asJsonSchema: true,
|
|
4940
|
+
* });
|
|
4941
|
+
* ```
|
|
4942
|
+
*/
|
|
4943
|
+
async getIntegrationForm(params) {
|
|
4944
|
+
const rawResult = await this.apiClient.getIntegrationForm(params);
|
|
4945
|
+
console.log("rawResult", JSON.stringify(rawResult, null, 2));
|
|
4946
|
+
if (isErrorResponse(rawResult)) {
|
|
4947
|
+
return rawResult;
|
|
4948
|
+
}
|
|
4949
|
+
const configuration = rawResult.data?.parameters || rawResult.data;
|
|
4950
|
+
const fields = configuration ?? [];
|
|
4951
|
+
const transformed = params.asJsonSchema ? transformFormToJsonSchema(fields) : transformFormToDefaults(fields);
|
|
4952
|
+
if (params.asJsonSchema) {
|
|
4953
|
+
const schema = transformed;
|
|
4954
|
+
if (schema.properties.secret) {
|
|
4955
|
+
schema.properties.secret.default = params.secret;
|
|
4956
|
+
}
|
|
4957
|
+
} else {
|
|
4958
|
+
const defaults = transformed;
|
|
4959
|
+
if ("secret" in defaults) {
|
|
4960
|
+
defaults.secret = params.secret;
|
|
4961
|
+
}
|
|
4962
|
+
}
|
|
4963
|
+
return {
|
|
4964
|
+
data: transformed,
|
|
4965
|
+
message: rawResult.message
|
|
4966
|
+
};
|
|
4967
|
+
}
|
|
4968
|
+
/**
|
|
4969
|
+
* Internal polling loop.
|
|
4970
|
+
* Repeatedly calls `getExecutionById` until the response `data` object is
|
|
4971
|
+
* non-empty (execution finished) or max attempts are exhausted.
|
|
4972
|
+
*/
|
|
4973
|
+
async pollExecution(executionId) {
|
|
4974
|
+
const debug = this.client.getConfig().debug;
|
|
4975
|
+
for (let attempt = 0; attempt < MAX_POLLING_ATTEMPTS; attempt++) {
|
|
4976
|
+
const result = await this.apiClient.getExecutionById(executionId);
|
|
4977
|
+
if (isErrorResponse(result)) {
|
|
4978
|
+
return result;
|
|
4979
|
+
}
|
|
4980
|
+
if (result.data && Object.keys(result.data).length > 0) {
|
|
4981
|
+
if (debug) {
|
|
4982
|
+
console.log(
|
|
4983
|
+
`[WorkflowResource] Execution ${executionId} completed after ${attempt + 1} poll(s)`
|
|
4984
|
+
);
|
|
4985
|
+
}
|
|
4986
|
+
return result;
|
|
4987
|
+
}
|
|
4988
|
+
await sleep$1(POLLING_INTERVAL_MS);
|
|
4989
|
+
}
|
|
4990
|
+
return {
|
|
4991
|
+
error: {
|
|
4992
|
+
code: "EXECUTION_TIMEOUT",
|
|
4993
|
+
message: `Execution ${executionId} did not complete within ${MAX_POLLING_ATTEMPTS} polling attempts`,
|
|
4994
|
+
meta: [
|
|
4995
|
+
`execution_id: ${executionId}`,
|
|
4996
|
+
`max_attempts: ${MAX_POLLING_ATTEMPTS}`
|
|
4997
|
+
]
|
|
4998
|
+
}
|
|
4999
|
+
};
|
|
5000
|
+
}
|
|
5001
|
+
}
|
|
5002
|
+
const STATUS_POLLING_INTERVAL_MS = 5e3;
|
|
5003
|
+
const MAX_STATUS_POLLING_ATTEMPTS = 60;
|
|
5004
|
+
const TERMINAL_STATUSES = [
|
|
5005
|
+
"running",
|
|
5006
|
+
"failed",
|
|
5007
|
+
"degraded",
|
|
5008
|
+
"suspended"
|
|
5009
|
+
];
|
|
5010
|
+
const DEFAULT_RESOURCES = {
|
|
5011
|
+
CPU: 0.1,
|
|
5012
|
+
MemoryMB: 128,
|
|
5013
|
+
MemoryMaxMB: 128
|
|
5014
|
+
};
|
|
5015
|
+
const DEFAULT_SCALING = {
|
|
5016
|
+
AutoStop: false,
|
|
5017
|
+
Min: 1,
|
|
5018
|
+
Max: 1,
|
|
5019
|
+
MaxIdleTime: 0
|
|
5020
|
+
};
|
|
5021
|
+
const SERVERLESS_ENDPOINTS = {
|
|
5022
|
+
list: {
|
|
5023
|
+
path: "/apps",
|
|
5024
|
+
method: "GET",
|
|
5025
|
+
authenticated: true
|
|
5026
|
+
},
|
|
5027
|
+
get: {
|
|
5028
|
+
path: "/apps/{app_id}",
|
|
5029
|
+
method: "GET",
|
|
5030
|
+
authenticated: true
|
|
5031
|
+
},
|
|
5032
|
+
create: {
|
|
5033
|
+
path: "/apps",
|
|
5034
|
+
method: "POST",
|
|
5035
|
+
authenticated: true
|
|
5036
|
+
},
|
|
5037
|
+
update: {
|
|
5038
|
+
path: "/apps/{app_id}",
|
|
5039
|
+
method: "PUT",
|
|
5040
|
+
authenticated: true
|
|
5041
|
+
},
|
|
5042
|
+
getBuilds: {
|
|
5043
|
+
path: "/apps/{app_id}/builds",
|
|
5044
|
+
method: "GET",
|
|
5045
|
+
authenticated: true
|
|
5046
|
+
},
|
|
5047
|
+
getLogs: {
|
|
5048
|
+
path: "/apps/{app_id}/logs",
|
|
5049
|
+
method: "GET",
|
|
5050
|
+
authenticated: true
|
|
5051
|
+
},
|
|
5052
|
+
getBuildLogs: {
|
|
5053
|
+
path: "/apps/{app_id}/builds/{build_id}/logs",
|
|
5054
|
+
method: "GET",
|
|
5055
|
+
authenticated: true
|
|
5056
|
+
}
|
|
5057
|
+
};
|
|
5058
|
+
function buildServerlessEndpointPath(endpoint, params = {}) {
|
|
5059
|
+
let path = endpoint.path;
|
|
5060
|
+
for (const [key, value] of Object.entries(params)) {
|
|
5061
|
+
path = path.replace(`{${key}}`, value);
|
|
5062
|
+
}
|
|
5063
|
+
return path;
|
|
5064
|
+
}
|
|
5065
|
+
class ServerlessApiClient extends BaseApiClient {
|
|
5066
|
+
constructor(apiKey, config = {}) {
|
|
5067
|
+
super(apiKey, config, SERVICE_PATHS.SERVERLESS);
|
|
5068
|
+
}
|
|
5069
|
+
/**
|
|
5070
|
+
* List all serverless functions with optional pagination and search.
|
|
5071
|
+
*/
|
|
5072
|
+
async list(params = {}) {
|
|
5073
|
+
try {
|
|
5074
|
+
const endpoint = SERVERLESS_ENDPOINTS.list;
|
|
5075
|
+
const query = new URLSearchParams({
|
|
5076
|
+
page: String(params.page ?? 1),
|
|
5077
|
+
limit: String(params.limit ?? 20),
|
|
5078
|
+
sortBy: params.sortBy ?? "CreatedAt",
|
|
5079
|
+
sortOrder: params.sortOrder ?? "desc"
|
|
5080
|
+
});
|
|
5081
|
+
if (params.query) {
|
|
5082
|
+
query.set("q", params.query);
|
|
5083
|
+
}
|
|
5084
|
+
const url = `${this.baseURL}${endpoint.path}?${query.toString()}`;
|
|
5085
|
+
const response = await this.httpAdapter.request({
|
|
5086
|
+
url,
|
|
5087
|
+
method: endpoint.method,
|
|
5088
|
+
headers: this.buildHeaders(),
|
|
5089
|
+
timeout: this.config.timeout
|
|
5090
|
+
});
|
|
5091
|
+
return response.data;
|
|
5092
|
+
} catch (error) {
|
|
5093
|
+
return this.formatErrorResponse(error, "SERVERLESS");
|
|
5094
|
+
}
|
|
5095
|
+
}
|
|
5096
|
+
/**
|
|
5097
|
+
* Get a serverless function by its ID.
|
|
5098
|
+
*/
|
|
5099
|
+
async get(appId) {
|
|
5100
|
+
try {
|
|
5101
|
+
const endpoint = SERVERLESS_ENDPOINTS.get;
|
|
5102
|
+
const path = buildServerlessEndpointPath(endpoint, { app_id: appId });
|
|
5103
|
+
const url = `${this.baseURL}${path}`;
|
|
5104
|
+
console.log("url", url);
|
|
5105
|
+
const response = await this.httpAdapter.request({
|
|
5106
|
+
url,
|
|
5107
|
+
method: endpoint.method,
|
|
5108
|
+
headers: this.buildHeaders(),
|
|
5109
|
+
timeout: this.config.timeout
|
|
5110
|
+
});
|
|
5111
|
+
console.log("response", response.data);
|
|
5112
|
+
return response.data;
|
|
5113
|
+
} catch (error) {
|
|
5114
|
+
return this.formatErrorResponse(error, "SERVERLESS");
|
|
5115
|
+
}
|
|
5116
|
+
}
|
|
5117
|
+
/**
|
|
5118
|
+
* Create a new serverless function.
|
|
5119
|
+
*/
|
|
5120
|
+
async create(payload) {
|
|
5121
|
+
try {
|
|
5122
|
+
const endpoint = SERVERLESS_ENDPOINTS.create;
|
|
5123
|
+
const url = `${this.baseURL}${endpoint.path}`;
|
|
5124
|
+
const response = await this.httpAdapter.request({
|
|
5125
|
+
url,
|
|
5126
|
+
method: endpoint.method,
|
|
5127
|
+
headers: this.buildHeaders(),
|
|
5128
|
+
data: payload,
|
|
5129
|
+
timeout: this.config.timeout
|
|
5130
|
+
});
|
|
5131
|
+
return response.data;
|
|
5132
|
+
} catch (error) {
|
|
5133
|
+
return this.formatErrorResponse(error, "SERVERLESS");
|
|
5134
|
+
}
|
|
5135
|
+
}
|
|
5136
|
+
/**
|
|
5137
|
+
* Update an existing serverless function.
|
|
5138
|
+
*/
|
|
5139
|
+
async update(params) {
|
|
5140
|
+
try {
|
|
5141
|
+
const endpoint = SERVERLESS_ENDPOINTS.update;
|
|
5142
|
+
const path = buildServerlessEndpointPath(endpoint, {
|
|
5143
|
+
app_id: params.appId
|
|
5144
|
+
});
|
|
5145
|
+
const url = `${this.baseURL}${path}`;
|
|
5146
|
+
const response = await this.httpAdapter.request({
|
|
5147
|
+
url,
|
|
5148
|
+
method: endpoint.method,
|
|
5149
|
+
headers: this.buildHeaders(),
|
|
5150
|
+
data: params.payload,
|
|
5151
|
+
timeout: this.config.timeout
|
|
5152
|
+
});
|
|
5153
|
+
return response.data;
|
|
5154
|
+
} catch (error) {
|
|
5155
|
+
return this.formatErrorResponse(error, "SERVERLESS");
|
|
5156
|
+
}
|
|
5157
|
+
}
|
|
5158
|
+
/**
|
|
5159
|
+
* List builds for a serverless function.
|
|
5160
|
+
*/
|
|
5161
|
+
async getBuilds(params) {
|
|
5162
|
+
try {
|
|
5163
|
+
const endpoint = SERVERLESS_ENDPOINTS.getBuilds;
|
|
5164
|
+
const path = buildServerlessEndpointPath(endpoint, {
|
|
5165
|
+
app_id: params.appId
|
|
5166
|
+
});
|
|
5167
|
+
const query = new URLSearchParams({
|
|
5168
|
+
page: String(params.page ?? 1),
|
|
5169
|
+
limit: String(params.limit ?? 20),
|
|
5170
|
+
sortBy: "CreatedAt",
|
|
5171
|
+
sortOrder: "desc"
|
|
5172
|
+
});
|
|
5173
|
+
const url = `${this.baseURL}${path}?${query.toString()}`;
|
|
5174
|
+
const response = await this.httpAdapter.request({
|
|
5175
|
+
url,
|
|
5176
|
+
method: endpoint.method,
|
|
5177
|
+
headers: this.buildHeaders(),
|
|
5178
|
+
timeout: this.config.timeout
|
|
5179
|
+
});
|
|
5180
|
+
return response.data;
|
|
5181
|
+
} catch (error) {
|
|
5182
|
+
return this.formatErrorResponse(error, "SERVERLESS");
|
|
5183
|
+
}
|
|
5184
|
+
}
|
|
5185
|
+
/**
|
|
5186
|
+
* Get runtime logs for a serverless function.
|
|
5187
|
+
*/
|
|
5188
|
+
async getLogs(params) {
|
|
5189
|
+
try {
|
|
5190
|
+
const endpoint = SERVERLESS_ENDPOINTS.getLogs;
|
|
5191
|
+
const path = buildServerlessEndpointPath(endpoint, {
|
|
5192
|
+
app_id: params.appId
|
|
5193
|
+
});
|
|
5194
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
5195
|
+
const defaultStart = now - 24 * 60 * 60;
|
|
5196
|
+
const query = new URLSearchParams({
|
|
5197
|
+
page: String(params.page ?? 1),
|
|
5198
|
+
limit: String(params.limit ?? 50),
|
|
5199
|
+
sortBy: "Timestamp",
|
|
5200
|
+
sortOrder: params.sortOrder ?? "DESC",
|
|
5201
|
+
timestampStart: String(params.timestampStart ?? defaultStart),
|
|
5202
|
+
timestampEnd: String(params.timestampEnd ?? now),
|
|
5203
|
+
metric_interval: "60"
|
|
5204
|
+
});
|
|
5205
|
+
const url = `${this.baseURL}${path}?${query.toString()}`;
|
|
5206
|
+
const response = await this.httpAdapter.request({
|
|
5207
|
+
url,
|
|
5208
|
+
method: endpoint.method,
|
|
5209
|
+
headers: this.buildHeaders(),
|
|
5210
|
+
timeout: this.config.timeout
|
|
5211
|
+
});
|
|
5212
|
+
return response.data;
|
|
5213
|
+
} catch (error) {
|
|
5214
|
+
return this.formatErrorResponse(error, "SERVERLESS");
|
|
5215
|
+
}
|
|
5216
|
+
}
|
|
5217
|
+
/**
|
|
5218
|
+
* Get build logs for a specific build of a serverless function.
|
|
5219
|
+
*/
|
|
5220
|
+
async getBuildLogs(params) {
|
|
5221
|
+
try {
|
|
5222
|
+
const endpoint = SERVERLESS_ENDPOINTS.getBuildLogs;
|
|
5223
|
+
const path = buildServerlessEndpointPath(endpoint, {
|
|
5224
|
+
app_id: params.appId,
|
|
5225
|
+
build_id: params.buildId
|
|
5226
|
+
});
|
|
5227
|
+
const query = new URLSearchParams({
|
|
5228
|
+
limit: "-1",
|
|
5229
|
+
tail: "false",
|
|
5230
|
+
sortOrder: "asc",
|
|
5231
|
+
sortBy: "Timestamp"
|
|
5232
|
+
});
|
|
5233
|
+
const url = `${this.baseURL}${path}?${query.toString()}`;
|
|
5234
|
+
const response = await this.httpAdapter.request({
|
|
5235
|
+
url,
|
|
5236
|
+
method: endpoint.method,
|
|
5237
|
+
headers: this.buildHeaders(),
|
|
5238
|
+
timeout: this.config.timeout
|
|
5239
|
+
});
|
|
5240
|
+
return response.data;
|
|
5241
|
+
} catch (error) {
|
|
5242
|
+
return this.formatErrorResponse(error, "SERVERLESS");
|
|
5243
|
+
}
|
|
5244
|
+
}
|
|
5245
|
+
}
|
|
5246
|
+
function sleep(ms) {
|
|
5247
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
5248
|
+
}
|
|
5249
|
+
class ServerlessResource extends BaseResource {
|
|
5250
|
+
constructor(client) {
|
|
5251
|
+
super(client, "/serverless");
|
|
5252
|
+
const config = client.getConfig();
|
|
5253
|
+
this.apiClient = new ServerlessApiClient(config.apiKey, {
|
|
5254
|
+
environment: config.environment,
|
|
5255
|
+
region: config.region,
|
|
5256
|
+
timeout: config.timeout,
|
|
5257
|
+
debug: config.debug
|
|
5258
|
+
});
|
|
5259
|
+
}
|
|
5260
|
+
/**
|
|
5261
|
+
* List all serverless functions with optional pagination and search.
|
|
5262
|
+
*
|
|
5263
|
+
* @param params - Optional pagination and filter parameters
|
|
5264
|
+
* @returns Paginated list of serverless functions
|
|
5265
|
+
*
|
|
5266
|
+
* @example
|
|
5267
|
+
* ```typescript
|
|
5268
|
+
* const list = await client.serverless.list();
|
|
5269
|
+
* const filtered = await client.serverless.list({ query: 'my-func', limit: 10 });
|
|
5270
|
+
* ```
|
|
5271
|
+
*/
|
|
5272
|
+
async list(params = {}) {
|
|
5273
|
+
return this.apiClient.list(params);
|
|
5274
|
+
}
|
|
5275
|
+
/**
|
|
5276
|
+
* Get a serverless function by its ID.
|
|
5277
|
+
*
|
|
5278
|
+
* @param appId - The serverless function ID
|
|
5279
|
+
* @returns The serverless function details
|
|
5280
|
+
*
|
|
5281
|
+
* @example
|
|
5282
|
+
* ```typescript
|
|
5283
|
+
* const fn = await client.serverless.get('serverless-id');
|
|
5284
|
+
* ```
|
|
5285
|
+
*/
|
|
5286
|
+
async get(appId) {
|
|
5287
|
+
return this.apiClient.get(appId);
|
|
5288
|
+
}
|
|
5289
|
+
/**
|
|
5290
|
+
* Create a new serverless function.
|
|
5291
|
+
*
|
|
5292
|
+
* Supports three runtime types:
|
|
5293
|
+
* - `code` — deploy code directly (blueprint)
|
|
5294
|
+
* - `git` — deploy from a Git repository
|
|
5295
|
+
* - `container` — deploy a Docker container
|
|
5296
|
+
*
|
|
5297
|
+
* @param params - The serverless creation payload
|
|
5298
|
+
* @returns The created serverless function
|
|
5299
|
+
*
|
|
5300
|
+
* @example
|
|
5301
|
+
* ```typescript
|
|
5302
|
+
* const fn = await client.serverless.create({
|
|
5303
|
+
* Name: 'my-api',
|
|
5304
|
+
* Runtime: 'code',
|
|
5305
|
+
* Resources: { CPU: 0.1, MemoryMB: 128, MemoryMaxMB: 128 },
|
|
5306
|
+
* Scaling: { AutoStop: false, Min: 1, Max: 1, MaxIdleTime: 0 },
|
|
5307
|
+
* CodeOpts: { Language: 'nodejs/20', Code: 'module.exports.handler = ...' },
|
|
5308
|
+
* });
|
|
5309
|
+
* ```
|
|
5310
|
+
*/
|
|
5311
|
+
async create(params) {
|
|
5312
|
+
return this.apiClient.create(params);
|
|
5313
|
+
}
|
|
5314
|
+
/**
|
|
5315
|
+
* Create a serverless function and poll until it reaches a terminal state.
|
|
5316
|
+
*
|
|
5317
|
+
* Combines `create()` + `pollStatus()` for a simpler workflow.
|
|
5318
|
+
*
|
|
5319
|
+
* @param params - The serverless creation payload
|
|
5320
|
+
* @returns The final serverless state after reaching a terminal status
|
|
5321
|
+
*
|
|
5322
|
+
* @example
|
|
5323
|
+
* ```typescript
|
|
5324
|
+
* const fn = await client.serverless.createAndWait({
|
|
5325
|
+
* Name: 'my-api',
|
|
5326
|
+
* Runtime: 'code',
|
|
5327
|
+
* CodeOpts: { Language: 'nodejs/20', Code: '...' },
|
|
5328
|
+
* Resources: { CPU: 0.1, MemoryMB: 128, MemoryMaxMB: 128 },
|
|
5329
|
+
* Scaling: { AutoStop: false, Min: 1, Max: 1, MaxIdleTime: 0 },
|
|
5330
|
+
* });
|
|
5331
|
+
* ```
|
|
5332
|
+
*/
|
|
5333
|
+
async createAndWait(params) {
|
|
5334
|
+
const createResult = await this.apiClient.create(params);
|
|
5335
|
+
if (isErrorResponse(createResult)) {
|
|
5336
|
+
return createResult;
|
|
5337
|
+
}
|
|
5338
|
+
const appId = createResult.data?.ID;
|
|
5339
|
+
if (!appId) {
|
|
5340
|
+
return {
|
|
5341
|
+
error: {
|
|
5342
|
+
code: "SERVERLESS_MISSING_ID",
|
|
5343
|
+
message: "Create API response did not contain an ID",
|
|
5344
|
+
meta: []
|
|
5345
|
+
}
|
|
5346
|
+
};
|
|
5347
|
+
}
|
|
5348
|
+
return this.pollStatus(appId);
|
|
5349
|
+
}
|
|
5350
|
+
/**
|
|
5351
|
+
* Update an existing serverless function.
|
|
5352
|
+
*
|
|
5353
|
+
* @param params - The update parameters (appId + partial payload)
|
|
5354
|
+
* @returns The updated serverless function
|
|
5355
|
+
*
|
|
5356
|
+
* @example
|
|
5357
|
+
* ```typescript
|
|
5358
|
+
* const updated = await client.serverless.update({
|
|
5359
|
+
* appId: 'serverless-id',
|
|
5360
|
+
* payload: { Scaling: { AutoStop: true, Min: 0, Max: 3, MaxIdleTime: 300 } },
|
|
5361
|
+
* });
|
|
5362
|
+
* ```
|
|
5363
|
+
*/
|
|
5364
|
+
async update(params) {
|
|
5365
|
+
return this.apiClient.update(params);
|
|
5366
|
+
}
|
|
5367
|
+
/**
|
|
5368
|
+
* Update a serverless function and poll until it reaches a terminal state.
|
|
5369
|
+
*
|
|
5370
|
+
* @param params - The update parameters (appId + partial payload)
|
|
5371
|
+
* @returns The final serverless state after reaching a terminal status
|
|
5372
|
+
*/
|
|
5373
|
+
async updateAndWait(params) {
|
|
5374
|
+
const updateResult = await this.apiClient.update(params);
|
|
5375
|
+
if (isErrorResponse(updateResult)) {
|
|
5376
|
+
return updateResult;
|
|
5377
|
+
}
|
|
5378
|
+
return this.pollStatus(params.appId);
|
|
5379
|
+
}
|
|
5380
|
+
/**
|
|
5381
|
+
* List builds for a serverless function.
|
|
5382
|
+
*
|
|
5383
|
+
* @param params - The app ID and optional pagination
|
|
5384
|
+
* @returns List of builds
|
|
5385
|
+
*
|
|
5386
|
+
* @example
|
|
5387
|
+
* ```typescript
|
|
5388
|
+
* const builds = await client.serverless.getBuilds({ appId: 'serverless-id' });
|
|
5389
|
+
* ```
|
|
5390
|
+
*/
|
|
5391
|
+
async getBuilds(params) {
|
|
5392
|
+
return this.apiClient.getBuilds(params);
|
|
5393
|
+
}
|
|
5394
|
+
/**
|
|
5395
|
+
* Get runtime logs for a serverless function.
|
|
5396
|
+
*
|
|
5397
|
+
* @param params - The app ID and optional time range / pagination
|
|
5398
|
+
* @returns Log entries
|
|
5399
|
+
*
|
|
5400
|
+
* @example
|
|
5401
|
+
* ```typescript
|
|
5402
|
+
* const logs = await client.serverless.getLogs({ appId: 'serverless-id' });
|
|
5403
|
+
* const recentLogs = await client.serverless.getLogs({
|
|
5404
|
+
* appId: 'serverless-id',
|
|
5405
|
+
* limit: 100,
|
|
5406
|
+
* sortOrder: 'DESC',
|
|
5407
|
+
* });
|
|
5408
|
+
* ```
|
|
5409
|
+
*/
|
|
5410
|
+
async getLogs(params) {
|
|
5411
|
+
return this.apiClient.getLogs(params);
|
|
5412
|
+
}
|
|
5413
|
+
/**
|
|
5414
|
+
* Get build logs for a specific build.
|
|
5415
|
+
*
|
|
5416
|
+
* @param params - The app ID and build ID
|
|
5417
|
+
* @returns Build log entries
|
|
5418
|
+
*
|
|
5419
|
+
* @example
|
|
5420
|
+
* ```typescript
|
|
5421
|
+
* const logs = await client.serverless.getBuildLogs({
|
|
5422
|
+
* appId: 'serverless-id',
|
|
5423
|
+
* buildId: 'build-id',
|
|
5424
|
+
* });
|
|
5425
|
+
* ```
|
|
5426
|
+
*/
|
|
5427
|
+
async getBuildLogs(params) {
|
|
5428
|
+
return this.apiClient.getBuildLogs(params);
|
|
5429
|
+
}
|
|
5430
|
+
/**
|
|
5431
|
+
* Poll a serverless function until it reaches a terminal status
|
|
5432
|
+
* (running, failed, degraded, or suspended).
|
|
5433
|
+
*
|
|
5434
|
+
* @param appId - The serverless function ID to poll
|
|
5435
|
+
* @param options - Optional polling configuration overrides
|
|
5436
|
+
* @returns The final serverless state or a timeout error
|
|
5437
|
+
*
|
|
5438
|
+
* @example
|
|
5439
|
+
* ```typescript
|
|
5440
|
+
* const result = await client.serverless.pollStatus('serverless-id');
|
|
5441
|
+
* ```
|
|
5442
|
+
*/
|
|
5443
|
+
async pollStatus(appId, options = {}) {
|
|
5444
|
+
const interval = options.intervalMs ?? STATUS_POLLING_INTERVAL_MS;
|
|
5445
|
+
const maxAttempts = options.maxAttempts ?? MAX_STATUS_POLLING_ATTEMPTS;
|
|
5446
|
+
const debug = this.client.getConfig().debug;
|
|
5447
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
5448
|
+
const result = await this.apiClient.get(appId);
|
|
5449
|
+
if (isErrorResponse(result)) {
|
|
5450
|
+
return result;
|
|
5451
|
+
}
|
|
5452
|
+
const status = result.data?.Status;
|
|
5453
|
+
if (debug) {
|
|
5454
|
+
console.log(
|
|
5455
|
+
`[ServerlessResource] Poll #${attempt + 1}: status=${status}`
|
|
5456
|
+
);
|
|
5457
|
+
}
|
|
5458
|
+
if (status && TERMINAL_STATUSES.includes(status)) {
|
|
5459
|
+
if (debug) {
|
|
5460
|
+
console.log(
|
|
5461
|
+
`[ServerlessResource] Reached terminal state: ${status} after ${attempt + 1} poll(s)`
|
|
5462
|
+
);
|
|
5463
|
+
}
|
|
5464
|
+
return result;
|
|
5465
|
+
}
|
|
5466
|
+
await sleep(interval);
|
|
5467
|
+
}
|
|
5468
|
+
return {
|
|
5469
|
+
error: {
|
|
5470
|
+
code: "SERVERLESS_STATUS_TIMEOUT",
|
|
5471
|
+
message: `Serverless ${appId} did not reach a terminal state within ${maxAttempts} polling attempts`,
|
|
5472
|
+
meta: [
|
|
5473
|
+
`app_id: ${appId}`,
|
|
5474
|
+
`max_attempts: ${maxAttempts}`,
|
|
5475
|
+
`interval_ms: ${interval}`
|
|
5476
|
+
]
|
|
5477
|
+
}
|
|
5478
|
+
};
|
|
5479
|
+
}
|
|
5480
|
+
}
|
|
5481
|
+
class BolticClient {
|
|
5482
|
+
constructor(apiKey, options = {}) {
|
|
5483
|
+
this.currentDatabase = null;
|
|
5484
|
+
this.clientOptions = options;
|
|
5485
|
+
this.configManager = new ConfigManager(
|
|
5486
|
+
apiKey,
|
|
5487
|
+
options.environment || "prod",
|
|
5488
|
+
options.region || "asia-south1",
|
|
5489
|
+
options
|
|
5490
|
+
);
|
|
5491
|
+
const config = this.configManager.getConfig();
|
|
5492
|
+
this.authManager = new AuthManager2({
|
|
5493
|
+
apiKey: config.apiKey,
|
|
5494
|
+
maxRetries: config.maxRetries
|
|
5495
|
+
});
|
|
5496
|
+
this.baseClient = new BaseClient(config, this.authManager);
|
|
5497
|
+
this.tableResource = new TableResource(this.baseClient);
|
|
5498
|
+
this.columnResource = new ColumnResource(this.baseClient);
|
|
5499
|
+
this.recordResource = new RecordResource(this.baseClient);
|
|
5500
|
+
this.sqlResource = new SqlResource(this.baseClient);
|
|
5501
|
+
this.indexResource = new IndexResource(this.baseClient);
|
|
5502
|
+
this.databaseResource = new DatabaseResource(this.baseClient);
|
|
5503
|
+
this.workflowResource = new WorkflowResource(this.baseClient);
|
|
5504
|
+
this.serverlessResource = new ServerlessResource(this.baseClient);
|
|
5505
|
+
this.currentDatabase = null;
|
|
5506
|
+
}
|
|
5507
|
+
/**
|
|
5508
|
+
* Get current database context
|
|
5509
|
+
*/
|
|
5510
|
+
getCurrentDatabase() {
|
|
5511
|
+
return this.currentDatabase;
|
|
5512
|
+
}
|
|
5513
|
+
/**
|
|
5514
|
+
* Switch to a different database using its internal name (slug).
|
|
5515
|
+
* All subsequent operations will use this database.
|
|
5516
|
+
*
|
|
5517
|
+
* If no internal name is provided, the SDK will switch back to the default database.
|
|
5518
|
+
*
|
|
5519
|
+
* @param dbInternalName - Database internal name/slug to switch to. If omitted or empty, default DB is used.
|
|
5520
|
+
*
|
|
5521
|
+
* @example
|
|
5522
|
+
* ```typescript
|
|
5523
|
+
* // Switch to a specific database by slug
|
|
5524
|
+
* await client.useDatabase('my_database_slug');
|
|
5525
|
+
*
|
|
5526
|
+
* // Switch back to default database
|
|
5527
|
+
* await client.useDatabase();
|
|
5528
|
+
* ```
|
|
5529
|
+
*/
|
|
5530
|
+
async useDatabase(dbInternalName) {
|
|
5531
|
+
console.log(`Database internal name:${dbInternalName}`);
|
|
5532
|
+
if (!dbInternalName || dbInternalName === "") {
|
|
5533
|
+
this.currentDatabase = null;
|
|
5534
|
+
return;
|
|
5535
|
+
}
|
|
5536
|
+
const result = await this.databaseResource.findOne(dbInternalName);
|
|
5537
|
+
console.log(`Result:${JSON.stringify(result, null, 2)}`);
|
|
5538
|
+
if (isErrorResponse(result)) {
|
|
5539
|
+
console.log(`Error:${result.error.message}`);
|
|
5540
|
+
throw new Error(
|
|
5541
|
+
result.error.message || `Failed to switch database to internal name '${dbInternalName}'`
|
|
5542
|
+
);
|
|
5543
|
+
}
|
|
5544
|
+
const db = result.data;
|
|
5545
|
+
this.currentDatabase = {
|
|
5546
|
+
databaseId: db.id,
|
|
5547
|
+
dbInternalName: db.db_internal_name || dbInternalName
|
|
5548
|
+
};
|
|
5549
|
+
}
|
|
5550
|
+
// Direct database operations
|
|
4867
5551
|
get databases() {
|
|
4868
5552
|
return {
|
|
4869
5553
|
create: (data) => this.databaseResource.create(data),
|
|
@@ -4972,6 +5656,74 @@ class BolticClient {
|
|
|
4972
5656
|
executeSQL: (query) => this.sqlResource.executeSQL(query, dbId)
|
|
4973
5657
|
};
|
|
4974
5658
|
}
|
|
5659
|
+
/**
|
|
5660
|
+
* Workflow integration operations.
|
|
5661
|
+
*
|
|
5662
|
+
* @example
|
|
5663
|
+
* ```typescript
|
|
5664
|
+
* // Execute and poll for result
|
|
5665
|
+
* const result = await client.workflow.executeIntegration({
|
|
5666
|
+
* nodes: [{ id: 'api1', data: { ... }, activity_data: { ... } }],
|
|
5667
|
+
* });
|
|
5668
|
+
*
|
|
5669
|
+
* // Get execution result by ID
|
|
5670
|
+
* const exec = await client.workflow.getIntegrationExecuteById('run-uuid');
|
|
5671
|
+
*
|
|
5672
|
+
* // List integrations
|
|
5673
|
+
* const integrations = await client.workflow.getIntegrations();
|
|
5674
|
+
* ```
|
|
5675
|
+
*/
|
|
5676
|
+
get workflow() {
|
|
5677
|
+
return {
|
|
5678
|
+
executeIntegration: (params) => this.workflowResource.executeIntegration(params),
|
|
5679
|
+
getIntegrationExecuteById: (executionId) => this.workflowResource.getIntegrationExecuteById(executionId),
|
|
5680
|
+
getIntegrations: (params) => this.workflowResource.getIntegrations(params),
|
|
5681
|
+
getCredentials: (params) => this.workflowResource.getCredentials(params),
|
|
5682
|
+
getIntegrationResource: (params) => this.workflowResource.getIntegrationResource(params),
|
|
5683
|
+
getIntegrationForm: (params) => this.workflowResource.getIntegrationForm(params)
|
|
5684
|
+
};
|
|
5685
|
+
}
|
|
5686
|
+
/**
|
|
5687
|
+
* Serverless function operations.
|
|
5688
|
+
*
|
|
5689
|
+
* @example
|
|
5690
|
+
* ```typescript
|
|
5691
|
+
* // List all serverless functions
|
|
5692
|
+
* const list = await client.serverless.list();
|
|
5693
|
+
*
|
|
5694
|
+
* // Create a new serverless function
|
|
5695
|
+
* const fn = await client.serverless.create({
|
|
5696
|
+
* Name: 'my-api',
|
|
5697
|
+
* Runtime: 'code',
|
|
5698
|
+
* CodeOpts: { Language: 'nodejs/20', Code: '...' },
|
|
5699
|
+
* Resources: { CPU: 0.1, MemoryMB: 128, MemoryMaxMB: 128 },
|
|
5700
|
+
* Scaling: { AutoStop: false, Min: 1, Max: 1, MaxIdleTime: 0 },
|
|
5701
|
+
* });
|
|
5702
|
+
*
|
|
5703
|
+
* // Get a serverless function by ID
|
|
5704
|
+
* const details = await client.serverless.get('serverless-id');
|
|
5705
|
+
*
|
|
5706
|
+
* // Get builds
|
|
5707
|
+
* const builds = await client.serverless.getBuilds({ appId: 'id' });
|
|
5708
|
+
*
|
|
5709
|
+
* // Get runtime logs
|
|
5710
|
+
* const logs = await client.serverless.getLogs({ appId: 'id' });
|
|
5711
|
+
* ```
|
|
5712
|
+
*/
|
|
5713
|
+
get serverless() {
|
|
5714
|
+
return {
|
|
5715
|
+
list: (params) => this.serverlessResource.list(params),
|
|
5716
|
+
get: (appId) => this.serverlessResource.get(appId),
|
|
5717
|
+
create: (params) => this.serverlessResource.create(params),
|
|
5718
|
+
createAndWait: (params) => this.serverlessResource.createAndWait(params),
|
|
5719
|
+
update: (params) => this.serverlessResource.update(params),
|
|
5720
|
+
updateAndWait: (params) => this.serverlessResource.updateAndWait(params),
|
|
5721
|
+
getBuilds: (params) => this.serverlessResource.getBuilds(params),
|
|
5722
|
+
getLogs: (params) => this.serverlessResource.getLogs(params),
|
|
5723
|
+
getBuildLogs: (params) => this.serverlessResource.getBuildLogs(params),
|
|
5724
|
+
pollStatus: (appId, options) => this.serverlessResource.pollStatus(appId, options)
|
|
5725
|
+
};
|
|
5726
|
+
}
|
|
4975
5727
|
// SQL resource access for testing
|
|
4976
5728
|
getSqlResource() {
|
|
4977
5729
|
return this.sqlResource;
|
|
@@ -5054,6 +5806,8 @@ class BolticClient {
|
|
|
5054
5806
|
this.sqlResource = new SqlResource(this.baseClient);
|
|
5055
5807
|
this.indexResource = new IndexResource(this.baseClient);
|
|
5056
5808
|
this.databaseResource = new DatabaseResource(this.baseClient);
|
|
5809
|
+
this.workflowResource = new WorkflowResource(this.baseClient);
|
|
5810
|
+
this.serverlessResource = new ServerlessResource(this.baseClient);
|
|
5057
5811
|
}
|
|
5058
5812
|
// Security methods to prevent API key exposure
|
|
5059
5813
|
toString() {
|
|
@@ -5081,7 +5835,16 @@ function createClient(apiKey, options = {}) {
|
|
|
5081
5835
|
const VERSION = "1.0.0";
|
|
5082
5836
|
exports.AuthManager = AuthManager$1;
|
|
5083
5837
|
exports.BolticClient = BolticClient;
|
|
5838
|
+
exports.DEFAULT_RESOURCES = DEFAULT_RESOURCES;
|
|
5839
|
+
exports.DEFAULT_SCALING = DEFAULT_SCALING;
|
|
5840
|
+
exports.MAX_STATUS_POLLING_ATTEMPTS = MAX_STATUS_POLLING_ATTEMPTS;
|
|
5841
|
+
exports.SERVICE_PATHS = SERVICE_PATHS;
|
|
5842
|
+
exports.STATUS_POLLING_INTERVAL_MS = STATUS_POLLING_INTERVAL_MS;
|
|
5843
|
+
exports.ServerlessApiClient = ServerlessApiClient;
|
|
5844
|
+
exports.ServerlessResource = ServerlessResource;
|
|
5845
|
+
exports.TERMINAL_STATUSES = TERMINAL_STATUSES;
|
|
5084
5846
|
exports.VERSION = VERSION;
|
|
5847
|
+
exports.WorkflowResource = WorkflowResource;
|
|
5085
5848
|
exports.createClient = createClient;
|
|
5086
5849
|
exports.createErrorWithContext = createErrorWithContext$1;
|
|
5087
5850
|
exports.formatError = formatError$1;
|
|
@@ -5089,4 +5852,7 @@ exports.getHttpStatusCode = getHttpStatusCode$1;
|
|
|
5089
5852
|
exports.isErrorResponse = isErrorResponse;
|
|
5090
5853
|
exports.isListResponse = isListResponse;
|
|
5091
5854
|
exports.isNetworkError = isNetworkError;
|
|
5855
|
+
exports.resolveServiceURL = resolveServiceURL;
|
|
5856
|
+
exports.transformFormToDefaults = transformFormToDefaults;
|
|
5857
|
+
exports.transformFormToJsonSchema = transformFormToJsonSchema;
|
|
5092
5858
|
//# sourceMappingURL=sdk.js.map
|