@tinycloud/sdk-services 3.0.0 → 3.1.0-beta.2
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/encryption/index.cjs.map +1 -1
- package/dist/encryption/index.js.map +1 -1
- package/dist/index.cjs +181 -145
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +53 -1
- package/dist/index.d.ts +53 -1
- package/dist/index.js +175 -145
- package/dist/index.js.map +1 -1
- package/dist/kv/index.cjs +94 -102
- package/dist/kv/index.cjs.map +1 -1
- package/dist/kv/index.d.cts +8 -1
- package/dist/kv/index.d.ts +8 -1
- package/dist/kv/index.js +94 -102
- package/dist/kv/index.js.map +1 -1
- package/dist/sql/index.cjs +44 -5
- package/dist/sql/index.cjs.map +1 -1
- package/dist/sql/index.js +44 -5
- package/dist/sql/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -55,6 +55,8 @@ __export(src_exports, {
|
|
|
55
55
|
SQLAction: () => SQLAction,
|
|
56
56
|
SQLMigrations: () => SQLMigrations,
|
|
57
57
|
SQLService: () => SQLService,
|
|
58
|
+
STORAGE_FULL_MESSAGE: () => STORAGE_FULL_MESSAGE,
|
|
59
|
+
STORAGE_WRITE_TOO_LARGE_MESSAGE: () => STORAGE_WRITE_TOO_LARGE_MESSAGE,
|
|
58
60
|
SecretsService: () => SecretsService,
|
|
59
61
|
ServiceContext: () => ServiceContext,
|
|
60
62
|
ServiceErrorEventSchema: () => ServiceErrorEventSchema,
|
|
@@ -73,6 +75,7 @@ __export(src_exports, {
|
|
|
73
75
|
authExpiredError: () => authExpiredError,
|
|
74
76
|
authRequiredError: () => authRequiredError,
|
|
75
77
|
authUnauthorizedError: () => authUnauthorizedError,
|
|
78
|
+
authorizationVerdictOf: () => authorizationVerdictOf,
|
|
76
79
|
base64Decode: () => base64Decode2,
|
|
77
80
|
base64Encode: () => base64Encode2,
|
|
78
81
|
buildCanonicalDecryptRequest: () => buildCanonicalDecryptRequest,
|
|
@@ -106,6 +109,7 @@ __export(src_exports, {
|
|
|
106
109
|
hexEncode: () => hexEncode2,
|
|
107
110
|
installTinyCloudDebugGlobals: () => installTinyCloudDebugGlobals,
|
|
108
111
|
isNetworkId: () => isNetworkId,
|
|
112
|
+
isStorageFullError: () => isStorageFullError,
|
|
109
113
|
networkDiscoveryKey: () => networkDiscoveryKey,
|
|
110
114
|
networkError: () => networkError,
|
|
111
115
|
notFoundError: () => notFoundError,
|
|
@@ -116,12 +120,14 @@ __export(src_exports, {
|
|
|
116
120
|
parsePermissionHint: () => parsePermissionHint,
|
|
117
121
|
parsePermissionHintFromErrorText: () => parsePermissionHintFromErrorText,
|
|
118
122
|
parseSecretCatalogKey: () => parseSecretCatalogKey,
|
|
123
|
+
parseStorageQuotaBytes: () => parseStorageQuotaBytes,
|
|
119
124
|
permissionDeniedError: () => permissionDeniedError,
|
|
120
125
|
resolveSecretListPrefix: () => resolveSecretListPrefix,
|
|
121
126
|
resolveSecretPath: () => resolveSecretPath,
|
|
122
127
|
serviceError: () => serviceError,
|
|
123
128
|
storageLimitReachedError: () => storageLimitReachedError,
|
|
124
129
|
storageQuotaExceededError: () => storageQuotaExceededError,
|
|
130
|
+
storageRejectionError: () => storageRejectionError,
|
|
125
131
|
timeoutError: () => timeoutError,
|
|
126
132
|
tinyCloudDebugLogger: () => tinyCloudDebugLogger,
|
|
127
133
|
utf8Decode: () => utf8Decode,
|
|
@@ -1135,6 +1141,37 @@ function parseAuthError(responseText) {
|
|
|
1135
1141
|
function authUnauthorizedError(service, message, meta) {
|
|
1136
1142
|
return serviceError(ErrorCodes.AUTH_UNAUTHORIZED, message, service, { meta });
|
|
1137
1143
|
}
|
|
1144
|
+
var MAX_CAUSE_DEPTH = 8;
|
|
1145
|
+
function errorStatusOf(node) {
|
|
1146
|
+
const meta = node.meta;
|
|
1147
|
+
const candidates = [
|
|
1148
|
+
node.status,
|
|
1149
|
+
node.statusCode,
|
|
1150
|
+
typeof meta === "object" && meta !== null ? meta.status : void 0
|
|
1151
|
+
];
|
|
1152
|
+
for (const candidate of candidates) {
|
|
1153
|
+
if (typeof candidate === "number" && Number.isInteger(candidate) && candidate >= 400 && candidate <= 599) {
|
|
1154
|
+
return candidate;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
return void 0;
|
|
1158
|
+
}
|
|
1159
|
+
function authorizationVerdictOf(error) {
|
|
1160
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1161
|
+
let sawUnauthorizedCode = false;
|
|
1162
|
+
let node = error;
|
|
1163
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH && typeof node === "object" && node !== null && !seen.has(node); depth += 1) {
|
|
1164
|
+
seen.add(node);
|
|
1165
|
+
const record = node;
|
|
1166
|
+
const status = errorStatusOf(record);
|
|
1167
|
+
if (status === 401) return "unauthenticated";
|
|
1168
|
+
if (status === 403) return "forbidden";
|
|
1169
|
+
if (status !== void 0) return "other";
|
|
1170
|
+
if (record.code === ErrorCodes.AUTH_UNAUTHORIZED) sawUnauthorizedCode = true;
|
|
1171
|
+
node = record.cause;
|
|
1172
|
+
}
|
|
1173
|
+
return sawUnauthorizedCode ? "forbidden" : void 0;
|
|
1174
|
+
}
|
|
1138
1175
|
function storageQuotaExceededError(service, message, meta) {
|
|
1139
1176
|
return {
|
|
1140
1177
|
code: ErrorCodes.STORAGE_QUOTA_EXCEEDED,
|
|
@@ -1151,6 +1188,23 @@ function storageLimitReachedError(service, message, meta) {
|
|
|
1151
1188
|
meta
|
|
1152
1189
|
};
|
|
1153
1190
|
}
|
|
1191
|
+
var STORAGE_FULL_MESSAGE = "TinyCloud storage is full, so this change was not saved. Reading still works. Free up space or upgrade your plan to save again.";
|
|
1192
|
+
var STORAGE_WRITE_TOO_LARGE_MESSAGE = "This change is larger than the TinyCloud storage you have left, so it was not saved. Reading still works. Free up space or upgrade your plan to save it.";
|
|
1193
|
+
function parseStorageQuotaBytes(responseText) {
|
|
1194
|
+
const match = responseText.match(/Used:\s*(\d+)\s*bytes,\s*Limit:\s*(\d+)\s*bytes/i);
|
|
1195
|
+
if (!match) return void 0;
|
|
1196
|
+
return {
|
|
1197
|
+
usedBytes: parseInt(match[1], 10),
|
|
1198
|
+
limitBytes: parseInt(match[2], 10)
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
function storageRejectionError(service, status, meta, responseText) {
|
|
1202
|
+
const quotaMeta = { ...meta, ...parseStorageQuotaBytes(responseText) };
|
|
1203
|
+
return status === 402 ? storageQuotaExceededError(service, STORAGE_FULL_MESSAGE, quotaMeta) : storageLimitReachedError(service, STORAGE_WRITE_TOO_LARGE_MESSAGE, quotaMeta);
|
|
1204
|
+
}
|
|
1205
|
+
function isStorageFullError(error) {
|
|
1206
|
+
return error?.code === ErrorCodes.STORAGE_QUOTA_EXCEEDED || error?.code === ErrorCodes.STORAGE_LIMIT_REACHED;
|
|
1207
|
+
}
|
|
1154
1208
|
function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
|
|
1155
1209
|
if (error instanceof Error) {
|
|
1156
1210
|
if (error.name === "AbortError") {
|
|
@@ -1544,47 +1598,21 @@ var KVService = class extends BaseService {
|
|
|
1544
1598
|
get config() {
|
|
1545
1599
|
return this._config;
|
|
1546
1600
|
}
|
|
1547
|
-
// Parses "Used: X bytes, Limit: Y bytes" from tinycloud-node error responses
|
|
1548
|
-
parseQuotaInfo(errorText) {
|
|
1549
|
-
const match = errorText.match(
|
|
1550
|
-
/Used:\s*(\d+)\s*bytes,\s*Limit:\s*(\d+)\s*bytes/i
|
|
1551
|
-
);
|
|
1552
|
-
if (match) {
|
|
1553
|
-
return {
|
|
1554
|
-
usedBytes: parseInt(match[1], 10),
|
|
1555
|
-
limitBytes: parseInt(match[2], 10)
|
|
1556
|
-
};
|
|
1557
|
-
}
|
|
1558
|
-
return void 0;
|
|
1559
|
-
}
|
|
1560
1601
|
handleQuotaErrorResponse(response, errorText, key) {
|
|
1561
|
-
if (response.status
|
|
1562
|
-
|
|
1563
|
-
return err(
|
|
1564
|
-
storageQuotaExceededError(
|
|
1565
|
-
"kv",
|
|
1566
|
-
`Storage quota exceeded for key "${key}": ${errorText}`,
|
|
1567
|
-
{
|
|
1568
|
-
status: response.status,
|
|
1569
|
-
...quotaInfo ? { usedBytes: quotaInfo.usedBytes, limitBytes: quotaInfo.limitBytes } : {}
|
|
1570
|
-
}
|
|
1571
|
-
)
|
|
1572
|
-
);
|
|
1602
|
+
if (response.status !== 402 && response.status !== 413) {
|
|
1603
|
+
return void 0;
|
|
1573
1604
|
}
|
|
1574
|
-
if (response.status === 413) {
|
|
1575
|
-
|
|
1576
|
-
return err(
|
|
1577
|
-
storageLimitReachedError(
|
|
1578
|
-
"kv",
|
|
1579
|
-
`Storage limit reached for key "${key}": ${errorText}`,
|
|
1580
|
-
{
|
|
1581
|
-
status: response.status,
|
|
1582
|
-
...quotaInfo ? { usedBytes: quotaInfo.usedBytes, limitBytes: quotaInfo.limitBytes } : {}
|
|
1583
|
-
}
|
|
1584
|
-
)
|
|
1585
|
-
);
|
|
1605
|
+
if (response.status === 413 && !parseStorageQuotaBytes(errorText)) {
|
|
1606
|
+
return void 0;
|
|
1586
1607
|
}
|
|
1587
|
-
return
|
|
1608
|
+
return err(
|
|
1609
|
+
storageRejectionError(
|
|
1610
|
+
"kv",
|
|
1611
|
+
response.status,
|
|
1612
|
+
{ status: response.status, statusText: response.statusText, key },
|
|
1613
|
+
errorText
|
|
1614
|
+
)
|
|
1615
|
+
);
|
|
1588
1616
|
}
|
|
1589
1617
|
/**
|
|
1590
1618
|
* Classify a KV 404 by reading the response body once.
|
|
@@ -1862,12 +1890,11 @@ var KVService = class extends BaseService {
|
|
|
1862
1890
|
if (!response.ok) {
|
|
1863
1891
|
const errorText = await response.text();
|
|
1864
1892
|
if (response.status === 401 || response.status === 403) {
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
}));
|
|
1893
|
+
return this.authorizationFailure(
|
|
1894
|
+
`Failed to batch read ${keys.length} key(s)`,
|
|
1895
|
+
response,
|
|
1896
|
+
errorText
|
|
1897
|
+
);
|
|
1871
1898
|
}
|
|
1872
1899
|
if (response.status === 413) {
|
|
1873
1900
|
return err(serviceError(
|
|
@@ -1966,23 +1993,39 @@ var KVService = class extends BaseService {
|
|
|
1966
1993
|
} catch {
|
|
1967
1994
|
}
|
|
1968
1995
|
if (response.status === 401 || response.status === 403) {
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
}));
|
|
1996
|
+
return this.authorizationFailure(
|
|
1997
|
+
`Failed to create signed read URL for key ${JSON.stringify(key)}`,
|
|
1998
|
+
response,
|
|
1999
|
+
errorText
|
|
2000
|
+
);
|
|
1975
2001
|
}
|
|
1976
2002
|
const code = response.status === 400 ? ErrorCodes.INVALID_INPUT : ErrorCodes.NETWORK_ERROR;
|
|
1977
2003
|
return err(
|
|
1978
2004
|
serviceError(
|
|
1979
2005
|
code,
|
|
1980
|
-
`Failed to create signed read URL for key
|
|
2006
|
+
`Failed to create signed read URL for key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
1981
2007
|
"kv",
|
|
1982
2008
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
1983
2009
|
)
|
|
1984
2010
|
);
|
|
1985
2011
|
}
|
|
2012
|
+
/**
|
|
2013
|
+
* AUTH_UNAUTHORIZED for a 401/403 response. The message keeps the HTTP
|
|
2014
|
+
* status and the server text (`<context>: <status> - <text>`, the same
|
|
2015
|
+
* shape as every other KV failure) so callers that rethrow only the message
|
|
2016
|
+
* still see the status; `meta.status` carries it for typed callers.
|
|
2017
|
+
* Resource/ability hints are parsed from the raw body, never the message.
|
|
2018
|
+
*/
|
|
2019
|
+
authorizationFailure(context, response, errorText, extraMeta = {}) {
|
|
2020
|
+
const { resource, action } = parseAuthError(errorText);
|
|
2021
|
+
const detail = errorText.trim().length > 0 ? errorText : response.statusText || "authorization failed";
|
|
2022
|
+
return err(authUnauthorizedError("kv", `${context}: ${response.status} - ${detail}`, {
|
|
2023
|
+
status: response.status,
|
|
2024
|
+
...action && { requiredAction: action },
|
|
2025
|
+
...resource && { resource },
|
|
2026
|
+
...extraMeta
|
|
2027
|
+
}));
|
|
2028
|
+
}
|
|
1986
2029
|
normalizeSignedReadUrlResponse(data) {
|
|
1987
2030
|
if (!data || typeof data !== "object") {
|
|
1988
2031
|
return void 0;
|
|
@@ -2025,14 +2068,13 @@ var KVService = class extends BaseService {
|
|
|
2025
2068
|
if (!response.ok) {
|
|
2026
2069
|
if (response.status === 401 || response.status === 403) {
|
|
2027
2070
|
const errorText2 = await response.text();
|
|
2028
|
-
const { resource, action } = parseAuthError(errorText2);
|
|
2029
2071
|
const permissionHint = parsePermissionHintFromErrorText(errorText2);
|
|
2030
|
-
return
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2072
|
+
return this.authorizationFailure(
|
|
2073
|
+
`Failed to get key ${JSON.stringify(key)}`,
|
|
2074
|
+
response,
|
|
2075
|
+
errorText2,
|
|
2076
|
+
permissionHint === void 0 ? {} : { permissionHint }
|
|
2077
|
+
);
|
|
2036
2078
|
}
|
|
2037
2079
|
if (response.status === 404) {
|
|
2038
2080
|
return this.classifyNotFound(response, key);
|
|
@@ -2041,7 +2083,7 @@ var KVService = class extends BaseService {
|
|
|
2041
2083
|
if (response.status === 413) {
|
|
2042
2084
|
return err(serviceError(
|
|
2043
2085
|
ErrorCodes.KV_RESPONSE_TOO_LARGE,
|
|
2044
|
-
`KV value at key
|
|
2086
|
+
`KV value at key ${JSON.stringify(key)} exceeds the requested response limit`,
|
|
2045
2087
|
"kv",
|
|
2046
2088
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2047
2089
|
));
|
|
@@ -2049,7 +2091,7 @@ var KVService = class extends BaseService {
|
|
|
2049
2091
|
return err(
|
|
2050
2092
|
serviceError(
|
|
2051
2093
|
ErrorCodes.NETWORK_ERROR,
|
|
2052
|
-
`Failed to get key
|
|
2094
|
+
`Failed to get key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
2053
2095
|
"kv",
|
|
2054
2096
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2055
2097
|
)
|
|
@@ -2105,21 +2147,18 @@ var KVService = class extends BaseService {
|
|
|
2105
2147
|
}
|
|
2106
2148
|
);
|
|
2107
2149
|
if (response.status === 401 || response.status === 403) {
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
...requiredAction && { requiredAction },
|
|
2114
|
-
...resource && { resource }
|
|
2115
|
-
}));
|
|
2150
|
+
return this.authorizationFailure(
|
|
2151
|
+
`Failed to put key ${JSON.stringify(key)}`,
|
|
2152
|
+
response,
|
|
2153
|
+
await response.text()
|
|
2154
|
+
);
|
|
2116
2155
|
}
|
|
2117
2156
|
if (!response.ok) {
|
|
2118
2157
|
const errorText = await response.text();
|
|
2119
2158
|
if (response.status === 412) {
|
|
2120
2159
|
return err(serviceError(
|
|
2121
2160
|
ErrorCodes.KV_PRECONDITION_FAILED,
|
|
2122
|
-
`KV precondition failed for key
|
|
2161
|
+
`KV precondition failed for key ${JSON.stringify(key)}`,
|
|
2123
2162
|
"kv",
|
|
2124
2163
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2125
2164
|
));
|
|
@@ -2127,7 +2166,7 @@ var KVService = class extends BaseService {
|
|
|
2127
2166
|
if (response.status === 503 && (options?.ifMatch !== void 0 || options?.ifNoneMatch !== void 0)) {
|
|
2128
2167
|
return err(serviceError(
|
|
2129
2168
|
ErrorCodes.KV_CONFLICT,
|
|
2130
|
-
`Concurrent KV update conflicted for key
|
|
2169
|
+
`Concurrent KV update conflicted for key ${JSON.stringify(key)}`,
|
|
2131
2170
|
"kv",
|
|
2132
2171
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2133
2172
|
));
|
|
@@ -2143,7 +2182,7 @@ var KVService = class extends BaseService {
|
|
|
2143
2182
|
return err(
|
|
2144
2183
|
serviceError(
|
|
2145
2184
|
ErrorCodes.KV_WRITE_FAILED,
|
|
2146
|
-
`Failed to put key
|
|
2185
|
+
`Failed to put key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
2147
2186
|
"kv",
|
|
2148
2187
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2149
2188
|
)
|
|
@@ -2237,12 +2276,11 @@ var KVService = class extends BaseService {
|
|
|
2237
2276
|
);
|
|
2238
2277
|
}
|
|
2239
2278
|
if (response.status === 401 || response.status === 403) {
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
}));
|
|
2279
|
+
return this.authorizationFailure(
|
|
2280
|
+
`Failed to batch put ${items.length} key(s)`,
|
|
2281
|
+
response,
|
|
2282
|
+
errorText
|
|
2283
|
+
);
|
|
2246
2284
|
}
|
|
2247
2285
|
const quotaError = this.handleQuotaErrorResponse(
|
|
2248
2286
|
response,
|
|
@@ -2363,13 +2401,11 @@ var KVService = class extends BaseService {
|
|
|
2363
2401
|
);
|
|
2364
2402
|
if (!response.ok) {
|
|
2365
2403
|
if (response.status === 401) {
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
...resource && { resource }
|
|
2372
|
-
}));
|
|
2404
|
+
return this.authorizationFailure(
|
|
2405
|
+
"Failed to list keys",
|
|
2406
|
+
response,
|
|
2407
|
+
await response.text()
|
|
2408
|
+
);
|
|
2373
2409
|
}
|
|
2374
2410
|
const errorText = await response.text();
|
|
2375
2411
|
return err(
|
|
@@ -2418,13 +2454,11 @@ var KVService = class extends BaseService {
|
|
|
2418
2454
|
);
|
|
2419
2455
|
if (!response.ok) {
|
|
2420
2456
|
if (response.status === 401) {
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
...resource && { resource }
|
|
2427
|
-
}));
|
|
2457
|
+
return this.authorizationFailure(
|
|
2458
|
+
`Failed to delete key ${JSON.stringify(key)}`,
|
|
2459
|
+
response,
|
|
2460
|
+
await response.text()
|
|
2461
|
+
);
|
|
2428
2462
|
}
|
|
2429
2463
|
if (response.status === 404) {
|
|
2430
2464
|
return this.classifyNotFound(response, key);
|
|
@@ -2433,7 +2467,7 @@ var KVService = class extends BaseService {
|
|
|
2433
2467
|
if (response.status === 412) {
|
|
2434
2468
|
return err(serviceError(
|
|
2435
2469
|
ErrorCodes.KV_PRECONDITION_FAILED,
|
|
2436
|
-
`KV precondition failed for key
|
|
2470
|
+
`KV precondition failed for key ${JSON.stringify(key)}`,
|
|
2437
2471
|
"kv",
|
|
2438
2472
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2439
2473
|
));
|
|
@@ -2441,7 +2475,7 @@ var KVService = class extends BaseService {
|
|
|
2441
2475
|
if (response.status === 503 && options?.ifMatch !== void 0) {
|
|
2442
2476
|
return err(serviceError(
|
|
2443
2477
|
ErrorCodes.KV_CONFLICT,
|
|
2444
|
-
`Concurrent KV delete conflicted for key
|
|
2478
|
+
`Concurrent KV delete conflicted for key ${JSON.stringify(key)}`,
|
|
2445
2479
|
"kv",
|
|
2446
2480
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2447
2481
|
));
|
|
@@ -2449,7 +2483,7 @@ var KVService = class extends BaseService {
|
|
|
2449
2483
|
return err(
|
|
2450
2484
|
serviceError(
|
|
2451
2485
|
ErrorCodes.NETWORK_ERROR,
|
|
2452
|
-
`Failed to delete key
|
|
2486
|
+
`Failed to delete key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
2453
2487
|
"kv",
|
|
2454
2488
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2455
2489
|
)
|
|
@@ -2482,13 +2516,11 @@ var KVService = class extends BaseService {
|
|
|
2482
2516
|
);
|
|
2483
2517
|
if (!response.ok) {
|
|
2484
2518
|
if (response.status === 401) {
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
...resource && { resource }
|
|
2491
|
-
}));
|
|
2519
|
+
return this.authorizationFailure(
|
|
2520
|
+
`Failed to get metadata for key ${JSON.stringify(key)}`,
|
|
2521
|
+
response,
|
|
2522
|
+
await response.text()
|
|
2523
|
+
);
|
|
2492
2524
|
}
|
|
2493
2525
|
if (response.status === 404) {
|
|
2494
2526
|
return this.classifyNotFound(response, key);
|
|
@@ -2497,7 +2529,7 @@ var KVService = class extends BaseService {
|
|
|
2497
2529
|
return err(
|
|
2498
2530
|
serviceError(
|
|
2499
2531
|
ErrorCodes.NETWORK_ERROR,
|
|
2500
|
-
`Failed to get metadata for key
|
|
2532
|
+
`Failed to get metadata for key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
2501
2533
|
"kv",
|
|
2502
2534
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2503
2535
|
)
|
|
@@ -2917,21 +2949,24 @@ var SQLService = class extends BaseService {
|
|
|
2917
2949
|
}
|
|
2918
2950
|
async applyMigrationsOnDbUnlocked(dbName, options) {
|
|
2919
2951
|
return this.withTelemetry("migrations.apply", dbName, async () => {
|
|
2920
|
-
const created = await this.ensureMigrationsTable(dbName, options.signal);
|
|
2921
|
-
if (!created.ok) return created;
|
|
2922
2952
|
const listed = await this.queryOnDb(
|
|
2923
2953
|
dbName,
|
|
2924
2954
|
`SELECT id FROM ${MIGRATIONS_TABLE} WHERE namespace = ? ORDER BY applied_at, id`,
|
|
2925
2955
|
[options.namespace],
|
|
2926
2956
|
{ signal: options.signal }
|
|
2927
2957
|
);
|
|
2928
|
-
|
|
2958
|
+
const tableMissing = !listed.ok && (listed.error.code === ErrorCodes.SQL_DATABASE_NOT_FOUND || isMissingTableError(listed.error.message));
|
|
2959
|
+
if (!listed.ok && !tableMissing) return listed;
|
|
2929
2960
|
const appliedIds = new Set(
|
|
2930
|
-
listed.data.rows.map((row) => rowValue(row, 0)).filter((id) => typeof id === "string")
|
|
2961
|
+
(listed.ok ? listed.data.rows : []).map((row) => rowValue(row, 0)).filter((id) => typeof id === "string")
|
|
2931
2962
|
);
|
|
2932
2963
|
const skipped = options.migrations.filter((migration) => appliedIds.has(migration.id)).map((migration) => migration.id);
|
|
2933
2964
|
const pending = options.migrations.filter((migration) => !appliedIds.has(migration.id));
|
|
2934
2965
|
const applied = [];
|
|
2966
|
+
if (pending.length > 0 && tableMissing) {
|
|
2967
|
+
const created = await this.ensureMigrationsTable(dbName, options.signal);
|
|
2968
|
+
if (!created.ok) return created;
|
|
2969
|
+
}
|
|
2935
2970
|
for (const migration of pending) {
|
|
2936
2971
|
const result = await this.applyOneMigration(dbName, options.namespace, migration, options.signal);
|
|
2937
2972
|
if (!result.ok) return result;
|
|
@@ -3034,6 +3069,10 @@ var SQLService = class extends BaseService {
|
|
|
3034
3069
|
}
|
|
3035
3070
|
async handleErrorResponse(response, operation) {
|
|
3036
3071
|
const errorText = await response.text();
|
|
3072
|
+
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
3073
|
+
if (response.status === 402) {
|
|
3074
|
+
return err(storageRejectionError("sql", 402, meta, errorText));
|
|
3075
|
+
}
|
|
3037
3076
|
const errorBody = parseServiceErrorBody(errorText);
|
|
3038
3077
|
const errorCode = this.mapHttpStatusToErrorCode(
|
|
3039
3078
|
response.status,
|
|
@@ -3046,7 +3085,6 @@ var SQLService = class extends BaseService {
|
|
|
3046
3085
|
errorText,
|
|
3047
3086
|
errorBody
|
|
3048
3087
|
);
|
|
3049
|
-
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
3050
3088
|
if (response.status === 401) {
|
|
3051
3089
|
const { resource, action } = parseAuthError(errorText);
|
|
3052
3090
|
if (action) meta.requiredAction = action;
|
|
@@ -3147,6 +3185,9 @@ function serializeSqlValues(values) {
|
|
|
3147
3185
|
(value) => value instanceof Uint8Array ? Array.from(value) : value
|
|
3148
3186
|
);
|
|
3149
3187
|
}
|
|
3188
|
+
function isMissingTableError(message) {
|
|
3189
|
+
return /no such table/i.test(message);
|
|
3190
|
+
}
|
|
3150
3191
|
function migrationKey(namespace, id) {
|
|
3151
3192
|
return `${encodeURIComponent(namespace)}:${encodeURIComponent(id)}`;
|
|
3152
3193
|
}
|
|
@@ -3468,6 +3509,10 @@ var DuckDbService = class extends BaseService {
|
|
|
3468
3509
|
}
|
|
3469
3510
|
async handleErrorResponse(response, operation) {
|
|
3470
3511
|
const errorText = await response.text();
|
|
3512
|
+
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
3513
|
+
if (response.status === 402) {
|
|
3514
|
+
return err(storageRejectionError("duckdb", 402, meta, errorText));
|
|
3515
|
+
}
|
|
3471
3516
|
const errorBody = parseServiceErrorBody(errorText);
|
|
3472
3517
|
const errorCode = this.mapHttpStatusToErrorCode(
|
|
3473
3518
|
response.status,
|
|
@@ -3480,7 +3525,6 @@ var DuckDbService = class extends BaseService {
|
|
|
3480
3525
|
errorText,
|
|
3481
3526
|
errorBody
|
|
3482
3527
|
);
|
|
3483
|
-
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
3484
3528
|
if (response.status === 401) {
|
|
3485
3529
|
const { resource, action } = parseAuthError(errorText);
|
|
3486
3530
|
if (action) meta.requiredAction = action;
|
|
@@ -3979,10 +4023,14 @@ async function responseError(service, message, response) {
|
|
|
3979
4023
|
}
|
|
3980
4024
|
} catch {
|
|
3981
4025
|
}
|
|
3982
|
-
|
|
4026
|
+
const error = wrapError(
|
|
3983
4027
|
service,
|
|
3984
4028
|
new Error(`${message}: ${response.status} ${detail}`)
|
|
3985
4029
|
);
|
|
4030
|
+
return {
|
|
4031
|
+
...error,
|
|
4032
|
+
meta: { ...error.meta, status: response.status, statusText: response.statusText }
|
|
4033
|
+
};
|
|
3986
4034
|
}
|
|
3987
4035
|
function isAbortError(error) {
|
|
3988
4036
|
return error instanceof DOMException && error.name === "AbortError";
|
|
@@ -4448,6 +4496,9 @@ function defaultVaultMessage(input) {
|
|
|
4448
4496
|
return input.message ?? `Public key not found for ${input.did}`;
|
|
4449
4497
|
case "STORAGE_ERROR":
|
|
4450
4498
|
return input.message ?? input.cause.message;
|
|
4499
|
+
case "STORAGE_QUOTA_EXCEEDED":
|
|
4500
|
+
case "STORAGE_LIMIT_REACHED":
|
|
4501
|
+
return input.message;
|
|
4451
4502
|
}
|
|
4452
4503
|
}
|
|
4453
4504
|
function vaultError(input) {
|
|
@@ -4458,6 +4509,15 @@ function vaultError(input) {
|
|
|
4458
4509
|
};
|
|
4459
4510
|
return { ok: false, error };
|
|
4460
4511
|
}
|
|
4512
|
+
function kvWriteError(context, error) {
|
|
4513
|
+
if (error.code === ErrorCodes.STORAGE_QUOTA_EXCEEDED || error.code === ErrorCodes.STORAGE_LIMIT_REACHED) {
|
|
4514
|
+
return vaultError({ code: error.code, message: error.message, meta: error.meta });
|
|
4515
|
+
}
|
|
4516
|
+
return vaultError({
|
|
4517
|
+
code: "STORAGE_ERROR",
|
|
4518
|
+
cause: new Error(`${context}: ${error.message}`)
|
|
4519
|
+
});
|
|
4520
|
+
}
|
|
4461
4521
|
var DataVaultService = class extends BaseService {
|
|
4462
4522
|
/**
|
|
4463
4523
|
* Create a new DataVaultService instance.
|
|
@@ -4740,12 +4800,7 @@ var DataVaultService = class extends BaseService {
|
|
|
4740
4800
|
JSON.stringify(envelopeResult.data)
|
|
4741
4801
|
);
|
|
4742
4802
|
if (!valuePutResult.ok) {
|
|
4743
|
-
return
|
|
4744
|
-
code: "STORAGE_ERROR",
|
|
4745
|
-
cause: new Error(
|
|
4746
|
-
`Failed to store encrypted value: ${valuePutResult.error.message}`
|
|
4747
|
-
)
|
|
4748
|
-
});
|
|
4803
|
+
return kvWriteError("Failed to store encrypted value", valuePutResult.error);
|
|
4749
4804
|
}
|
|
4750
4805
|
return { ok: true, data: void 0 };
|
|
4751
4806
|
} catch (error) {
|
|
@@ -4963,12 +5018,7 @@ var DataVaultService = class extends BaseService {
|
|
|
4963
5018
|
keyPayload
|
|
4964
5019
|
);
|
|
4965
5020
|
if (!keyPutResult.ok) {
|
|
4966
|
-
return
|
|
4967
|
-
code: "STORAGE_ERROR",
|
|
4968
|
-
cause: new Error(
|
|
4969
|
-
`Failed to store key blob: ${keyPutResult.error.message}`
|
|
4970
|
-
)
|
|
4971
|
-
});
|
|
5021
|
+
return kvWriteError("Failed to store key blob", keyPutResult.error);
|
|
4972
5022
|
}
|
|
4973
5023
|
const valuePayload = JSON.stringify({
|
|
4974
5024
|
data: base64Encode(encrypted),
|
|
@@ -4979,12 +5029,7 @@ var DataVaultService = class extends BaseService {
|
|
|
4979
5029
|
valuePayload
|
|
4980
5030
|
);
|
|
4981
5031
|
if (!valuePutResult.ok) {
|
|
4982
|
-
return
|
|
4983
|
-
code: "STORAGE_ERROR",
|
|
4984
|
-
cause: new Error(
|
|
4985
|
-
`Failed to store encrypted value: ${valuePutResult.error.message}`
|
|
4986
|
-
)
|
|
4987
|
-
});
|
|
5032
|
+
return kvWriteError("Failed to store encrypted value", valuePutResult.error);
|
|
4988
5033
|
}
|
|
4989
5034
|
return ok(void 0);
|
|
4990
5035
|
} catch (error) {
|
|
@@ -5315,12 +5360,7 @@ var DataVaultService = class extends BaseService {
|
|
|
5315
5360
|
grantPayload
|
|
5316
5361
|
);
|
|
5317
5362
|
if (!grantPutResult.ok) {
|
|
5318
|
-
return
|
|
5319
|
-
code: "STORAGE_ERROR",
|
|
5320
|
-
cause: new Error(
|
|
5321
|
-
`Failed to store grant: ${grantPutResult.error.message}`
|
|
5322
|
-
)
|
|
5323
|
-
});
|
|
5363
|
+
return kvWriteError("Failed to store grant", grantPutResult.error);
|
|
5324
5364
|
}
|
|
5325
5365
|
return ok(void 0);
|
|
5326
5366
|
} catch (error) {
|
|
@@ -5665,12 +5705,7 @@ var DataVaultService = class extends BaseService {
|
|
|
5665
5705
|
keyPayload
|
|
5666
5706
|
);
|
|
5667
5707
|
if (!keyPutResult.ok) {
|
|
5668
|
-
return
|
|
5669
|
-
code: "STORAGE_ERROR",
|
|
5670
|
-
cause: new Error(
|
|
5671
|
-
`Failed to store rotated key blob: ${keyPutResult.error.message}`
|
|
5672
|
-
)
|
|
5673
|
-
});
|
|
5708
|
+
return kvWriteError("Failed to store rotated key blob", keyPutResult.error);
|
|
5674
5709
|
}
|
|
5675
5710
|
const valuePayload = JSON.stringify({
|
|
5676
5711
|
data: base64Encode(encrypted),
|
|
@@ -5681,12 +5716,7 @@ var DataVaultService = class extends BaseService {
|
|
|
5681
5716
|
valuePayload
|
|
5682
5717
|
);
|
|
5683
5718
|
if (!valuePutResult.ok) {
|
|
5684
|
-
return
|
|
5685
|
-
code: "STORAGE_ERROR",
|
|
5686
|
-
cause: new Error(
|
|
5687
|
-
`Failed to store re-encrypted value: ${valuePutResult.error.message}`
|
|
5688
|
-
)
|
|
5689
|
-
});
|
|
5719
|
+
return kvWriteError("Failed to store re-encrypted value", valuePutResult.error);
|
|
5690
5720
|
}
|
|
5691
5721
|
for (const did of remainingGrantees) {
|
|
5692
5722
|
const grantResult = await this.reencrypt(key, did);
|
|
@@ -7016,6 +7046,8 @@ var import_decrypt_transport_response_error3 = require("@tinycloud/sdk-services/
|
|
|
7016
7046
|
SQLAction,
|
|
7017
7047
|
SQLMigrations,
|
|
7018
7048
|
SQLService,
|
|
7049
|
+
STORAGE_FULL_MESSAGE,
|
|
7050
|
+
STORAGE_WRITE_TOO_LARGE_MESSAGE,
|
|
7019
7051
|
SecretsService,
|
|
7020
7052
|
ServiceContext,
|
|
7021
7053
|
ServiceErrorEventSchema,
|
|
@@ -7034,6 +7066,7 @@ var import_decrypt_transport_response_error3 = require("@tinycloud/sdk-services/
|
|
|
7034
7066
|
authExpiredError,
|
|
7035
7067
|
authRequiredError,
|
|
7036
7068
|
authUnauthorizedError,
|
|
7069
|
+
authorizationVerdictOf,
|
|
7037
7070
|
base64Decode,
|
|
7038
7071
|
base64Encode,
|
|
7039
7072
|
buildCanonicalDecryptRequest,
|
|
@@ -7067,6 +7100,7 @@ var import_decrypt_transport_response_error3 = require("@tinycloud/sdk-services/
|
|
|
7067
7100
|
hexEncode,
|
|
7068
7101
|
installTinyCloudDebugGlobals,
|
|
7069
7102
|
isNetworkId,
|
|
7103
|
+
isStorageFullError,
|
|
7070
7104
|
networkDiscoveryKey,
|
|
7071
7105
|
networkError,
|
|
7072
7106
|
notFoundError,
|
|
@@ -7077,12 +7111,14 @@ var import_decrypt_transport_response_error3 = require("@tinycloud/sdk-services/
|
|
|
7077
7111
|
parsePermissionHint,
|
|
7078
7112
|
parsePermissionHintFromErrorText,
|
|
7079
7113
|
parseSecretCatalogKey,
|
|
7114
|
+
parseStorageQuotaBytes,
|
|
7080
7115
|
permissionDeniedError,
|
|
7081
7116
|
resolveSecretListPrefix,
|
|
7082
7117
|
resolveSecretPath,
|
|
7083
7118
|
serviceError,
|
|
7084
7119
|
storageLimitReachedError,
|
|
7085
7120
|
storageQuotaExceededError,
|
|
7121
|
+
storageRejectionError,
|
|
7086
7122
|
timeoutError,
|
|
7087
7123
|
tinyCloudDebugLogger,
|
|
7088
7124
|
utf8Decode,
|