@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/kv/index.cjs
CHANGED
|
@@ -183,6 +183,20 @@ function storageLimitReachedError(service, message, meta) {
|
|
|
183
183
|
meta
|
|
184
184
|
};
|
|
185
185
|
}
|
|
186
|
+
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.";
|
|
187
|
+
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.";
|
|
188
|
+
function parseStorageQuotaBytes(responseText) {
|
|
189
|
+
const match = responseText.match(/Used:\s*(\d+)\s*bytes,\s*Limit:\s*(\d+)\s*bytes/i);
|
|
190
|
+
if (!match) return void 0;
|
|
191
|
+
return {
|
|
192
|
+
usedBytes: parseInt(match[1], 10),
|
|
193
|
+
limitBytes: parseInt(match[2], 10)
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function storageRejectionError(service, status, meta, responseText) {
|
|
197
|
+
const quotaMeta = { ...meta, ...parseStorageQuotaBytes(responseText) };
|
|
198
|
+
return status === 402 ? storageQuotaExceededError(service, STORAGE_FULL_MESSAGE, quotaMeta) : storageLimitReachedError(service, STORAGE_WRITE_TOO_LARGE_MESSAGE, quotaMeta);
|
|
199
|
+
}
|
|
186
200
|
function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
|
|
187
201
|
if (error instanceof Error) {
|
|
188
202
|
if (error.name === "AbortError") {
|
|
@@ -573,47 +587,21 @@ var KVService = class extends BaseService {
|
|
|
573
587
|
get config() {
|
|
574
588
|
return this._config;
|
|
575
589
|
}
|
|
576
|
-
// Parses "Used: X bytes, Limit: Y bytes" from tinycloud-node error responses
|
|
577
|
-
parseQuotaInfo(errorText) {
|
|
578
|
-
const match = errorText.match(
|
|
579
|
-
/Used:\s*(\d+)\s*bytes,\s*Limit:\s*(\d+)\s*bytes/i
|
|
580
|
-
);
|
|
581
|
-
if (match) {
|
|
582
|
-
return {
|
|
583
|
-
usedBytes: parseInt(match[1], 10),
|
|
584
|
-
limitBytes: parseInt(match[2], 10)
|
|
585
|
-
};
|
|
586
|
-
}
|
|
587
|
-
return void 0;
|
|
588
|
-
}
|
|
589
590
|
handleQuotaErrorResponse(response, errorText, key) {
|
|
590
|
-
if (response.status
|
|
591
|
-
|
|
592
|
-
return err(
|
|
593
|
-
storageQuotaExceededError(
|
|
594
|
-
"kv",
|
|
595
|
-
`Storage quota exceeded for key "${key}": ${errorText}`,
|
|
596
|
-
{
|
|
597
|
-
status: response.status,
|
|
598
|
-
...quotaInfo ? { usedBytes: quotaInfo.usedBytes, limitBytes: quotaInfo.limitBytes } : {}
|
|
599
|
-
}
|
|
600
|
-
)
|
|
601
|
-
);
|
|
591
|
+
if (response.status !== 402 && response.status !== 413) {
|
|
592
|
+
return void 0;
|
|
602
593
|
}
|
|
603
|
-
if (response.status === 413) {
|
|
604
|
-
|
|
605
|
-
return err(
|
|
606
|
-
storageLimitReachedError(
|
|
607
|
-
"kv",
|
|
608
|
-
`Storage limit reached for key "${key}": ${errorText}`,
|
|
609
|
-
{
|
|
610
|
-
status: response.status,
|
|
611
|
-
...quotaInfo ? { usedBytes: quotaInfo.usedBytes, limitBytes: quotaInfo.limitBytes } : {}
|
|
612
|
-
}
|
|
613
|
-
)
|
|
614
|
-
);
|
|
594
|
+
if (response.status === 413 && !parseStorageQuotaBytes(errorText)) {
|
|
595
|
+
return void 0;
|
|
615
596
|
}
|
|
616
|
-
return
|
|
597
|
+
return err(
|
|
598
|
+
storageRejectionError(
|
|
599
|
+
"kv",
|
|
600
|
+
response.status,
|
|
601
|
+
{ status: response.status, statusText: response.statusText, key },
|
|
602
|
+
errorText
|
|
603
|
+
)
|
|
604
|
+
);
|
|
617
605
|
}
|
|
618
606
|
/**
|
|
619
607
|
* Classify a KV 404 by reading the response body once.
|
|
@@ -891,12 +879,11 @@ var KVService = class extends BaseService {
|
|
|
891
879
|
if (!response.ok) {
|
|
892
880
|
const errorText = await response.text();
|
|
893
881
|
if (response.status === 401 || response.status === 403) {
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
}));
|
|
882
|
+
return this.authorizationFailure(
|
|
883
|
+
`Failed to batch read ${keys.length} key(s)`,
|
|
884
|
+
response,
|
|
885
|
+
errorText
|
|
886
|
+
);
|
|
900
887
|
}
|
|
901
888
|
if (response.status === 413) {
|
|
902
889
|
return err(serviceError(
|
|
@@ -995,23 +982,39 @@ var KVService = class extends BaseService {
|
|
|
995
982
|
} catch {
|
|
996
983
|
}
|
|
997
984
|
if (response.status === 401 || response.status === 403) {
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
}));
|
|
985
|
+
return this.authorizationFailure(
|
|
986
|
+
`Failed to create signed read URL for key ${JSON.stringify(key)}`,
|
|
987
|
+
response,
|
|
988
|
+
errorText
|
|
989
|
+
);
|
|
1004
990
|
}
|
|
1005
991
|
const code = response.status === 400 ? ErrorCodes.INVALID_INPUT : ErrorCodes.NETWORK_ERROR;
|
|
1006
992
|
return err(
|
|
1007
993
|
serviceError(
|
|
1008
994
|
code,
|
|
1009
|
-
`Failed to create signed read URL for key
|
|
995
|
+
`Failed to create signed read URL for key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
1010
996
|
"kv",
|
|
1011
997
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
1012
998
|
)
|
|
1013
999
|
);
|
|
1014
1000
|
}
|
|
1001
|
+
/**
|
|
1002
|
+
* AUTH_UNAUTHORIZED for a 401/403 response. The message keeps the HTTP
|
|
1003
|
+
* status and the server text (`<context>: <status> - <text>`, the same
|
|
1004
|
+
* shape as every other KV failure) so callers that rethrow only the message
|
|
1005
|
+
* still see the status; `meta.status` carries it for typed callers.
|
|
1006
|
+
* Resource/ability hints are parsed from the raw body, never the message.
|
|
1007
|
+
*/
|
|
1008
|
+
authorizationFailure(context, response, errorText, extraMeta = {}) {
|
|
1009
|
+
const { resource, action } = parseAuthError(errorText);
|
|
1010
|
+
const detail = errorText.trim().length > 0 ? errorText : response.statusText || "authorization failed";
|
|
1011
|
+
return err(authUnauthorizedError("kv", `${context}: ${response.status} - ${detail}`, {
|
|
1012
|
+
status: response.status,
|
|
1013
|
+
...action && { requiredAction: action },
|
|
1014
|
+
...resource && { resource },
|
|
1015
|
+
...extraMeta
|
|
1016
|
+
}));
|
|
1017
|
+
}
|
|
1015
1018
|
normalizeSignedReadUrlResponse(data) {
|
|
1016
1019
|
if (!data || typeof data !== "object") {
|
|
1017
1020
|
return void 0;
|
|
@@ -1054,14 +1057,13 @@ var KVService = class extends BaseService {
|
|
|
1054
1057
|
if (!response.ok) {
|
|
1055
1058
|
if (response.status === 401 || response.status === 403) {
|
|
1056
1059
|
const errorText2 = await response.text();
|
|
1057
|
-
const { resource, action } = parseAuthError(errorText2);
|
|
1058
1060
|
const permissionHint = parsePermissionHintFromErrorText(errorText2);
|
|
1059
|
-
return
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1061
|
+
return this.authorizationFailure(
|
|
1062
|
+
`Failed to get key ${JSON.stringify(key)}`,
|
|
1063
|
+
response,
|
|
1064
|
+
errorText2,
|
|
1065
|
+
permissionHint === void 0 ? {} : { permissionHint }
|
|
1066
|
+
);
|
|
1065
1067
|
}
|
|
1066
1068
|
if (response.status === 404) {
|
|
1067
1069
|
return this.classifyNotFound(response, key);
|
|
@@ -1070,7 +1072,7 @@ var KVService = class extends BaseService {
|
|
|
1070
1072
|
if (response.status === 413) {
|
|
1071
1073
|
return err(serviceError(
|
|
1072
1074
|
ErrorCodes.KV_RESPONSE_TOO_LARGE,
|
|
1073
|
-
`KV value at key
|
|
1075
|
+
`KV value at key ${JSON.stringify(key)} exceeds the requested response limit`,
|
|
1074
1076
|
"kv",
|
|
1075
1077
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
1076
1078
|
));
|
|
@@ -1078,7 +1080,7 @@ var KVService = class extends BaseService {
|
|
|
1078
1080
|
return err(
|
|
1079
1081
|
serviceError(
|
|
1080
1082
|
ErrorCodes.NETWORK_ERROR,
|
|
1081
|
-
`Failed to get key
|
|
1083
|
+
`Failed to get key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
1082
1084
|
"kv",
|
|
1083
1085
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
1084
1086
|
)
|
|
@@ -1134,21 +1136,18 @@ var KVService = class extends BaseService {
|
|
|
1134
1136
|
}
|
|
1135
1137
|
);
|
|
1136
1138
|
if (response.status === 401 || response.status === 403) {
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
...requiredAction && { requiredAction },
|
|
1143
|
-
...resource && { resource }
|
|
1144
|
-
}));
|
|
1139
|
+
return this.authorizationFailure(
|
|
1140
|
+
`Failed to put key ${JSON.stringify(key)}`,
|
|
1141
|
+
response,
|
|
1142
|
+
await response.text()
|
|
1143
|
+
);
|
|
1145
1144
|
}
|
|
1146
1145
|
if (!response.ok) {
|
|
1147
1146
|
const errorText = await response.text();
|
|
1148
1147
|
if (response.status === 412) {
|
|
1149
1148
|
return err(serviceError(
|
|
1150
1149
|
ErrorCodes.KV_PRECONDITION_FAILED,
|
|
1151
|
-
`KV precondition failed for key
|
|
1150
|
+
`KV precondition failed for key ${JSON.stringify(key)}`,
|
|
1152
1151
|
"kv",
|
|
1153
1152
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
1154
1153
|
));
|
|
@@ -1156,7 +1155,7 @@ var KVService = class extends BaseService {
|
|
|
1156
1155
|
if (response.status === 503 && (options?.ifMatch !== void 0 || options?.ifNoneMatch !== void 0)) {
|
|
1157
1156
|
return err(serviceError(
|
|
1158
1157
|
ErrorCodes.KV_CONFLICT,
|
|
1159
|
-
`Concurrent KV update conflicted for key
|
|
1158
|
+
`Concurrent KV update conflicted for key ${JSON.stringify(key)}`,
|
|
1160
1159
|
"kv",
|
|
1161
1160
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
1162
1161
|
));
|
|
@@ -1172,7 +1171,7 @@ var KVService = class extends BaseService {
|
|
|
1172
1171
|
return err(
|
|
1173
1172
|
serviceError(
|
|
1174
1173
|
ErrorCodes.KV_WRITE_FAILED,
|
|
1175
|
-
`Failed to put key
|
|
1174
|
+
`Failed to put key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
1176
1175
|
"kv",
|
|
1177
1176
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
1178
1177
|
)
|
|
@@ -1266,12 +1265,11 @@ var KVService = class extends BaseService {
|
|
|
1266
1265
|
);
|
|
1267
1266
|
}
|
|
1268
1267
|
if (response.status === 401 || response.status === 403) {
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
}));
|
|
1268
|
+
return this.authorizationFailure(
|
|
1269
|
+
`Failed to batch put ${items.length} key(s)`,
|
|
1270
|
+
response,
|
|
1271
|
+
errorText
|
|
1272
|
+
);
|
|
1275
1273
|
}
|
|
1276
1274
|
const quotaError = this.handleQuotaErrorResponse(
|
|
1277
1275
|
response,
|
|
@@ -1392,13 +1390,11 @@ var KVService = class extends BaseService {
|
|
|
1392
1390
|
);
|
|
1393
1391
|
if (!response.ok) {
|
|
1394
1392
|
if (response.status === 401) {
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
...resource && { resource }
|
|
1401
|
-
}));
|
|
1393
|
+
return this.authorizationFailure(
|
|
1394
|
+
"Failed to list keys",
|
|
1395
|
+
response,
|
|
1396
|
+
await response.text()
|
|
1397
|
+
);
|
|
1402
1398
|
}
|
|
1403
1399
|
const errorText = await response.text();
|
|
1404
1400
|
return err(
|
|
@@ -1447,13 +1443,11 @@ var KVService = class extends BaseService {
|
|
|
1447
1443
|
);
|
|
1448
1444
|
if (!response.ok) {
|
|
1449
1445
|
if (response.status === 401) {
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
...resource && { resource }
|
|
1456
|
-
}));
|
|
1446
|
+
return this.authorizationFailure(
|
|
1447
|
+
`Failed to delete key ${JSON.stringify(key)}`,
|
|
1448
|
+
response,
|
|
1449
|
+
await response.text()
|
|
1450
|
+
);
|
|
1457
1451
|
}
|
|
1458
1452
|
if (response.status === 404) {
|
|
1459
1453
|
return this.classifyNotFound(response, key);
|
|
@@ -1462,7 +1456,7 @@ var KVService = class extends BaseService {
|
|
|
1462
1456
|
if (response.status === 412) {
|
|
1463
1457
|
return err(serviceError(
|
|
1464
1458
|
ErrorCodes.KV_PRECONDITION_FAILED,
|
|
1465
|
-
`KV precondition failed for key
|
|
1459
|
+
`KV precondition failed for key ${JSON.stringify(key)}`,
|
|
1466
1460
|
"kv",
|
|
1467
1461
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
1468
1462
|
));
|
|
@@ -1470,7 +1464,7 @@ var KVService = class extends BaseService {
|
|
|
1470
1464
|
if (response.status === 503 && options?.ifMatch !== void 0) {
|
|
1471
1465
|
return err(serviceError(
|
|
1472
1466
|
ErrorCodes.KV_CONFLICT,
|
|
1473
|
-
`Concurrent KV delete conflicted for key
|
|
1467
|
+
`Concurrent KV delete conflicted for key ${JSON.stringify(key)}`,
|
|
1474
1468
|
"kv",
|
|
1475
1469
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
1476
1470
|
));
|
|
@@ -1478,7 +1472,7 @@ var KVService = class extends BaseService {
|
|
|
1478
1472
|
return err(
|
|
1479
1473
|
serviceError(
|
|
1480
1474
|
ErrorCodes.NETWORK_ERROR,
|
|
1481
|
-
`Failed to delete key
|
|
1475
|
+
`Failed to delete key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
1482
1476
|
"kv",
|
|
1483
1477
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
1484
1478
|
)
|
|
@@ -1511,13 +1505,11 @@ var KVService = class extends BaseService {
|
|
|
1511
1505
|
);
|
|
1512
1506
|
if (!response.ok) {
|
|
1513
1507
|
if (response.status === 401) {
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
...resource && { resource }
|
|
1520
|
-
}));
|
|
1508
|
+
return this.authorizationFailure(
|
|
1509
|
+
`Failed to get metadata for key ${JSON.stringify(key)}`,
|
|
1510
|
+
response,
|
|
1511
|
+
await response.text()
|
|
1512
|
+
);
|
|
1521
1513
|
}
|
|
1522
1514
|
if (response.status === 404) {
|
|
1523
1515
|
return this.classifyNotFound(response, key);
|
|
@@ -1526,7 +1518,7 @@ var KVService = class extends BaseService {
|
|
|
1526
1518
|
return err(
|
|
1527
1519
|
serviceError(
|
|
1528
1520
|
ErrorCodes.NETWORK_ERROR,
|
|
1529
|
-
`Failed to get metadata for key
|
|
1521
|
+
`Failed to get metadata for key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
|
|
1530
1522
|
"kv",
|
|
1531
1523
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
1532
1524
|
)
|