@tinycloud/sdk-services 2.8.0 → 2.10.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/{BaseService-DxSU4U-v.d.cts → BaseService-BhpVpA9b.d.cts} +1 -1
- package/dist/{BaseService-BiYeqCRT.d.ts → BaseService-CuV-ZVPs.d.ts} +1 -1
- 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.map +1 -1
- package/dist/index.cjs +231 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -5
- package/dist/index.d.ts +35 -5
- package/dist/index.js +231 -5
- 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 +216 -2
- package/dist/kv/index.cjs.map +1 -1
- package/dist/kv/index.d.cts +34 -3
- package/dist/kv/index.d.ts +34 -3
- package/dist/kv/index.js +216 -2
- package/dist/kv/index.js.map +1 -1
- package/dist/sql/index.cjs.map +1 -1
- package/dist/sql/index.d.cts +2 -2
- package/dist/sql/index.d.ts +2 -2
- package/dist/sql/index.js.map +1 -1
- package/dist/{types-KCcgZiab.d.cts → types-qwMmB7qB.d.cts} +1 -0
- package/dist/{types-KCcgZiab.d.ts → types-qwMmB7qB.d.ts} +1 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -514,7 +514,9 @@ function createKVResponseSchema(dataSchema) {
|
|
|
514
514
|
var GenericKVResponseSchema = createKVResponseSchema(import_zod.z.unknown());
|
|
515
515
|
var KVListResponseSchema = import_zod.z.object({
|
|
516
516
|
/** Array of keys matching the list criteria */
|
|
517
|
-
keys: import_zod.z.array(import_zod.z.string())
|
|
517
|
+
keys: import_zod.z.array(import_zod.z.string()),
|
|
518
|
+
truncated: import_zod.z.boolean().optional(),
|
|
519
|
+
nextCursor: import_zod.z.string().optional()
|
|
518
520
|
});
|
|
519
521
|
var KVListResultSchema = createResultSchema(KVListResponseSchema);
|
|
520
522
|
var ServiceRequestEventSchema = import_zod.z.object({
|
|
@@ -1418,6 +1420,20 @@ var PrefixedKVService = class _PrefixedKVService {
|
|
|
1418
1420
|
const fullKey = this.getFullKey(key);
|
|
1419
1421
|
return this._kv.get(fullKey, { ...options, prefix: "" });
|
|
1420
1422
|
}
|
|
1423
|
+
async batchGet(keys, options) {
|
|
1424
|
+
const response = await this._kv.batchGet(
|
|
1425
|
+
keys.map((key) => this.getFullKey(key)),
|
|
1426
|
+
{ ...options, prefix: "" }
|
|
1427
|
+
);
|
|
1428
|
+
if (!response.ok) return response;
|
|
1429
|
+
return ok({
|
|
1430
|
+
...response.data,
|
|
1431
|
+
results: response.data.results.map((item, index) => ({
|
|
1432
|
+
...item,
|
|
1433
|
+
key: keys[index]
|
|
1434
|
+
}))
|
|
1435
|
+
});
|
|
1436
|
+
}
|
|
1421
1437
|
/**
|
|
1422
1438
|
* Store a value at a key.
|
|
1423
1439
|
*/
|
|
@@ -1462,6 +1478,20 @@ var PrefixedKVService = class _PrefixedKVService {
|
|
|
1462
1478
|
const fullKey = this.getFullKey(key);
|
|
1463
1479
|
return this._kv.head(fullKey, { ...options, prefix: "" });
|
|
1464
1480
|
}
|
|
1481
|
+
async batchHead(keys, options) {
|
|
1482
|
+
const response = await this._kv.batchHead(
|
|
1483
|
+
keys.map((key) => this.getFullKey(key)),
|
|
1484
|
+
{ ...options, prefix: "" }
|
|
1485
|
+
);
|
|
1486
|
+
if (!response.ok) return response;
|
|
1487
|
+
return ok({
|
|
1488
|
+
...response.data,
|
|
1489
|
+
results: response.data.results.map((item, index) => ({
|
|
1490
|
+
...item,
|
|
1491
|
+
key: keys[index]
|
|
1492
|
+
}))
|
|
1493
|
+
});
|
|
1494
|
+
}
|
|
1465
1495
|
/**
|
|
1466
1496
|
* Create a short-lived signed URL for reading a KV object.
|
|
1467
1497
|
*/
|
|
@@ -1490,6 +1520,7 @@ var KVAction = {
|
|
|
1490
1520
|
};
|
|
1491
1521
|
|
|
1492
1522
|
// src/kv/KVService.ts
|
|
1523
|
+
var MAX_KV_BATCH_READ_ITEMS = 100;
|
|
1493
1524
|
function encodeKvBatchPartName(path) {
|
|
1494
1525
|
return encodeURIComponent(path).replace(
|
|
1495
1526
|
/[!'()*]/g,
|
|
@@ -1724,6 +1755,173 @@ var KVService = class extends BaseService {
|
|
|
1724
1755
|
get: (name) => headers.get(name)
|
|
1725
1756
|
};
|
|
1726
1757
|
}
|
|
1758
|
+
createBatchResponseHeaders(values) {
|
|
1759
|
+
const normalized = new Map(
|
|
1760
|
+
Object.entries(values).map(([name, value]) => [name.toLowerCase(), value])
|
|
1761
|
+
);
|
|
1762
|
+
return this.createResponseHeaders({
|
|
1763
|
+
get: (name) => normalized.get(name.toLowerCase()) ?? null
|
|
1764
|
+
});
|
|
1765
|
+
}
|
|
1766
|
+
parseBatchValue(dataBase64, headers, raw = false, binary = false) {
|
|
1767
|
+
const encoded = globalThis.atob(dataBase64);
|
|
1768
|
+
const bytes = Uint8Array.from(encoded, (character) => character.charCodeAt(0));
|
|
1769
|
+
if (binary) return bytes;
|
|
1770
|
+
const text = new TextDecoder().decode(bytes);
|
|
1771
|
+
if (raw) return text;
|
|
1772
|
+
const contentType = Object.entries(headers).find(
|
|
1773
|
+
([name]) => name.toLowerCase() === "content-type"
|
|
1774
|
+
)?.[1];
|
|
1775
|
+
return contentType?.includes("application/json") ? JSON.parse(text) : text;
|
|
1776
|
+
}
|
|
1777
|
+
normalizeBatchReadResponse(data, paths, requireData) {
|
|
1778
|
+
if (!data || typeof data !== "object") return void 0;
|
|
1779
|
+
const response = data;
|
|
1780
|
+
if (!Array.isArray(response.results) || response.results.length !== paths.length) {
|
|
1781
|
+
return void 0;
|
|
1782
|
+
}
|
|
1783
|
+
for (let index = 0; index < response.results.length; index++) {
|
|
1784
|
+
const item = response.results[index];
|
|
1785
|
+
if (!item || typeof item !== "object" || item.key !== paths[index] || typeof item.ok !== "boolean") {
|
|
1786
|
+
return void 0;
|
|
1787
|
+
}
|
|
1788
|
+
if (item.ok && (!item.headers || typeof item.headers !== "object" || Object.values(item.headers).some((value) => typeof value !== "string") || requireData && typeof item.dataBase64 !== "string")) {
|
|
1789
|
+
return void 0;
|
|
1790
|
+
}
|
|
1791
|
+
if (!item.ok && (!item.error || typeof item.error.code !== "string" || typeof item.error.message !== "string")) {
|
|
1792
|
+
return void 0;
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
return response;
|
|
1796
|
+
}
|
|
1797
|
+
async batchRead(keys, action, options) {
|
|
1798
|
+
if (!this.requireAuth()) return err(authRequiredError("kv"));
|
|
1799
|
+
if (keys.length === 0) return ok({ results: [], count: 0 });
|
|
1800
|
+
if (keys.length > MAX_KV_BATCH_READ_ITEMS) {
|
|
1801
|
+
return err(serviceError(
|
|
1802
|
+
ErrorCodes.INVALID_INPUT,
|
|
1803
|
+
`KV batch reads accept at most ${MAX_KV_BATCH_READ_ITEMS} keys`,
|
|
1804
|
+
"kv"
|
|
1805
|
+
));
|
|
1806
|
+
}
|
|
1807
|
+
if (keys.length === 1) {
|
|
1808
|
+
const key = keys[0];
|
|
1809
|
+
const result = action === KVAction.GET ? await this.get(key, options) : await this.head(key, options);
|
|
1810
|
+
return ok({
|
|
1811
|
+
results: [{ key, result }],
|
|
1812
|
+
count: 1
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1815
|
+
if (!this.context.invokeAny) {
|
|
1816
|
+
return err(serviceError(
|
|
1817
|
+
ErrorCodes.INVALID_INPUT,
|
|
1818
|
+
"KV batch reads require SDK runtime support for multi-resource invocations",
|
|
1819
|
+
"kv"
|
|
1820
|
+
));
|
|
1821
|
+
}
|
|
1822
|
+
const getOptions = action === KVAction.GET ? options : void 0;
|
|
1823
|
+
if (getOptions?.maxResponseBytes !== void 0 && (!Number.isSafeInteger(getOptions.maxResponseBytes) || getOptions.maxResponseBytes <= 0)) {
|
|
1824
|
+
return err(serviceError(
|
|
1825
|
+
ErrorCodes.INVALID_INPUT,
|
|
1826
|
+
"KV maxResponseBytes must be a positive safe integer",
|
|
1827
|
+
"kv"
|
|
1828
|
+
));
|
|
1829
|
+
}
|
|
1830
|
+
const paths = keys.map((key) => this.getFullPath(key, options?.prefix));
|
|
1831
|
+
if (new Set(paths).size !== paths.length) {
|
|
1832
|
+
return err(serviceError(
|
|
1833
|
+
ErrorCodes.INVALID_INPUT,
|
|
1834
|
+
"KV batch read received duplicate keys after prefix resolution",
|
|
1835
|
+
"kv"
|
|
1836
|
+
));
|
|
1837
|
+
}
|
|
1838
|
+
try {
|
|
1839
|
+
const session = this.context.session;
|
|
1840
|
+
const invocationHeaders = this.context.invokeAny(
|
|
1841
|
+
session,
|
|
1842
|
+
paths.map((path) => ({
|
|
1843
|
+
spaceId: session.spaceId,
|
|
1844
|
+
service: "kv",
|
|
1845
|
+
path,
|
|
1846
|
+
action
|
|
1847
|
+
}))
|
|
1848
|
+
);
|
|
1849
|
+
const limitHeaders = {};
|
|
1850
|
+
if (getOptions?.maxResponseBytes !== void 0) {
|
|
1851
|
+
limitHeaders["x-tinycloud-max-response-bytes"] = String(
|
|
1852
|
+
getOptions.maxResponseBytes
|
|
1853
|
+
);
|
|
1854
|
+
}
|
|
1855
|
+
const headers = Array.isArray(invocationHeaders) ? [...invocationHeaders, ...Object.entries(limitHeaders)] : { ...invocationHeaders, ...limitHeaders };
|
|
1856
|
+
const response = await this.context.fetch(`${this.host}/invoke`, {
|
|
1857
|
+
method: "POST",
|
|
1858
|
+
headers,
|
|
1859
|
+
signal: this.combineSignals(options?.signal)
|
|
1860
|
+
});
|
|
1861
|
+
if (!response.ok) {
|
|
1862
|
+
const errorText = await response.text();
|
|
1863
|
+
if (response.status === 401 || response.status === 403) {
|
|
1864
|
+
const { resource, action: requiredAction } = parseAuthError(errorText);
|
|
1865
|
+
return err(authUnauthorizedError("kv", errorText, {
|
|
1866
|
+
status: response.status,
|
|
1867
|
+
...requiredAction && { requiredAction },
|
|
1868
|
+
...resource && { resource }
|
|
1869
|
+
}));
|
|
1870
|
+
}
|
|
1871
|
+
if (response.status === 413) {
|
|
1872
|
+
return err(serviceError(
|
|
1873
|
+
ErrorCodes.KV_RESPONSE_TOO_LARGE,
|
|
1874
|
+
"A KV batch value exceeds the requested response limit",
|
|
1875
|
+
"kv",
|
|
1876
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
1877
|
+
));
|
|
1878
|
+
}
|
|
1879
|
+
return err(serviceError(
|
|
1880
|
+
ErrorCodes.NETWORK_ERROR,
|
|
1881
|
+
`Failed to batch read ${keys.length} key(s): ${response.status} - ${errorText}`,
|
|
1882
|
+
"kv",
|
|
1883
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
1884
|
+
));
|
|
1885
|
+
}
|
|
1886
|
+
const payload = this.normalizeBatchReadResponse(
|
|
1887
|
+
await response.json(),
|
|
1888
|
+
paths,
|
|
1889
|
+
action === KVAction.GET
|
|
1890
|
+
);
|
|
1891
|
+
if (!payload) {
|
|
1892
|
+
return err(serviceError(
|
|
1893
|
+
ErrorCodes.NETWORK_ERROR,
|
|
1894
|
+
"KV batch read response did not match the requested keys",
|
|
1895
|
+
"kv"
|
|
1896
|
+
));
|
|
1897
|
+
}
|
|
1898
|
+
const results = payload.results.map((item, index) => {
|
|
1899
|
+
if (!item.ok) {
|
|
1900
|
+
return {
|
|
1901
|
+
key: keys[index],
|
|
1902
|
+
result: err(serviceError(item.error.code, item.error.message, "kv"))
|
|
1903
|
+
};
|
|
1904
|
+
}
|
|
1905
|
+
const headers2 = item.headers;
|
|
1906
|
+
const data = action === KVAction.HEAD ? void 0 : this.parseBatchValue(
|
|
1907
|
+
item.dataBase64,
|
|
1908
|
+
headers2,
|
|
1909
|
+
getOptions?.raw,
|
|
1910
|
+
getOptions?.binary
|
|
1911
|
+
);
|
|
1912
|
+
return {
|
|
1913
|
+
key: keys[index],
|
|
1914
|
+
result: ok({
|
|
1915
|
+
data,
|
|
1916
|
+
headers: this.createBatchResponseHeaders(headers2)
|
|
1917
|
+
})
|
|
1918
|
+
};
|
|
1919
|
+
});
|
|
1920
|
+
return ok({ results, count: results.length });
|
|
1921
|
+
} catch (error) {
|
|
1922
|
+
return err(wrapError("kv", error));
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1727
1925
|
/**
|
|
1728
1926
|
* Parse response body based on content type.
|
|
1729
1927
|
*
|
|
@@ -1870,6 +2068,13 @@ var KVService = class extends BaseService {
|
|
|
1870
2068
|
}
|
|
1871
2069
|
});
|
|
1872
2070
|
}
|
|
2071
|
+
async batchGet(keys, options) {
|
|
2072
|
+
return this.withTelemetry(
|
|
2073
|
+
"batchGet",
|
|
2074
|
+
String(keys.length),
|
|
2075
|
+
() => this.batchRead(keys, KVAction.GET, options)
|
|
2076
|
+
);
|
|
2077
|
+
}
|
|
1873
2078
|
/**
|
|
1874
2079
|
* Store a value at a key.
|
|
1875
2080
|
*/
|
|
@@ -2077,7 +2282,10 @@ var KVService = class extends BaseService {
|
|
|
2077
2282
|
KVAction.LIST,
|
|
2078
2283
|
void 0,
|
|
2079
2284
|
options?.signal,
|
|
2080
|
-
options?.limit === void 0 ? void 0 : {
|
|
2285
|
+
options?.limit === void 0 && options?.cursor === void 0 ? void 0 : {
|
|
2286
|
+
...options?.limit === void 0 ? {} : { "x-tinycloud-limit": String(options.limit) },
|
|
2287
|
+
...options?.cursor === void 0 ? {} : { "x-tinycloud-cursor": options.cursor }
|
|
2288
|
+
}
|
|
2081
2289
|
);
|
|
2082
2290
|
if (!response.ok) {
|
|
2083
2291
|
if (response.status === 401) {
|
|
@@ -2109,7 +2317,8 @@ var KVService = class extends BaseService {
|
|
|
2109
2317
|
}
|
|
2110
2318
|
return ok({
|
|
2111
2319
|
keys,
|
|
2112
|
-
...response.headers.get("x-tinycloud-truncated") === null ? {} : { truncated: response.headers.get("x-tinycloud-truncated") === "true" }
|
|
2320
|
+
...response.headers.get("x-tinycloud-truncated") === null ? {} : { truncated: response.headers.get("x-tinycloud-truncated") === "true" },
|
|
2321
|
+
...response.headers.get("x-tinycloud-next-cursor") === null ? {} : { nextCursor: response.headers.get("x-tinycloud-next-cursor") ?? void 0 }
|
|
2113
2322
|
});
|
|
2114
2323
|
} catch (error) {
|
|
2115
2324
|
return err(wrapError("kv", error));
|
|
@@ -2229,6 +2438,13 @@ var KVService = class extends BaseService {
|
|
|
2229
2438
|
}
|
|
2230
2439
|
});
|
|
2231
2440
|
}
|
|
2441
|
+
async batchHead(keys, options) {
|
|
2442
|
+
return this.withTelemetry(
|
|
2443
|
+
"batchHead",
|
|
2444
|
+
String(keys.length),
|
|
2445
|
+
() => this.batchRead(keys, KVAction.HEAD, options)
|
|
2446
|
+
);
|
|
2447
|
+
}
|
|
2232
2448
|
/**
|
|
2233
2449
|
* Create a short-lived signed URL for reading a KV object.
|
|
2234
2450
|
*/
|
|
@@ -4827,6 +5043,10 @@ var DataVaultService = class extends BaseService {
|
|
|
4827
5043
|
* @returns Result with array of key names (vault/ prefix stripped)
|
|
4828
5044
|
*/
|
|
4829
5045
|
async list(options) {
|
|
5046
|
+
const page = await this.listPage(options);
|
|
5047
|
+
return page.ok ? { ok: true, data: page.data.keys } : page;
|
|
5048
|
+
}
|
|
5049
|
+
async listPage(options) {
|
|
4830
5050
|
return this.withTelemetry("list", options?.prefix, async () => {
|
|
4831
5051
|
if (!this.isUnlocked) {
|
|
4832
5052
|
return vaultError({
|
|
@@ -4844,7 +5064,9 @@ var DataVaultService = class extends BaseService {
|
|
|
4844
5064
|
const listPrefix = options?.prefix ? `vault/${options.prefix}` : "vault/";
|
|
4845
5065
|
const listResult = await this.tc.kv.list({
|
|
4846
5066
|
prefix: listPrefix,
|
|
4847
|
-
removePrefix: true
|
|
5067
|
+
removePrefix: true,
|
|
5068
|
+
...options?.limit === void 0 ? {} : { limit: options.limit },
|
|
5069
|
+
...options?.cursor === void 0 ? {} : { cursor: options.cursor }
|
|
4848
5070
|
});
|
|
4849
5071
|
if (!listResult.ok) {
|
|
4850
5072
|
return vaultError({
|
|
@@ -4861,7 +5083,11 @@ var DataVaultService = class extends BaseService {
|
|
|
4861
5083
|
(k) => k.startsWith(userPrefix) ? k.slice(userPrefix.length) : k
|
|
4862
5084
|
);
|
|
4863
5085
|
}
|
|
4864
|
-
return ok(
|
|
5086
|
+
return ok({
|
|
5087
|
+
keys,
|
|
5088
|
+
truncated: listResult.data.truncated === true,
|
|
5089
|
+
...listResult.data.nextCursor === void 0 ? {} : { nextCursor: listResult.data.nextCursor }
|
|
5090
|
+
});
|
|
4865
5091
|
} catch (error) {
|
|
4866
5092
|
return vaultError({
|
|
4867
5093
|
code: "STORAGE_ERROR",
|