get-db9 0.4.1 → 0.5.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/dist/{client-CXv2ZlbR.d.cts → client-UKXFQNll.d.cts} +49 -3
- package/dist/{client-CXv2ZlbR.d.ts → client-UKXFQNll.d.ts} +49 -3
- package/dist/client.cjs +309 -176
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +309 -176
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +313 -177
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +313 -177
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -48,6 +48,9 @@ var Db9ConflictError = class extends Db9Error {
|
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
// src/http.ts
|
|
51
|
+
function delay(ms) {
|
|
52
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
53
|
+
}
|
|
51
54
|
function createHttpClient(options) {
|
|
52
55
|
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
53
56
|
const baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
@@ -56,38 +59,61 @@ function createHttpClient(options) {
|
|
|
56
59
|
if (params) {
|
|
57
60
|
const searchParams = new URLSearchParams();
|
|
58
61
|
for (const [key, value] of Object.entries(params)) {
|
|
59
|
-
if (value !== void 0)
|
|
60
|
-
searchParams.set(key, value);
|
|
61
|
-
}
|
|
62
|
+
if (value !== void 0) searchParams.set(key, value);
|
|
62
63
|
}
|
|
63
64
|
const qs = searchParams.toString();
|
|
64
65
|
if (qs) url += `?${qs}`;
|
|
65
66
|
}
|
|
66
|
-
const
|
|
67
|
+
const reqHeaders = {
|
|
67
68
|
"Content-Type": "application/json",
|
|
68
69
|
...options.headers
|
|
69
70
|
};
|
|
70
|
-
const init = { method, headers };
|
|
71
|
+
const init = { method, headers: reqHeaders };
|
|
71
72
|
if (body !== void 0) {
|
|
72
73
|
init.body = JSON.stringify(body);
|
|
73
74
|
}
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
const maxAttempts = Math.min(options.maxRetries ?? 0, 3) + 1;
|
|
76
|
+
const baseDelay = options.retryDelay ?? 1e3;
|
|
77
|
+
let lastError;
|
|
78
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
79
|
+
let timeoutId;
|
|
80
|
+
try {
|
|
81
|
+
const fetchInit = { ...init };
|
|
82
|
+
if (options.timeout) {
|
|
83
|
+
const controller = new AbortController();
|
|
84
|
+
fetchInit.signal = controller.signal;
|
|
85
|
+
timeoutId = setTimeout(() => controller.abort(), options.timeout);
|
|
86
|
+
}
|
|
87
|
+
const response = await fetchFn(url, fetchInit);
|
|
88
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
if (response.status >= 500 && attempt < maxAttempts - 1) {
|
|
91
|
+
lastError = await Db9Error.fromResponse(response);
|
|
92
|
+
await delay(baseDelay * Math.pow(2, attempt));
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
throw await Db9Error.fromResponse(response);
|
|
96
|
+
}
|
|
97
|
+
if (response.status === 204) return void 0;
|
|
98
|
+
return response.json();
|
|
99
|
+
} catch (err) {
|
|
100
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
101
|
+
if (err instanceof TypeError && attempt < maxAttempts - 1) {
|
|
102
|
+
lastError = err;
|
|
103
|
+
await delay(baseDelay * Math.pow(2, attempt));
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
throw err;
|
|
107
|
+
}
|
|
80
108
|
}
|
|
81
|
-
|
|
109
|
+
throw lastError;
|
|
82
110
|
}
|
|
83
111
|
async function requestRaw(method, path, body, params, customHeaders) {
|
|
84
112
|
let url = `${baseUrl}${path}`;
|
|
85
113
|
if (params) {
|
|
86
114
|
const searchParams = new URLSearchParams();
|
|
87
115
|
for (const [key, value] of Object.entries(params)) {
|
|
88
|
-
if (value !== void 0)
|
|
89
|
-
searchParams.set(key, value);
|
|
90
|
-
}
|
|
116
|
+
if (value !== void 0) searchParams.set(key, value);
|
|
91
117
|
}
|
|
92
118
|
const qs = searchParams.toString();
|
|
93
119
|
if (qs) url += `?${qs}`;
|
|
@@ -96,15 +122,23 @@ function createHttpClient(options) {
|
|
|
96
122
|
...options.headers,
|
|
97
123
|
...customHeaders
|
|
98
124
|
};
|
|
99
|
-
const
|
|
100
|
-
if (body !== void 0)
|
|
101
|
-
|
|
125
|
+
const fetchInit = { method, headers };
|
|
126
|
+
if (body !== void 0) fetchInit.body = body;
|
|
127
|
+
let timeoutId;
|
|
128
|
+
if (options.timeout) {
|
|
129
|
+
const controller = new AbortController();
|
|
130
|
+
fetchInit.signal = controller.signal;
|
|
131
|
+
timeoutId = setTimeout(() => controller.abort(), options.timeout);
|
|
102
132
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
133
|
+
try {
|
|
134
|
+
const response = await fetchFn(url, fetchInit);
|
|
135
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
136
|
+
if (!response.ok) throw await Db9Error.fromResponse(response);
|
|
137
|
+
return response;
|
|
138
|
+
} catch (err) {
|
|
139
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
140
|
+
throw err;
|
|
106
141
|
}
|
|
107
|
-
return response;
|
|
108
142
|
}
|
|
109
143
|
return {
|
|
110
144
|
get: (path, params) => request("GET", path, void 0, params),
|
|
@@ -112,7 +146,9 @@ function createHttpClient(options) {
|
|
|
112
146
|
put: (path, body) => request("PUT", path, body),
|
|
113
147
|
del: (path) => request("DELETE", path),
|
|
114
148
|
getRaw: (path, params) => requestRaw("GET", path, void 0, params),
|
|
115
|
-
putRaw: (path, body, headers) => requestRaw("PUT", path, body, void 0, headers)
|
|
149
|
+
putRaw: (path, body, headers) => requestRaw("PUT", path, body, void 0, headers),
|
|
150
|
+
postRaw: (path, body, headers) => requestRaw("POST", path, body, void 0, headers),
|
|
151
|
+
delRaw: (path, params) => requestRaw("DELETE", path, void 0, params)
|
|
116
152
|
};
|
|
117
153
|
}
|
|
118
154
|
|
|
@@ -232,7 +268,10 @@ function createDb9Client(options = {}) {
|
|
|
232
268
|
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
233
269
|
const publicClient = createHttpClient({
|
|
234
270
|
baseUrl,
|
|
235
|
-
fetch: options.fetch
|
|
271
|
+
fetch: options.fetch,
|
|
272
|
+
timeout: options.timeout,
|
|
273
|
+
maxRetries: options.maxRetries,
|
|
274
|
+
retryDelay: options.retryDelay
|
|
236
275
|
});
|
|
237
276
|
async function getAuthClient() {
|
|
238
277
|
if (!token && !tokenLoaded) {
|
|
@@ -255,35 +294,118 @@ function createDb9Client(options = {}) {
|
|
|
255
294
|
return createHttpClient({
|
|
256
295
|
baseUrl,
|
|
257
296
|
fetch: options.fetch,
|
|
258
|
-
headers: { Authorization: `Bearer ${token}` }
|
|
297
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
298
|
+
timeout: options.timeout,
|
|
299
|
+
maxRetries: options.maxRetries,
|
|
300
|
+
retryDelay: options.retryDelay
|
|
259
301
|
});
|
|
260
302
|
}
|
|
303
|
+
let refreshPromise = null;
|
|
304
|
+
async function refreshAnonymousToken() {
|
|
305
|
+
const creds = await store.load();
|
|
306
|
+
if (!creds?.anonymous_id || !creds?.anonymous_secret) {
|
|
307
|
+
throw new Error("Not an anonymous session");
|
|
308
|
+
}
|
|
309
|
+
const resp = await publicClient.post(
|
|
310
|
+
"/customer/anonymous-refresh",
|
|
311
|
+
{
|
|
312
|
+
anonymous_id: creds.anonymous_id,
|
|
313
|
+
anonymous_secret: creds.anonymous_secret
|
|
314
|
+
}
|
|
315
|
+
);
|
|
316
|
+
token = resp.token;
|
|
317
|
+
await store.save({ ...creds, token: resp.token });
|
|
318
|
+
}
|
|
319
|
+
async function withAuthRetry(operation) {
|
|
320
|
+
const client = await getAuthClient();
|
|
321
|
+
try {
|
|
322
|
+
return await operation(client);
|
|
323
|
+
} catch (err) {
|
|
324
|
+
if (!(err instanceof Db9Error) || err.statusCode !== 401) {
|
|
325
|
+
throw err;
|
|
326
|
+
}
|
|
327
|
+
try {
|
|
328
|
+
if (!refreshPromise) {
|
|
329
|
+
refreshPromise = refreshAnonymousToken();
|
|
330
|
+
}
|
|
331
|
+
await refreshPromise;
|
|
332
|
+
} catch {
|
|
333
|
+
throw err;
|
|
334
|
+
} finally {
|
|
335
|
+
refreshPromise = null;
|
|
336
|
+
}
|
|
337
|
+
const newClient = await getAuthClient();
|
|
338
|
+
return operation(newClient);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
261
341
|
function deriveFs9Url(dbId) {
|
|
262
342
|
const origin = baseUrl.replace(/\/api\/?$/, "");
|
|
263
343
|
return `${origin}/fs9/${dbId}`;
|
|
264
344
|
}
|
|
265
|
-
|
|
345
|
+
function getFsClient(dbId) {
|
|
346
|
+
const fs9Base = deriveFs9Url(dbId) + "/api/v1";
|
|
347
|
+
return createHttpClient({
|
|
348
|
+
baseUrl: fs9Base,
|
|
349
|
+
fetch: options.fetch,
|
|
350
|
+
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
|
351
|
+
timeout: options.timeout,
|
|
352
|
+
maxRetries: options.maxRetries,
|
|
353
|
+
retryDelay: options.retryDelay
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
async function withFsAuthRetry(dbId, operation) {
|
|
266
357
|
if (!token && !tokenLoaded) {
|
|
267
358
|
await getAuthClient();
|
|
268
359
|
}
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
360
|
+
const client = getFsClient(dbId);
|
|
361
|
+
try {
|
|
362
|
+
return await operation(client);
|
|
363
|
+
} catch (err) {
|
|
364
|
+
if (!(err instanceof Db9Error) || err.statusCode !== 401) {
|
|
365
|
+
throw err;
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
if (!refreshPromise) {
|
|
369
|
+
refreshPromise = refreshAnonymousToken();
|
|
370
|
+
}
|
|
371
|
+
await refreshPromise;
|
|
372
|
+
} catch {
|
|
373
|
+
throw err;
|
|
374
|
+
} finally {
|
|
375
|
+
refreshPromise = null;
|
|
376
|
+
}
|
|
377
|
+
const newClient = getFsClient(dbId);
|
|
378
|
+
return operation(newClient);
|
|
277
379
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
380
|
+
}
|
|
381
|
+
function parseSqlError(raw) {
|
|
382
|
+
try {
|
|
383
|
+
const parsed = JSON.parse(raw);
|
|
384
|
+
if (typeof parsed === "object" && parsed !== null && typeof parsed.message === "string") {
|
|
385
|
+
return parsed;
|
|
386
|
+
}
|
|
387
|
+
} catch {
|
|
281
388
|
}
|
|
282
|
-
const
|
|
283
|
-
if (
|
|
284
|
-
|
|
389
|
+
const pgMatch = raw.match(/^(?:ERROR:\s*)?(.+?)(?:\s+DETAIL:\s+(.+?))?(?:\s+HINT:\s+(.+?))?(?:\s+\(SQLSTATE\s+(\w+)\))?$/s);
|
|
390
|
+
if (pgMatch && pgMatch[1]) {
|
|
391
|
+
const result = { message: pgMatch[1].trim() };
|
|
392
|
+
if (pgMatch[2]) result.detail = pgMatch[2].trim();
|
|
393
|
+
if (pgMatch[3]) result.hint = pgMatch[3].trim();
|
|
394
|
+
if (pgMatch[4]) result.code = pgMatch[4];
|
|
395
|
+
return result;
|
|
285
396
|
}
|
|
286
|
-
return
|
|
397
|
+
return { message: raw };
|
|
398
|
+
}
|
|
399
|
+
async function fsStat(dbId, path) {
|
|
400
|
+
return withFsAuthRetry(
|
|
401
|
+
dbId,
|
|
402
|
+
(client) => client.get("/stat", { path })
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
async function fetchAnonymousSecret() {
|
|
406
|
+
return withAuthRetry(
|
|
407
|
+
(client) => client.post("/customer/anonymous-secret", {})
|
|
408
|
+
);
|
|
287
409
|
}
|
|
288
410
|
return {
|
|
289
411
|
auth: {
|
|
@@ -298,195 +420,206 @@ function createDb9Client(options = {}) {
|
|
|
298
420
|
req
|
|
299
421
|
),
|
|
300
422
|
// Authenticated endpoints
|
|
301
|
-
me: async () =>
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
const client = await getAuthClient();
|
|
307
|
-
return client.get(
|
|
308
|
-
"/customer/anonymous-secret"
|
|
309
|
-
);
|
|
423
|
+
me: async () => withAuthRetry(
|
|
424
|
+
(client) => client.get("/customer/me")
|
|
425
|
+
),
|
|
426
|
+
getAnonymousSecret: () => {
|
|
427
|
+
return fetchAnonymousSecret();
|
|
310
428
|
},
|
|
311
|
-
claim: async (req) =>
|
|
312
|
-
|
|
313
|
-
|
|
429
|
+
claim: async (req) => withAuthRetry(
|
|
430
|
+
(client) => client.post("/customer/claim", req)
|
|
431
|
+
),
|
|
432
|
+
ensureAnonymousSecret: async () => {
|
|
433
|
+
const creds = await store.load();
|
|
434
|
+
if (!creds?.anonymous_id || creds.anonymous_secret) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
const resp = await fetchAnonymousSecret();
|
|
438
|
+
await store.save({
|
|
439
|
+
...creds,
|
|
440
|
+
anonymous_secret: resp.anonymous_secret
|
|
441
|
+
});
|
|
314
442
|
}
|
|
315
443
|
},
|
|
316
444
|
tokens: {
|
|
317
|
-
list: async () =>
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
445
|
+
list: async () => withAuthRetry(
|
|
446
|
+
(client) => client.get("/customer/tokens")
|
|
447
|
+
),
|
|
448
|
+
revoke: async (tokenId) => withAuthRetry(
|
|
449
|
+
(client) => client.del(`/customer/tokens/${tokenId}`)
|
|
450
|
+
),
|
|
451
|
+
create: async (req) => withAuthRetry(
|
|
452
|
+
(client) => client.post("/customer/tokens", req)
|
|
453
|
+
)
|
|
325
454
|
},
|
|
326
455
|
databases: {
|
|
327
456
|
// ── CRUD ──────────────────────────────────────────────────
|
|
328
|
-
create: async (req) =>
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
get: async (databaseId) => {
|
|
337
|
-
const client = await getAuthClient();
|
|
338
|
-
return client.get(
|
|
457
|
+
create: async (req) => withAuthRetry(
|
|
458
|
+
(client) => client.post("/customer/databases", req)
|
|
459
|
+
),
|
|
460
|
+
list: async () => withAuthRetry(
|
|
461
|
+
(client) => client.get("/customer/databases")
|
|
462
|
+
),
|
|
463
|
+
get: async (databaseId) => withAuthRetry(
|
|
464
|
+
(client) => client.get(
|
|
339
465
|
`/customer/databases/${databaseId}`
|
|
340
|
-
)
|
|
341
|
-
|
|
342
|
-
delete: async (databaseId) =>
|
|
343
|
-
|
|
344
|
-
return client.del(
|
|
466
|
+
)
|
|
467
|
+
),
|
|
468
|
+
delete: async (databaseId) => withAuthRetry(
|
|
469
|
+
(client) => client.del(
|
|
345
470
|
`/customer/databases/${databaseId}`
|
|
346
|
-
)
|
|
347
|
-
|
|
348
|
-
resetPassword: async (databaseId) =>
|
|
349
|
-
|
|
350
|
-
return client.post(
|
|
471
|
+
)
|
|
472
|
+
),
|
|
473
|
+
resetPassword: async (databaseId) => withAuthRetry(
|
|
474
|
+
(client) => client.post(
|
|
351
475
|
`/customer/databases/${databaseId}/reset-password`
|
|
352
|
-
)
|
|
353
|
-
|
|
354
|
-
observability: async (databaseId) =>
|
|
355
|
-
|
|
356
|
-
return client.get(
|
|
476
|
+
)
|
|
477
|
+
),
|
|
478
|
+
observability: async (databaseId) => withAuthRetry(
|
|
479
|
+
(client) => client.get(
|
|
357
480
|
`/customer/databases/${databaseId}/observability`
|
|
358
|
-
)
|
|
359
|
-
|
|
481
|
+
)
|
|
482
|
+
),
|
|
360
483
|
// ── SQL Execution ─────────────────────────────────────────
|
|
361
484
|
sql: async (databaseId, query) => {
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
485
|
+
const result = await withAuthRetry(
|
|
486
|
+
(client) => client.post(
|
|
487
|
+
`/customer/databases/${databaseId}/sql`,
|
|
488
|
+
{ query }
|
|
489
|
+
)
|
|
366
490
|
);
|
|
491
|
+
if (result.error && typeof result.error === "string") {
|
|
492
|
+
result.error = parseSqlError(result.error);
|
|
493
|
+
}
|
|
494
|
+
return result;
|
|
367
495
|
},
|
|
368
496
|
sqlFile: async (databaseId, fileContent) => {
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
497
|
+
const result = await withAuthRetry(
|
|
498
|
+
(client) => client.post(
|
|
499
|
+
`/customer/databases/${databaseId}/sql`,
|
|
500
|
+
{ file_content: fileContent }
|
|
501
|
+
)
|
|
373
502
|
);
|
|
503
|
+
if (result.error && typeof result.error === "string") {
|
|
504
|
+
result.error = parseSqlError(result.error);
|
|
505
|
+
}
|
|
506
|
+
return result;
|
|
374
507
|
},
|
|
375
508
|
// ── Schema & Dump ─────────────────────────────────────────
|
|
376
|
-
schema: async (databaseId) =>
|
|
377
|
-
|
|
378
|
-
return client.get(
|
|
509
|
+
schema: async (databaseId) => withAuthRetry(
|
|
510
|
+
(client) => client.get(
|
|
379
511
|
`/customer/databases/${databaseId}/schema`
|
|
380
|
-
)
|
|
381
|
-
|
|
382
|
-
dump: async (databaseId, req) =>
|
|
383
|
-
|
|
384
|
-
return client.post(
|
|
512
|
+
)
|
|
513
|
+
),
|
|
514
|
+
dump: async (databaseId, req) => withAuthRetry(
|
|
515
|
+
(client) => client.post(
|
|
385
516
|
`/customer/databases/${databaseId}/dump`,
|
|
386
517
|
req
|
|
387
|
-
)
|
|
388
|
-
|
|
518
|
+
)
|
|
519
|
+
),
|
|
389
520
|
// ── Migrations ────────────────────────────────────────────
|
|
390
|
-
applyMigration: async (databaseId, req) =>
|
|
391
|
-
|
|
392
|
-
return client.post(
|
|
521
|
+
applyMigration: async (databaseId, req) => withAuthRetry(
|
|
522
|
+
(client) => client.post(
|
|
393
523
|
`/customer/databases/${databaseId}/migrations`,
|
|
394
524
|
req
|
|
395
|
-
)
|
|
396
|
-
|
|
397
|
-
listMigrations: async (databaseId) =>
|
|
398
|
-
|
|
399
|
-
return client.get(
|
|
525
|
+
)
|
|
526
|
+
),
|
|
527
|
+
listMigrations: async (databaseId) => withAuthRetry(
|
|
528
|
+
(client) => client.get(
|
|
400
529
|
`/customer/databases/${databaseId}/migrations`
|
|
401
|
-
)
|
|
402
|
-
|
|
530
|
+
)
|
|
531
|
+
),
|
|
403
532
|
// ── Branching ─────────────────────────────────────────────
|
|
404
|
-
branch: async (databaseId, req) =>
|
|
405
|
-
|
|
406
|
-
return client.post(
|
|
533
|
+
branch: async (databaseId, req) => withAuthRetry(
|
|
534
|
+
(client) => client.post(
|
|
407
535
|
`/customer/databases/${databaseId}/branch`,
|
|
408
536
|
req
|
|
409
|
-
)
|
|
410
|
-
|
|
537
|
+
)
|
|
538
|
+
),
|
|
411
539
|
// ── User Management ───────────────────────────────────────
|
|
412
540
|
users: {
|
|
413
|
-
list: async (databaseId) =>
|
|
414
|
-
|
|
415
|
-
return client.get(
|
|
541
|
+
list: async (databaseId) => withAuthRetry(
|
|
542
|
+
(client) => client.get(
|
|
416
543
|
`/customer/databases/${databaseId}/users`
|
|
417
|
-
)
|
|
418
|
-
|
|
419
|
-
create: async (databaseId, req) =>
|
|
420
|
-
|
|
421
|
-
return client.post(
|
|
544
|
+
)
|
|
545
|
+
),
|
|
546
|
+
create: async (databaseId, req) => withAuthRetry(
|
|
547
|
+
(client) => client.post(
|
|
422
548
|
`/customer/databases/${databaseId}/users`,
|
|
423
549
|
req
|
|
424
|
-
)
|
|
425
|
-
|
|
426
|
-
delete: async (databaseId, username) =>
|
|
427
|
-
|
|
428
|
-
return client.del(
|
|
550
|
+
)
|
|
551
|
+
),
|
|
552
|
+
delete: async (databaseId, username) => withAuthRetry(
|
|
553
|
+
(client) => client.del(
|
|
429
554
|
`/customer/databases/${databaseId}/users/${username}`
|
|
430
|
-
)
|
|
431
|
-
|
|
555
|
+
)
|
|
556
|
+
)
|
|
432
557
|
}
|
|
433
558
|
},
|
|
434
559
|
fs: {
|
|
435
560
|
list: async (dbId, path, options2) => {
|
|
436
|
-
const params =
|
|
437
|
-
if (options2?.recursive) params.
|
|
438
|
-
|
|
439
|
-
"GET",
|
|
561
|
+
const params = { path };
|
|
562
|
+
if (options2?.recursive) params.recursive = "true";
|
|
563
|
+
return withFsAuthRetry(
|
|
440
564
|
dbId,
|
|
441
|
-
|
|
565
|
+
(client) => client.get("/readdir", params)
|
|
442
566
|
);
|
|
443
|
-
return response.json();
|
|
444
567
|
},
|
|
445
568
|
read: async (dbId, path) => {
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
`/download?${params.toString()}`
|
|
451
|
-
);
|
|
452
|
-
return response.text();
|
|
569
|
+
return withFsAuthRetry(dbId, async (client) => {
|
|
570
|
+
const resp = await client.getRaw("/download", { path });
|
|
571
|
+
return resp.text();
|
|
572
|
+
});
|
|
453
573
|
},
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
574
|
+
readBinary: async (dbId, path) => {
|
|
575
|
+
return withFsAuthRetry(dbId, async (client) => {
|
|
576
|
+
const resp = await client.getRaw("/download", { path });
|
|
577
|
+
return resp.arrayBuffer();
|
|
578
|
+
});
|
|
457
579
|
},
|
|
458
|
-
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
"GET",
|
|
580
|
+
write: async (dbId, path, content) => {
|
|
581
|
+
const contentType = typeof content === "string" ? "text/plain" : "application/octet-stream";
|
|
582
|
+
await withFsAuthRetry(
|
|
462
583
|
dbId,
|
|
463
|
-
`/
|
|
584
|
+
(client) => client.putRaw(`/upload?${new URLSearchParams({ path })}`, content, { "Content-Type": contentType })
|
|
464
585
|
);
|
|
465
|
-
|
|
586
|
+
},
|
|
587
|
+
stat: (dbId, path) => {
|
|
588
|
+
return fsStat(dbId, path);
|
|
589
|
+
},
|
|
590
|
+
exists: async (dbId, path) => {
|
|
591
|
+
try {
|
|
592
|
+
await fsStat(dbId, path);
|
|
593
|
+
return true;
|
|
594
|
+
} catch (err) {
|
|
595
|
+
if (err instanceof Db9Error && err.statusCode === 404) {
|
|
596
|
+
return false;
|
|
597
|
+
}
|
|
598
|
+
throw err;
|
|
599
|
+
}
|
|
466
600
|
},
|
|
467
601
|
mkdir: async (dbId, path) => {
|
|
468
|
-
|
|
469
|
-
"POST",
|
|
602
|
+
await withFsAuthRetry(
|
|
470
603
|
dbId,
|
|
471
|
-
"
|
|
472
|
-
JSON.stringify({
|
|
473
|
-
path,
|
|
474
|
-
flags: { create: true, directory: true }
|
|
475
|
-
}),
|
|
476
|
-
"application/json"
|
|
604
|
+
(client) => client.postRaw(`/mkdir?${new URLSearchParams({ path, recursive: "true" })}`)
|
|
477
605
|
);
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
606
|
+
},
|
|
607
|
+
remove: async (dbId, path) => {
|
|
608
|
+
await withFsAuthRetry(
|
|
481
609
|
dbId,
|
|
482
|
-
"/
|
|
483
|
-
JSON.stringify({ handle_id }),
|
|
484
|
-
"application/json"
|
|
610
|
+
(client) => client.delRaw("/remove", { path })
|
|
485
611
|
);
|
|
486
612
|
},
|
|
487
|
-
|
|
488
|
-
const params =
|
|
489
|
-
|
|
613
|
+
events: async (dbId, options2) => {
|
|
614
|
+
const params = {};
|
|
615
|
+
if (options2?.limit !== void 0) params.limit = String(options2.limit);
|
|
616
|
+
if (options2?.offset !== void 0) params.offset = String(options2.offset);
|
|
617
|
+
if (options2?.path) params.path = options2.path;
|
|
618
|
+
if (options2?.type) params.type = options2.type;
|
|
619
|
+
return withFsAuthRetry(
|
|
620
|
+
dbId,
|
|
621
|
+
(client) => client.get("/events", params)
|
|
622
|
+
);
|
|
490
623
|
}
|
|
491
624
|
}
|
|
492
625
|
};
|
|
@@ -498,7 +631,10 @@ async function instantDatabase(options = {}) {
|
|
|
498
631
|
const client = createDb9Client({
|
|
499
632
|
baseUrl: options.baseUrl,
|
|
500
633
|
fetch: options.fetch,
|
|
501
|
-
credentialStore: options.credentialStore
|
|
634
|
+
credentialStore: options.credentialStore,
|
|
635
|
+
timeout: options.timeout,
|
|
636
|
+
maxRetries: options.maxRetries,
|
|
637
|
+
retryDelay: options.retryDelay
|
|
502
638
|
});
|
|
503
639
|
const existing = await client.databases.list();
|
|
504
640
|
const found = existing.find((db) => db.name === dbName);
|