@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.cjs
CHANGED
|
@@ -155,6 +155,10 @@ var ErrorCodes = {
|
|
|
155
155
|
AUTH_EXPIRED: "AUTH_EXPIRED",
|
|
156
156
|
AUTH_REQUIRED: "AUTH_REQUIRED",
|
|
157
157
|
AUTH_UNAUTHORIZED: "AUTH_UNAUTHORIZED",
|
|
158
|
+
/** HTTP 401: the delegation the invocation cites was revoked. */
|
|
159
|
+
AUTH_DELEGATION_REVOKED: "AUTH_DELEGATION_REVOKED",
|
|
160
|
+
/** HTTP 401: a delegation the cited one rests on was revoked. */
|
|
161
|
+
AUTH_DELEGATION_ANCESTOR_REVOKED: "AUTH_DELEGATION_ANCESTOR_REVOKED",
|
|
158
162
|
NETWORK_ERROR: "NETWORK_ERROR",
|
|
159
163
|
TIMEOUT: "TIMEOUT",
|
|
160
164
|
ABORTED: "ABORTED",
|
|
@@ -166,6 +170,10 @@ var ErrorCodes = {
|
|
|
166
170
|
KV_PRECONDITION_FAILED: "KV_PRECONDITION_FAILED",
|
|
167
171
|
KV_CONFLICT: "KV_CONFLICT",
|
|
168
172
|
KV_RESPONSE_TOO_LARGE: "KV_RESPONSE_TOO_LARGE",
|
|
173
|
+
/** HTTP 410 from the change feed: discard sync state and restart without a cursor; `meta.reason` says why. */
|
|
174
|
+
KV_SYNC_RESET_REQUIRED: "KV_SYNC_RESET_REQUIRED",
|
|
175
|
+
/** HTTP 403 from the change feed: the retention grant was refused; `meta.reason` says why. */
|
|
176
|
+
KV_RETENTION_GRANT_REFUSED: "KV_RETENTION_GRANT_REFUSED",
|
|
169
177
|
// SQL-specific errors
|
|
170
178
|
SQL_ERROR: "SQL_ERROR",
|
|
171
179
|
SQL_PERMISSION_DENIED: "SQL_PERMISSION_DENIED",
|
|
@@ -1205,11 +1213,31 @@ function networkError(service, message, cause) {
|
|
|
1205
1213
|
cause
|
|
1206
1214
|
};
|
|
1207
1215
|
}
|
|
1208
|
-
|
|
1216
|
+
var RequestTimeoutError = class extends Error {
|
|
1217
|
+
constructor(timeoutMs) {
|
|
1218
|
+
super(`Request timed out after ${timeoutMs}ms.`);
|
|
1219
|
+
this.name = "TimeoutError";
|
|
1220
|
+
this.timeoutMs = timeoutMs;
|
|
1221
|
+
}
|
|
1222
|
+
};
|
|
1223
|
+
function isRequestTimeoutError(error) {
|
|
1224
|
+
return error instanceof RequestTimeoutError || error instanceof Error && error.name === "TimeoutError" && typeof error.timeoutMs === "number";
|
|
1225
|
+
}
|
|
1226
|
+
function timeoutError(service, timeoutMs, cause) {
|
|
1227
|
+
if (timeoutMs === void 0) {
|
|
1228
|
+
return {
|
|
1229
|
+
code: ErrorCodes.TIMEOUT,
|
|
1230
|
+
message: "Request timed out.",
|
|
1231
|
+
service,
|
|
1232
|
+
...cause === void 0 ? {} : { cause }
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1209
1235
|
return {
|
|
1210
1236
|
code: ErrorCodes.TIMEOUT,
|
|
1211
|
-
message:
|
|
1212
|
-
service
|
|
1237
|
+
message: `Request timed out after ${timeoutMs}ms.`,
|
|
1238
|
+
service,
|
|
1239
|
+
...cause === void 0 ? {} : { cause },
|
|
1240
|
+
meta: { timeoutMs }
|
|
1213
1241
|
};
|
|
1214
1242
|
}
|
|
1215
1243
|
function abortedError(service) {
|
|
@@ -1373,6 +1401,9 @@ function isStorageFullError(error) {
|
|
|
1373
1401
|
}
|
|
1374
1402
|
function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
|
|
1375
1403
|
if (error instanceof Error) {
|
|
1404
|
+
if (isRequestTimeoutError(error)) {
|
|
1405
|
+
return timeoutError(service, error.timeoutMs, error);
|
|
1406
|
+
}
|
|
1376
1407
|
if (error.name === "AbortError") {
|
|
1377
1408
|
return abortedError(service);
|
|
1378
1409
|
}
|
|
@@ -1397,6 +1428,7 @@ function errorResult(error) {
|
|
|
1397
1428
|
}
|
|
1398
1429
|
|
|
1399
1430
|
// src/base/BaseService.ts
|
|
1431
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
1400
1432
|
var BaseService = class {
|
|
1401
1433
|
constructor() {
|
|
1402
1434
|
/**
|
|
@@ -1577,6 +1609,64 @@ var BaseService = class {
|
|
|
1577
1609
|
}
|
|
1578
1610
|
return controller.signal;
|
|
1579
1611
|
}
|
|
1612
|
+
/**
|
|
1613
|
+
* Create the abort signal for one request, bounded by the request timeout.
|
|
1614
|
+
*
|
|
1615
|
+
* The signal aborts when the service signs out, the context aborts, the
|
|
1616
|
+
* caller's `signal` aborts, or the timeout elapses, whichever comes first.
|
|
1617
|
+
* A timeout aborts with a {@link RequestTimeoutError} (`TimeoutError`), which
|
|
1618
|
+
* `wrapError` maps to `ErrorCodes.TIMEOUT`; the other sources keep their own
|
|
1619
|
+
* reason (normally `AbortError`, mapped to `ErrorCodes.ABORTED`).
|
|
1620
|
+
*
|
|
1621
|
+
* The timeout is `timeoutMs` when given, otherwise `config.timeout`. Only a
|
|
1622
|
+
* positive, finite value (at most 2^31-1 ms) applies; `undefined`, `0`, and
|
|
1623
|
+
* `Infinity` mean no timeout, so a per-call `0` opts out of a configured one.
|
|
1624
|
+
*
|
|
1625
|
+
* Callers must call `dispose()` once the response body has been consumed,
|
|
1626
|
+
* which clears the timer and removes the listeners this adds to the
|
|
1627
|
+
* long-lived service and context signals.
|
|
1628
|
+
*
|
|
1629
|
+
* @param signal - The caller's abort signal for this request
|
|
1630
|
+
* @param timeoutMs - Per-request timeout override in milliseconds
|
|
1631
|
+
*/
|
|
1632
|
+
createRequestSignal(signal, timeoutMs) {
|
|
1633
|
+
const controller = new AbortController();
|
|
1634
|
+
const detachers = [];
|
|
1635
|
+
let timer;
|
|
1636
|
+
const dispose = () => {
|
|
1637
|
+
if (timer !== void 0) {
|
|
1638
|
+
clearTimeout(timer);
|
|
1639
|
+
timer = void 0;
|
|
1640
|
+
}
|
|
1641
|
+
for (const detach of detachers.splice(0)) {
|
|
1642
|
+
detach();
|
|
1643
|
+
}
|
|
1644
|
+
};
|
|
1645
|
+
const abort = (reason) => {
|
|
1646
|
+
dispose();
|
|
1647
|
+
controller.abort(reason);
|
|
1648
|
+
};
|
|
1649
|
+
const requestSignal = { signal: controller.signal, dispose };
|
|
1650
|
+
const parents = [
|
|
1651
|
+
this.abortController.signal,
|
|
1652
|
+
this.context?.abortSignal,
|
|
1653
|
+
signal
|
|
1654
|
+
].filter((parent) => parent !== void 0);
|
|
1655
|
+
for (const parent of parents) {
|
|
1656
|
+
if (parent.aborted) {
|
|
1657
|
+
abort(parent.reason);
|
|
1658
|
+
return requestSignal;
|
|
1659
|
+
}
|
|
1660
|
+
const onAbort = () => abort(parent.reason);
|
|
1661
|
+
parent.addEventListener("abort", onAbort, { once: true });
|
|
1662
|
+
detachers.push(() => parent.removeEventListener("abort", onAbort));
|
|
1663
|
+
}
|
|
1664
|
+
const timeout = timeoutMs ?? this._config.timeout;
|
|
1665
|
+
if (typeof timeout === "number" && timeout > 0 && timeout <= MAX_TIMER_DELAY_MS) {
|
|
1666
|
+
timer = setTimeout(() => abort(new RequestTimeoutError(timeout)), timeout);
|
|
1667
|
+
}
|
|
1668
|
+
return requestSignal;
|
|
1669
|
+
}
|
|
1580
1670
|
/**
|
|
1581
1671
|
* Wrap an operation with error handling and telemetry.
|
|
1582
1672
|
*
|
|
@@ -1685,6 +1775,30 @@ var PrefixedKVService = class _PrefixedKVService {
|
|
|
1685
1775
|
removePrefix
|
|
1686
1776
|
});
|
|
1687
1777
|
}
|
|
1778
|
+
/**
|
|
1779
|
+
* Read the change feed for everything under this prefix. A view with an
|
|
1780
|
+
* empty prefix (`""` or `"/"`) is refused: the node does not serve a
|
|
1781
|
+
* whole-space feed.
|
|
1782
|
+
*/
|
|
1783
|
+
async changes(options) {
|
|
1784
|
+
if (this._prefix.replace(/\/+$/, "") === "") {
|
|
1785
|
+
return err(serviceError(
|
|
1786
|
+
ErrorCodes.INVALID_INPUT,
|
|
1787
|
+
"KV changes needs a non-empty prefix; this view has none",
|
|
1788
|
+
"kv"
|
|
1789
|
+
));
|
|
1790
|
+
}
|
|
1791
|
+
const syncPrefix = `${this._prefix}/`;
|
|
1792
|
+
const response = await this._kv.changes({ ...options, prefix: syncPrefix });
|
|
1793
|
+
if (!response.ok) return response;
|
|
1794
|
+
return ok({
|
|
1795
|
+
...response.data,
|
|
1796
|
+
changes: response.data.changes.map((change) => ({
|
|
1797
|
+
...change,
|
|
1798
|
+
key: change.key.startsWith(syncPrefix) ? change.key.slice(syncPrefix.length) : change.key
|
|
1799
|
+
}))
|
|
1800
|
+
});
|
|
1801
|
+
}
|
|
1688
1802
|
/**
|
|
1689
1803
|
* Delete a key.
|
|
1690
1804
|
*/
|
|
@@ -1737,11 +1851,18 @@ var KVAction = {
|
|
|
1737
1851
|
PUT: "tinycloud.kv/put",
|
|
1738
1852
|
LIST: "tinycloud.kv/list",
|
|
1739
1853
|
DELETE: "tinycloud.kv/del",
|
|
1740
|
-
HEAD: "tinycloud.kv/metadata"
|
|
1854
|
+
HEAD: "tinycloud.kv/metadata",
|
|
1855
|
+
/** The change feed; never implied by `*` or `tinycloud.kv/*`. */
|
|
1856
|
+
SYNC: "tinycloud.kv/sync",
|
|
1857
|
+
/** Retention attestation; presented through `retentionGrant`, never invoked or implied. */
|
|
1858
|
+
RETAIN: "tinycloud.kv/retain"
|
|
1741
1859
|
};
|
|
1742
1860
|
|
|
1743
1861
|
// src/kv/KVService.ts
|
|
1744
1862
|
var MAX_KV_BATCH_READ_ITEMS = 100;
|
|
1863
|
+
function isJsonObject(value) {
|
|
1864
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1865
|
+
}
|
|
1745
1866
|
function encodeKvBatchPartName(path) {
|
|
1746
1867
|
return encodeURIComponent(path).replace(
|
|
1747
1868
|
/[!'()*]/g,
|
|
@@ -1837,7 +1958,7 @@ var KVService = class extends BaseService {
|
|
|
1837
1958
|
* @param path - Resource path
|
|
1838
1959
|
* @param action - KV action
|
|
1839
1960
|
* @param body - Optional request body
|
|
1840
|
-
* @param signal -
|
|
1961
|
+
* @param signal - Request signal from createRequestSignal()
|
|
1841
1962
|
* @returns Fetch response
|
|
1842
1963
|
*/
|
|
1843
1964
|
async invokeOperation(path, action, body, signal, extraHeaders) {
|
|
@@ -1853,7 +1974,7 @@ var KVService = class extends BaseService {
|
|
|
1853
1974
|
method: "POST",
|
|
1854
1975
|
headers: requestHeaders,
|
|
1855
1976
|
body,
|
|
1856
|
-
signal
|
|
1977
|
+
signal
|
|
1857
1978
|
});
|
|
1858
1979
|
}
|
|
1859
1980
|
/**
|
|
@@ -2030,6 +2151,7 @@ var KVService = class extends BaseService {
|
|
|
2030
2151
|
"kv"
|
|
2031
2152
|
));
|
|
2032
2153
|
}
|
|
2154
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2033
2155
|
try {
|
|
2034
2156
|
const session = this.context.session;
|
|
2035
2157
|
const invocationHeaders = this.context.invokeAny(
|
|
@@ -2051,7 +2173,7 @@ var KVService = class extends BaseService {
|
|
|
2051
2173
|
const response = await this.context.fetch(`${this.host}/invoke`, {
|
|
2052
2174
|
method: "POST",
|
|
2053
2175
|
headers,
|
|
2054
|
-
signal:
|
|
2176
|
+
signal: request.signal
|
|
2055
2177
|
});
|
|
2056
2178
|
if (!response.ok) {
|
|
2057
2179
|
const errorText = response.status === 401 || response.status === 403 ? await this.readAuthorizationText(response) : await response.text();
|
|
@@ -2116,6 +2238,8 @@ var KVService = class extends BaseService {
|
|
|
2116
2238
|
return ok({ results, count: results.length });
|
|
2117
2239
|
} catch (error) {
|
|
2118
2240
|
return err(wrapError("kv", error));
|
|
2241
|
+
} finally {
|
|
2242
|
+
request.dispose();
|
|
2119
2243
|
}
|
|
2120
2244
|
}
|
|
2121
2245
|
/**
|
|
@@ -2248,12 +2372,13 @@ var KVService = class extends BaseService {
|
|
|
2248
2372
|
));
|
|
2249
2373
|
}
|
|
2250
2374
|
const path = this.getFullPath(key, options?.prefix);
|
|
2375
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2251
2376
|
try {
|
|
2252
2377
|
const response = await this.invokeOperation(
|
|
2253
2378
|
path,
|
|
2254
2379
|
KVAction.GET,
|
|
2255
2380
|
void 0,
|
|
2256
|
-
|
|
2381
|
+
request.signal,
|
|
2257
2382
|
options?.maxResponseBytes === void 0 ? void 0 : { "x-tinycloud-max-response-bytes": String(options.maxResponseBytes) }
|
|
2258
2383
|
);
|
|
2259
2384
|
if (!response.ok) {
|
|
@@ -2310,6 +2435,8 @@ var KVService = class extends BaseService {
|
|
|
2310
2435
|
});
|
|
2311
2436
|
} catch (error) {
|
|
2312
2437
|
return err(wrapError("kv", error));
|
|
2438
|
+
} finally {
|
|
2439
|
+
request.dispose();
|
|
2313
2440
|
}
|
|
2314
2441
|
});
|
|
2315
2442
|
}
|
|
@@ -2337,12 +2464,13 @@ var KVService = class extends BaseService {
|
|
|
2337
2464
|
}
|
|
2338
2465
|
const path = this.getFullPath(key, options?.prefix);
|
|
2339
2466
|
const body = this.serializePutValue(value, options?.contentType);
|
|
2467
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2340
2468
|
try {
|
|
2341
2469
|
const response = await this.invokeOperation(
|
|
2342
2470
|
path,
|
|
2343
2471
|
KVAction.PUT,
|
|
2344
2472
|
body,
|
|
2345
|
-
|
|
2473
|
+
request.signal,
|
|
2346
2474
|
{
|
|
2347
2475
|
...options?.ifMatch === void 0 ? {} : { "if-match": options.ifMatch },
|
|
2348
2476
|
...options?.ifNoneMatch === void 0 ? {} : { "if-none-match": options.ifNoneMatch }
|
|
@@ -2398,6 +2526,8 @@ var KVService = class extends BaseService {
|
|
|
2398
2526
|
});
|
|
2399
2527
|
} catch (error) {
|
|
2400
2528
|
return err(wrapError("kv", error));
|
|
2529
|
+
} finally {
|
|
2530
|
+
request.dispose();
|
|
2401
2531
|
}
|
|
2402
2532
|
});
|
|
2403
2533
|
}
|
|
@@ -2437,6 +2567,7 @@ var KVService = class extends BaseService {
|
|
|
2437
2567
|
seen.add(path);
|
|
2438
2568
|
}
|
|
2439
2569
|
let requestMayHaveDispatched = false;
|
|
2570
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2440
2571
|
try {
|
|
2441
2572
|
const body = new FormData();
|
|
2442
2573
|
for (let index = 0; index < items.length; index++) {
|
|
@@ -2459,7 +2590,7 @@ var KVService = class extends BaseService {
|
|
|
2459
2590
|
method: "POST",
|
|
2460
2591
|
headers,
|
|
2461
2592
|
body,
|
|
2462
|
-
signal:
|
|
2593
|
+
signal: request.signal
|
|
2463
2594
|
};
|
|
2464
2595
|
const fetchFn = this.context.fetch;
|
|
2465
2596
|
requestMayHaveDispatched = true;
|
|
@@ -2510,14 +2641,16 @@ var KVService = class extends BaseService {
|
|
|
2510
2641
|
rawBody = await response.json();
|
|
2511
2642
|
} catch (jsonError) {
|
|
2512
2643
|
const cause = jsonError instanceof Error ? jsonError : new Error(String(jsonError));
|
|
2644
|
+
const timedOut = isRequestTimeoutError(cause);
|
|
2513
2645
|
return err(
|
|
2514
2646
|
serviceError(
|
|
2515
|
-
ErrorCodes.NETWORK_ERROR,
|
|
2516
|
-
`KV batchPut response was not valid JSON: ${cause.message}`,
|
|
2647
|
+
timedOut ? ErrorCodes.TIMEOUT : ErrorCodes.NETWORK_ERROR,
|
|
2648
|
+
timedOut ? `KV batchPut response body did not arrive in time: ${cause.message}` : `KV batchPut response was not valid JSON: ${cause.message}`,
|
|
2517
2649
|
"kv",
|
|
2518
2650
|
{
|
|
2519
2651
|
cause,
|
|
2520
2652
|
meta: {
|
|
2653
|
+
...timedOut ? { timeoutMs: cause.timeoutMs } : {},
|
|
2521
2654
|
requestMayHaveDispatched: true,
|
|
2522
2655
|
responseReceived: true,
|
|
2523
2656
|
status: response.status,
|
|
@@ -2572,6 +2705,8 @@ var KVService = class extends BaseService {
|
|
|
2572
2705
|
...wrapped,
|
|
2573
2706
|
meta: { ...wrapped.meta, requestMayHaveDispatched }
|
|
2574
2707
|
});
|
|
2708
|
+
} finally {
|
|
2709
|
+
request.dispose();
|
|
2575
2710
|
}
|
|
2576
2711
|
});
|
|
2577
2712
|
}
|
|
@@ -2594,12 +2729,13 @@ var KVService = class extends BaseService {
|
|
|
2594
2729
|
if (options?.path) {
|
|
2595
2730
|
listPath = listPath ? `${listPath}/${options.path}` : options.path;
|
|
2596
2731
|
}
|
|
2732
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2597
2733
|
try {
|
|
2598
2734
|
const response = await this.invokeOperation(
|
|
2599
2735
|
listPath,
|
|
2600
2736
|
KVAction.LIST,
|
|
2601
2737
|
void 0,
|
|
2602
|
-
|
|
2738
|
+
request.signal,
|
|
2603
2739
|
options?.limit === void 0 && options?.cursor === void 0 ? void 0 : {
|
|
2604
2740
|
...options?.limit === void 0 ? {} : { "x-tinycloud-limit": String(options.limit) },
|
|
2605
2741
|
...options?.cursor === void 0 ? {} : { "x-tinycloud-cursor": options.cursor }
|
|
@@ -2640,9 +2776,174 @@ var KVService = class extends BaseService {
|
|
|
2640
2776
|
});
|
|
2641
2777
|
} catch (error) {
|
|
2642
2778
|
return err(wrapError("kv", error));
|
|
2779
|
+
} finally {
|
|
2780
|
+
request.dispose();
|
|
2781
|
+
}
|
|
2782
|
+
});
|
|
2783
|
+
}
|
|
2784
|
+
/**
|
|
2785
|
+
* Read one page of the `tinycloud.kv/sync` change feed for a prefix.
|
|
2786
|
+
*/
|
|
2787
|
+
async changes(options) {
|
|
2788
|
+
return this.withTelemetry("changes", options?.prefix, async () => {
|
|
2789
|
+
if (!this.requireAuth()) {
|
|
2790
|
+
return err(authRequiredError("kv"));
|
|
2791
|
+
}
|
|
2792
|
+
if (typeof options?.prefix !== "string" || options.prefix.length === 0) {
|
|
2793
|
+
return err(serviceError(
|
|
2794
|
+
ErrorCodes.INVALID_INPUT,
|
|
2795
|
+
"KV changes prefix must be a non-empty string",
|
|
2796
|
+
"kv"
|
|
2797
|
+
));
|
|
2798
|
+
}
|
|
2799
|
+
if (options.limit !== void 0 && (!Number.isInteger(options.limit) || options.limit < 1 || options.limit > 1e3)) {
|
|
2800
|
+
return err(serviceError(
|
|
2801
|
+
ErrorCodes.INVALID_INPUT,
|
|
2802
|
+
"KV changes limit must be an integer from 1 through 1000",
|
|
2803
|
+
"kv"
|
|
2804
|
+
));
|
|
2805
|
+
}
|
|
2806
|
+
const headers = {};
|
|
2807
|
+
if (options.limit !== void 0) headers["x-tinycloud-limit"] = String(options.limit);
|
|
2808
|
+
if (options.cursor !== void 0) headers["x-tinycloud-cursor"] = options.cursor;
|
|
2809
|
+
if (options.retentionGrant !== void 0) {
|
|
2810
|
+
headers["x-tinycloud-retention-grant"] = options.retentionGrant;
|
|
2811
|
+
}
|
|
2812
|
+
const request = this.createRequestSignal(options.signal, options.timeout);
|
|
2813
|
+
try {
|
|
2814
|
+
const response = await this.invokeOperation(
|
|
2815
|
+
options.prefix,
|
|
2816
|
+
KVAction.SYNC,
|
|
2817
|
+
void 0,
|
|
2818
|
+
request.signal,
|
|
2819
|
+
headers
|
|
2820
|
+
);
|
|
2821
|
+
if (!response.ok) {
|
|
2822
|
+
return await this.changesFailure(response, options.prefix, request.signal);
|
|
2823
|
+
}
|
|
2824
|
+
const text = await response.text();
|
|
2825
|
+
let body;
|
|
2826
|
+
try {
|
|
2827
|
+
body = JSON.parse(text);
|
|
2828
|
+
} catch {
|
|
2829
|
+
body = void 0;
|
|
2830
|
+
}
|
|
2831
|
+
const page = this.normalizeChangesResponse(body);
|
|
2832
|
+
if (!page) {
|
|
2833
|
+
return err(serviceError(
|
|
2834
|
+
ErrorCodes.NETWORK_ERROR,
|
|
2835
|
+
"KV changes response was not a tinycloud.kv/sync page",
|
|
2836
|
+
"kv",
|
|
2837
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2838
|
+
));
|
|
2839
|
+
}
|
|
2840
|
+
return ok(page);
|
|
2841
|
+
} catch (error) {
|
|
2842
|
+
return err(wrapError("kv", error));
|
|
2843
|
+
} finally {
|
|
2844
|
+
request.dispose();
|
|
2643
2845
|
}
|
|
2644
2846
|
});
|
|
2645
2847
|
}
|
|
2848
|
+
/**
|
|
2849
|
+
* Map a failed `kv/sync` response. 410 and the retention 403 carry
|
|
2850
|
+
* `{"error":{"code","reason"}}`; a revoked grant is a 401 whose text names
|
|
2851
|
+
* `delegation-revoked` or `delegation-ancestor-revoked`. A body read that
|
|
2852
|
+
* fails because the request was cancelled or timed out rethrows, so the
|
|
2853
|
+
* caller sees `ABORTED`/`TIMEOUT` rather than a mapped status.
|
|
2854
|
+
*/
|
|
2855
|
+
async changesFailure(response, prefix, signal) {
|
|
2856
|
+
if (response.status === 404) {
|
|
2857
|
+
return this.classifyNotFound(response, prefix);
|
|
2858
|
+
}
|
|
2859
|
+
let errorText;
|
|
2860
|
+
try {
|
|
2861
|
+
errorText = await response.text();
|
|
2862
|
+
} catch (error) {
|
|
2863
|
+
if (signal.aborted) throw error;
|
|
2864
|
+
errorText = "";
|
|
2865
|
+
}
|
|
2866
|
+
const meta = { status: response.status, statusText: response.statusText };
|
|
2867
|
+
let reason;
|
|
2868
|
+
let bodyCode;
|
|
2869
|
+
try {
|
|
2870
|
+
const body = JSON.parse(errorText);
|
|
2871
|
+
const error = isJsonObject(body) ? body.error : void 0;
|
|
2872
|
+
if (isJsonObject(error)) {
|
|
2873
|
+
if (typeof error.code === "string") bodyCode = error.code;
|
|
2874
|
+
if (typeof error.reason === "string") reason = error.reason;
|
|
2875
|
+
}
|
|
2876
|
+
} catch {
|
|
2877
|
+
}
|
|
2878
|
+
const context = `Failed to read KV changes for ${JSON.stringify(prefix)}`;
|
|
2879
|
+
if (response.status === 410) {
|
|
2880
|
+
return err(serviceError(
|
|
2881
|
+
ErrorCodes.KV_SYNC_RESET_REQUIRED,
|
|
2882
|
+
`${context}: the node requires a reset (${reason ?? "reason not given"}); discard sync state and restart without a cursor`,
|
|
2883
|
+
"kv",
|
|
2884
|
+
{ meta: { ...meta, reason } }
|
|
2885
|
+
));
|
|
2886
|
+
}
|
|
2887
|
+
if (response.status === 403 && bodyCode === "RETENTION_GRANT_REFUSED") {
|
|
2888
|
+
return err(serviceError(
|
|
2889
|
+
ErrorCodes.KV_RETENTION_GRANT_REFUSED,
|
|
2890
|
+
`${context}: the retention grant was refused (${reason ?? "reason not given"})`,
|
|
2891
|
+
"kv",
|
|
2892
|
+
{ meta: { ...meta, reason } }
|
|
2893
|
+
));
|
|
2894
|
+
}
|
|
2895
|
+
if (response.status === 401) {
|
|
2896
|
+
const revoked = /\bdelegation-ancestor-revoked\b/.test(errorText) ? ErrorCodes.AUTH_DELEGATION_ANCESTOR_REVOKED : /\bdelegation-revoked\b/.test(errorText) ? ErrorCodes.AUTH_DELEGATION_REVOKED : void 0;
|
|
2897
|
+
if (revoked !== void 0) {
|
|
2898
|
+
return err(serviceError(revoked, `${context}: 401 - ${errorText}`, "kv", { meta }));
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
if (response.status === 401 || response.status === 403) {
|
|
2902
|
+
return this.authorizationFailure(context, response, errorText, [prefix], KVAction.SYNC);
|
|
2903
|
+
}
|
|
2904
|
+
return err(serviceError(
|
|
2905
|
+
response.status === 400 ? ErrorCodes.INVALID_INPUT : ErrorCodes.NETWORK_ERROR,
|
|
2906
|
+
`${context}: ${response.status} - ${errorText}`,
|
|
2907
|
+
"kv",
|
|
2908
|
+
{ meta }
|
|
2909
|
+
));
|
|
2910
|
+
}
|
|
2911
|
+
normalizeChangesResponse(data) {
|
|
2912
|
+
if (!isJsonObject(data)) return void 0;
|
|
2913
|
+
const { changes, more, cursor, source, authority } = data;
|
|
2914
|
+
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)) {
|
|
2915
|
+
return void 0;
|
|
2916
|
+
}
|
|
2917
|
+
const { notBefore, expiresAt, retainUntil } = authority;
|
|
2918
|
+
if (notBefore !== null && typeof notBefore !== "string" || expiresAt !== null && typeof expiresAt !== "string" || retainUntil !== null && typeof retainUntil !== "string") {
|
|
2919
|
+
return void 0;
|
|
2920
|
+
}
|
|
2921
|
+
const parsed = [];
|
|
2922
|
+
for (const change of changes) {
|
|
2923
|
+
if (!isJsonObject(change) || typeof change.key !== "string") return void 0;
|
|
2924
|
+
if (change.deleted === true) {
|
|
2925
|
+
parsed.push({ key: change.key, deleted: true });
|
|
2926
|
+
continue;
|
|
2927
|
+
}
|
|
2928
|
+
const { metadata } = change;
|
|
2929
|
+
if (change.deleted !== false || typeof change.etag !== "string" || !isJsonObject(metadata) || !Object.values(metadata).every((value) => typeof value === "string")) {
|
|
2930
|
+
return void 0;
|
|
2931
|
+
}
|
|
2932
|
+
parsed.push({
|
|
2933
|
+
key: change.key,
|
|
2934
|
+
deleted: false,
|
|
2935
|
+
etag: change.etag,
|
|
2936
|
+
metadata
|
|
2937
|
+
});
|
|
2938
|
+
}
|
|
2939
|
+
return {
|
|
2940
|
+
changes: parsed,
|
|
2941
|
+
more,
|
|
2942
|
+
cursor,
|
|
2943
|
+
source: { nodeDid: source.nodeDid, space: source.space, prefix: source.prefix },
|
|
2944
|
+
authority: { notBefore, expiresAt, retainUntil }
|
|
2945
|
+
};
|
|
2946
|
+
}
|
|
2646
2947
|
/**
|
|
2647
2948
|
* Delete a key.
|
|
2648
2949
|
*/
|
|
@@ -2652,12 +2953,13 @@ var KVService = class extends BaseService {
|
|
|
2652
2953
|
return err(authRequiredError("kv"));
|
|
2653
2954
|
}
|
|
2654
2955
|
const path = this.getFullPath(key, options?.prefix);
|
|
2956
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2655
2957
|
try {
|
|
2656
2958
|
const response = await this.invokeOperation(
|
|
2657
2959
|
path,
|
|
2658
2960
|
KVAction.DELETE,
|
|
2659
2961
|
void 0,
|
|
2660
|
-
|
|
2962
|
+
request.signal,
|
|
2661
2963
|
options?.ifMatch === void 0 ? void 0 : { "if-match": options.ifMatch }
|
|
2662
2964
|
);
|
|
2663
2965
|
if (!response.ok) {
|
|
@@ -2705,6 +3007,8 @@ var KVService = class extends BaseService {
|
|
|
2705
3007
|
});
|
|
2706
3008
|
} catch (error) {
|
|
2707
3009
|
return err(wrapError("kv", error));
|
|
3010
|
+
} finally {
|
|
3011
|
+
request.dispose();
|
|
2708
3012
|
}
|
|
2709
3013
|
});
|
|
2710
3014
|
}
|
|
@@ -2717,12 +3021,13 @@ var KVService = class extends BaseService {
|
|
|
2717
3021
|
return err(authRequiredError("kv"));
|
|
2718
3022
|
}
|
|
2719
3023
|
const path = this.getFullPath(key, options?.prefix);
|
|
3024
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2720
3025
|
try {
|
|
2721
3026
|
const response = await this.invokeOperation(
|
|
2722
3027
|
path,
|
|
2723
3028
|
KVAction.HEAD,
|
|
2724
3029
|
void 0,
|
|
2725
|
-
|
|
3030
|
+
request.signal
|
|
2726
3031
|
);
|
|
2727
3032
|
if (!response.ok) {
|
|
2728
3033
|
if (response.status === 401 || response.status === 403) {
|
|
@@ -2753,6 +3058,8 @@ var KVService = class extends BaseService {
|
|
|
2753
3058
|
});
|
|
2754
3059
|
} catch (error) {
|
|
2755
3060
|
return err(wrapError("kv", error));
|
|
3061
|
+
} finally {
|
|
3062
|
+
request.dispose();
|
|
2756
3063
|
}
|
|
2757
3064
|
});
|
|
2758
3065
|
}
|
|
@@ -2790,12 +3097,13 @@ var KVService = class extends BaseService {
|
|
|
2790
3097
|
if (options?.etag !== void 0) {
|
|
2791
3098
|
body.etag = options.etag;
|
|
2792
3099
|
}
|
|
3100
|
+
const request = this.createRequestSignal(options?.signal, options?.timeout);
|
|
2793
3101
|
try {
|
|
2794
3102
|
const response = await this.context.fetch(`${this.host}/signed/kv`, {
|
|
2795
3103
|
method: "POST",
|
|
2796
3104
|
headers: this.withJsonContentType(headers),
|
|
2797
3105
|
body: JSON.stringify(body),
|
|
2798
|
-
signal:
|
|
3106
|
+
signal: request.signal
|
|
2799
3107
|
});
|
|
2800
3108
|
if (!response.ok) {
|
|
2801
3109
|
return this.createSignedReadUrlError(response, key, path);
|
|
@@ -2815,6 +3123,8 @@ var KVService = class extends BaseService {
|
|
|
2815
3123
|
return ok(signedUrl);
|
|
2816
3124
|
} catch (error) {
|
|
2817
3125
|
return err(wrapError("kv", error));
|
|
3126
|
+
} finally {
|
|
3127
|
+
request.dispose();
|
|
2818
3128
|
}
|
|
2819
3129
|
});
|
|
2820
3130
|
}
|
|
@@ -3028,6 +3338,7 @@ var SQLService = class extends BaseService {
|
|
|
3028
3338
|
if (!this.requireAuth()) {
|
|
3029
3339
|
return err(authRequiredError("sql"));
|
|
3030
3340
|
}
|
|
3341
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3031
3342
|
try {
|
|
3032
3343
|
const body = {
|
|
3033
3344
|
action: "query",
|
|
@@ -3041,7 +3352,7 @@ var SQLService = class extends BaseService {
|
|
|
3041
3352
|
dbName,
|
|
3042
3353
|
action,
|
|
3043
3354
|
body,
|
|
3044
|
-
|
|
3355
|
+
request.signal
|
|
3045
3356
|
);
|
|
3046
3357
|
if (!response.ok) {
|
|
3047
3358
|
return this.handleErrorResponse(response, "query", dbName, [action]);
|
|
@@ -3050,6 +3361,8 @@ var SQLService = class extends BaseService {
|
|
|
3050
3361
|
return ok(data);
|
|
3051
3362
|
} catch (error) {
|
|
3052
3363
|
return err(wrapError("sql", error));
|
|
3364
|
+
} finally {
|
|
3365
|
+
request.dispose();
|
|
3053
3366
|
}
|
|
3054
3367
|
});
|
|
3055
3368
|
}
|
|
@@ -3058,6 +3371,7 @@ var SQLService = class extends BaseService {
|
|
|
3058
3371
|
if (!this.requireAuth()) {
|
|
3059
3372
|
return err(authRequiredError("sql"));
|
|
3060
3373
|
}
|
|
3374
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3061
3375
|
try {
|
|
3062
3376
|
const body = {
|
|
3063
3377
|
action: "execute",
|
|
@@ -3078,7 +3392,7 @@ var SQLService = class extends BaseService {
|
|
|
3078
3392
|
dbName,
|
|
3079
3393
|
requestedActions,
|
|
3080
3394
|
body,
|
|
3081
|
-
|
|
3395
|
+
request.signal
|
|
3082
3396
|
);
|
|
3083
3397
|
if (!response.ok) {
|
|
3084
3398
|
return this.handleErrorResponse(response, "execute", dbName, requestedActions);
|
|
@@ -3087,6 +3401,8 @@ var SQLService = class extends BaseService {
|
|
|
3087
3401
|
return ok(data);
|
|
3088
3402
|
} catch (error) {
|
|
3089
3403
|
return err(wrapError("sql", error));
|
|
3404
|
+
} finally {
|
|
3405
|
+
request.dispose();
|
|
3090
3406
|
}
|
|
3091
3407
|
});
|
|
3092
3408
|
}
|
|
@@ -3095,13 +3411,14 @@ var SQLService = class extends BaseService {
|
|
|
3095
3411
|
if (!this.requireAuth()) {
|
|
3096
3412
|
return err(authRequiredError("sql"));
|
|
3097
3413
|
}
|
|
3414
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3098
3415
|
try {
|
|
3099
3416
|
const requestedActions = this.actionsForSqlBatch(statements);
|
|
3100
3417
|
const response = await this.invokeSQL(
|
|
3101
3418
|
dbName,
|
|
3102
3419
|
requestedActions,
|
|
3103
3420
|
{ action: "batch", statements },
|
|
3104
|
-
|
|
3421
|
+
request.signal
|
|
3105
3422
|
);
|
|
3106
3423
|
if (!response.ok) {
|
|
3107
3424
|
return this.handleErrorResponse(response, "batch", dbName, requestedActions);
|
|
@@ -3110,6 +3427,8 @@ var SQLService = class extends BaseService {
|
|
|
3110
3427
|
return ok(data);
|
|
3111
3428
|
} catch (error) {
|
|
3112
3429
|
return err(wrapError("sql", error));
|
|
3430
|
+
} finally {
|
|
3431
|
+
request.dispose();
|
|
3113
3432
|
}
|
|
3114
3433
|
});
|
|
3115
3434
|
}
|
|
@@ -3118,12 +3437,13 @@ var SQLService = class extends BaseService {
|
|
|
3118
3437
|
if (!this.requireAuth()) {
|
|
3119
3438
|
return err(authRequiredError("sql"));
|
|
3120
3439
|
}
|
|
3440
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3121
3441
|
try {
|
|
3122
3442
|
const response = await this.invokeSQL(
|
|
3123
3443
|
dbName,
|
|
3124
3444
|
SQLAction.WRITE,
|
|
3125
3445
|
{ action: "execute_statement", name, params: params ?? [] },
|
|
3126
|
-
|
|
3446
|
+
request.signal
|
|
3127
3447
|
);
|
|
3128
3448
|
if (!response.ok) {
|
|
3129
3449
|
return this.handleErrorResponse(response, "executeStatement", dbName, [SQLAction.WRITE]);
|
|
@@ -3132,6 +3452,8 @@ var SQLService = class extends BaseService {
|
|
|
3132
3452
|
return ok(data);
|
|
3133
3453
|
} catch (error) {
|
|
3134
3454
|
return err(wrapError("sql", error));
|
|
3455
|
+
} finally {
|
|
3456
|
+
request.dispose();
|
|
3135
3457
|
}
|
|
3136
3458
|
});
|
|
3137
3459
|
}
|
|
@@ -3140,12 +3462,13 @@ var SQLService = class extends BaseService {
|
|
|
3140
3462
|
if (!this.requireAuth()) {
|
|
3141
3463
|
return err(authRequiredError("sql"));
|
|
3142
3464
|
}
|
|
3465
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3143
3466
|
try {
|
|
3144
3467
|
const response = await this.invokeSQL(
|
|
3145
3468
|
dbName,
|
|
3146
3469
|
SQLAction.READ,
|
|
3147
3470
|
{ action: "export" },
|
|
3148
|
-
|
|
3471
|
+
request.signal
|
|
3149
3472
|
);
|
|
3150
3473
|
if (!response.ok) {
|
|
3151
3474
|
return this.handleErrorResponse(response, "export", dbName, [SQLAction.READ]);
|
|
@@ -3159,6 +3482,8 @@ var SQLService = class extends BaseService {
|
|
|
3159
3482
|
return ok(text);
|
|
3160
3483
|
} catch (error) {
|
|
3161
3484
|
return err(wrapError("sql", error));
|
|
3485
|
+
} finally {
|
|
3486
|
+
request.dispose();
|
|
3162
3487
|
}
|
|
3163
3488
|
});
|
|
3164
3489
|
}
|
|
@@ -3249,7 +3574,7 @@ var SQLService = class extends BaseService {
|
|
|
3249
3574
|
"Content-Type": "application/json"
|
|
3250
3575
|
},
|
|
3251
3576
|
body: JSON.stringify(body),
|
|
3252
|
-
signal
|
|
3577
|
+
signal
|
|
3253
3578
|
});
|
|
3254
3579
|
}
|
|
3255
3580
|
actionForSql(sql, fallback) {
|
|
@@ -3513,12 +3838,13 @@ var DuckDbService = class extends BaseService {
|
|
|
3513
3838
|
if (!this.requireAuth()) {
|
|
3514
3839
|
return err(authRequiredError("duckdb"));
|
|
3515
3840
|
}
|
|
3841
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3516
3842
|
try {
|
|
3517
3843
|
const response = await this.invokeDuckDb(
|
|
3518
3844
|
dbName,
|
|
3519
3845
|
DuckDbAction.READ,
|
|
3520
3846
|
{ action: "query", sql, params: params ?? [] },
|
|
3521
|
-
|
|
3847
|
+
request.signal
|
|
3522
3848
|
);
|
|
3523
3849
|
if (!response.ok) {
|
|
3524
3850
|
return this.handleErrorResponse(response, "query");
|
|
@@ -3527,6 +3853,8 @@ var DuckDbService = class extends BaseService {
|
|
|
3527
3853
|
return ok(data);
|
|
3528
3854
|
} catch (error) {
|
|
3529
3855
|
return err(wrapError("duckdb", error));
|
|
3856
|
+
} finally {
|
|
3857
|
+
request.dispose();
|
|
3530
3858
|
}
|
|
3531
3859
|
});
|
|
3532
3860
|
}
|
|
@@ -3535,12 +3863,13 @@ var DuckDbService = class extends BaseService {
|
|
|
3535
3863
|
if (!this.requireAuth()) {
|
|
3536
3864
|
return err(authRequiredError("duckdb"));
|
|
3537
3865
|
}
|
|
3866
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3538
3867
|
try {
|
|
3539
3868
|
const response = await this.invokeDuckDb(
|
|
3540
3869
|
dbName,
|
|
3541
3870
|
DuckDbAction.READ,
|
|
3542
3871
|
{ action: "query", sql, params: params ?? [] },
|
|
3543
|
-
|
|
3872
|
+
request.signal,
|
|
3544
3873
|
{ Accept: "application/vnd.apache.arrow.stream" }
|
|
3545
3874
|
);
|
|
3546
3875
|
if (!response.ok) {
|
|
@@ -3550,6 +3879,8 @@ var DuckDbService = class extends BaseService {
|
|
|
3550
3879
|
return ok(buffer);
|
|
3551
3880
|
} catch (error) {
|
|
3552
3881
|
return err(wrapError("duckdb", error));
|
|
3882
|
+
} finally {
|
|
3883
|
+
request.dispose();
|
|
3553
3884
|
}
|
|
3554
3885
|
});
|
|
3555
3886
|
}
|
|
@@ -3558,6 +3889,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3558
3889
|
if (!this.requireAuth()) {
|
|
3559
3890
|
return err(authRequiredError("duckdb"));
|
|
3560
3891
|
}
|
|
3892
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3561
3893
|
try {
|
|
3562
3894
|
const body = {
|
|
3563
3895
|
action: "execute",
|
|
@@ -3571,7 +3903,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3571
3903
|
dbName,
|
|
3572
3904
|
DuckDbAction.WRITE,
|
|
3573
3905
|
body,
|
|
3574
|
-
|
|
3906
|
+
request.signal
|
|
3575
3907
|
);
|
|
3576
3908
|
if (!response.ok) {
|
|
3577
3909
|
return this.handleErrorResponse(response, "execute");
|
|
@@ -3580,6 +3912,8 @@ var DuckDbService = class extends BaseService {
|
|
|
3580
3912
|
return ok(data);
|
|
3581
3913
|
} catch (error) {
|
|
3582
3914
|
return err(wrapError("duckdb", error));
|
|
3915
|
+
} finally {
|
|
3916
|
+
request.dispose();
|
|
3583
3917
|
}
|
|
3584
3918
|
});
|
|
3585
3919
|
}
|
|
@@ -3588,6 +3922,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3588
3922
|
if (!this.requireAuth()) {
|
|
3589
3923
|
return err(authRequiredError("duckdb"));
|
|
3590
3924
|
}
|
|
3925
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3591
3926
|
try {
|
|
3592
3927
|
const body = {
|
|
3593
3928
|
action: "batch",
|
|
@@ -3600,7 +3935,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3600
3935
|
dbName,
|
|
3601
3936
|
DuckDbAction.WRITE,
|
|
3602
3937
|
body,
|
|
3603
|
-
|
|
3938
|
+
request.signal
|
|
3604
3939
|
);
|
|
3605
3940
|
if (!response.ok) {
|
|
3606
3941
|
return this.handleErrorResponse(response, "batch");
|
|
@@ -3609,6 +3944,8 @@ var DuckDbService = class extends BaseService {
|
|
|
3609
3944
|
return ok(data);
|
|
3610
3945
|
} catch (error) {
|
|
3611
3946
|
return err(wrapError("duckdb", error));
|
|
3947
|
+
} finally {
|
|
3948
|
+
request.dispose();
|
|
3612
3949
|
}
|
|
3613
3950
|
});
|
|
3614
3951
|
}
|
|
@@ -3617,12 +3954,13 @@ var DuckDbService = class extends BaseService {
|
|
|
3617
3954
|
if (!this.requireAuth()) {
|
|
3618
3955
|
return err(authRequiredError("duckdb"));
|
|
3619
3956
|
}
|
|
3957
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3620
3958
|
try {
|
|
3621
3959
|
const response = await this.invokeDuckDb(
|
|
3622
3960
|
dbName,
|
|
3623
3961
|
DuckDbAction.WRITE,
|
|
3624
3962
|
{ action: "executeStatement", name, params: params ?? [] },
|
|
3625
|
-
|
|
3963
|
+
request.signal
|
|
3626
3964
|
);
|
|
3627
3965
|
if (!response.ok) {
|
|
3628
3966
|
return this.handleErrorResponse(response, "executeStatement");
|
|
@@ -3631,6 +3969,8 @@ var DuckDbService = class extends BaseService {
|
|
|
3631
3969
|
return ok(data);
|
|
3632
3970
|
} catch (error) {
|
|
3633
3971
|
return err(wrapError("duckdb", error));
|
|
3972
|
+
} finally {
|
|
3973
|
+
request.dispose();
|
|
3634
3974
|
}
|
|
3635
3975
|
});
|
|
3636
3976
|
}
|
|
@@ -3639,12 +3979,13 @@ var DuckDbService = class extends BaseService {
|
|
|
3639
3979
|
if (!this.requireAuth()) {
|
|
3640
3980
|
return err(authRequiredError("duckdb"));
|
|
3641
3981
|
}
|
|
3982
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3642
3983
|
try {
|
|
3643
3984
|
const response = await this.invokeDuckDb(
|
|
3644
3985
|
dbName,
|
|
3645
3986
|
DuckDbAction.READ,
|
|
3646
3987
|
{ action: "describe" },
|
|
3647
|
-
|
|
3988
|
+
request.signal
|
|
3648
3989
|
);
|
|
3649
3990
|
if (!response.ok) {
|
|
3650
3991
|
return this.handleErrorResponse(response, "describe");
|
|
@@ -3653,6 +3994,8 @@ var DuckDbService = class extends BaseService {
|
|
|
3653
3994
|
return ok(data);
|
|
3654
3995
|
} catch (error) {
|
|
3655
3996
|
return err(wrapError("duckdb", error));
|
|
3997
|
+
} finally {
|
|
3998
|
+
request.dispose();
|
|
3656
3999
|
}
|
|
3657
4000
|
});
|
|
3658
4001
|
}
|
|
@@ -3661,12 +4004,13 @@ var DuckDbService = class extends BaseService {
|
|
|
3661
4004
|
if (!this.requireAuth()) {
|
|
3662
4005
|
return err(authRequiredError("duckdb"));
|
|
3663
4006
|
}
|
|
4007
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3664
4008
|
try {
|
|
3665
4009
|
const response = await this.invokeDuckDb(
|
|
3666
4010
|
dbName,
|
|
3667
4011
|
DuckDbAction.EXPORT,
|
|
3668
4012
|
{ action: "export" },
|
|
3669
|
-
|
|
4013
|
+
request.signal
|
|
3670
4014
|
);
|
|
3671
4015
|
if (!response.ok) {
|
|
3672
4016
|
return this.handleErrorResponse(response, "export");
|
|
@@ -3675,6 +4019,8 @@ var DuckDbService = class extends BaseService {
|
|
|
3675
4019
|
return ok(blob);
|
|
3676
4020
|
} catch (error) {
|
|
3677
4021
|
return err(wrapError("duckdb", error));
|
|
4022
|
+
} finally {
|
|
4023
|
+
request.dispose();
|
|
3678
4024
|
}
|
|
3679
4025
|
});
|
|
3680
4026
|
}
|
|
@@ -3683,6 +4029,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3683
4029
|
if (!this.requireAuth()) {
|
|
3684
4030
|
return err(authRequiredError("duckdb"));
|
|
3685
4031
|
}
|
|
4032
|
+
const request = this.createRequestSignal(options?.signal);
|
|
3686
4033
|
try {
|
|
3687
4034
|
const session = this.context.session;
|
|
3688
4035
|
const headers = this.context.invoke(
|
|
@@ -3698,7 +4045,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3698
4045
|
"Content-Type": "application/x-duckdb"
|
|
3699
4046
|
},
|
|
3700
4047
|
body: new Blob([data]),
|
|
3701
|
-
signal:
|
|
4048
|
+
signal: request.signal
|
|
3702
4049
|
});
|
|
3703
4050
|
if (!response.ok) {
|
|
3704
4051
|
return this.handleErrorResponse(response, "import");
|
|
@@ -3706,6 +4053,8 @@ var DuckDbService = class extends BaseService {
|
|
|
3706
4053
|
return ok(void 0);
|
|
3707
4054
|
} catch (error) {
|
|
3708
4055
|
return err(wrapError("duckdb", error));
|
|
4056
|
+
} finally {
|
|
4057
|
+
request.dispose();
|
|
3709
4058
|
}
|
|
3710
4059
|
});
|
|
3711
4060
|
}
|
|
@@ -3721,7 +4070,7 @@ var DuckDbService = class extends BaseService {
|
|
|
3721
4070
|
...extraHeaders
|
|
3722
4071
|
},
|
|
3723
4072
|
body: JSON.stringify(body),
|
|
3724
|
-
signal
|
|
4073
|
+
signal
|
|
3725
4074
|
});
|
|
3726
4075
|
}
|
|
3727
4076
|
async handleErrorResponse(response, operation) {
|
|
@@ -6142,6 +6491,7 @@ var SecretsService = class {
|
|
|
6142
6491
|
}
|
|
6143
6492
|
async listAll() {
|
|
6144
6493
|
const entries = /* @__PURE__ */ new Map();
|
|
6494
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
6145
6495
|
let cursor;
|
|
6146
6496
|
do {
|
|
6147
6497
|
const result = await this.vault.listPage({
|
|
@@ -6164,6 +6514,14 @@ var SecretsService = class {
|
|
|
6164
6514
|
"Secret catalog listing was truncated without a continuation cursor."
|
|
6165
6515
|
);
|
|
6166
6516
|
}
|
|
6517
|
+
if (cursor !== void 0) {
|
|
6518
|
+
if (seenCursors.has(cursor)) {
|
|
6519
|
+
return invalidSecretInput(
|
|
6520
|
+
"Secret catalog listing repeated a continuation cursor; the node does not support paged KV lists."
|
|
6521
|
+
);
|
|
6522
|
+
}
|
|
6523
|
+
seenCursors.add(cursor);
|
|
6524
|
+
}
|
|
6167
6525
|
} while (cursor !== void 0);
|
|
6168
6526
|
return {
|
|
6169
6527
|
ok: true,
|