@tinycloud/sdk-services 3.1.0-beta.6 → 3.1.0-beta.9
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/{BaseService-BhpVpA9b.d.cts → BaseService-B_UKhVht.d.ts} +74 -2
- package/dist/{BaseService-CuV-ZVPs.d.ts → BaseService-DWbPbov7.d.cts} +74 -2
- package/dist/encryption/index.cjs +93 -3
- package/dist/encryption/index.cjs.map +1 -1
- package/dist/encryption/index.d.cts +2 -2
- package/dist/encryption/index.d.ts +2 -2
- package/dist/encryption/index.js +93 -3
- package/dist/encryption/index.js.map +1 -1
- package/dist/index.cjs +389 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -42
- package/dist/index.d.ts +14 -42
- package/dist/index.js +389 -31
- package/dist/index.js.map +1 -1
- package/dist/internal/decrypt-transport-response-error.d.cts +1 -1
- package/dist/internal/decrypt-transport-response-error.d.ts +1 -1
- package/dist/kv/index.cjs +326 -16
- package/dist/kv/index.cjs.map +1 -1
- package/dist/kv/index.d.cts +192 -13
- package/dist/kv/index.d.ts +192 -13
- package/dist/kv/index.js +326 -16
- package/dist/kv/index.js.map +1 -1
- package/dist/sql/index.cjs +114 -9
- package/dist/sql/index.cjs.map +1 -1
- package/dist/sql/index.d.cts +6 -3
- package/dist/sql/index.d.ts +6 -3
- package/dist/sql/index.js +114 -9
- package/dist/sql/index.js.map +1 -1
- package/dist/{types-qwMmB7qB.d.cts → types-CVwwxqXF.d.cts} +8 -0
- package/dist/{types-qwMmB7qB.d.ts → types-CVwwxqXF.d.ts} +8 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -5,6 +5,10 @@ var ErrorCodes = {
|
|
|
5
5
|
AUTH_EXPIRED: "AUTH_EXPIRED",
|
|
6
6
|
AUTH_REQUIRED: "AUTH_REQUIRED",
|
|
7
7
|
AUTH_UNAUTHORIZED: "AUTH_UNAUTHORIZED",
|
|
8
|
+
/** HTTP 401: the delegation the invocation cites was revoked. */
|
|
9
|
+
AUTH_DELEGATION_REVOKED: "AUTH_DELEGATION_REVOKED",
|
|
10
|
+
/** HTTP 401: a delegation the cited one rests on was revoked. */
|
|
11
|
+
AUTH_DELEGATION_ANCESTOR_REVOKED: "AUTH_DELEGATION_ANCESTOR_REVOKED",
|
|
8
12
|
NETWORK_ERROR: "NETWORK_ERROR",
|
|
9
13
|
TIMEOUT: "TIMEOUT",
|
|
10
14
|
ABORTED: "ABORTED",
|
|
@@ -16,6 +20,10 @@ var ErrorCodes = {
|
|
|
16
20
|
KV_PRECONDITION_FAILED: "KV_PRECONDITION_FAILED",
|
|
17
21
|
KV_CONFLICT: "KV_CONFLICT",
|
|
18
22
|
KV_RESPONSE_TOO_LARGE: "KV_RESPONSE_TOO_LARGE",
|
|
23
|
+
/** HTTP 410 from the change feed: discard sync state and restart without a cursor; `meta.reason` says why. */
|
|
24
|
+
KV_SYNC_RESET_REQUIRED: "KV_SYNC_RESET_REQUIRED",
|
|
25
|
+
/** HTTP 403 from the change feed: the retention grant was refused; `meta.reason` says why. */
|
|
26
|
+
KV_RETENTION_GRANT_REFUSED: "KV_RETENTION_GRANT_REFUSED",
|
|
19
27
|
// SQL-specific errors
|
|
20
28
|
SQL_ERROR: "SQL_ERROR",
|
|
21
29
|
SQL_PERMISSION_DENIED: "SQL_PERMISSION_DENIED",
|
|
@@ -1055,11 +1063,31 @@ function networkError(service, message, cause) {
|
|
|
1055
1063
|
cause
|
|
1056
1064
|
};
|
|
1057
1065
|
}
|
|
1058
|
-
|
|
1066
|
+
var RequestTimeoutError = class extends Error {
|
|
1067
|
+
constructor(timeoutMs) {
|
|
1068
|
+
super(`Request timed out after ${timeoutMs}ms.`);
|
|
1069
|
+
this.name = "TimeoutError";
|
|
1070
|
+
this.timeoutMs = timeoutMs;
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
function isRequestTimeoutError(error) {
|
|
1074
|
+
return error instanceof RequestTimeoutError || error instanceof Error && error.name === "TimeoutError" && typeof error.timeoutMs === "number";
|
|
1075
|
+
}
|
|
1076
|
+
function timeoutError(service, timeoutMs, cause) {
|
|
1077
|
+
if (timeoutMs === void 0) {
|
|
1078
|
+
return {
|
|
1079
|
+
code: ErrorCodes.TIMEOUT,
|
|
1080
|
+
message: "Request timed out.",
|
|
1081
|
+
service,
|
|
1082
|
+
...cause === void 0 ? {} : { cause }
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1059
1085
|
return {
|
|
1060
1086
|
code: ErrorCodes.TIMEOUT,
|
|
1061
|
-
message:
|
|
1062
|
-
service
|
|
1087
|
+
message: `Request timed out after ${timeoutMs}ms.`,
|
|
1088
|
+
service,
|
|
1089
|
+
...cause === void 0 ? {} : { cause },
|
|
1090
|
+
meta: { timeoutMs }
|
|
1063
1091
|
};
|
|
1064
1092
|
}
|
|
1065
1093
|
function abortedError(service) {
|
|
@@ -1223,6 +1251,9 @@ function isStorageFullError(error) {
|
|
|
1223
1251
|
}
|
|
1224
1252
|
function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
|
|
1225
1253
|
if (error instanceof Error) {
|
|
1254
|
+
if (isRequestTimeoutError(error)) {
|
|
1255
|
+
return timeoutError(service, error.timeoutMs, error);
|
|
1256
|
+
}
|
|
1226
1257
|
if (error.name === "AbortError") {
|
|
1227
1258
|
return abortedError(service);
|
|
1228
1259
|
}
|
|
@@ -1247,6 +1278,7 @@ function errorResult(error) {
|
|
|
1247
1278
|
}
|
|
1248
1279
|
|
|
1249
1280
|
// src/base/BaseService.ts
|
|
1281
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
1250
1282
|
var BaseService = class {
|
|
1251
1283
|
constructor() {
|
|
1252
1284
|
/**
|
|
@@ -1427,6 +1459,64 @@ var BaseService = class {
|
|
|
1427
1459
|
}
|
|
1428
1460
|
return controller.signal;
|
|
1429
1461
|
}
|
|
1462
|
+
/**
|
|
1463
|
+
* Create the abort signal for one request, bounded by the request timeout.
|
|
1464
|
+
*
|
|
1465
|
+
* The signal aborts when the service signs out, the context aborts, the
|
|
1466
|
+
* caller's `signal` aborts, or the timeout elapses, whichever comes first.
|
|
1467
|
+
* A timeout aborts with a {@link RequestTimeoutError} (`TimeoutError`), which
|
|
1468
|
+
* `wrapError` maps to `ErrorCodes.TIMEOUT`; the other sources keep their own
|
|
1469
|
+
* reason (normally `AbortError`, mapped to `ErrorCodes.ABORTED`).
|
|
1470
|
+
*
|
|
1471
|
+
* The timeout is `timeoutMs` when given, otherwise `config.timeout`. Only a
|
|
1472
|
+
* positive, finite value (at most 2^31-1 ms) applies; `undefined`, `0`, and
|
|
1473
|
+
* `Infinity` mean no timeout, so a per-call `0` opts out of a configured one.
|
|
1474
|
+
*
|
|
1475
|
+
* Callers must call `dispose()` once the response body has been consumed,
|
|
1476
|
+
* which clears the timer and removes the listeners this adds to the
|
|
1477
|
+
* long-lived service and context signals.
|
|
1478
|
+
*
|
|
1479
|
+
* @param signal - The caller's abort signal for this request
|
|
1480
|
+
* @param timeoutMs - Per-request timeout override in milliseconds
|
|
1481
|
+
*/
|
|
1482
|
+
createRequestSignal(signal, timeoutMs) {
|
|
1483
|
+
const controller = new AbortController();
|
|
1484
|
+
const detachers = [];
|
|
1485
|
+
let timer;
|
|
1486
|
+
const dispose = () => {
|
|
1487
|
+
if (timer !== void 0) {
|
|
1488
|
+
clearTimeout(timer);
|
|
1489
|
+
timer = void 0;
|
|
1490
|
+
}
|
|
1491
|
+
for (const detach of detachers.splice(0)) {
|
|
1492
|
+
detach();
|
|
1493
|
+
}
|
|
1494
|
+
};
|
|
1495
|
+
const abort = (reason) => {
|
|
1496
|
+
dispose();
|
|
1497
|
+
controller.abort(reason);
|
|
1498
|
+
};
|
|
1499
|
+
const requestSignal = { signal: controller.signal, dispose };
|
|
1500
|
+
const parents = [
|
|
1501
|
+
this.abortController.signal,
|
|
1502
|
+
this.context?.abortSignal,
|
|
1503
|
+
signal
|
|
1504
|
+
].filter((parent) => parent !== void 0);
|
|
1505
|
+
for (const parent of parents) {
|
|
1506
|
+
if (parent.aborted) {
|
|
1507
|
+
abort(parent.reason);
|
|
1508
|
+
return requestSignal;
|
|
1509
|
+
}
|
|
1510
|
+
const onAbort = () => abort(parent.reason);
|
|
1511
|
+
parent.addEventListener("abort", onAbort, { once: true });
|
|
1512
|
+
detachers.push(() => parent.removeEventListener("abort", onAbort));
|
|
1513
|
+
}
|
|
1514
|
+
const timeout = timeoutMs ?? this._config.timeout;
|
|
1515
|
+
if (typeof timeout === "number" && timeout > 0 && timeout <= MAX_TIMER_DELAY_MS) {
|
|
1516
|
+
timer = setTimeout(() => abort(new RequestTimeoutError(timeout)), timeout);
|
|
1517
|
+
}
|
|
1518
|
+
return requestSignal;
|
|
1519
|
+
}
|
|
1430
1520
|
/**
|
|
1431
1521
|
* Wrap an operation with error handling and telemetry.
|
|
1432
1522
|
*
|
|
@@ -1535,6 +1625,30 @@ var PrefixedKVService = class _PrefixedKVService {
|
|
|
1535
1625
|
removePrefix
|
|
1536
1626
|
});
|
|
1537
1627
|
}
|
|
1628
|
+
/**
|
|
1629
|
+
* Read the change feed for everything under this prefix. A view with an
|
|
1630
|
+
* empty prefix (`""` or `"/"`) is refused: the node does not serve a
|
|
1631
|
+
* whole-space feed.
|
|
1632
|
+
*/
|
|
1633
|
+
async changes(options) {
|
|
1634
|
+
if (this._prefix.replace(/\/+$/, "") === "") {
|
|
1635
|
+
return err(serviceError(
|
|
1636
|
+
ErrorCodes.INVALID_INPUT,
|
|
1637
|
+
"KV changes needs a non-empty prefix; this view has none",
|
|
1638
|
+
"kv"
|
|
1639
|
+
));
|
|
1640
|
+
}
|
|
1641
|
+
const syncPrefix = `${this._prefix}/`;
|
|
1642
|
+
const response = await this._kv.changes({ ...options, prefix: syncPrefix });
|
|
1643
|
+
if (!response.ok) return response;
|
|
1644
|
+
return ok({
|
|
1645
|
+
...response.data,
|
|
1646
|
+
changes: response.data.changes.map((change) => ({
|
|
1647
|
+
...change,
|
|
1648
|
+
key: change.key.startsWith(syncPrefix) ? change.key.slice(syncPrefix.length) : change.key
|
|
1649
|
+
}))
|
|
1650
|
+
});
|
|
1651
|
+
}
|
|
1538
1652
|
/**
|
|
1539
1653
|
* Delete a key.
|
|
1540
1654
|
*/
|
|
@@ -1587,11 +1701,18 @@ var KVAction = {
|
|
|
1587
1701
|
PUT: "tinycloud.kv/put",
|
|
1588
1702
|
LIST: "tinycloud.kv/list",
|
|
1589
1703
|
DELETE: "tinycloud.kv/del",
|
|
1590
|
-
HEAD: "tinycloud.kv/metadata"
|
|
1704
|
+
HEAD: "tinycloud.kv/metadata",
|
|
1705
|
+
/** The change feed; never implied by `*` or `tinycloud.kv/*`. */
|
|
1706
|
+
SYNC: "tinycloud.kv/sync",
|
|
1707
|
+
/** Retention attestation; presented through `retentionGrant`, never invoked or implied. */
|
|
1708
|
+
RETAIN: "tinycloud.kv/retain"
|
|
1591
1709
|
};
|
|
1592
1710
|
|
|
1593
1711
|
// src/kv/KVService.ts
|
|
1594
1712
|
var MAX_KV_BATCH_READ_ITEMS = 100;
|
|
1713
|
+
function isJsonObject(value) {
|
|
1714
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1715
|
+
}
|
|
1595
1716
|
function encodeKvBatchPartName(path) {
|
|
1596
1717
|
return encodeURIComponent(path).replace(
|
|
1597
1718
|
/[!'()*]/g,
|
|
@@ -1687,7 +1808,7 @@ var KVService = class extends BaseService {
|
|
|
1687
1808
|
* @param path - Resource path
|
|
1688
1809
|
* @param action - KV action
|
|
1689
1810
|
* @param body - Optional request body
|
|
1690
|
-
* @param signal -
|
|
1811
|
+
* @param signal - Request signal from createRequestSignal()
|
|
1691
1812
|
* @returns Fetch response
|
|
1692
1813
|
*/
|
|
1693
1814
|
async invokeOperation(path, action, body, signal, extraHeaders) {
|
|
@@ -1703,7 +1824,7 @@ var KVService = class extends BaseService {
|
|
|
1703
1824
|
method: "POST",
|
|
1704
1825
|
headers: requestHeaders,
|
|
1705
1826
|
body,
|
|
1706
|
-
signal
|
|
1827
|
+
signal
|
|
1707
1828
|
});
|
|
1708
1829
|
}
|
|
1709
1830
|
/**
|
|
@@ -1880,6 +2001,7 @@ var KVService = class extends BaseService {
|
|
|
1880
2001
|
"kv"
|
|
1881
2002
|
));
|
|
1882
2003
|
}
|
|
2004
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
1883
2005
|
try {
|
|
1884
2006
|
const session = this.context.session;
|
|
1885
2007
|
const invocationHeaders = this.context.invokeAny(
|
|
@@ -1901,7 +2023,7 @@ var KVService = class extends BaseService {
|
|
|
1901
2023
|
const response = await this.context.fetch(`${this.host}/invoke`, {
|
|
1902
2024
|
method: "POST",
|
|
1903
2025
|
headers,
|
|
1904
|
-
signal:
|
|
2026
|
+
signal: request.signal
|
|
1905
2027
|
});
|
|
1906
2028
|
if (!response.ok) {
|
|
1907
2029
|
const errorText = response.status === 401 || response.status === 403 ? await this.readAuthorizationText(response) : await response.text();
|
|
@@ -1966,6 +2088,8 @@ var KVService = class extends BaseService {
|
|
|
1966
2088
|
return ok({ results, count: results.length });
|
|
1967
2089
|
} catch (error) {
|
|
1968
2090
|
return err(wrapError("kv", error));
|
|
2091
|
+
} finally {
|
|
2092
|
+
request.dispose();
|
|
1969
2093
|
}
|
|
1970
2094
|
}
|
|
1971
2095
|
/**
|
|
@@ -2098,12 +2222,13 @@ var KVService = class extends BaseService {
|
|
|
2098
2222
|
));
|
|
2099
2223
|
}
|
|
2100
2224
|
const path = this.getFullPath(key, options?.prefix);
|
|
2225
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2101
2226
|
try {
|
|
2102
2227
|
const response = await this.invokeOperation(
|
|
2103
2228
|
path,
|
|
2104
2229
|
KVAction.GET,
|
|
2105
2230
|
void 0,
|
|
2106
|
-
|
|
2231
|
+
request.signal,
|
|
2107
2232
|
options?.maxResponseBytes === void 0 ? void 0 : { "x-tinycloud-max-response-bytes": String(options.maxResponseBytes) }
|
|
2108
2233
|
);
|
|
2109
2234
|
if (!response.ok) {
|
|
@@ -2160,6 +2285,8 @@ var KVService = class extends BaseService {
|
|
|
2160
2285
|
});
|
|
2161
2286
|
} catch (error) {
|
|
2162
2287
|
return err(wrapError("kv", error));
|
|
2288
|
+
} finally {
|
|
2289
|
+
request.dispose();
|
|
2163
2290
|
}
|
|
2164
2291
|
});
|
|
2165
2292
|
}
|
|
@@ -2187,12 +2314,13 @@ var KVService = class extends BaseService {
|
|
|
2187
2314
|
}
|
|
2188
2315
|
const path = this.getFullPath(key, options?.prefix);
|
|
2189
2316
|
const body = this.serializePutValue(value, options?.contentType);
|
|
2317
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2190
2318
|
try {
|
|
2191
2319
|
const response = await this.invokeOperation(
|
|
2192
2320
|
path,
|
|
2193
2321
|
KVAction.PUT,
|
|
2194
2322
|
body,
|
|
2195
|
-
|
|
2323
|
+
request.signal,
|
|
2196
2324
|
{
|
|
2197
2325
|
...options?.ifMatch === void 0 ? {} : { "if-match": options.ifMatch },
|
|
2198
2326
|
...options?.ifNoneMatch === void 0 ? {} : { "if-none-match": options.ifNoneMatch }
|
|
@@ -2248,6 +2376,8 @@ var KVService = class extends BaseService {
|
|
|
2248
2376
|
});
|
|
2249
2377
|
} catch (error) {
|
|
2250
2378
|
return err(wrapError("kv", error));
|
|
2379
|
+
} finally {
|
|
2380
|
+
request.dispose();
|
|
2251
2381
|
}
|
|
2252
2382
|
});
|
|
2253
2383
|
}
|
|
@@ -2287,6 +2417,7 @@ var KVService = class extends BaseService {
|
|
|
2287
2417
|
seen.add(path);
|
|
2288
2418
|
}
|
|
2289
2419
|
let requestMayHaveDispatched = false;
|
|
2420
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2290
2421
|
try {
|
|
2291
2422
|
const body = new FormData();
|
|
2292
2423
|
for (let index = 0; index < items.length; index++) {
|
|
@@ -2309,7 +2440,7 @@ var KVService = class extends BaseService {
|
|
|
2309
2440
|
method: "POST",
|
|
2310
2441
|
headers,
|
|
2311
2442
|
body,
|
|
2312
|
-
signal:
|
|
2443
|
+
signal: request.signal
|
|
2313
2444
|
};
|
|
2314
2445
|
const fetchFn = this.context.fetch;
|
|
2315
2446
|
requestMayHaveDispatched = true;
|
|
@@ -2360,14 +2491,16 @@ var KVService = class extends BaseService {
|
|
|
2360
2491
|
rawBody = await response.json();
|
|
2361
2492
|
} catch (jsonError) {
|
|
2362
2493
|
const cause = jsonError instanceof Error ? jsonError : new Error(String(jsonError));
|
|
2494
|
+
const timedOut = isRequestTimeoutError(cause);
|
|
2363
2495
|
return err(
|
|
2364
2496
|
serviceError(
|
|
2365
|
-
ErrorCodes.NETWORK_ERROR,
|
|
2366
|
-
`KV batchPut response was not valid JSON: ${cause.message}`,
|
|
2497
|
+
timedOut ? ErrorCodes.TIMEOUT : ErrorCodes.NETWORK_ERROR,
|
|
2498
|
+
timedOut ? `KV batchPut response body did not arrive in time: ${cause.message}` : `KV batchPut response was not valid JSON: ${cause.message}`,
|
|
2367
2499
|
"kv",
|
|
2368
2500
|
{
|
|
2369
2501
|
cause,
|
|
2370
2502
|
meta: {
|
|
2503
|
+
...timedOut ? { timeoutMs: cause.timeoutMs } : {},
|
|
2371
2504
|
requestMayHaveDispatched: true,
|
|
2372
2505
|
responseReceived: true,
|
|
2373
2506
|
status: response.status,
|
|
@@ -2422,6 +2555,8 @@ var KVService = class extends BaseService {
|
|
|
2422
2555
|
...wrapped,
|
|
2423
2556
|
meta: { ...wrapped.meta, requestMayHaveDispatched }
|
|
2424
2557
|
});
|
|
2558
|
+
} finally {
|
|
2559
|
+
request.dispose();
|
|
2425
2560
|
}
|
|
2426
2561
|
});
|
|
2427
2562
|
}
|
|
@@ -2444,12 +2579,13 @@ var KVService = class extends BaseService {
|
|
|
2444
2579
|
if (options?.path) {
|
|
2445
2580
|
listPath = listPath ? `${listPath}/${options.path}` : options.path;
|
|
2446
2581
|
}
|
|
2582
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2447
2583
|
try {
|
|
2448
2584
|
const response = await this.invokeOperation(
|
|
2449
2585
|
listPath,
|
|
2450
2586
|
KVAction.LIST,
|
|
2451
2587
|
void 0,
|
|
2452
|
-
|
|
2588
|
+
request.signal,
|
|
2453
2589
|
options?.limit === void 0 && options?.cursor === void 0 ? void 0 : {
|
|
2454
2590
|
...options?.limit === void 0 ? {} : { "x-tinycloud-limit": String(options.limit) },
|
|
2455
2591
|
...options?.cursor === void 0 ? {} : { "x-tinycloud-cursor": options.cursor }
|
|
@@ -2490,9 +2626,174 @@ var KVService = class extends BaseService {
|
|
|
2490
2626
|
});
|
|
2491
2627
|
} catch (error) {
|
|
2492
2628
|
return err(wrapError("kv", error));
|
|
2629
|
+
} finally {
|
|
2630
|
+
request.dispose();
|
|
2631
|
+
}
|
|
2632
|
+
});
|
|
2633
|
+
}
|
|
2634
|
+
/**
|
|
2635
|
+
* Read one page of the `tinycloud.kv/sync` change feed for a prefix.
|
|
2636
|
+
*/
|
|
2637
|
+
async changes(options) {
|
|
2638
|
+
return this.withTelemetry("changes", options?.prefix, async () => {
|
|
2639
|
+
if (!this.requireAuth()) {
|
|
2640
|
+
return err(authRequiredError("kv"));
|
|
2641
|
+
}
|
|
2642
|
+
if (typeof options?.prefix !== "string" || options.prefix.length === 0) {
|
|
2643
|
+
return err(serviceError(
|
|
2644
|
+
ErrorCodes.INVALID_INPUT,
|
|
2645
|
+
"KV changes prefix must be a non-empty string",
|
|
2646
|
+
"kv"
|
|
2647
|
+
));
|
|
2648
|
+
}
|
|
2649
|
+
if (options.limit !== void 0 && (!Number.isInteger(options.limit) || options.limit < 1 || options.limit > 1e3)) {
|
|
2650
|
+
return err(serviceError(
|
|
2651
|
+
ErrorCodes.INVALID_INPUT,
|
|
2652
|
+
"KV changes limit must be an integer from 1 through 1000",
|
|
2653
|
+
"kv"
|
|
2654
|
+
));
|
|
2655
|
+
}
|
|
2656
|
+
const headers = {};
|
|
2657
|
+
if (options.limit !== void 0) headers["x-tinycloud-limit"] = String(options.limit);
|
|
2658
|
+
if (options.cursor !== void 0) headers["x-tinycloud-cursor"] = options.cursor;
|
|
2659
|
+
if (options.retentionGrant !== void 0) {
|
|
2660
|
+
headers["x-tinycloud-retention-grant"] = options.retentionGrant;
|
|
2661
|
+
}
|
|
2662
|
+
const request = this.createRequestSignal(options.signal, options.timeout);
|
|
2663
|
+
try {
|
|
2664
|
+
const response = await this.invokeOperation(
|
|
2665
|
+
options.prefix,
|
|
2666
|
+
KVAction.SYNC,
|
|
2667
|
+
void 0,
|
|
2668
|
+
request.signal,
|
|
2669
|
+
headers
|
|
2670
|
+
);
|
|
2671
|
+
if (!response.ok) {
|
|
2672
|
+
return await this.changesFailure(response, options.prefix, request.signal);
|
|
2673
|
+
}
|
|
2674
|
+
const text = await response.text();
|
|
2675
|
+
let body;
|
|
2676
|
+
try {
|
|
2677
|
+
body = JSON.parse(text);
|
|
2678
|
+
} catch {
|
|
2679
|
+
body = void 0;
|
|
2680
|
+
}
|
|
2681
|
+
const page = this.normalizeChangesResponse(body);
|
|
2682
|
+
if (!page) {
|
|
2683
|
+
return err(serviceError(
|
|
2684
|
+
ErrorCodes.NETWORK_ERROR,
|
|
2685
|
+
"KV changes response was not a tinycloud.kv/sync page",
|
|
2686
|
+
"kv",
|
|
2687
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2688
|
+
));
|
|
2689
|
+
}
|
|
2690
|
+
return ok(page);
|
|
2691
|
+
} catch (error) {
|
|
2692
|
+
return err(wrapError("kv", error));
|
|
2693
|
+
} finally {
|
|
2694
|
+
request.dispose();
|
|
2493
2695
|
}
|
|
2494
2696
|
});
|
|
2495
2697
|
}
|
|
2698
|
+
/**
|
|
2699
|
+
* Map a failed `kv/sync` response. 410 and the retention 403 carry
|
|
2700
|
+
* `{"error":{"code","reason"}}`; a revoked grant is a 401 whose text names
|
|
2701
|
+
* `delegation-revoked` or `delegation-ancestor-revoked`. A body read that
|
|
2702
|
+
* fails because the request was cancelled or timed out rethrows, so the
|
|
2703
|
+
* caller sees `ABORTED`/`TIMEOUT` rather than a mapped status.
|
|
2704
|
+
*/
|
|
2705
|
+
async changesFailure(response, prefix, signal) {
|
|
2706
|
+
if (response.status === 404) {
|
|
2707
|
+
return this.classifyNotFound(response, prefix);
|
|
2708
|
+
}
|
|
2709
|
+
let errorText;
|
|
2710
|
+
try {
|
|
2711
|
+
errorText = await response.text();
|
|
2712
|
+
} catch (error) {
|
|
2713
|
+
if (signal.aborted) throw error;
|
|
2714
|
+
errorText = "";
|
|
2715
|
+
}
|
|
2716
|
+
const meta = { status: response.status, statusText: response.statusText };
|
|
2717
|
+
let reason;
|
|
2718
|
+
let bodyCode;
|
|
2719
|
+
try {
|
|
2720
|
+
const body = JSON.parse(errorText);
|
|
2721
|
+
const error = isJsonObject(body) ? body.error : void 0;
|
|
2722
|
+
if (isJsonObject(error)) {
|
|
2723
|
+
if (typeof error.code === "string") bodyCode = error.code;
|
|
2724
|
+
if (typeof error.reason === "string") reason = error.reason;
|
|
2725
|
+
}
|
|
2726
|
+
} catch {
|
|
2727
|
+
}
|
|
2728
|
+
const context = `Failed to read KV changes for ${JSON.stringify(prefix)}`;
|
|
2729
|
+
if (response.status === 410) {
|
|
2730
|
+
return err(serviceError(
|
|
2731
|
+
ErrorCodes.KV_SYNC_RESET_REQUIRED,
|
|
2732
|
+
`${context}: the node requires a reset (${reason ?? "reason not given"}); discard sync state and restart without a cursor`,
|
|
2733
|
+
"kv",
|
|
2734
|
+
{ meta: { ...meta, reason } }
|
|
2735
|
+
));
|
|
2736
|
+
}
|
|
2737
|
+
if (response.status === 403 && bodyCode === "RETENTION_GRANT_REFUSED") {
|
|
2738
|
+
return err(serviceError(
|
|
2739
|
+
ErrorCodes.KV_RETENTION_GRANT_REFUSED,
|
|
2740
|
+
`${context}: the retention grant was refused (${reason ?? "reason not given"})`,
|
|
2741
|
+
"kv",
|
|
2742
|
+
{ meta: { ...meta, reason } }
|
|
2743
|
+
));
|
|
2744
|
+
}
|
|
2745
|
+
if (response.status === 401) {
|
|
2746
|
+
const revoked = /\bdelegation-ancestor-revoked\b/.test(errorText) ? ErrorCodes.AUTH_DELEGATION_ANCESTOR_REVOKED : /\bdelegation-revoked\b/.test(errorText) ? ErrorCodes.AUTH_DELEGATION_REVOKED : void 0;
|
|
2747
|
+
if (revoked !== void 0) {
|
|
2748
|
+
return err(serviceError(revoked, `${context}: 401 - ${errorText}`, "kv", { meta }));
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
if (response.status === 401 || response.status === 403) {
|
|
2752
|
+
return this.authorizationFailure(context, response, errorText, [prefix], KVAction.SYNC);
|
|
2753
|
+
}
|
|
2754
|
+
return err(serviceError(
|
|
2755
|
+
response.status === 400 ? ErrorCodes.INVALID_INPUT : ErrorCodes.NETWORK_ERROR,
|
|
2756
|
+
`${context}: ${response.status} - ${errorText}`,
|
|
2757
|
+
"kv",
|
|
2758
|
+
{ meta }
|
|
2759
|
+
));
|
|
2760
|
+
}
|
|
2761
|
+
normalizeChangesResponse(data) {
|
|
2762
|
+
if (!isJsonObject(data)) return void 0;
|
|
2763
|
+
const { changes, more, cursor, source, authority } = data;
|
|
2764
|
+
if (!Array.isArray(changes) || typeof more !== "boolean" || typeof cursor !== "string" || !isJsonObject(source) || typeof source.nodeDid !== "string" || typeof source.space !== "string" || typeof source.prefix !== "string" || !isJsonObject(authority)) {
|
|
2765
|
+
return void 0;
|
|
2766
|
+
}
|
|
2767
|
+
const { notBefore, expiresAt, retainUntil } = authority;
|
|
2768
|
+
if (notBefore !== null && typeof notBefore !== "string" || expiresAt !== null && typeof expiresAt !== "string" || retainUntil !== null && typeof retainUntil !== "string") {
|
|
2769
|
+
return void 0;
|
|
2770
|
+
}
|
|
2771
|
+
const parsed = [];
|
|
2772
|
+
for (const change of changes) {
|
|
2773
|
+
if (!isJsonObject(change) || typeof change.key !== "string") return void 0;
|
|
2774
|
+
if (change.deleted === true) {
|
|
2775
|
+
parsed.push({ key: change.key, deleted: true });
|
|
2776
|
+
continue;
|
|
2777
|
+
}
|
|
2778
|
+
const { metadata } = change;
|
|
2779
|
+
if (change.deleted !== false || typeof change.etag !== "string" || !isJsonObject(metadata) || !Object.values(metadata).every((value) => typeof value === "string")) {
|
|
2780
|
+
return void 0;
|
|
2781
|
+
}
|
|
2782
|
+
parsed.push({
|
|
2783
|
+
key: change.key,
|
|
2784
|
+
deleted: false,
|
|
2785
|
+
etag: change.etag,
|
|
2786
|
+
metadata
|
|
2787
|
+
});
|
|
2788
|
+
}
|
|
2789
|
+
return {
|
|
2790
|
+
changes: parsed,
|
|
2791
|
+
more,
|
|
2792
|
+
cursor,
|
|
2793
|
+
source: { nodeDid: source.nodeDid, space: source.space, prefix: source.prefix },
|
|
2794
|
+
authority: { notBefore, expiresAt, retainUntil }
|
|
2795
|
+
};
|
|
2796
|
+
}
|
|
2496
2797
|
/**
|
|
2497
2798
|
* Delete a key.
|
|
2498
2799
|
*/
|
|
@@ -2502,12 +2803,13 @@ var KVService = class extends BaseService {
|
|
|
2502
2803
|
return err(authRequiredError("kv"));
|
|
2503
2804
|
}
|
|
2504
2805
|
const path = this.getFullPath(key, options?.prefix);
|
|
2806
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2505
2807
|
try {
|
|
2506
2808
|
const response = await this.invokeOperation(
|
|
2507
2809
|
path,
|
|
2508
2810
|
KVAction.DELETE,
|
|
2509
2811
|
void 0,
|
|
2510
|
-
|
|
2812
|
+
request.signal,
|
|
2511
2813
|
options?.ifMatch === void 0 ? void 0 : { "if-match": options.ifMatch }
|
|
2512
2814
|
);
|
|
2513
2815
|
if (!response.ok) {
|
|
@@ -2555,6 +2857,8 @@ var KVService = class extends BaseService {
|
|
|
2555
2857
|
});
|
|
2556
2858
|
} catch (error) {
|
|
2557
2859
|
return err(wrapError("kv", error));
|
|
2860
|
+
} finally {
|
|
2861
|
+
request.dispose();
|
|
2558
2862
|
}
|
|
2559
2863
|
});
|
|
2560
2864
|
}
|
|
@@ -2567,12 +2871,13 @@ var KVService = class extends BaseService {
|
|
|
2567
2871
|
return err(authRequiredError("kv"));
|
|
2568
2872
|
}
|
|
2569
2873
|
const path = this.getFullPath(key, options?.prefix);
|
|
2874
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2570
2875
|
try {
|
|
2571
2876
|
const response = await this.invokeOperation(
|
|
2572
2877
|
path,
|
|
2573
2878
|
KVAction.HEAD,
|
|
2574
2879
|
void 0,
|
|
2575
|
-
|
|
2880
|
+
request.signal
|
|
2576
2881
|
);
|
|
2577
2882
|
if (!response.ok) {
|
|
2578
2883
|
if (response.status === 401 || response.status === 403) {
|
|
@@ -2603,6 +2908,8 @@ var KVService = class extends BaseService {
|
|
|
2603
2908
|
});
|
|
2604
2909
|
} catch (error) {
|
|
2605
2910
|
return err(wrapError("kv", error));
|
|
2911
|
+
} finally {
|
|
2912
|
+
request.dispose();
|
|
2606
2913
|
}
|
|
2607
2914
|
});
|
|
2608
2915
|
}
|
|
@@ -2640,12 +2947,13 @@ var KVService = class extends BaseService {
|
|
|
2640
2947
|
if (options?.etag !== void 0) {
|
|
2641
2948
|
body.etag = options.etag;
|
|
2642
2949
|
}
|
|
2950
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2643
2951
|
try {
|
|
2644
2952
|
const response = await this.context.fetch(`${this.host}/signed/kv`, {
|
|
2645
2953
|
method: "POST",
|
|
2646
2954
|
headers: this.withJsonContentType(headers),
|
|
2647
2955
|
body: JSON.stringify(body),
|
|
2648
|
-
signal:
|
|
2956
|
+
signal: request.signal
|
|
2649
2957
|
});
|
|
2650
2958
|
if (!response.ok) {
|
|
2651
2959
|
return this.createSignedReadUrlError(response, key, path);
|
|
@@ -2665,6 +2973,8 @@ var KVService = class extends BaseService {
|
|
|
2665
2973
|
return ok(signedUrl);
|
|
2666
2974
|
} catch (error) {
|
|
2667
2975
|
return err(wrapError("kv", error));
|
|
2976
|
+
} finally {
|
|
2977
|
+
request.dispose();
|
|
2668
2978
|
}
|
|
2669
2979
|
});
|
|
2670
2980
|
}
|
|
@@ -2878,6 +3188,7 @@ var SQLService = class extends BaseService {
|
|
|
2878
3188
|
if (!this.requireAuth()) {
|
|
2879
3189
|
return err(authRequiredError("sql"));
|
|
2880
3190
|
}
|
|
3191
|
+
const request = this.createRequestSignal(options?.signal);
|
|
2881
3192
|
try {
|
|
2882
3193
|
const body = {
|
|
2883
3194
|
action: "query",
|
|
@@ -2891,7 +3202,7 @@ var SQLService = class extends BaseService {
|
|
|
2891
3202
|
dbName,
|
|
2892
3203
|
action,
|
|
2893
3204
|
body,
|
|
2894
|
-
|
|
3205
|
+
request.signal
|
|
2895
3206
|
);
|
|
2896
3207
|
if (!response.ok) {
|
|
2897
3208
|
return this.handleErrorResponse(response, "query", dbName, [action]);
|
|
@@ -2900,6 +3211,8 @@ var SQLService = class extends BaseService {
|
|
|
2900
3211
|
return ok(data);
|
|
2901
3212
|
} catch (error) {
|
|
2902
3213
|
return err(wrapError("sql", error));
|
|
3214
|
+
} finally {
|
|
3215
|
+
request.dispose();
|
|
2903
3216
|
}
|
|
2904
3217
|
});
|
|
2905
3218
|
}
|
|
@@ -2908,6 +3221,7 @@ var SQLService = class extends BaseService {
|
|
|
2908
3221
|
if (!this.requireAuth()) {
|
|
2909
3222
|
return err(authRequiredError("sql"));
|
|
2910
3223
|
}
|
|
3224
|
+
const request = this.createRequestSignal(options?.signal);
|
|
2911
3225
|
try {
|
|
2912
3226
|
const body = {
|
|
2913
3227
|
action: "execute",
|
|
@@ -2928,7 +3242,7 @@ var SQLService = class extends BaseService {
|
|
|
2928
3242
|
dbName,
|
|
2929
3243
|
requestedActions,
|
|
2930
3244
|
body,
|
|
2931
|
-
|
|
3245
|
+
request.signal
|
|
2932
3246
|
);
|
|
2933
3247
|
if (!response.ok) {
|
|
2934
3248
|
return this.handleErrorResponse(response, "execute", dbName, requestedActions);
|
|
@@ -2937,6 +3251,8 @@ var SQLService = class extends BaseService {
|
|
|
2937
3251
|
return ok(data);
|
|
2938
3252
|
} catch (error) {
|
|
2939
3253
|
return err(wrapError("sql", error));
|
|
3254
|
+
} finally {
|
|
3255
|
+
request.dispose();
|
|
2940
3256
|
}
|
|
2941
3257
|
});
|
|
2942
3258
|
}
|
|
@@ -2945,13 +3261,14 @@ var SQLService = class extends BaseService {
|
|
|
2945
3261
|
if (!this.requireAuth()) {
|
|
2946
3262
|
return err(authRequiredError("sql"));
|
|
2947
3263
|
}
|
|
3264
|
+
const request = this.createRequestSignal(options?.signal);
|
|
2948
3265
|
try {
|
|
2949
3266
|
const requestedActions = this.actionsForSqlBatch(statements);
|
|
2950
3267
|
const response = await this.invokeSQL(
|
|
2951
3268
|
dbName,
|
|
2952
3269
|
requestedActions,
|
|
2953
3270
|
{ action: "batch", statements },
|
|
2954
|
-
|
|
3271
|
+
request.signal
|
|
2955
3272
|
);
|
|
2956
3273
|
if (!response.ok) {
|
|
2957
3274
|
return this.handleErrorResponse(response, "batch", dbName, requestedActions);
|
|
@@ -2960,6 +3277,8 @@ var SQLService = class extends BaseService {
|
|
|
2960
3277
|
return ok(data);
|
|
2961
3278
|
} catch (error) {
|
|
2962
3279
|
return err(wrapError("sql", error));
|
|
3280
|
+
} finally {
|
|
3281
|
+
request.dispose();
|
|
2963
3282
|
}
|
|
2964
3283
|
});
|
|
2965
3284
|
}
|
|
@@ -2968,12 +3287,13 @@ var SQLService = class extends BaseService {
|
|
|
2968
3287
|
if (!this.requireAuth()) {
|
|
2969
3288
|
return err(authRequiredError("sql"));
|
|
2970
3289
|
}
|
|
3290
|
+
const request = this.createRequestSignal(options?.signal);
|
|
2971
3291
|
try {
|
|
2972
3292
|
const response = await this.invokeSQL(
|
|
2973
3293
|
dbName,
|
|
2974
3294
|
SQLAction.WRITE,
|
|
2975
3295
|
{ action: "execute_statement", name, params: params ?? [] },
|
|
2976
|
-
|
|
3296
|
+
request.signal
|
|
2977
3297
|
);
|
|
2978
3298
|
if (!response.ok) {
|
|
2979
3299
|
return this.handleErrorResponse(response, "executeStatement", dbName, [SQLAction.WRITE]);
|
|
@@ -2982,6 +3302,8 @@ var SQLService = class extends BaseService {
|
|
|
2982
3302
|
return ok(data);
|
|
2983
3303
|
} catch (error) {
|
|
2984
3304
|
return err(wrapError("sql", error));
|
|
3305
|
+
} finally {
|
|
3306
|
+
request.dispose();
|
|
2985
3307
|
}
|
|
2986
3308
|
});
|
|
2987
3309
|
}
|
|
@@ -2990,12 +3312,13 @@ var SQLService = class extends BaseService {
|
|
|
2990
3312
|
if (!this.requireAuth()) {
|
|
2991
3313
|
return err(authRequiredError("sql"));
|
|
2992
3314
|
}
|
|
3315
|
+
const request = this.createRequestSignal(options?.signal);
|
|
2993
3316
|
try {
|
|
2994
3317
|
const response = await this.invokeSQL(
|
|
2995
3318
|
dbName,
|
|
2996
3319
|
SQLAction.READ,
|
|
2997
3320
|
{ action: "export" },
|
|
2998
|
-
|
|
3321
|
+
request.signal
|
|
2999
3322
|
);
|
|
3000
3323
|
if (!response.ok) {
|
|
3001
3324
|
return this.handleErrorResponse(response, "export", dbName, [SQLAction.READ]);
|
|
@@ -3009,6 +3332,8 @@ var SQLService = class extends BaseService {
|
|
|
3009
3332
|
return ok(text);
|
|
3010
3333
|
} catch (error) {
|
|
3011
3334
|
return err(wrapError("sql", error));
|
|
3335
|
+
} finally {
|
|
3336
|
+
request.dispose();
|
|
3012
3337
|
}
|
|
3013
3338
|
});
|
|
3014
3339
|
}
|
|
@@ -3099,7 +3424,7 @@ var SQLService = class extends BaseService {
|
|
|
3099
3424
|
"Content-Type": "application/json"
|
|
3100
3425
|
},
|
|
3101
3426
|
body: JSON.stringify(body),
|
|
3102
|
-
signal
|
|
3427
|
+
signal
|
|
3103
3428
|
});
|
|
3104
3429
|
}
|
|
3105
3430
|
actionForSql(sql, fallback) {
|
|
@@ -3363,12 +3688,13 @@ var DuckDbService = class extends BaseService {
|
|
|
3363
3688
|
if (!this.requireAuth()) {
|
|
3364
3689
|
return err(authRequiredError("duckdb"));
|
|
3365
3690
|
}
|
|
3691
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3366
3692
|
try {
|
|
3367
3693
|
const response = await this.invokeDuckDb(
|
|
3368
3694
|
dbName,
|
|
3369
3695
|
DuckDbAction.READ,
|
|
3370
3696
|
{ action: "query", sql, params: params ?? [] },
|
|
3371
|
-
|
|
3697
|
+
request.signal
|
|
3372
3698
|
);
|
|
3373
3699
|
if (!response.ok) {
|
|
3374
3700
|
return this.handleErrorResponse(response, "query");
|
|
@@ -3377,6 +3703,8 @@ var DuckDbService = class extends BaseService {
|
|
|
3377
3703
|
return ok(data);
|
|
3378
3704
|
} catch (error) {
|
|
3379
3705
|
return err(wrapError("duckdb", error));
|
|
3706
|
+
} finally {
|
|
3707
|
+
request.dispose();
|
|
3380
3708
|
}
|
|
3381
3709
|
});
|
|
3382
3710
|
}
|
|
@@ -3385,12 +3713,13 @@ var DuckDbService = class extends BaseService {
|
|
|
3385
3713
|
if (!this.requireAuth()) {
|
|
3386
3714
|
return err(authRequiredError("duckdb"));
|
|
3387
3715
|
}
|
|
3716
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3388
3717
|
try {
|
|
3389
3718
|
const response = await this.invokeDuckDb(
|
|
3390
3719
|
dbName,
|
|
3391
3720
|
DuckDbAction.READ,
|
|
3392
3721
|
{ action: "query", sql, params: params ?? [] },
|
|
3393
|
-
|
|
3722
|
+
request.signal,
|
|
3394
3723
|
{ Accept: "application/vnd.apache.arrow.stream" }
|
|
3395
3724
|
);
|
|
3396
3725
|
if (!response.ok) {
|
|
@@ -3400,6 +3729,8 @@ var DuckDbService = class extends BaseService {
|
|
|
3400
3729
|
return ok(buffer);
|
|
3401
3730
|
} catch (error) {
|
|
3402
3731
|
return err(wrapError("duckdb", error));
|
|
3732
|
+
} finally {
|
|
3733
|
+
request.dispose();
|
|
3403
3734
|
}
|
|
3404
3735
|
});
|
|
3405
3736
|
}
|
|
@@ -3408,6 +3739,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3408
3739
|
if (!this.requireAuth()) {
|
|
3409
3740
|
return err(authRequiredError("duckdb"));
|
|
3410
3741
|
}
|
|
3742
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3411
3743
|
try {
|
|
3412
3744
|
const body = {
|
|
3413
3745
|
action: "execute",
|
|
@@ -3421,7 +3753,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3421
3753
|
dbName,
|
|
3422
3754
|
DuckDbAction.WRITE,
|
|
3423
3755
|
body,
|
|
3424
|
-
|
|
3756
|
+
request.signal
|
|
3425
3757
|
);
|
|
3426
3758
|
if (!response.ok) {
|
|
3427
3759
|
return this.handleErrorResponse(response, "execute");
|
|
@@ -3430,6 +3762,8 @@ var DuckDbService = class extends BaseService {
|
|
|
3430
3762
|
return ok(data);
|
|
3431
3763
|
} catch (error) {
|
|
3432
3764
|
return err(wrapError("duckdb", error));
|
|
3765
|
+
} finally {
|
|
3766
|
+
request.dispose();
|
|
3433
3767
|
}
|
|
3434
3768
|
});
|
|
3435
3769
|
}
|
|
@@ -3438,6 +3772,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3438
3772
|
if (!this.requireAuth()) {
|
|
3439
3773
|
return err(authRequiredError("duckdb"));
|
|
3440
3774
|
}
|
|
3775
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3441
3776
|
try {
|
|
3442
3777
|
const body = {
|
|
3443
3778
|
action: "batch",
|
|
@@ -3450,7 +3785,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3450
3785
|
dbName,
|
|
3451
3786
|
DuckDbAction.WRITE,
|
|
3452
3787
|
body,
|
|
3453
|
-
|
|
3788
|
+
request.signal
|
|
3454
3789
|
);
|
|
3455
3790
|
if (!response.ok) {
|
|
3456
3791
|
return this.handleErrorResponse(response, "batch");
|
|
@@ -3459,6 +3794,8 @@ var DuckDbService = class extends BaseService {
|
|
|
3459
3794
|
return ok(data);
|
|
3460
3795
|
} catch (error) {
|
|
3461
3796
|
return err(wrapError("duckdb", error));
|
|
3797
|
+
} finally {
|
|
3798
|
+
request.dispose();
|
|
3462
3799
|
}
|
|
3463
3800
|
});
|
|
3464
3801
|
}
|
|
@@ -3467,12 +3804,13 @@ var DuckDbService = class extends BaseService {
|
|
|
3467
3804
|
if (!this.requireAuth()) {
|
|
3468
3805
|
return err(authRequiredError("duckdb"));
|
|
3469
3806
|
}
|
|
3807
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3470
3808
|
try {
|
|
3471
3809
|
const response = await this.invokeDuckDb(
|
|
3472
3810
|
dbName,
|
|
3473
3811
|
DuckDbAction.WRITE,
|
|
3474
3812
|
{ action: "executeStatement", name, params: params ?? [] },
|
|
3475
|
-
|
|
3813
|
+
request.signal
|
|
3476
3814
|
);
|
|
3477
3815
|
if (!response.ok) {
|
|
3478
3816
|
return this.handleErrorResponse(response, "executeStatement");
|
|
@@ -3481,6 +3819,8 @@ var DuckDbService = class extends BaseService {
|
|
|
3481
3819
|
return ok(data);
|
|
3482
3820
|
} catch (error) {
|
|
3483
3821
|
return err(wrapError("duckdb", error));
|
|
3822
|
+
} finally {
|
|
3823
|
+
request.dispose();
|
|
3484
3824
|
}
|
|
3485
3825
|
});
|
|
3486
3826
|
}
|
|
@@ -3489,12 +3829,13 @@ var DuckDbService = class extends BaseService {
|
|
|
3489
3829
|
if (!this.requireAuth()) {
|
|
3490
3830
|
return err(authRequiredError("duckdb"));
|
|
3491
3831
|
}
|
|
3832
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3492
3833
|
try {
|
|
3493
3834
|
const response = await this.invokeDuckDb(
|
|
3494
3835
|
dbName,
|
|
3495
3836
|
DuckDbAction.READ,
|
|
3496
3837
|
{ action: "describe" },
|
|
3497
|
-
|
|
3838
|
+
request.signal
|
|
3498
3839
|
);
|
|
3499
3840
|
if (!response.ok) {
|
|
3500
3841
|
return this.handleErrorResponse(response, "describe");
|
|
@@ -3503,6 +3844,8 @@ var DuckDbService = class extends BaseService {
|
|
|
3503
3844
|
return ok(data);
|
|
3504
3845
|
} catch (error) {
|
|
3505
3846
|
return err(wrapError("duckdb", error));
|
|
3847
|
+
} finally {
|
|
3848
|
+
request.dispose();
|
|
3506
3849
|
}
|
|
3507
3850
|
});
|
|
3508
3851
|
}
|
|
@@ -3511,12 +3854,13 @@ var DuckDbService = class extends BaseService {
|
|
|
3511
3854
|
if (!this.requireAuth()) {
|
|
3512
3855
|
return err(authRequiredError("duckdb"));
|
|
3513
3856
|
}
|
|
3857
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3514
3858
|
try {
|
|
3515
3859
|
const response = await this.invokeDuckDb(
|
|
3516
3860
|
dbName,
|
|
3517
3861
|
DuckDbAction.EXPORT,
|
|
3518
3862
|
{ action: "export" },
|
|
3519
|
-
|
|
3863
|
+
request.signal
|
|
3520
3864
|
);
|
|
3521
3865
|
if (!response.ok) {
|
|
3522
3866
|
return this.handleErrorResponse(response, "export");
|
|
@@ -3525,6 +3869,8 @@ var DuckDbService = class extends BaseService {
|
|
|
3525
3869
|
return ok(blob);
|
|
3526
3870
|
} catch (error) {
|
|
3527
3871
|
return err(wrapError("duckdb", error));
|
|
3872
|
+
} finally {
|
|
3873
|
+
request.dispose();
|
|
3528
3874
|
}
|
|
3529
3875
|
});
|
|
3530
3876
|
}
|
|
@@ -3533,6 +3879,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3533
3879
|
if (!this.requireAuth()) {
|
|
3534
3880
|
return err(authRequiredError("duckdb"));
|
|
3535
3881
|
}
|
|
3882
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3536
3883
|
try {
|
|
3537
3884
|
const session = this.context.session;
|
|
3538
3885
|
const headers = this.context.invoke(
|
|
@@ -3548,7 +3895,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3548
3895
|
"Content-Type": "application/x-duckdb"
|
|
3549
3896
|
},
|
|
3550
3897
|
body: new Blob([data]),
|
|
3551
|
-
signal:
|
|
3898
|
+
signal: request.signal
|
|
3552
3899
|
});
|
|
3553
3900
|
if (!response.ok) {
|
|
3554
3901
|
return this.handleErrorResponse(response, "import");
|
|
@@ -3556,6 +3903,8 @@ var DuckDbService = class extends BaseService {
|
|
|
3556
3903
|
return ok(void 0);
|
|
3557
3904
|
} catch (error) {
|
|
3558
3905
|
return err(wrapError("duckdb", error));
|
|
3906
|
+
} finally {
|
|
3907
|
+
request.dispose();
|
|
3559
3908
|
}
|
|
3560
3909
|
});
|
|
3561
3910
|
}
|
|
@@ -3571,7 +3920,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3571
3920
|
...extraHeaders
|
|
3572
3921
|
},
|
|
3573
3922
|
body: JSON.stringify(body),
|
|
3574
|
-
signal
|
|
3923
|
+
signal
|
|
3575
3924
|
});
|
|
3576
3925
|
}
|
|
3577
3926
|
async handleErrorResponse(response, operation) {
|
|
@@ -5992,6 +6341,7 @@ var SecretsService = class {
|
|
|
5992
6341
|
}
|
|
5993
6342
|
async listAll() {
|
|
5994
6343
|
const entries = /* @__PURE__ */ new Map();
|
|
6344
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
5995
6345
|
let cursor;
|
|
5996
6346
|
do {
|
|
5997
6347
|
const result = await this.vault.listPage({
|
|
@@ -6014,6 +6364,14 @@ var SecretsService = class {
|
|
|
6014
6364
|
"Secret catalog listing was truncated without a continuation cursor."
|
|
6015
6365
|
);
|
|
6016
6366
|
}
|
|
6367
|
+
if (cursor !== void 0) {
|
|
6368
|
+
if (seenCursors.has(cursor)) {
|
|
6369
|
+
return invalidSecretInput(
|
|
6370
|
+
"Secret catalog listing repeated a continuation cursor; the node does not support paged KV lists."
|
|
6371
|
+
);
|
|
6372
|
+
}
|
|
6373
|
+
seenCursors.add(cursor);
|
|
6374
|
+
}
|
|
6017
6375
|
} while (cursor !== void 0);
|
|
6018
6376
|
return {
|
|
6019
6377
|
ok: true,
|