@boltic/sdk 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/databases/index.d.ts +82 -0
- package/dist/databases/index.js +1 -1
- package/dist/databases/index.mjs +1 -1
- package/dist/databases/test-client-DzMli6cH.js +2 -0
- package/dist/databases/test-client-DzMli6cH.js.map +1 -0
- package/dist/databases/test-client-rR_4EBUe.mjs +2 -0
- package/dist/databases/test-client-rR_4EBUe.mjs.map +1 -0
- package/dist/databases/testing.d.ts +82 -0
- package/dist/databases/testing.js +1 -1
- package/dist/databases/testing.mjs +1 -1
- package/dist/sdk.js +559 -22
- package/dist/sdk.js.map +1 -1
- package/dist/sdk.mjs +559 -22
- package/dist/sdk.mjs.map +1 -1
- package/dist/types/index.d.ts +271 -0
- package/package.json +1 -1
- package/dist/databases/test-client-BEAX5vfC.mjs +0 -2
- package/dist/databases/test-client-BEAX5vfC.mjs.map +0 -1
- package/dist/databases/test-client-BgkvBtst.js +0 -2
- package/dist/databases/test-client-BgkvBtst.js.map +0 -1
package/dist/sdk.js
CHANGED
|
@@ -236,6 +236,20 @@ Context: ${JSON.stringify(context, null, 2)}`;
|
|
|
236
236
|
}
|
|
237
237
|
return String(error);
|
|
238
238
|
}
|
|
239
|
+
function decodeArrayBufferErrorBody(buffer) {
|
|
240
|
+
const txt = new TextDecoder().decode(buffer);
|
|
241
|
+
try {
|
|
242
|
+
return JSON.parse(txt);
|
|
243
|
+
} catch {
|
|
244
|
+
return txt;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function normalizeAxiosDataAfterResponse(config, status, data) {
|
|
248
|
+
if (config.responseType !== "arraybuffer" || !(data instanceof ArrayBuffer) || status < 400) {
|
|
249
|
+
return data;
|
|
250
|
+
}
|
|
251
|
+
return decodeArrayBufferErrorBody(data);
|
|
252
|
+
}
|
|
239
253
|
class AxiosAdapter {
|
|
240
254
|
constructor() {
|
|
241
255
|
try {
|
|
@@ -249,21 +263,36 @@ class AxiosAdapter {
|
|
|
249
263
|
}
|
|
250
264
|
async request(config) {
|
|
251
265
|
try {
|
|
266
|
+
const isFormData = typeof FormData !== "undefined" && config.data instanceof FormData;
|
|
267
|
+
let headers = config.headers;
|
|
268
|
+
if (isFormData && headers) {
|
|
269
|
+
headers = { ...headers };
|
|
270
|
+
delete headers["Content-Type"];
|
|
271
|
+
delete headers["content-type"];
|
|
272
|
+
}
|
|
252
273
|
const axiosConfig = {
|
|
253
274
|
url: config.url,
|
|
254
275
|
method: config.method.toLowerCase(),
|
|
255
|
-
headers
|
|
276
|
+
headers,
|
|
256
277
|
params: config.params,
|
|
257
278
|
data: config.data,
|
|
258
279
|
timeout: config.timeout,
|
|
259
280
|
signal: config.signal,
|
|
260
281
|
validateStatus: () => true
|
|
261
282
|
};
|
|
283
|
+
if (config.responseType === "arraybuffer") {
|
|
284
|
+
axiosConfig.responseType = "arraybuffer";
|
|
285
|
+
}
|
|
262
286
|
const response = await this.axios(axiosConfig);
|
|
287
|
+
const responseData = normalizeAxiosDataAfterResponse(
|
|
288
|
+
config,
|
|
289
|
+
response.status,
|
|
290
|
+
response.data
|
|
291
|
+
);
|
|
263
292
|
if (response.status < 200 || response.status >= 300) {
|
|
264
|
-
const isHtmlError = typeof
|
|
293
|
+
const isHtmlError = typeof responseData === "string" && responseData.trim().startsWith("<!DOCTYPE") || typeof responseData === "string" && responseData.includes("<html");
|
|
265
294
|
if (isHtmlError) {
|
|
266
|
-
const htmlContent =
|
|
295
|
+
const htmlContent = responseData;
|
|
267
296
|
const preMatch = htmlContent.match(/<pre>(.*?)<\/pre>/s);
|
|
268
297
|
const errorMessage = preMatch ? preMatch[1].trim() : `HTTP ${response.status}: ${response.statusText}`;
|
|
269
298
|
throw createErrorWithContext(errorMessage, {
|
|
@@ -274,9 +303,9 @@ class AxiosAdapter {
|
|
|
274
303
|
isHtmlError: true
|
|
275
304
|
});
|
|
276
305
|
}
|
|
277
|
-
if (
|
|
306
|
+
if (responseData && typeof responseData === "object" && "error" in responseData) {
|
|
278
307
|
return {
|
|
279
|
-
data:
|
|
308
|
+
data: responseData,
|
|
280
309
|
status: response.status,
|
|
281
310
|
statusText: response.statusText,
|
|
282
311
|
headers: response.headers || {}
|
|
@@ -289,12 +318,12 @@ class AxiosAdapter {
|
|
|
289
318
|
method: config.method,
|
|
290
319
|
status: response.status,
|
|
291
320
|
statusText: response.statusText,
|
|
292
|
-
responseData
|
|
321
|
+
responseData
|
|
293
322
|
}
|
|
294
323
|
);
|
|
295
324
|
}
|
|
296
325
|
return {
|
|
297
|
-
data:
|
|
326
|
+
data: responseData,
|
|
298
327
|
status: response.status,
|
|
299
328
|
statusText: response.statusText,
|
|
300
329
|
headers: response.headers || {}
|
|
@@ -337,6 +366,26 @@ class AxiosAdapter {
|
|
|
337
366
|
}
|
|
338
367
|
}
|
|
339
368
|
}
|
|
369
|
+
async function parseFetchBodyDefault(response) {
|
|
370
|
+
const contentType = response.headers.get("content-type");
|
|
371
|
+
if (contentType?.includes("application/json")) {
|
|
372
|
+
return response.json();
|
|
373
|
+
}
|
|
374
|
+
return response.text();
|
|
375
|
+
}
|
|
376
|
+
async function parseFetchBodyArrayBuffer(response) {
|
|
377
|
+
const buf = await response.arrayBuffer();
|
|
378
|
+
if (response.status >= 400) {
|
|
379
|
+
return decodeArrayBufferErrorBody(buf);
|
|
380
|
+
}
|
|
381
|
+
return buf;
|
|
382
|
+
}
|
|
383
|
+
async function parseFetchResponseData(response, config) {
|
|
384
|
+
if (config.responseType === "arraybuffer") {
|
|
385
|
+
return parseFetchBodyArrayBuffer(response);
|
|
386
|
+
}
|
|
387
|
+
return parseFetchBodyDefault(response);
|
|
388
|
+
}
|
|
340
389
|
class FetchAdapter {
|
|
341
390
|
async request(config) {
|
|
342
391
|
const url = new URL(config.url);
|
|
@@ -347,16 +396,21 @@ class FetchAdapter {
|
|
|
347
396
|
}
|
|
348
397
|
});
|
|
349
398
|
}
|
|
399
|
+
const isFormData = typeof FormData !== "undefined" && config.data instanceof FormData;
|
|
400
|
+
const headerMap = { ...config.headers || {} };
|
|
401
|
+
if (!isFormData) {
|
|
402
|
+
headerMap["Content-Type"] = headerMap["Content-Type"] ?? headerMap["content-type"] ?? "application/json";
|
|
403
|
+
} else {
|
|
404
|
+
delete headerMap["Content-Type"];
|
|
405
|
+
delete headerMap["content-type"];
|
|
406
|
+
}
|
|
350
407
|
const init = {
|
|
351
408
|
method: config.method,
|
|
352
|
-
headers:
|
|
353
|
-
"Content-Type": "application/json",
|
|
354
|
-
...config.headers
|
|
355
|
-
},
|
|
409
|
+
headers: headerMap,
|
|
356
410
|
signal: config.signal
|
|
357
411
|
};
|
|
358
412
|
if (config.data && ["POST", "PUT", "PATCH", "DELETE"].includes(config.method)) {
|
|
359
|
-
init.body = JSON.stringify(config.data);
|
|
413
|
+
init.body = isFormData ? config.data : JSON.stringify(config.data);
|
|
360
414
|
}
|
|
361
415
|
try {
|
|
362
416
|
const controller = new AbortController();
|
|
@@ -380,13 +434,10 @@ class FetchAdapter {
|
|
|
380
434
|
if (timeoutId) {
|
|
381
435
|
clearTimeout(timeoutId);
|
|
382
436
|
}
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
} else {
|
|
388
|
-
data = await response.text();
|
|
389
|
-
}
|
|
437
|
+
const data = await parseFetchResponseData(
|
|
438
|
+
response,
|
|
439
|
+
config
|
|
440
|
+
);
|
|
390
441
|
const headers = {};
|
|
391
442
|
response.headers.forEach((value, key) => {
|
|
392
443
|
headers[key] = value;
|
|
@@ -550,7 +601,8 @@ const SERVICE_PATHS = {
|
|
|
550
601
|
DATABASES: "/service/sdk/boltic-tables/v1",
|
|
551
602
|
WORKFLOW_TEMPORAL: "/service/panel/temporal/v1.0",
|
|
552
603
|
INTEGRATION: "/service/panel/integration/v1",
|
|
553
|
-
SERVERLESS: "/service/panel/serverless/v1.0"
|
|
604
|
+
SERVERLESS: "/service/panel/serverless/v1.0",
|
|
605
|
+
STORAGE: "/service/panel/storage/v1.0"
|
|
554
606
|
};
|
|
555
607
|
class BaseApiClient {
|
|
556
608
|
constructor(apiKey, config = {}, servicePath = SERVICE_PATHS.DATABASES) {
|
|
@@ -4077,7 +4129,10 @@ class SqlApiClient extends BaseApiClient {
|
|
|
4077
4129
|
const response = await this.httpAdapter.request({
|
|
4078
4130
|
url,
|
|
4079
4131
|
method: endpoint.method,
|
|
4080
|
-
headers:
|
|
4132
|
+
headers: {
|
|
4133
|
+
...this.buildHeaders(),
|
|
4134
|
+
"x-request-source": "sdk"
|
|
4135
|
+
},
|
|
4081
4136
|
data: request,
|
|
4082
4137
|
timeout: this.config.timeout
|
|
4083
4138
|
});
|
|
@@ -4108,7 +4163,10 @@ class SqlApiClient extends BaseApiClient {
|
|
|
4108
4163
|
const response = await this.httpAdapter.request({
|
|
4109
4164
|
url,
|
|
4110
4165
|
method: endpoint.method,
|
|
4111
|
-
headers:
|
|
4166
|
+
headers: {
|
|
4167
|
+
...this.buildHeaders(),
|
|
4168
|
+
"x-request-source": "sdk"
|
|
4169
|
+
},
|
|
4112
4170
|
data: request,
|
|
4113
4171
|
timeout: this.config.timeout
|
|
4114
4172
|
});
|
|
@@ -5478,6 +5536,466 @@ class ServerlessResource extends BaseResource {
|
|
|
5478
5536
|
};
|
|
5479
5537
|
}
|
|
5480
5538
|
}
|
|
5539
|
+
const DEFAULT_STORAGE_TYPE = "gcs";
|
|
5540
|
+
const MAX_SIGNED_URL_EXPIRE_MINUTES = 7 * 24 * 60;
|
|
5541
|
+
const STORAGE_ENDPOINTS = {
|
|
5542
|
+
list: {
|
|
5543
|
+
path: "/storage/list",
|
|
5544
|
+
method: "GET",
|
|
5545
|
+
authenticated: true
|
|
5546
|
+
},
|
|
5547
|
+
upload: {
|
|
5548
|
+
path: "/storage/upload",
|
|
5549
|
+
method: "POST",
|
|
5550
|
+
authenticated: true
|
|
5551
|
+
},
|
|
5552
|
+
directory: {
|
|
5553
|
+
path: "/storage/directory",
|
|
5554
|
+
method: "POST",
|
|
5555
|
+
authenticated: true
|
|
5556
|
+
},
|
|
5557
|
+
deleteFile: {
|
|
5558
|
+
path: "/storage/file",
|
|
5559
|
+
method: "DELETE",
|
|
5560
|
+
authenticated: true
|
|
5561
|
+
},
|
|
5562
|
+
objectAccess: {
|
|
5563
|
+
path: "/storage/change-object-access",
|
|
5564
|
+
method: "POST",
|
|
5565
|
+
authenticated: true
|
|
5566
|
+
},
|
|
5567
|
+
fileExport: {
|
|
5568
|
+
path: "/storage/file-export",
|
|
5569
|
+
method: "POST",
|
|
5570
|
+
authenticated: true
|
|
5571
|
+
}
|
|
5572
|
+
};
|
|
5573
|
+
function buildStorageEndpointPath(endpoint) {
|
|
5574
|
+
return endpoint.path;
|
|
5575
|
+
}
|
|
5576
|
+
const ERR_PREFIX = "STORAGE";
|
|
5577
|
+
class StorageApiClient extends BaseApiClient {
|
|
5578
|
+
constructor(apiKey, config = {}) {
|
|
5579
|
+
super(apiKey, config, SERVICE_PATHS.STORAGE);
|
|
5580
|
+
}
|
|
5581
|
+
/** Shared try/catch + http — same idea as inlined blocks in serverless/workflow clients, but DRY for storage. */
|
|
5582
|
+
async requestStorage(config) {
|
|
5583
|
+
try {
|
|
5584
|
+
const response = await this.httpAdapter.request(config);
|
|
5585
|
+
return response.data;
|
|
5586
|
+
} catch (error) {
|
|
5587
|
+
return this.formatErrorResponse(error, ERR_PREFIX);
|
|
5588
|
+
}
|
|
5589
|
+
}
|
|
5590
|
+
url(path, query) {
|
|
5591
|
+
const qs = query?.toString();
|
|
5592
|
+
return qs ? `${this.baseURL}${path}?${qs}` : `${this.baseURL}${path}`;
|
|
5593
|
+
}
|
|
5594
|
+
storageTypeQuery(storageType) {
|
|
5595
|
+
const q = new URLSearchParams();
|
|
5596
|
+
q.set("storageType", storageType ?? DEFAULT_STORAGE_TYPE);
|
|
5597
|
+
return q;
|
|
5598
|
+
}
|
|
5599
|
+
listQuery(params) {
|
|
5600
|
+
const q = this.storageTypeQuery(params.storageType);
|
|
5601
|
+
if (params.basePath !== void 0) {
|
|
5602
|
+
q.set("basePath", params.basePath);
|
|
5603
|
+
}
|
|
5604
|
+
if (params.pageSize !== void 0) {
|
|
5605
|
+
q.set("pageSize", String(params.pageSize));
|
|
5606
|
+
}
|
|
5607
|
+
if (params.nextPageToken !== void 0) {
|
|
5608
|
+
q.set("nextPageToken", params.nextPageToken);
|
|
5609
|
+
}
|
|
5610
|
+
return q;
|
|
5611
|
+
}
|
|
5612
|
+
/** `expire_in` is minutes; clamp to max temporary URL lifetime (7 days). */
|
|
5613
|
+
normalizeExpireInMinutes(raw) {
|
|
5614
|
+
const n = typeof raw === "number" ? raw : Number(raw);
|
|
5615
|
+
if (!Number.isFinite(n) || n <= 0) {
|
|
5616
|
+
throw new Error(
|
|
5617
|
+
"expire_in must be a positive number of minutes (max 7 days for temporary signed URLs)"
|
|
5618
|
+
);
|
|
5619
|
+
}
|
|
5620
|
+
const truncated = Math.trunc(n);
|
|
5621
|
+
return Math.min(Math.max(1, truncated), MAX_SIGNED_URL_EXPIRE_MINUTES);
|
|
5622
|
+
}
|
|
5623
|
+
isTruthyFormFlag(v) {
|
|
5624
|
+
if (v === void 0) return false;
|
|
5625
|
+
if (typeof v === "boolean") return v;
|
|
5626
|
+
const s = String(v).toLowerCase();
|
|
5627
|
+
return s === "true" || s === "1" || s === "yes";
|
|
5628
|
+
}
|
|
5629
|
+
/**
|
|
5630
|
+
* `public` shortcut: true + no expire_in → permanent; true + expire_in → temporary signed URL; false → private.
|
|
5631
|
+
* Legacy: omit `public` and pass `is_public` / `is_public_permanent` / `expire_in` as before.
|
|
5632
|
+
*/
|
|
5633
|
+
appendUploadVisibility(form, params) {
|
|
5634
|
+
const hasPublic = Object.prototype.hasOwnProperty.call(params, "public");
|
|
5635
|
+
if (hasPublic) {
|
|
5636
|
+
const pub = this.isTruthyFormFlag(params.public);
|
|
5637
|
+
if (!pub) {
|
|
5638
|
+
form.append("is_public", "false");
|
|
5639
|
+
return;
|
|
5640
|
+
}
|
|
5641
|
+
if (params.expire_in !== void 0) {
|
|
5642
|
+
form.append("is_public", "true");
|
|
5643
|
+
form.append(
|
|
5644
|
+
"expire_in",
|
|
5645
|
+
String(this.normalizeExpireInMinutes(params.expire_in))
|
|
5646
|
+
);
|
|
5647
|
+
return;
|
|
5648
|
+
}
|
|
5649
|
+
form.append("is_public", "false");
|
|
5650
|
+
form.append("is_public_permanent", "true");
|
|
5651
|
+
return;
|
|
5652
|
+
}
|
|
5653
|
+
if (params.is_public !== void 0) {
|
|
5654
|
+
form.append("is_public", String(params.is_public));
|
|
5655
|
+
}
|
|
5656
|
+
if (params.expire_in !== void 0) {
|
|
5657
|
+
form.append(
|
|
5658
|
+
"expire_in",
|
|
5659
|
+
String(this.normalizeExpireInMinutes(params.expire_in))
|
|
5660
|
+
);
|
|
5661
|
+
}
|
|
5662
|
+
if (params.is_public_permanent !== void 0) {
|
|
5663
|
+
form.append("is_public_permanent", String(params.is_public_permanent));
|
|
5664
|
+
}
|
|
5665
|
+
}
|
|
5666
|
+
buildUploadForm(params) {
|
|
5667
|
+
const logicalName = params.filename ?? params.file_name;
|
|
5668
|
+
if (logicalName == null || logicalName === "") {
|
|
5669
|
+
throw new Error("upload requires filename or file_name");
|
|
5670
|
+
}
|
|
5671
|
+
const form = new FormData();
|
|
5672
|
+
form.append("file", params.file, logicalName);
|
|
5673
|
+
form.append("filename", logicalName);
|
|
5674
|
+
if (params.filepath !== void 0) {
|
|
5675
|
+
form.append("filepath", params.filepath);
|
|
5676
|
+
}
|
|
5677
|
+
if (params.overwrite !== void 0) {
|
|
5678
|
+
form.append("overwrite", String(params.overwrite));
|
|
5679
|
+
}
|
|
5680
|
+
this.appendUploadVisibility(form, params);
|
|
5681
|
+
return form;
|
|
5682
|
+
}
|
|
5683
|
+
isErrorResult(result) {
|
|
5684
|
+
return typeof result === "object" && result !== null && "error" in result && result.error !== void 0;
|
|
5685
|
+
}
|
|
5686
|
+
isAclErrorResult(result) {
|
|
5687
|
+
return typeof result === "object" && result !== null && "error" in result && result.error !== void 0;
|
|
5688
|
+
}
|
|
5689
|
+
buildObjectAccessSummary(filePath, row, fallbackPublic) {
|
|
5690
|
+
const isPublic = row != null ? Boolean(row.isPublic) : fallbackPublic;
|
|
5691
|
+
return {
|
|
5692
|
+
message: isPublic ? "File has been made publicly accessible." : "File's public access has been revoked, making it private.",
|
|
5693
|
+
name: row?.name ?? row?.fullPath ?? filePath,
|
|
5694
|
+
size: row?.size ?? null,
|
|
5695
|
+
updated: row?.updatedAt ?? null,
|
|
5696
|
+
public: isPublic
|
|
5697
|
+
};
|
|
5698
|
+
}
|
|
5699
|
+
/**
|
|
5700
|
+
* Parses Hawkeye `POST /change-object-access` success JSON
|
|
5701
|
+
* `{ message, name, size, updated, public }`.
|
|
5702
|
+
*/
|
|
5703
|
+
parseChangeObjectAccessResponse(raw) {
|
|
5704
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
5705
|
+
const o = raw;
|
|
5706
|
+
if (typeof o.name !== "string" || typeof o.public !== "boolean") {
|
|
5707
|
+
return null;
|
|
5708
|
+
}
|
|
5709
|
+
const message = typeof o.message === "string" && o.message.length > 0 ? o.message : o.public ? "File has been made publicly accessible." : "File's public access has been revoked, making it private.";
|
|
5710
|
+
const size = o.size === void 0 || o.size === null ? null : String(o.size);
|
|
5711
|
+
const updated = o.updated === void 0 || o.updated === null ? null : String(o.updated);
|
|
5712
|
+
return {
|
|
5713
|
+
message,
|
|
5714
|
+
name: o.name,
|
|
5715
|
+
size,
|
|
5716
|
+
updated,
|
|
5717
|
+
public: o.public
|
|
5718
|
+
};
|
|
5719
|
+
}
|
|
5720
|
+
/** Resolves the list row for a full object path (same folder semantics as download size resolution). */
|
|
5721
|
+
async findFileListItem(filePath, storageType) {
|
|
5722
|
+
const lastSlash = filePath.lastIndexOf("/");
|
|
5723
|
+
const nameOnly = lastSlash === -1 ? filePath : filePath.slice(lastSlash + 1);
|
|
5724
|
+
const folderPrefix = lastSlash === -1 ? "" : filePath.slice(0, lastSlash);
|
|
5725
|
+
const basePath = folderPrefix ? `${folderPrefix}/` : "";
|
|
5726
|
+
const result = await this.list({ basePath, storageType });
|
|
5727
|
+
if (this.isErrorResult(result)) return result;
|
|
5728
|
+
const rows = result.files?.data ?? [];
|
|
5729
|
+
return rows.find(
|
|
5730
|
+
(r) => r.fullPath === filePath || !r.isDirectory && (r.name === nameOnly || r.fullPath === filePath)
|
|
5731
|
+
) ?? null;
|
|
5732
|
+
}
|
|
5733
|
+
/** Keep only SDK list fields; flatten metadata to `size` / `updatedAt`. */
|
|
5734
|
+
normalizeListItem(raw) {
|
|
5735
|
+
const meta = raw.metadata ?? {};
|
|
5736
|
+
let size;
|
|
5737
|
+
if (meta.size !== void 0 && meta.size !== null) {
|
|
5738
|
+
size = String(meta.size);
|
|
5739
|
+
}
|
|
5740
|
+
const updatedRaw = meta.updated ?? meta.timeUpdated;
|
|
5741
|
+
let updatedAt;
|
|
5742
|
+
if (updatedRaw !== void 0 && updatedRaw !== null) {
|
|
5743
|
+
updatedAt = String(updatedRaw);
|
|
5744
|
+
}
|
|
5745
|
+
const name = raw.name;
|
|
5746
|
+
const parentPath = raw.parentPath;
|
|
5747
|
+
const isDirectory = Boolean(raw.isDirectory);
|
|
5748
|
+
let fullPath;
|
|
5749
|
+
if (!isDirectory && name) {
|
|
5750
|
+
fullPath = parentPath ? `${parentPath}/${name}` : name;
|
|
5751
|
+
}
|
|
5752
|
+
const cdnRaw = raw.cdnUrl;
|
|
5753
|
+
const cdnUrl = cdnRaw === void 0 || cdnRaw === null ? null : cdnRaw;
|
|
5754
|
+
const item = {
|
|
5755
|
+
name,
|
|
5756
|
+
path: raw.path,
|
|
5757
|
+
folderName: raw.folderName,
|
|
5758
|
+
parentPath,
|
|
5759
|
+
isDirectory,
|
|
5760
|
+
isPublic: raw.isPublic,
|
|
5761
|
+
cdnUrl,
|
|
5762
|
+
fullPath
|
|
5763
|
+
};
|
|
5764
|
+
if (size !== void 0) item.size = size;
|
|
5765
|
+
if (updatedAt !== void 0) item.updatedAt = updatedAt;
|
|
5766
|
+
return item;
|
|
5767
|
+
}
|
|
5768
|
+
/** Map wire `shareable_link` to `temporary_sharable_link`. */
|
|
5769
|
+
normalizeUploadData(raw) {
|
|
5770
|
+
const message = String(raw.message ?? "");
|
|
5771
|
+
const path = String(raw.path ?? "");
|
|
5772
|
+
const out = { message, path };
|
|
5773
|
+
const link = raw.temporary_sharable_link ?? raw.shareable_link;
|
|
5774
|
+
if (link !== void 0 && link !== null && String(link) !== "") {
|
|
5775
|
+
out.temporary_sharable_link = String(link);
|
|
5776
|
+
}
|
|
5777
|
+
if (raw.public_url !== void 0 && raw.public_url !== null) {
|
|
5778
|
+
out.public_url = String(raw.public_url);
|
|
5779
|
+
}
|
|
5780
|
+
return out;
|
|
5781
|
+
}
|
|
5782
|
+
normalizeListResponse(data) {
|
|
5783
|
+
const payload = data.files;
|
|
5784
|
+
if (!payload?.data) return data;
|
|
5785
|
+
return {
|
|
5786
|
+
files: {
|
|
5787
|
+
...payload,
|
|
5788
|
+
data: payload.data.map(
|
|
5789
|
+
(item) => this.normalizeListItem(item)
|
|
5790
|
+
)
|
|
5791
|
+
}
|
|
5792
|
+
};
|
|
5793
|
+
}
|
|
5794
|
+
async list(params = {}) {
|
|
5795
|
+
const endpoint = STORAGE_ENDPOINTS.list;
|
|
5796
|
+
const path = buildStorageEndpointPath(endpoint);
|
|
5797
|
+
const result = await this.requestStorage({
|
|
5798
|
+
url: this.url(path, this.listQuery(params)),
|
|
5799
|
+
method: endpoint.method,
|
|
5800
|
+
headers: this.buildHeaders(),
|
|
5801
|
+
timeout: this.config.timeout
|
|
5802
|
+
});
|
|
5803
|
+
if (this.isErrorResult(result)) return result;
|
|
5804
|
+
return this.normalizeListResponse(result);
|
|
5805
|
+
}
|
|
5806
|
+
async createFolder(body) {
|
|
5807
|
+
const endpoint = STORAGE_ENDPOINTS.directory;
|
|
5808
|
+
const path = buildStorageEndpointPath(endpoint);
|
|
5809
|
+
const q = this.storageTypeQuery(body.storageType);
|
|
5810
|
+
return this.requestStorage({
|
|
5811
|
+
url: this.url(path, q),
|
|
5812
|
+
method: endpoint.method,
|
|
5813
|
+
headers: this.buildHeaders(),
|
|
5814
|
+
data: { folder_path: body.folder_path },
|
|
5815
|
+
timeout: this.config.timeout
|
|
5816
|
+
});
|
|
5817
|
+
}
|
|
5818
|
+
async deleteFile(params) {
|
|
5819
|
+
const endpoint = STORAGE_ENDPOINTS.deleteFile;
|
|
5820
|
+
const path = buildStorageEndpointPath(endpoint);
|
|
5821
|
+
const q = this.storageTypeQuery(params.storageType);
|
|
5822
|
+
q.set("filename", params.filename);
|
|
5823
|
+
const data = {};
|
|
5824
|
+
if (params.filepath !== void 0) {
|
|
5825
|
+
data.filepath = params.filepath;
|
|
5826
|
+
}
|
|
5827
|
+
if (params.totalsize !== void 0) {
|
|
5828
|
+
data.totalsize = params.totalsize;
|
|
5829
|
+
}
|
|
5830
|
+
return this.requestStorage({
|
|
5831
|
+
url: this.url(path, q),
|
|
5832
|
+
method: endpoint.method,
|
|
5833
|
+
headers: this.buildHeaders(),
|
|
5834
|
+
data: Object.keys(data).length ? data : void 0,
|
|
5835
|
+
timeout: this.config.timeout
|
|
5836
|
+
});
|
|
5837
|
+
}
|
|
5838
|
+
/**
|
|
5839
|
+
* `POST /change-object-access` — used by `makePublic` / `makePrivate`.
|
|
5840
|
+
* Preferring API body `{ message, name, size, updated, public }`; otherwise falls back to a parent list.
|
|
5841
|
+
*/
|
|
5842
|
+
async setObjectAccess(body) {
|
|
5843
|
+
const endpoint = STORAGE_ENDPOINTS.objectAccess;
|
|
5844
|
+
const path = buildStorageEndpointPath(endpoint);
|
|
5845
|
+
const acl = await this.requestStorage({
|
|
5846
|
+
url: this.url(path),
|
|
5847
|
+
method: endpoint.method,
|
|
5848
|
+
headers: this.buildHeaders(),
|
|
5849
|
+
data: {
|
|
5850
|
+
file_path: body.file_path,
|
|
5851
|
+
public: body.public
|
|
5852
|
+
},
|
|
5853
|
+
timeout: this.config.timeout
|
|
5854
|
+
});
|
|
5855
|
+
if (this.isAclErrorResult(acl)) return acl;
|
|
5856
|
+
const fromApi = this.parseChangeObjectAccessResponse(acl);
|
|
5857
|
+
if (fromApi !== null) {
|
|
5858
|
+
return fromApi;
|
|
5859
|
+
}
|
|
5860
|
+
const row = await this.findFileListItem(body.file_path);
|
|
5861
|
+
if (this.isAclErrorResult(row)) return row;
|
|
5862
|
+
return this.buildObjectAccessSummary(body.file_path, row, body.public);
|
|
5863
|
+
}
|
|
5864
|
+
async upload(params) {
|
|
5865
|
+
const endpoint = STORAGE_ENDPOINTS.upload;
|
|
5866
|
+
const path = buildStorageEndpointPath(endpoint);
|
|
5867
|
+
const q = this.storageTypeQuery(params.storageType);
|
|
5868
|
+
const headers = { ...this.buildHeaders() };
|
|
5869
|
+
delete headers["Content-Type"];
|
|
5870
|
+
const result = await this.requestStorage({
|
|
5871
|
+
url: this.url(path, q),
|
|
5872
|
+
method: endpoint.method,
|
|
5873
|
+
headers,
|
|
5874
|
+
data: this.buildUploadForm(params),
|
|
5875
|
+
timeout: this.config.timeout
|
|
5876
|
+
});
|
|
5877
|
+
if (this.isAclErrorResult(result)) return result;
|
|
5878
|
+
return this.normalizeUploadData(result);
|
|
5879
|
+
}
|
|
5880
|
+
async resolveFileSizeBytes(fileName, storageType) {
|
|
5881
|
+
const lastSlash = fileName.lastIndexOf("/");
|
|
5882
|
+
const nameOnly = lastSlash === -1 ? fileName : fileName.slice(lastSlash + 1);
|
|
5883
|
+
const folderPrefix = lastSlash === -1 ? "" : fileName.slice(0, lastSlash);
|
|
5884
|
+
const basePath = folderPrefix ? `${folderPrefix}/` : "";
|
|
5885
|
+
const result = await this.list({ basePath, storageType });
|
|
5886
|
+
if (this.isErrorResult(result)) {
|
|
5887
|
+
throw new Error(
|
|
5888
|
+
result.error?.message ?? "List failed while resolving file size"
|
|
5889
|
+
);
|
|
5890
|
+
}
|
|
5891
|
+
const rows = result.files?.data ?? [];
|
|
5892
|
+
const hit = rows.find(
|
|
5893
|
+
(r) => r.fullPath === fileName || !r.isDirectory && r.name === nameOnly
|
|
5894
|
+
);
|
|
5895
|
+
const s = hit?.size;
|
|
5896
|
+
if (s === void 0) {
|
|
5897
|
+
throw new Error(
|
|
5898
|
+
`Could not resolve size for "${fileName}". Pass sizeBytes (from list() item size).`
|
|
5899
|
+
);
|
|
5900
|
+
}
|
|
5901
|
+
return Number(s);
|
|
5902
|
+
}
|
|
5903
|
+
/**
|
|
5904
|
+
* Download file bytes via `POST /file-export` (range 0..size-1).
|
|
5905
|
+
*/
|
|
5906
|
+
async downloadFile(params) {
|
|
5907
|
+
try {
|
|
5908
|
+
const sizeBytes = params.sizeBytes !== void 0 ? Number(params.sizeBytes) : await this.resolveFileSizeBytes(
|
|
5909
|
+
params.file_name,
|
|
5910
|
+
params.storageType
|
|
5911
|
+
);
|
|
5912
|
+
if (!Number.isFinite(sizeBytes) || sizeBytes <= 0) {
|
|
5913
|
+
throw new Error(
|
|
5914
|
+
"Invalid or unknown file size. Pass sizeBytes from list() item size."
|
|
5915
|
+
);
|
|
5916
|
+
}
|
|
5917
|
+
const endpoint = STORAGE_ENDPOINTS.fileExport;
|
|
5918
|
+
const path = buildStorageEndpointPath(endpoint);
|
|
5919
|
+
const q = this.storageTypeQuery(params.storageType);
|
|
5920
|
+
const response = await this.httpAdapter.request({
|
|
5921
|
+
url: this.url(path, q),
|
|
5922
|
+
method: "POST",
|
|
5923
|
+
headers: { ...this.buildHeaders(), Accept: "*/*" },
|
|
5924
|
+
data: {
|
|
5925
|
+
file_name: params.file_name,
|
|
5926
|
+
start_byte: 0,
|
|
5927
|
+
end_byte: sizeBytes - 1
|
|
5928
|
+
},
|
|
5929
|
+
timeout: this.config.timeout,
|
|
5930
|
+
responseType: "arraybuffer"
|
|
5931
|
+
});
|
|
5932
|
+
if (response.status < 200 || response.status >= 300) {
|
|
5933
|
+
const d = response.data;
|
|
5934
|
+
if (d && typeof d === "object" && d !== null && "error" in d) {
|
|
5935
|
+
return d;
|
|
5936
|
+
}
|
|
5937
|
+
return this.formatErrorResponse(
|
|
5938
|
+
new Error(`Download failed: HTTP ${response.status}`),
|
|
5939
|
+
ERR_PREFIX
|
|
5940
|
+
);
|
|
5941
|
+
}
|
|
5942
|
+
if (!(response.data instanceof ArrayBuffer)) {
|
|
5943
|
+
throw new Error("Expected binary response body");
|
|
5944
|
+
}
|
|
5945
|
+
const headers = response.headers;
|
|
5946
|
+
const ct = headers["content-type"] ?? headers["Content-Type"] ?? void 0;
|
|
5947
|
+
return {
|
|
5948
|
+
bytes: response.data,
|
|
5949
|
+
status: response.status,
|
|
5950
|
+
contentType: ct
|
|
5951
|
+
};
|
|
5952
|
+
} catch (error) {
|
|
5953
|
+
return this.formatErrorResponse(error, ERR_PREFIX);
|
|
5954
|
+
}
|
|
5955
|
+
}
|
|
5956
|
+
}
|
|
5957
|
+
class StorageResource extends BaseResource {
|
|
5958
|
+
constructor(client) {
|
|
5959
|
+
super(client, "/storage");
|
|
5960
|
+
const config = client.getConfig();
|
|
5961
|
+
this.apiClient = new StorageApiClient(config.apiKey, {
|
|
5962
|
+
environment: config.environment,
|
|
5963
|
+
region: config.region,
|
|
5964
|
+
timeout: config.timeout,
|
|
5965
|
+
debug: config.debug,
|
|
5966
|
+
headers: config.headers
|
|
5967
|
+
});
|
|
5968
|
+
}
|
|
5969
|
+
async list(params = {}) {
|
|
5970
|
+
return this.apiClient.list(params);
|
|
5971
|
+
}
|
|
5972
|
+
/** Direct upload — `POST /upload` (multipart); server persists the object. */
|
|
5973
|
+
async upload(params) {
|
|
5974
|
+
return this.apiClient.upload(params);
|
|
5975
|
+
}
|
|
5976
|
+
async createFolder(params) {
|
|
5977
|
+
return this.apiClient.createFolder(params);
|
|
5978
|
+
}
|
|
5979
|
+
async deleteFile(params) {
|
|
5980
|
+
return this.apiClient.deleteFile(params);
|
|
5981
|
+
}
|
|
5982
|
+
async makePublic(filePath) {
|
|
5983
|
+
return this.apiClient.setObjectAccess({
|
|
5984
|
+
file_path: filePath,
|
|
5985
|
+
public: true
|
|
5986
|
+
});
|
|
5987
|
+
}
|
|
5988
|
+
async makePrivate(filePath) {
|
|
5989
|
+
return this.apiClient.setObjectAccess({
|
|
5990
|
+
file_path: filePath,
|
|
5991
|
+
public: false
|
|
5992
|
+
});
|
|
5993
|
+
}
|
|
5994
|
+
/** Download file bytes via `POST /file-export` (full file). */
|
|
5995
|
+
async downloadFile(params) {
|
|
5996
|
+
return this.apiClient.downloadFile(params);
|
|
5997
|
+
}
|
|
5998
|
+
}
|
|
5481
5999
|
class BolticClient {
|
|
5482
6000
|
constructor(apiKey, options = {}) {
|
|
5483
6001
|
this.currentDatabase = null;
|
|
@@ -5502,6 +6020,7 @@ class BolticClient {
|
|
|
5502
6020
|
this.databaseResource = new DatabaseResource(this.baseClient);
|
|
5503
6021
|
this.workflowResource = new WorkflowResource(this.baseClient);
|
|
5504
6022
|
this.serverlessResource = new ServerlessResource(this.baseClient);
|
|
6023
|
+
this.storageResource = new StorageResource(this.baseClient);
|
|
5505
6024
|
this.currentDatabase = null;
|
|
5506
6025
|
}
|
|
5507
6026
|
/**
|
|
@@ -5724,6 +6243,17 @@ class BolticClient {
|
|
|
5724
6243
|
pollStatus: (appId, options) => this.serverlessResource.pollStatus(appId, options)
|
|
5725
6244
|
};
|
|
5726
6245
|
}
|
|
6246
|
+
get storage() {
|
|
6247
|
+
return {
|
|
6248
|
+
list: (params) => this.storageResource.list(params),
|
|
6249
|
+
upload: (params) => this.storageResource.upload(params),
|
|
6250
|
+
createFolder: (params) => this.storageResource.createFolder(params),
|
|
6251
|
+
deleteFile: (params) => this.storageResource.deleteFile(params),
|
|
6252
|
+
makePublic: (filePath) => this.storageResource.makePublic(filePath),
|
|
6253
|
+
makePrivate: (filePath) => this.storageResource.makePrivate(filePath),
|
|
6254
|
+
downloadFile: (params) => this.storageResource.downloadFile(params)
|
|
6255
|
+
};
|
|
6256
|
+
}
|
|
5727
6257
|
// SQL resource access for testing
|
|
5728
6258
|
getSqlResource() {
|
|
5729
6259
|
return this.sqlResource;
|
|
@@ -5808,6 +6338,7 @@ class BolticClient {
|
|
|
5808
6338
|
this.databaseResource = new DatabaseResource(this.baseClient);
|
|
5809
6339
|
this.workflowResource = new WorkflowResource(this.baseClient);
|
|
5810
6340
|
this.serverlessResource = new ServerlessResource(this.baseClient);
|
|
6341
|
+
this.storageResource = new StorageResource(this.baseClient);
|
|
5811
6342
|
}
|
|
5812
6343
|
// Security methods to prevent API key exposure
|
|
5813
6344
|
toString() {
|
|
@@ -5837,14 +6368,20 @@ exports.AuthManager = AuthManager$1;
|
|
|
5837
6368
|
exports.BolticClient = BolticClient;
|
|
5838
6369
|
exports.DEFAULT_RESOURCES = DEFAULT_RESOURCES;
|
|
5839
6370
|
exports.DEFAULT_SCALING = DEFAULT_SCALING;
|
|
6371
|
+
exports.DEFAULT_STORAGE_TYPE = DEFAULT_STORAGE_TYPE;
|
|
6372
|
+
exports.MAX_SIGNED_URL_EXPIRE_MINUTES = MAX_SIGNED_URL_EXPIRE_MINUTES;
|
|
5840
6373
|
exports.MAX_STATUS_POLLING_ATTEMPTS = MAX_STATUS_POLLING_ATTEMPTS;
|
|
5841
6374
|
exports.SERVICE_PATHS = SERVICE_PATHS;
|
|
5842
6375
|
exports.STATUS_POLLING_INTERVAL_MS = STATUS_POLLING_INTERVAL_MS;
|
|
6376
|
+
exports.STORAGE_ENDPOINTS = STORAGE_ENDPOINTS;
|
|
5843
6377
|
exports.ServerlessApiClient = ServerlessApiClient;
|
|
5844
6378
|
exports.ServerlessResource = ServerlessResource;
|
|
6379
|
+
exports.StorageApiClient = StorageApiClient;
|
|
6380
|
+
exports.StorageResource = StorageResource;
|
|
5845
6381
|
exports.TERMINAL_STATUSES = TERMINAL_STATUSES;
|
|
5846
6382
|
exports.VERSION = VERSION;
|
|
5847
6383
|
exports.WorkflowResource = WorkflowResource;
|
|
6384
|
+
exports.buildStorageEndpointPath = buildStorageEndpointPath;
|
|
5848
6385
|
exports.createClient = createClient;
|
|
5849
6386
|
exports.createErrorWithContext = createErrorWithContext$1;
|
|
5850
6387
|
exports.formatError = formatError$1;
|