connectbase-client 3.48.2 → 3.50.0
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/CHANGELOG.md +12 -0
- package/README.md +7 -0
- package/dist/connect-base.umd.js +5 -5
- package/dist/index.d.mts +93 -4
- package/dist/index.d.ts +93 -4
- package/dist/index.js +113 -8
- package/dist/index.mjs +113 -8
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1269,6 +1269,7 @@ var DatabaseAPI = class {
|
|
|
1269
1269
|
if (options?.limit) params.append("limit", options.limit.toString());
|
|
1270
1270
|
if (options?.offset) params.append("offset", options.offset.toString());
|
|
1271
1271
|
if (options?.count === false) params.append("count", "false");
|
|
1272
|
+
if (options?.cursor) params.append("cursor", options.cursor);
|
|
1272
1273
|
const queryString = params.toString();
|
|
1273
1274
|
const url = queryString ? `${prefix}/tables/${tableId}/data?${queryString}` : `${prefix}/tables/${tableId}/data`;
|
|
1274
1275
|
return this.http.get(url);
|
|
@@ -1288,7 +1289,8 @@ var DatabaseAPI = class {
|
|
|
1288
1289
|
offset: options.offset,
|
|
1289
1290
|
select: options.select,
|
|
1290
1291
|
exclude: options.exclude,
|
|
1291
|
-
count: options.count
|
|
1292
|
+
count: options.count,
|
|
1293
|
+
cursor: options.cursor
|
|
1292
1294
|
}
|
|
1293
1295
|
);
|
|
1294
1296
|
}
|
|
@@ -2249,18 +2251,27 @@ var StorageAPI = class {
|
|
|
2249
2251
|
* Presigned URL 로 직접 업로드. 호출 전에 URL 스킴(https)을 검증해
|
|
2250
2252
|
* 서버 응답을 그대로 신뢰하는 SSRF/오용 경로를 차단.
|
|
2251
2253
|
* 타임아웃과 외부 signal 을 모두 지원한다.
|
|
2254
|
+
*
|
|
2255
|
+
* `onProgress` 가 주어지고 `XMLHttpRequest` 를 쓸 수 있는(브라우저) 환경이면
|
|
2256
|
+
* XHR 의 `upload.onprogress` 로 바이트 단위 진행률을 보고한다. 그 외에는
|
|
2257
|
+
* fetch 로 업로드하고 시작(0%)/완료(100%)만 통지한다(Node/Edge 호환).
|
|
2252
2258
|
*/
|
|
2253
2259
|
async uploadToPresigned(rawUrl, file, options) {
|
|
2254
2260
|
const parsed = validateExternalUrl(rawUrl, {
|
|
2255
2261
|
allowLocalhost: isLocalhostOrigin(),
|
|
2256
2262
|
context: "storage.presigned-url"
|
|
2257
2263
|
});
|
|
2264
|
+
const url = parsed.toString();
|
|
2265
|
+
if (options?.onProgress && typeof XMLHttpRequest !== "undefined") {
|
|
2266
|
+
return this.putViaXhr(url, file, options.onProgress, options);
|
|
2267
|
+
}
|
|
2258
2268
|
const { signal, cleanup } = createTimeoutController({
|
|
2259
2269
|
timeout: options?.timeout,
|
|
2260
2270
|
signal: options?.signal
|
|
2261
2271
|
});
|
|
2262
2272
|
try {
|
|
2263
|
-
|
|
2273
|
+
options?.onProgress?.({ loaded: 0, total: file.size, percentage: 0 });
|
|
2274
|
+
const response = await fetch(url, {
|
|
2264
2275
|
method: "PUT",
|
|
2265
2276
|
body: file,
|
|
2266
2277
|
headers: {
|
|
@@ -2275,10 +2286,79 @@ var StorageAPI = class {
|
|
|
2275
2286
|
"PRESIGNED_UPLOAD_FAILED"
|
|
2276
2287
|
);
|
|
2277
2288
|
}
|
|
2289
|
+
options?.onProgress?.({ loaded: file.size, total: file.size, percentage: 100 });
|
|
2278
2290
|
} finally {
|
|
2279
2291
|
cleanup();
|
|
2280
2292
|
}
|
|
2281
2293
|
}
|
|
2294
|
+
/**
|
|
2295
|
+
* XMLHttpRequest 기반 PUT 업로드. `upload.onprogress` 로 바이트 진행률을
|
|
2296
|
+
* 보고하며, 외부 signal(취소)과 타임아웃을 모두 지원한다. URL 은 호출 전에
|
|
2297
|
+
* 이미 검증된 값을 받는다(uploadToPresigned 에서 스킴 검증 수행).
|
|
2298
|
+
*/
|
|
2299
|
+
putViaXhr(url, file, onProgress, options) {
|
|
2300
|
+
return new Promise((resolve, reject) => {
|
|
2301
|
+
const external = options?.signal;
|
|
2302
|
+
if (external?.aborted) {
|
|
2303
|
+
reject(external.reason ?? new DOMException("Aborted", "AbortError"));
|
|
2304
|
+
return;
|
|
2305
|
+
}
|
|
2306
|
+
const xhr = new XMLHttpRequest();
|
|
2307
|
+
xhr.open("PUT", url, true);
|
|
2308
|
+
xhr.setRequestHeader("Content-Type", file.type || "application/octet-stream");
|
|
2309
|
+
const timeout = options?.timeout ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
2310
|
+
if (timeout > 0 && Number.isFinite(timeout)) {
|
|
2311
|
+
xhr.timeout = timeout;
|
|
2312
|
+
}
|
|
2313
|
+
let abortListener = null;
|
|
2314
|
+
const cleanup = () => {
|
|
2315
|
+
if (external && abortListener) {
|
|
2316
|
+
external.removeEventListener("abort", abortListener);
|
|
2317
|
+
}
|
|
2318
|
+
};
|
|
2319
|
+
if (external) {
|
|
2320
|
+
abortListener = () => xhr.abort();
|
|
2321
|
+
external.addEventListener("abort", abortListener, { once: true });
|
|
2322
|
+
}
|
|
2323
|
+
xhr.upload.onprogress = (event) => {
|
|
2324
|
+
if (!event.lengthComputable) return;
|
|
2325
|
+
const total = event.total || file.size;
|
|
2326
|
+
onProgress({
|
|
2327
|
+
loaded: event.loaded,
|
|
2328
|
+
total,
|
|
2329
|
+
percentage: total > 0 ? Math.round(event.loaded / total * 100) : 0
|
|
2330
|
+
});
|
|
2331
|
+
};
|
|
2332
|
+
xhr.onload = () => {
|
|
2333
|
+
cleanup();
|
|
2334
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
2335
|
+
onProgress({ loaded: file.size, total: file.size, percentage: 100 });
|
|
2336
|
+
resolve();
|
|
2337
|
+
} else {
|
|
2338
|
+
reject(
|
|
2339
|
+
new ApiError(
|
|
2340
|
+
xhr.status,
|
|
2341
|
+
`Upload failed: ${xhr.statusText || "unknown error"}`,
|
|
2342
|
+
"PRESIGNED_UPLOAD_FAILED"
|
|
2343
|
+
)
|
|
2344
|
+
);
|
|
2345
|
+
}
|
|
2346
|
+
};
|
|
2347
|
+
xhr.onerror = () => {
|
|
2348
|
+
cleanup();
|
|
2349
|
+
reject(new ApiError(0, "Upload failed: network error", "PRESIGNED_UPLOAD_FAILED"));
|
|
2350
|
+
};
|
|
2351
|
+
xhr.ontimeout = () => {
|
|
2352
|
+
cleanup();
|
|
2353
|
+
reject(new DOMException(`Request timed out after ${timeout}ms`, "TimeoutError"));
|
|
2354
|
+
};
|
|
2355
|
+
xhr.onabort = () => {
|
|
2356
|
+
cleanup();
|
|
2357
|
+
reject(external?.reason ?? new DOMException("Aborted", "AbortError"));
|
|
2358
|
+
};
|
|
2359
|
+
xhr.send(file);
|
|
2360
|
+
});
|
|
2361
|
+
}
|
|
2282
2362
|
/**
|
|
2283
2363
|
* 파일 목록 조회
|
|
2284
2364
|
*
|
|
@@ -2308,14 +2388,28 @@ var StorageAPI = class {
|
|
|
2308
2388
|
*
|
|
2309
2389
|
* 서버를 거치지 않고 Object Storage에 직접 업로드합니다.
|
|
2310
2390
|
*
|
|
2391
|
+
* 3번째 인자는 부모 폴더 ID(문자열) 또는 옵션 객체를 받습니다. 옵션으로
|
|
2392
|
+
* `onProgress` 콜백을 넘기면 업로드 진행률(%)을 실시간으로 받을 수 있습니다
|
|
2393
|
+
* (브라우저 환경). 기존 `uploadFile(id, file, 'folder-id')` 호출과 하위 호환됩니다.
|
|
2394
|
+
*
|
|
2311
2395
|
* @example
|
|
2312
2396
|
* ```ts
|
|
2313
2397
|
* const fileInput = document.querySelector('input[type="file"]')
|
|
2314
2398
|
* const result = await cb.storage.uploadFile('storage-id', fileInput.files[0])
|
|
2315
2399
|
* console.log(result.url) // 업로드된 파일 URL
|
|
2400
|
+
*
|
|
2401
|
+
* // 특정 폴더에 업로드 (기존 방식 그대로)
|
|
2402
|
+
* await cb.storage.uploadFile('storage-id', file, 'folder-id')
|
|
2403
|
+
*
|
|
2404
|
+
* // 진행률 표시 + 특정 폴더
|
|
2405
|
+
* await cb.storage.uploadFile('storage-id', file, {
|
|
2406
|
+
* parentId: 'folder-id',
|
|
2407
|
+
* onProgress: (p) => console.log(`${p.percentage}%`), // { loaded, total, percentage }
|
|
2408
|
+
* })
|
|
2316
2409
|
* ```
|
|
2317
2410
|
*/
|
|
2318
|
-
async uploadFile(storageId, file,
|
|
2411
|
+
async uploadFile(storageId, file, parentIdOrOptions) {
|
|
2412
|
+
const options = typeof parentIdOrOptions === "string" ? { parentId: parentIdOrOptions } : parentIdOrOptions ?? {};
|
|
2319
2413
|
const prefix = this.getPublicPrefix();
|
|
2320
2414
|
const presignedResponse = await this.http.post(
|
|
2321
2415
|
`${prefix}/storages/files/${storageId}/presigned-url`,
|
|
@@ -2323,10 +2417,14 @@ var StorageAPI = class {
|
|
|
2323
2417
|
file_name: file.name,
|
|
2324
2418
|
file_size: file.size,
|
|
2325
2419
|
mime_type: file.type || "application/octet-stream",
|
|
2326
|
-
parent_id: parentId
|
|
2420
|
+
parent_id: options.parentId
|
|
2327
2421
|
}
|
|
2328
2422
|
);
|
|
2329
|
-
await this.uploadToPresigned(presignedResponse.upload_url, file
|
|
2423
|
+
await this.uploadToPresigned(presignedResponse.upload_url, file, {
|
|
2424
|
+
onProgress: options.onProgress,
|
|
2425
|
+
signal: options.signal,
|
|
2426
|
+
timeout: options.timeout
|
|
2427
|
+
});
|
|
2330
2428
|
const completeResponse = await this.http.post(
|
|
2331
2429
|
`${prefix}/storages/files/${storageId}/complete-upload`,
|
|
2332
2430
|
{ file_id: presignedResponse.file_id }
|
|
@@ -2345,11 +2443,14 @@ var StorageAPI = class {
|
|
|
2345
2443
|
}
|
|
2346
2444
|
/**
|
|
2347
2445
|
* 여러 파일 업로드
|
|
2446
|
+
*
|
|
2447
|
+
* `onProgress` 를 옵션으로 넘기면 **파일별로** 진행률 콜백이 호출됩니다
|
|
2448
|
+
* (각 파일마다 0→100%). 전체 진행률이 필요하면 완료된 파일 수를 직접 집계하세요.
|
|
2348
2449
|
*/
|
|
2349
|
-
async uploadFiles(storageId, files,
|
|
2450
|
+
async uploadFiles(storageId, files, parentIdOrOptions) {
|
|
2350
2451
|
const results = [];
|
|
2351
2452
|
for (const file of files) {
|
|
2352
|
-
const result = await this.uploadFile(storageId, file,
|
|
2453
|
+
const result = await this.uploadFile(storageId, file, parentIdOrOptions);
|
|
2353
2454
|
results.push(result);
|
|
2354
2455
|
}
|
|
2355
2456
|
return results;
|
|
@@ -2448,7 +2549,11 @@ var StorageAPI = class {
|
|
|
2448
2549
|
overwrite
|
|
2449
2550
|
}
|
|
2450
2551
|
);
|
|
2451
|
-
await this.uploadToPresigned(presignedResponse.upload_url, file
|
|
2552
|
+
await this.uploadToPresigned(presignedResponse.upload_url, file, {
|
|
2553
|
+
onProgress: options?.onProgress,
|
|
2554
|
+
signal: options?.signal,
|
|
2555
|
+
timeout: options?.timeout
|
|
2556
|
+
});
|
|
2452
2557
|
const completeResponse = await this.http.post(
|
|
2453
2558
|
`${prefix}/storages/files/${storageId}/complete-upload`,
|
|
2454
2559
|
{ file_id: presignedResponse.file_id }
|