@tinycloud/sdk-services 3.1.0-beta.1 → 3.1.0-beta.6
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 +106 -97
- package/dist/encryption/index.cjs.map +1 -1
- package/dist/encryption/index.js +106 -97
- package/dist/encryption/index.js.map +1 -1
- package/dist/index.cjs +344 -227
- 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 +319 -209
- package/dist/index.js.map +1 -1
- package/dist/kv/index.cjs +236 -58
- package/dist/kv/index.cjs.map +1 -1
- package/dist/kv/index.d.cts +5 -2
- package/dist/kv/index.d.ts +5 -2
- package/dist/kv/index.js +236 -58
- package/dist/kv/index.js.map +1 -1
- package/dist/sql/index.cjs +77 -26
- package/dist/sql/index.cjs.map +1 -1
- package/dist/sql/index.js +68 -17
- package/dist/sql/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -896,6 +896,106 @@ var ServiceContext = class {
|
|
|
896
896
|
}
|
|
897
897
|
};
|
|
898
898
|
|
|
899
|
+
// src/errors.ts
|
|
900
|
+
import { CAPABILITY_REGISTRY } from "@tinycloud/bootstrap";
|
|
901
|
+
|
|
902
|
+
// src/encryption/networkId.ts
|
|
903
|
+
var URN_PREFIX = "urn:tinycloud:encryption:";
|
|
904
|
+
var NETWORK_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
905
|
+
var PKH_EIP155_DID_RE = /^did:pkh:eip155:(\d+):(0x[a-fA-F0-9]{40})$/;
|
|
906
|
+
var NetworkIdError = class extends Error {
|
|
907
|
+
constructor(message) {
|
|
908
|
+
super(message);
|
|
909
|
+
this.name = "NetworkIdError";
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
function parseNetworkId(networkId) {
|
|
913
|
+
if (typeof networkId !== "string" || networkId.length === 0) {
|
|
914
|
+
throw new NetworkIdError("networkId must be a non-empty string");
|
|
915
|
+
}
|
|
916
|
+
if (!networkId.startsWith(URN_PREFIX)) {
|
|
917
|
+
throw new NetworkIdError(
|
|
918
|
+
`networkId must start with ${URN_PREFIX} (got ${JSON.stringify(networkId)})`
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
const body = networkId.slice(URN_PREFIX.length);
|
|
922
|
+
const lastColon = body.lastIndexOf(":");
|
|
923
|
+
if (lastColon <= 0 || lastColon === body.length - 1) {
|
|
924
|
+
throw new NetworkIdError(
|
|
925
|
+
`networkId missing ownerDid or name segment (got ${JSON.stringify(networkId)})`
|
|
926
|
+
);
|
|
927
|
+
}
|
|
928
|
+
const ownerDid = body.slice(0, lastColon);
|
|
929
|
+
const name = body.slice(lastColon + 1);
|
|
930
|
+
if (!ownerDid.startsWith("did:")) {
|
|
931
|
+
throw new NetworkIdError(
|
|
932
|
+
`networkId ownerDid must be a DID (got ${JSON.stringify(ownerDid)})`
|
|
933
|
+
);
|
|
934
|
+
}
|
|
935
|
+
const didParts = ownerDid.split(":");
|
|
936
|
+
if (didParts.length < 3 || didParts.some((p) => p.length === 0)) {
|
|
937
|
+
throw new NetworkIdError(
|
|
938
|
+
`networkId ownerDid is not a well-formed DID (got ${JSON.stringify(ownerDid)})`
|
|
939
|
+
);
|
|
940
|
+
}
|
|
941
|
+
if (!NETWORK_NAME_RE.test(name)) {
|
|
942
|
+
throw new NetworkIdError(
|
|
943
|
+
`networkId name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
944
|
+
);
|
|
945
|
+
}
|
|
946
|
+
return { networkId, ownerDid, name };
|
|
947
|
+
}
|
|
948
|
+
function buildNetworkId(ownerDid, name) {
|
|
949
|
+
if (typeof ownerDid !== "string" || !ownerDid.startsWith("did:")) {
|
|
950
|
+
throw new NetworkIdError("ownerDid must be a DID");
|
|
951
|
+
}
|
|
952
|
+
if (typeof name !== "string" || !NETWORK_NAME_RE.test(name)) {
|
|
953
|
+
throw new NetworkIdError(
|
|
954
|
+
`network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
955
|
+
);
|
|
956
|
+
}
|
|
957
|
+
const networkId = `${URN_PREFIX}${ownerDid}:${name}`;
|
|
958
|
+
parseNetworkId(networkId);
|
|
959
|
+
return networkId;
|
|
960
|
+
}
|
|
961
|
+
function isNetworkId(networkId) {
|
|
962
|
+
if (typeof networkId !== "string") {
|
|
963
|
+
return false;
|
|
964
|
+
}
|
|
965
|
+
try {
|
|
966
|
+
parseNetworkId(networkId);
|
|
967
|
+
return true;
|
|
968
|
+
} catch {
|
|
969
|
+
return false;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
function parsePkhOwnerDid(ownerDid) {
|
|
973
|
+
const match = ownerDid.match(PKH_EIP155_DID_RE);
|
|
974
|
+
if (!match) return null;
|
|
975
|
+
return {
|
|
976
|
+
chainId: match[1],
|
|
977
|
+
address: match[2].toLowerCase()
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
function ownerDidMatches(a, b) {
|
|
981
|
+
const aPkh = parsePkhOwnerDid(a);
|
|
982
|
+
const bPkh = parsePkhOwnerDid(b);
|
|
983
|
+
if (aPkh && bPkh) {
|
|
984
|
+
return aPkh.chainId === bPkh.chainId && aPkh.address === bPkh.address;
|
|
985
|
+
}
|
|
986
|
+
return a === b;
|
|
987
|
+
}
|
|
988
|
+
function networkDiscoveryKey(name) {
|
|
989
|
+
if (!NETWORK_NAME_RE.test(name)) {
|
|
990
|
+
throw new NetworkIdError(
|
|
991
|
+
`network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
return `.well-known/encryption/network/${name}`;
|
|
995
|
+
}
|
|
996
|
+
var ENCRYPTION_NETWORK_URN_PREFIX = URN_PREFIX;
|
|
997
|
+
var NETWORK_NAME_PATTERN = NETWORK_NAME_RE;
|
|
998
|
+
|
|
899
999
|
// src/errors.ts
|
|
900
1000
|
function parsePermissionHint(value) {
|
|
901
1001
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
@@ -993,6 +1093,70 @@ function parseAuthError(responseText) {
|
|
|
993
1093
|
function authUnauthorizedError(service, message, meta) {
|
|
994
1094
|
return serviceError(ErrorCodes.AUTH_UNAUTHORIZED, message, service, { meta });
|
|
995
1095
|
}
|
|
1096
|
+
var grantableActions = new Set(
|
|
1097
|
+
CAPABILITY_REGISTRY.map(({ urn }) => urn).filter((urn) => !urn.endsWith("/*"))
|
|
1098
|
+
);
|
|
1099
|
+
var capabilityServices = new Set(
|
|
1100
|
+
CAPABILITY_REGISTRY.map(({ service }) => service.slice("tinycloud.".length))
|
|
1101
|
+
);
|
|
1102
|
+
function parseCapabilityResource(resource, service) {
|
|
1103
|
+
if (resource.length === 0 || resource.length > 1024 || !capabilityServices.has(service) || /[\s\p{C}*#]/u.test(resource) || resource.includes("://")) return void 0;
|
|
1104
|
+
const segments = resource.split("/");
|
|
1105
|
+
if (!/^tinycloud:[A-Za-z0-9][A-Za-z0-9:._-]*$/.test(segments[0])) return void 0;
|
|
1106
|
+
const serviceIndex = segments.findIndex(
|
|
1107
|
+
(segment, index) => index > 0 && capabilityServices.has(segment)
|
|
1108
|
+
);
|
|
1109
|
+
if (serviceIndex < 1 || segments[serviceIndex] !== service) return void 0;
|
|
1110
|
+
if (segments.slice(1, serviceIndex).some(
|
|
1111
|
+
(segment) => segment.length === 0 || segment === "." || segment === ".."
|
|
1112
|
+
)) return void 0;
|
|
1113
|
+
const pathSegments = segments.slice(serviceIndex + 1);
|
|
1114
|
+
if (pathSegments.some((segment) => segment === "." || segment === "..")) return void 0;
|
|
1115
|
+
if (service !== "kv" && (pathSegments.length === 0 || pathSegments[pathSegments.length - 1] === "")) return void 0;
|
|
1116
|
+
return {
|
|
1117
|
+
space: segments.slice(0, serviceIndex).join("/"),
|
|
1118
|
+
path: pathSegments.join("/")
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
function safeCapabilityResource(value, service, action) {
|
|
1122
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 1024) return false;
|
|
1123
|
+
if (service === "encryption" && value.startsWith("urn:tinycloud:encryption:")) {
|
|
1124
|
+
if (!/^[A-Za-z0-9_][A-Za-z0-9_.:/-]*$/.test(value) || value.includes("//") || value.split("/").some((segment) => segment === "." || segment === "..")) return false;
|
|
1125
|
+
try {
|
|
1126
|
+
parseNetworkId(value);
|
|
1127
|
+
return true;
|
|
1128
|
+
} catch {
|
|
1129
|
+
return false;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
const parsed = parseCapabilityResource(value, service);
|
|
1133
|
+
return parsed !== void 0 && (!parsed.path.endsWith("/") || service === "kv" && action === "tinycloud.kv/list") && (parsed.path !== "" || service === "kv" && action === "tinycloud.kv/list");
|
|
1134
|
+
}
|
|
1135
|
+
function validatedCapabilityOf(error) {
|
|
1136
|
+
const verdict = authorizationVerdictOf(error);
|
|
1137
|
+
if (verdict !== "unauthenticated" && verdict !== "forbidden") return void 0;
|
|
1138
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1139
|
+
let node = error;
|
|
1140
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH && typeof node === "object" && node !== null && !seen.has(node); depth += 1) {
|
|
1141
|
+
seen.add(node);
|
|
1142
|
+
const record = node;
|
|
1143
|
+
const status = errorStatusOf(record);
|
|
1144
|
+
const meta = record.meta;
|
|
1145
|
+
if ((status === 401 || status === 403 || status === void 0 && record.code === ErrorCodes.AUTH_UNAUTHORIZED) && typeof meta === "object" && meta !== null && !Array.isArray(meta)) {
|
|
1146
|
+
const metadata = meta;
|
|
1147
|
+
const { resource, requiredAction } = metadata;
|
|
1148
|
+
if (typeof requiredAction === "string" && grantableActions.has(requiredAction)) {
|
|
1149
|
+
const actionService = requiredAction.slice("tinycloud.".length, requiredAction.indexOf("/"));
|
|
1150
|
+
const explicitService = record.service === void 0 ? metadata.service : record.service;
|
|
1151
|
+
if (safeCapabilityResource(resource, actionService, requiredAction) && (explicitService === void 0 || explicitService === actionService || explicitService === `tinycloud.${actionService}`)) {
|
|
1152
|
+
return { resource, requiredAction };
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
node = record.cause;
|
|
1157
|
+
}
|
|
1158
|
+
return void 0;
|
|
1159
|
+
}
|
|
996
1160
|
var MAX_CAUSE_DEPTH = 8;
|
|
997
1161
|
function errorStatusOf(node) {
|
|
998
1162
|
const meta = node.meta;
|
|
@@ -1040,6 +1204,23 @@ function storageLimitReachedError(service, message, meta) {
|
|
|
1040
1204
|
meta
|
|
1041
1205
|
};
|
|
1042
1206
|
}
|
|
1207
|
+
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.";
|
|
1208
|
+
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.";
|
|
1209
|
+
function parseStorageQuotaBytes(responseText) {
|
|
1210
|
+
const match = responseText.match(/Used:\s*(\d+)\s*bytes,\s*Limit:\s*(\d+)\s*bytes/i);
|
|
1211
|
+
if (!match) return void 0;
|
|
1212
|
+
return {
|
|
1213
|
+
usedBytes: parseInt(match[1], 10),
|
|
1214
|
+
limitBytes: parseInt(match[2], 10)
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
function storageRejectionError(service, status, meta, responseText) {
|
|
1218
|
+
const quotaMeta = { ...meta, ...parseStorageQuotaBytes(responseText) };
|
|
1219
|
+
return status === 402 ? storageQuotaExceededError(service, STORAGE_FULL_MESSAGE, quotaMeta) : storageLimitReachedError(service, STORAGE_WRITE_TOO_LARGE_MESSAGE, quotaMeta);
|
|
1220
|
+
}
|
|
1221
|
+
function isStorageFullError(error) {
|
|
1222
|
+
return error?.code === ErrorCodes.STORAGE_QUOTA_EXCEEDED || error?.code === ErrorCodes.STORAGE_LIMIT_REACHED;
|
|
1223
|
+
}
|
|
1043
1224
|
function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
|
|
1044
1225
|
if (error instanceof Error) {
|
|
1045
1226
|
if (error.name === "AbortError") {
|
|
@@ -1433,47 +1614,21 @@ var KVService = class extends BaseService {
|
|
|
1433
1614
|
get config() {
|
|
1434
1615
|
return this._config;
|
|
1435
1616
|
}
|
|
1436
|
-
// Parses "Used: X bytes, Limit: Y bytes" from tinycloud-node error responses
|
|
1437
|
-
parseQuotaInfo(errorText) {
|
|
1438
|
-
const match = errorText.match(
|
|
1439
|
-
/Used:\s*(\d+)\s*bytes,\s*Limit:\s*(\d+)\s*bytes/i
|
|
1440
|
-
);
|
|
1441
|
-
if (match) {
|
|
1442
|
-
return {
|
|
1443
|
-
usedBytes: parseInt(match[1], 10),
|
|
1444
|
-
limitBytes: parseInt(match[2], 10)
|
|
1445
|
-
};
|
|
1446
|
-
}
|
|
1447
|
-
return void 0;
|
|
1448
|
-
}
|
|
1449
1617
|
handleQuotaErrorResponse(response, errorText, key) {
|
|
1450
|
-
if (response.status
|
|
1451
|
-
|
|
1452
|
-
return err(
|
|
1453
|
-
storageQuotaExceededError(
|
|
1454
|
-
"kv",
|
|
1455
|
-
`Storage quota exceeded for key ${JSON.stringify(key)}: ${errorText}`,
|
|
1456
|
-
{
|
|
1457
|
-
status: response.status,
|
|
1458
|
-
...quotaInfo ? { usedBytes: quotaInfo.usedBytes, limitBytes: quotaInfo.limitBytes } : {}
|
|
1459
|
-
}
|
|
1460
|
-
)
|
|
1461
|
-
);
|
|
1618
|
+
if (response.status !== 402 && response.status !== 413) {
|
|
1619
|
+
return void 0;
|
|
1462
1620
|
}
|
|
1463
|
-
if (response.status === 413) {
|
|
1464
|
-
|
|
1465
|
-
return err(
|
|
1466
|
-
storageLimitReachedError(
|
|
1467
|
-
"kv",
|
|
1468
|
-
`Storage limit reached for key ${JSON.stringify(key)}: ${errorText}`,
|
|
1469
|
-
{
|
|
1470
|
-
status: response.status,
|
|
1471
|
-
...quotaInfo ? { usedBytes: quotaInfo.usedBytes, limitBytes: quotaInfo.limitBytes } : {}
|
|
1472
|
-
}
|
|
1473
|
-
)
|
|
1474
|
-
);
|
|
1621
|
+
if (response.status === 413 && !parseStorageQuotaBytes(errorText)) {
|
|
1622
|
+
return void 0;
|
|
1475
1623
|
}
|
|
1476
|
-
return
|
|
1624
|
+
return err(
|
|
1625
|
+
storageRejectionError(
|
|
1626
|
+
"kv",
|
|
1627
|
+
response.status,
|
|
1628
|
+
{ status: response.status, statusText: response.statusText, key },
|
|
1629
|
+
errorText
|
|
1630
|
+
)
|
|
1631
|
+
);
|
|
1477
1632
|
}
|
|
1478
1633
|
/**
|
|
1479
1634
|
* Classify a KV 404 by reading the response body once.
|
|
@@ -1749,12 +1904,14 @@ var KVService = class extends BaseService {
|
|
|
1749
1904
|
signal: this.combineSignals(options?.signal)
|
|
1750
1905
|
});
|
|
1751
1906
|
if (!response.ok) {
|
|
1752
|
-
const errorText = await response.text();
|
|
1907
|
+
const errorText = response.status === 401 || response.status === 403 ? await this.readAuthorizationText(response) : await response.text();
|
|
1753
1908
|
if (response.status === 401 || response.status === 403) {
|
|
1754
1909
|
return this.authorizationFailure(
|
|
1755
1910
|
`Failed to batch read ${keys.length} key(s)`,
|
|
1756
1911
|
response,
|
|
1757
|
-
errorText
|
|
1912
|
+
errorText,
|
|
1913
|
+
paths,
|
|
1914
|
+
action
|
|
1758
1915
|
);
|
|
1759
1916
|
}
|
|
1760
1917
|
if (response.status === 413) {
|
|
@@ -1844,7 +2001,7 @@ var KVService = class extends BaseService {
|
|
|
1844
2001
|
return text;
|
|
1845
2002
|
}
|
|
1846
2003
|
}
|
|
1847
|
-
async createSignedReadUrlError(response, key) {
|
|
2004
|
+
async createSignedReadUrlError(response, key, path) {
|
|
1848
2005
|
let errorText = response.statusText;
|
|
1849
2006
|
try {
|
|
1850
2007
|
const text = await response.text();
|
|
@@ -1857,7 +2014,9 @@ var KVService = class extends BaseService {
|
|
|
1857
2014
|
return this.authorizationFailure(
|
|
1858
2015
|
`Failed to create signed read URL for key ${JSON.stringify(key)}`,
|
|
1859
2016
|
response,
|
|
1860
|
-
errorText
|
|
2017
|
+
errorText,
|
|
2018
|
+
[path],
|
|
2019
|
+
KVAction.GET
|
|
1861
2020
|
);
|
|
1862
2021
|
}
|
|
1863
2022
|
const code = response.status === 400 ? ErrorCodes.INVALID_INPUT : ErrorCodes.NETWORK_ERROR;
|
|
@@ -1870,21 +2029,42 @@ var KVService = class extends BaseService {
|
|
|
1870
2029
|
)
|
|
1871
2030
|
);
|
|
1872
2031
|
}
|
|
2032
|
+
/** A known 401/403 keeps its typed status even if reading its body fails. */
|
|
2033
|
+
async readAuthorizationText(response) {
|
|
2034
|
+
try {
|
|
2035
|
+
return await response.text();
|
|
2036
|
+
} catch {
|
|
2037
|
+
return "";
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
1873
2040
|
/**
|
|
1874
2041
|
* AUTH_UNAUTHORIZED for a 401/403 response. The message keeps the HTTP
|
|
1875
2042
|
* status and the server text (`<context>: <status> - <text>`, the same
|
|
1876
2043
|
* shape as every other KV failure) so callers that rethrow only the message
|
|
1877
2044
|
* still see the status; `meta.status` carries it for typed callers.
|
|
1878
|
-
*
|
|
2045
|
+
* Server hints must match the requested path/action (whether the node sends
|
|
2046
|
+
* a relative path or full resource); metadata uses only the request-derived
|
|
2047
|
+
* canonical resource under the authenticated session's space.
|
|
1879
2048
|
*/
|
|
1880
|
-
authorizationFailure(context, response, errorText, extraMeta = {}) {
|
|
2049
|
+
authorizationFailure(context, response, errorText, paths, expectedAction, extraMeta = {}) {
|
|
1881
2050
|
const { resource, action } = parseAuthError(errorText);
|
|
2051
|
+
const requestedPath = paths.find(
|
|
2052
|
+
(path) => resource === path || resource === `${this.context.session.spaceId}/kv/${path}`
|
|
2053
|
+
);
|
|
2054
|
+
const capability = requestedPath !== void 0 && action === expectedAction ? validatedCapabilityOf({
|
|
2055
|
+
service: "kv",
|
|
2056
|
+
code: ErrorCodes.AUTH_UNAUTHORIZED,
|
|
2057
|
+
meta: {
|
|
2058
|
+
status: response.status,
|
|
2059
|
+
resource: `${this.context.session.spaceId}/kv/${requestedPath}`,
|
|
2060
|
+
requiredAction: action
|
|
2061
|
+
}
|
|
2062
|
+
}) : void 0;
|
|
1882
2063
|
const detail = errorText.trim().length > 0 ? errorText : response.statusText || "authorization failed";
|
|
1883
2064
|
return err(authUnauthorizedError("kv", `${context}: ${response.status} - ${detail}`, {
|
|
1884
2065
|
status: response.status,
|
|
1885
|
-
...
|
|
1886
|
-
...
|
|
1887
|
-
...extraMeta
|
|
2066
|
+
...extraMeta,
|
|
2067
|
+
...capability
|
|
1888
2068
|
}));
|
|
1889
2069
|
}
|
|
1890
2070
|
normalizeSignedReadUrlResponse(data) {
|
|
@@ -1928,13 +2108,24 @@ var KVService = class extends BaseService {
|
|
|
1928
2108
|
);
|
|
1929
2109
|
if (!response.ok) {
|
|
1930
2110
|
if (response.status === 401 || response.status === 403) {
|
|
1931
|
-
const errorText2 = await
|
|
2111
|
+
const errorText2 = await this.readAuthorizationText(response);
|
|
1932
2112
|
const permissionHint = parsePermissionHintFromErrorText(errorText2);
|
|
2113
|
+
const structuredCapability = permissionHint?.service === "tinycloud.kv" && permissionHint.space === this.context.session.spaceId && permissionHint.path === path ? validatedCapabilityOf({
|
|
2114
|
+
service: "kv",
|
|
2115
|
+
code: ErrorCodes.AUTH_UNAUTHORIZED,
|
|
2116
|
+
meta: {
|
|
2117
|
+
status: response.status,
|
|
2118
|
+
resource: `${this.context.session.spaceId}/kv/${path}`,
|
|
2119
|
+
requiredAction: KVAction.GET
|
|
2120
|
+
}
|
|
2121
|
+
}) : void 0;
|
|
1933
2122
|
return this.authorizationFailure(
|
|
1934
2123
|
`Failed to get key ${JSON.stringify(key)}`,
|
|
1935
2124
|
response,
|
|
1936
2125
|
errorText2,
|
|
1937
|
-
|
|
2126
|
+
[path],
|
|
2127
|
+
KVAction.GET,
|
|
2128
|
+
structuredCapability ? { permissionHint, ...structuredCapability } : {}
|
|
1938
2129
|
);
|
|
1939
2130
|
}
|
|
1940
2131
|
if (response.status === 404) {
|
|
@@ -2011,7 +2202,9 @@ var KVService = class extends BaseService {
|
|
|
2011
2202
|
return this.authorizationFailure(
|
|
2012
2203
|
`Failed to put key ${JSON.stringify(key)}`,
|
|
2013
2204
|
response,
|
|
2014
|
-
await
|
|
2205
|
+
await this.readAuthorizationText(response),
|
|
2206
|
+
[path],
|
|
2207
|
+
KVAction.PUT
|
|
2015
2208
|
);
|
|
2016
2209
|
}
|
|
2017
2210
|
if (!response.ok) {
|
|
@@ -2140,7 +2333,9 @@ var KVService = class extends BaseService {
|
|
|
2140
2333
|
return this.authorizationFailure(
|
|
2141
2334
|
`Failed to batch put ${items.length} key(s)`,
|
|
2142
2335
|
response,
|
|
2143
|
-
errorText
|
|
2336
|
+
errorText,
|
|
2337
|
+
paths,
|
|
2338
|
+
KVAction.PUT
|
|
2144
2339
|
);
|
|
2145
2340
|
}
|
|
2146
2341
|
const quotaError = this.handleQuotaErrorResponse(
|
|
@@ -2261,11 +2456,13 @@ var KVService = class extends BaseService {
|
|
|
2261
2456
|
}
|
|
2262
2457
|
);
|
|
2263
2458
|
if (!response.ok) {
|
|
2264
|
-
if (response.status === 401) {
|
|
2459
|
+
if (response.status === 401 || response.status === 403) {
|
|
2265
2460
|
return this.authorizationFailure(
|
|
2266
2461
|
"Failed to list keys",
|
|
2267
2462
|
response,
|
|
2268
|
-
await
|
|
2463
|
+
await this.readAuthorizationText(response),
|
|
2464
|
+
[listPath],
|
|
2465
|
+
KVAction.LIST
|
|
2269
2466
|
);
|
|
2270
2467
|
}
|
|
2271
2468
|
const errorText = await response.text();
|
|
@@ -2314,11 +2511,13 @@ var KVService = class extends BaseService {
|
|
|
2314
2511
|
options?.ifMatch === void 0 ? void 0 : { "if-match": options.ifMatch }
|
|
2315
2512
|
);
|
|
2316
2513
|
if (!response.ok) {
|
|
2317
|
-
if (response.status === 401) {
|
|
2514
|
+
if (response.status === 401 || response.status === 403) {
|
|
2318
2515
|
return this.authorizationFailure(
|
|
2319
2516
|
`Failed to delete key ${JSON.stringify(key)}`,
|
|
2320
2517
|
response,
|
|
2321
|
-
await
|
|
2518
|
+
await this.readAuthorizationText(response),
|
|
2519
|
+
[path],
|
|
2520
|
+
KVAction.DELETE
|
|
2322
2521
|
);
|
|
2323
2522
|
}
|
|
2324
2523
|
if (response.status === 404) {
|
|
@@ -2376,11 +2575,13 @@ var KVService = class extends BaseService {
|
|
|
2376
2575
|
options?.signal
|
|
2377
2576
|
);
|
|
2378
2577
|
if (!response.ok) {
|
|
2379
|
-
if (response.status === 401) {
|
|
2578
|
+
if (response.status === 401 || response.status === 403) {
|
|
2380
2579
|
return this.authorizationFailure(
|
|
2381
2580
|
`Failed to get metadata for key ${JSON.stringify(key)}`,
|
|
2382
2581
|
response,
|
|
2383
|
-
await
|
|
2582
|
+
await this.readAuthorizationText(response),
|
|
2583
|
+
[path],
|
|
2584
|
+
KVAction.HEAD
|
|
2384
2585
|
);
|
|
2385
2586
|
}
|
|
2386
2587
|
if (response.status === 404) {
|
|
@@ -2447,7 +2648,7 @@ var KVService = class extends BaseService {
|
|
|
2447
2648
|
signal: this.combineSignals(options?.signal)
|
|
2448
2649
|
});
|
|
2449
2650
|
if (!response.ok) {
|
|
2450
|
-
return this.createSignedReadUrlError(response, key);
|
|
2651
|
+
return this.createSignedReadUrlError(response, key, path);
|
|
2451
2652
|
}
|
|
2452
2653
|
const signedUrl = this.normalizeSignedReadUrlResponse(
|
|
2453
2654
|
await response.json()
|
|
@@ -2685,14 +2886,15 @@ var SQLService = class extends BaseService {
|
|
|
2685
2886
|
};
|
|
2686
2887
|
if (options?.maxRows !== void 0) body.maxRows = options.maxRows;
|
|
2687
2888
|
if (options?.maxBytes !== void 0) body.maxBytes = options.maxBytes;
|
|
2889
|
+
const action = this.actionForSql(sql, SQLAction.READ);
|
|
2688
2890
|
const response = await this.invokeSQL(
|
|
2689
2891
|
dbName,
|
|
2690
|
-
|
|
2892
|
+
action,
|
|
2691
2893
|
body,
|
|
2692
2894
|
options?.signal
|
|
2693
2895
|
);
|
|
2694
2896
|
if (!response.ok) {
|
|
2695
|
-
return this.handleErrorResponse(response, "query");
|
|
2897
|
+
return this.handleErrorResponse(response, "query", dbName, [action]);
|
|
2696
2898
|
}
|
|
2697
2899
|
const data = await response.json();
|
|
2698
2900
|
return ok(data);
|
|
@@ -2721,14 +2923,15 @@ var SQLService = class extends BaseService {
|
|
|
2721
2923
|
(statement) => this.actionForSql(statement, SQLAction.SCHEMA)
|
|
2722
2924
|
)
|
|
2723
2925
|
];
|
|
2926
|
+
const requestedActions = this.dedupeActions(actions);
|
|
2724
2927
|
const response = await this.invokeSQL(
|
|
2725
2928
|
dbName,
|
|
2726
|
-
|
|
2929
|
+
requestedActions,
|
|
2727
2930
|
body,
|
|
2728
2931
|
options?.signal
|
|
2729
2932
|
);
|
|
2730
2933
|
if (!response.ok) {
|
|
2731
|
-
return this.handleErrorResponse(response, "execute");
|
|
2934
|
+
return this.handleErrorResponse(response, "execute", dbName, requestedActions);
|
|
2732
2935
|
}
|
|
2733
2936
|
const data = await response.json();
|
|
2734
2937
|
return ok(data);
|
|
@@ -2743,14 +2946,15 @@ var SQLService = class extends BaseService {
|
|
|
2743
2946
|
return err(authRequiredError("sql"));
|
|
2744
2947
|
}
|
|
2745
2948
|
try {
|
|
2949
|
+
const requestedActions = this.actionsForSqlBatch(statements);
|
|
2746
2950
|
const response = await this.invokeSQL(
|
|
2747
2951
|
dbName,
|
|
2748
|
-
|
|
2952
|
+
requestedActions,
|
|
2749
2953
|
{ action: "batch", statements },
|
|
2750
2954
|
options?.signal
|
|
2751
2955
|
);
|
|
2752
2956
|
if (!response.ok) {
|
|
2753
|
-
return this.handleErrorResponse(response, "batch");
|
|
2957
|
+
return this.handleErrorResponse(response, "batch", dbName, requestedActions);
|
|
2754
2958
|
}
|
|
2755
2959
|
const data = await response.json();
|
|
2756
2960
|
return ok(data);
|
|
@@ -2772,7 +2976,7 @@ var SQLService = class extends BaseService {
|
|
|
2772
2976
|
options?.signal
|
|
2773
2977
|
);
|
|
2774
2978
|
if (!response.ok) {
|
|
2775
|
-
return this.handleErrorResponse(response, "executeStatement");
|
|
2979
|
+
return this.handleErrorResponse(response, "executeStatement", dbName, [SQLAction.WRITE]);
|
|
2776
2980
|
}
|
|
2777
2981
|
const data = await response.json();
|
|
2778
2982
|
return ok(data);
|
|
@@ -2794,7 +2998,7 @@ var SQLService = class extends BaseService {
|
|
|
2794
2998
|
options?.signal
|
|
2795
2999
|
);
|
|
2796
3000
|
if (!response.ok) {
|
|
2797
|
-
return this.handleErrorResponse(response, "export");
|
|
3001
|
+
return this.handleErrorResponse(response, "export", dbName, [SQLAction.READ]);
|
|
2798
3002
|
}
|
|
2799
3003
|
const resp = response;
|
|
2800
3004
|
if (typeof resp.blob === "function") {
|
|
@@ -2810,21 +3014,24 @@ var SQLService = class extends BaseService {
|
|
|
2810
3014
|
}
|
|
2811
3015
|
async applyMigrationsOnDbUnlocked(dbName, options) {
|
|
2812
3016
|
return this.withTelemetry("migrations.apply", dbName, async () => {
|
|
2813
|
-
const created = await this.ensureMigrationsTable(dbName, options.signal);
|
|
2814
|
-
if (!created.ok) return created;
|
|
2815
3017
|
const listed = await this.queryOnDb(
|
|
2816
3018
|
dbName,
|
|
2817
3019
|
`SELECT id FROM ${MIGRATIONS_TABLE} WHERE namespace = ? ORDER BY applied_at, id`,
|
|
2818
3020
|
[options.namespace],
|
|
2819
3021
|
{ signal: options.signal }
|
|
2820
3022
|
);
|
|
2821
|
-
|
|
3023
|
+
const tableMissing = !listed.ok && (listed.error.code === ErrorCodes.SQL_DATABASE_NOT_FOUND || isMissingTableError(listed.error.message));
|
|
3024
|
+
if (!listed.ok && !tableMissing) return listed;
|
|
2822
3025
|
const appliedIds = new Set(
|
|
2823
|
-
listed.data.rows.map((row) => rowValue(row, 0)).filter((id) => typeof id === "string")
|
|
3026
|
+
(listed.ok ? listed.data.rows : []).map((row) => rowValue(row, 0)).filter((id) => typeof id === "string")
|
|
2824
3027
|
);
|
|
2825
3028
|
const skipped = options.migrations.filter((migration) => appliedIds.has(migration.id)).map((migration) => migration.id);
|
|
2826
3029
|
const pending = options.migrations.filter((migration) => !appliedIds.has(migration.id));
|
|
2827
3030
|
const applied = [];
|
|
3031
|
+
if (pending.length > 0 && tableMissing) {
|
|
3032
|
+
const created = await this.ensureMigrationsTable(dbName, options.signal);
|
|
3033
|
+
if (!created.ok) return created;
|
|
3034
|
+
}
|
|
2828
3035
|
for (const migration of pending) {
|
|
2829
3036
|
const result = await this.applyOneMigration(dbName, options.namespace, migration, options.signal);
|
|
2830
3037
|
if (!result.ok) return result;
|
|
@@ -2925,8 +3132,12 @@ var SQLService = class extends BaseService {
|
|
|
2925
3132
|
}))
|
|
2926
3133
|
);
|
|
2927
3134
|
}
|
|
2928
|
-
async handleErrorResponse(response, operation) {
|
|
3135
|
+
async handleErrorResponse(response, operation, dbName, requestedActions) {
|
|
2929
3136
|
const errorText = await response.text();
|
|
3137
|
+
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
3138
|
+
if (response.status === 402) {
|
|
3139
|
+
return err(storageRejectionError("sql", 402, meta, errorText));
|
|
3140
|
+
}
|
|
2930
3141
|
const errorBody = parseServiceErrorBody(errorText);
|
|
2931
3142
|
const errorCode = this.mapHttpStatusToErrorCode(
|
|
2932
3143
|
response.status,
|
|
@@ -2939,11 +3150,12 @@ var SQLService = class extends BaseService {
|
|
|
2939
3150
|
errorText,
|
|
2940
3151
|
errorBody
|
|
2941
3152
|
);
|
|
2942
|
-
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
2943
3153
|
if (response.status === 401) {
|
|
2944
|
-
const {
|
|
2945
|
-
if (action
|
|
2946
|
-
|
|
3154
|
+
const { action } = parseAuthError(errorText);
|
|
3155
|
+
if (action && requestedActions.includes(action)) {
|
|
3156
|
+
meta.requiredAction = action;
|
|
3157
|
+
meta.resource = `${this.context.session.spaceId}/sql/${dbName}`;
|
|
3158
|
+
}
|
|
2947
3159
|
}
|
|
2948
3160
|
return err(
|
|
2949
3161
|
serviceError(errorCode, message, "sql", { meta })
|
|
@@ -3040,6 +3252,9 @@ function serializeSqlValues(values) {
|
|
|
3040
3252
|
(value) => value instanceof Uint8Array ? Array.from(value) : value
|
|
3041
3253
|
);
|
|
3042
3254
|
}
|
|
3255
|
+
function isMissingTableError(message) {
|
|
3256
|
+
return /no such table/i.test(message);
|
|
3257
|
+
}
|
|
3043
3258
|
function migrationKey(namespace, id) {
|
|
3044
3259
|
return `${encodeURIComponent(namespace)}:${encodeURIComponent(id)}`;
|
|
3045
3260
|
}
|
|
@@ -3361,6 +3576,10 @@ var DuckDbService = class extends BaseService {
|
|
|
3361
3576
|
}
|
|
3362
3577
|
async handleErrorResponse(response, operation) {
|
|
3363
3578
|
const errorText = await response.text();
|
|
3579
|
+
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
3580
|
+
if (response.status === 402) {
|
|
3581
|
+
return err(storageRejectionError("duckdb", 402, meta, errorText));
|
|
3582
|
+
}
|
|
3364
3583
|
const errorBody = parseServiceErrorBody(errorText);
|
|
3365
3584
|
const errorCode = this.mapHttpStatusToErrorCode(
|
|
3366
3585
|
response.status,
|
|
@@ -3373,7 +3592,6 @@ var DuckDbService = class extends BaseService {
|
|
|
3373
3592
|
errorText,
|
|
3374
3593
|
errorBody
|
|
3375
3594
|
);
|
|
3376
|
-
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
3377
3595
|
if (response.status === 401) {
|
|
3378
3596
|
const { resource, action } = parseAuthError(errorText);
|
|
3379
3597
|
if (action) meta.requiredAction = action;
|
|
@@ -4345,6 +4563,9 @@ function defaultVaultMessage(input) {
|
|
|
4345
4563
|
return input.message ?? `Public key not found for ${input.did}`;
|
|
4346
4564
|
case "STORAGE_ERROR":
|
|
4347
4565
|
return input.message ?? input.cause.message;
|
|
4566
|
+
case "STORAGE_QUOTA_EXCEEDED":
|
|
4567
|
+
case "STORAGE_LIMIT_REACHED":
|
|
4568
|
+
return input.message;
|
|
4348
4569
|
}
|
|
4349
4570
|
}
|
|
4350
4571
|
function vaultError(input) {
|
|
@@ -4355,6 +4576,15 @@ function vaultError(input) {
|
|
|
4355
4576
|
};
|
|
4356
4577
|
return { ok: false, error };
|
|
4357
4578
|
}
|
|
4579
|
+
function kvWriteError(context, error) {
|
|
4580
|
+
if (error.code === ErrorCodes.STORAGE_QUOTA_EXCEEDED || error.code === ErrorCodes.STORAGE_LIMIT_REACHED) {
|
|
4581
|
+
return vaultError({ code: error.code, message: error.message, meta: error.meta });
|
|
4582
|
+
}
|
|
4583
|
+
return vaultError({
|
|
4584
|
+
code: "STORAGE_ERROR",
|
|
4585
|
+
cause: new Error(`${context}: ${error.message}`)
|
|
4586
|
+
});
|
|
4587
|
+
}
|
|
4358
4588
|
var DataVaultService = class extends BaseService {
|
|
4359
4589
|
/**
|
|
4360
4590
|
* Create a new DataVaultService instance.
|
|
@@ -4637,12 +4867,7 @@ var DataVaultService = class extends BaseService {
|
|
|
4637
4867
|
JSON.stringify(envelopeResult.data)
|
|
4638
4868
|
);
|
|
4639
4869
|
if (!valuePutResult.ok) {
|
|
4640
|
-
return
|
|
4641
|
-
code: "STORAGE_ERROR",
|
|
4642
|
-
cause: new Error(
|
|
4643
|
-
`Failed to store encrypted value: ${valuePutResult.error.message}`
|
|
4644
|
-
)
|
|
4645
|
-
});
|
|
4870
|
+
return kvWriteError("Failed to store encrypted value", valuePutResult.error);
|
|
4646
4871
|
}
|
|
4647
4872
|
return { ok: true, data: void 0 };
|
|
4648
4873
|
} catch (error) {
|
|
@@ -4860,12 +5085,7 @@ var DataVaultService = class extends BaseService {
|
|
|
4860
5085
|
keyPayload
|
|
4861
5086
|
);
|
|
4862
5087
|
if (!keyPutResult.ok) {
|
|
4863
|
-
return
|
|
4864
|
-
code: "STORAGE_ERROR",
|
|
4865
|
-
cause: new Error(
|
|
4866
|
-
`Failed to store key blob: ${keyPutResult.error.message}`
|
|
4867
|
-
)
|
|
4868
|
-
});
|
|
5088
|
+
return kvWriteError("Failed to store key blob", keyPutResult.error);
|
|
4869
5089
|
}
|
|
4870
5090
|
const valuePayload = JSON.stringify({
|
|
4871
5091
|
data: base64Encode(encrypted),
|
|
@@ -4876,12 +5096,7 @@ var DataVaultService = class extends BaseService {
|
|
|
4876
5096
|
valuePayload
|
|
4877
5097
|
);
|
|
4878
5098
|
if (!valuePutResult.ok) {
|
|
4879
|
-
return
|
|
4880
|
-
code: "STORAGE_ERROR",
|
|
4881
|
-
cause: new Error(
|
|
4882
|
-
`Failed to store encrypted value: ${valuePutResult.error.message}`
|
|
4883
|
-
)
|
|
4884
|
-
});
|
|
5099
|
+
return kvWriteError("Failed to store encrypted value", valuePutResult.error);
|
|
4885
5100
|
}
|
|
4886
5101
|
return ok(void 0);
|
|
4887
5102
|
} catch (error) {
|
|
@@ -5212,12 +5427,7 @@ var DataVaultService = class extends BaseService {
|
|
|
5212
5427
|
grantPayload
|
|
5213
5428
|
);
|
|
5214
5429
|
if (!grantPutResult.ok) {
|
|
5215
|
-
return
|
|
5216
|
-
code: "STORAGE_ERROR",
|
|
5217
|
-
cause: new Error(
|
|
5218
|
-
`Failed to store grant: ${grantPutResult.error.message}`
|
|
5219
|
-
)
|
|
5220
|
-
});
|
|
5430
|
+
return kvWriteError("Failed to store grant", grantPutResult.error);
|
|
5221
5431
|
}
|
|
5222
5432
|
return ok(void 0);
|
|
5223
5433
|
} catch (error) {
|
|
@@ -5562,12 +5772,7 @@ var DataVaultService = class extends BaseService {
|
|
|
5562
5772
|
keyPayload
|
|
5563
5773
|
);
|
|
5564
5774
|
if (!keyPutResult.ok) {
|
|
5565
|
-
return
|
|
5566
|
-
code: "STORAGE_ERROR",
|
|
5567
|
-
cause: new Error(
|
|
5568
|
-
`Failed to store rotated key blob: ${keyPutResult.error.message}`
|
|
5569
|
-
)
|
|
5570
|
-
});
|
|
5775
|
+
return kvWriteError("Failed to store rotated key blob", keyPutResult.error);
|
|
5571
5776
|
}
|
|
5572
5777
|
const valuePayload = JSON.stringify({
|
|
5573
5778
|
data: base64Encode(encrypted),
|
|
@@ -5578,12 +5783,7 @@ var DataVaultService = class extends BaseService {
|
|
|
5578
5783
|
valuePayload
|
|
5579
5784
|
);
|
|
5580
5785
|
if (!valuePutResult.ok) {
|
|
5581
|
-
return
|
|
5582
|
-
code: "STORAGE_ERROR",
|
|
5583
|
-
cause: new Error(
|
|
5584
|
-
`Failed to store re-encrypted value: ${valuePutResult.error.message}`
|
|
5585
|
-
)
|
|
5586
|
-
});
|
|
5786
|
+
return kvWriteError("Failed to store re-encrypted value", valuePutResult.error);
|
|
5587
5787
|
}
|
|
5588
5788
|
for (const did of remainingGrantees) {
|
|
5589
5789
|
const grantResult = await this.reencrypt(key, did);
|
|
@@ -5934,103 +6134,6 @@ function canonicalHashHex(sha256, value) {
|
|
|
5934
6134
|
return hexEncode2(sha256(utf8Encode(canonical)));
|
|
5935
6135
|
}
|
|
5936
6136
|
|
|
5937
|
-
// src/encryption/networkId.ts
|
|
5938
|
-
var URN_PREFIX = "urn:tinycloud:encryption:";
|
|
5939
|
-
var NETWORK_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
5940
|
-
var PKH_EIP155_DID_RE = /^did:pkh:eip155:(\d+):(0x[a-fA-F0-9]{40})$/;
|
|
5941
|
-
var NetworkIdError = class extends Error {
|
|
5942
|
-
constructor(message) {
|
|
5943
|
-
super(message);
|
|
5944
|
-
this.name = "NetworkIdError";
|
|
5945
|
-
}
|
|
5946
|
-
};
|
|
5947
|
-
function parseNetworkId(networkId) {
|
|
5948
|
-
if (typeof networkId !== "string" || networkId.length === 0) {
|
|
5949
|
-
throw new NetworkIdError("networkId must be a non-empty string");
|
|
5950
|
-
}
|
|
5951
|
-
if (!networkId.startsWith(URN_PREFIX)) {
|
|
5952
|
-
throw new NetworkIdError(
|
|
5953
|
-
`networkId must start with ${URN_PREFIX} (got ${JSON.stringify(networkId)})`
|
|
5954
|
-
);
|
|
5955
|
-
}
|
|
5956
|
-
const body = networkId.slice(URN_PREFIX.length);
|
|
5957
|
-
const lastColon = body.lastIndexOf(":");
|
|
5958
|
-
if (lastColon <= 0 || lastColon === body.length - 1) {
|
|
5959
|
-
throw new NetworkIdError(
|
|
5960
|
-
`networkId missing ownerDid or name segment (got ${JSON.stringify(networkId)})`
|
|
5961
|
-
);
|
|
5962
|
-
}
|
|
5963
|
-
const ownerDid = body.slice(0, lastColon);
|
|
5964
|
-
const name = body.slice(lastColon + 1);
|
|
5965
|
-
if (!ownerDid.startsWith("did:")) {
|
|
5966
|
-
throw new NetworkIdError(
|
|
5967
|
-
`networkId ownerDid must be a DID (got ${JSON.stringify(ownerDid)})`
|
|
5968
|
-
);
|
|
5969
|
-
}
|
|
5970
|
-
const didParts = ownerDid.split(":");
|
|
5971
|
-
if (didParts.length < 3 || didParts.some((p) => p.length === 0)) {
|
|
5972
|
-
throw new NetworkIdError(
|
|
5973
|
-
`networkId ownerDid is not a well-formed DID (got ${JSON.stringify(ownerDid)})`
|
|
5974
|
-
);
|
|
5975
|
-
}
|
|
5976
|
-
if (!NETWORK_NAME_RE.test(name)) {
|
|
5977
|
-
throw new NetworkIdError(
|
|
5978
|
-
`networkId name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
5979
|
-
);
|
|
5980
|
-
}
|
|
5981
|
-
return { networkId, ownerDid, name };
|
|
5982
|
-
}
|
|
5983
|
-
function buildNetworkId(ownerDid, name) {
|
|
5984
|
-
if (typeof ownerDid !== "string" || !ownerDid.startsWith("did:")) {
|
|
5985
|
-
throw new NetworkIdError("ownerDid must be a DID");
|
|
5986
|
-
}
|
|
5987
|
-
if (typeof name !== "string" || !NETWORK_NAME_RE.test(name)) {
|
|
5988
|
-
throw new NetworkIdError(
|
|
5989
|
-
`network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
5990
|
-
);
|
|
5991
|
-
}
|
|
5992
|
-
const networkId = `${URN_PREFIX}${ownerDid}:${name}`;
|
|
5993
|
-
parseNetworkId(networkId);
|
|
5994
|
-
return networkId;
|
|
5995
|
-
}
|
|
5996
|
-
function isNetworkId(networkId) {
|
|
5997
|
-
if (typeof networkId !== "string") {
|
|
5998
|
-
return false;
|
|
5999
|
-
}
|
|
6000
|
-
try {
|
|
6001
|
-
parseNetworkId(networkId);
|
|
6002
|
-
return true;
|
|
6003
|
-
} catch {
|
|
6004
|
-
return false;
|
|
6005
|
-
}
|
|
6006
|
-
}
|
|
6007
|
-
function parsePkhOwnerDid(ownerDid) {
|
|
6008
|
-
const match = ownerDid.match(PKH_EIP155_DID_RE);
|
|
6009
|
-
if (!match) return null;
|
|
6010
|
-
return {
|
|
6011
|
-
chainId: match[1],
|
|
6012
|
-
address: match[2].toLowerCase()
|
|
6013
|
-
};
|
|
6014
|
-
}
|
|
6015
|
-
function ownerDidMatches(a, b) {
|
|
6016
|
-
const aPkh = parsePkhOwnerDid(a);
|
|
6017
|
-
const bPkh = parsePkhOwnerDid(b);
|
|
6018
|
-
if (aPkh && bPkh) {
|
|
6019
|
-
return aPkh.chainId === bPkh.chainId && aPkh.address === bPkh.address;
|
|
6020
|
-
}
|
|
6021
|
-
return a === b;
|
|
6022
|
-
}
|
|
6023
|
-
function networkDiscoveryKey(name) {
|
|
6024
|
-
if (!NETWORK_NAME_RE.test(name)) {
|
|
6025
|
-
throw new NetworkIdError(
|
|
6026
|
-
`network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
6027
|
-
);
|
|
6028
|
-
}
|
|
6029
|
-
return `.well-known/encryption/network/${name}`;
|
|
6030
|
-
}
|
|
6031
|
-
var ENCRYPTION_NETWORK_URN_PREFIX = URN_PREFIX;
|
|
6032
|
-
var NETWORK_NAME_PATTERN = NETWORK_NAME_RE;
|
|
6033
|
-
|
|
6034
6137
|
// src/encryption/types.ts
|
|
6035
6138
|
var DEFAULT_ENCRYPTION_ALG = "x25519-aes256gcm/v1";
|
|
6036
6139
|
var ENVELOPE_VERSION = 1;
|
|
@@ -6912,6 +7015,8 @@ export {
|
|
|
6912
7015
|
SQLAction,
|
|
6913
7016
|
SQLMigrations,
|
|
6914
7017
|
SQLService,
|
|
7018
|
+
STORAGE_FULL_MESSAGE,
|
|
7019
|
+
STORAGE_WRITE_TOO_LARGE_MESSAGE,
|
|
6915
7020
|
SecretsService,
|
|
6916
7021
|
ServiceContext,
|
|
6917
7022
|
ServiceErrorEventSchema,
|
|
@@ -6964,22 +7069,26 @@ export {
|
|
|
6964
7069
|
hexEncode2 as hexEncode,
|
|
6965
7070
|
installTinyCloudDebugGlobals,
|
|
6966
7071
|
isNetworkId,
|
|
7072
|
+
isStorageFullError,
|
|
6967
7073
|
networkDiscoveryKey,
|
|
6968
7074
|
networkError,
|
|
6969
7075
|
notFoundError,
|
|
6970
7076
|
ok,
|
|
6971
7077
|
openWrappedKey,
|
|
6972
7078
|
parseAuthError,
|
|
7079
|
+
parseCapabilityResource,
|
|
6973
7080
|
parseNetworkId,
|
|
6974
7081
|
parsePermissionHint,
|
|
6975
7082
|
parsePermissionHintFromErrorText,
|
|
6976
7083
|
parseSecretCatalogKey,
|
|
7084
|
+
parseStorageQuotaBytes,
|
|
6977
7085
|
permissionDeniedError,
|
|
6978
7086
|
resolveSecretListPrefix,
|
|
6979
7087
|
resolveSecretPath,
|
|
6980
7088
|
serviceError,
|
|
6981
7089
|
storageLimitReachedError,
|
|
6982
7090
|
storageQuotaExceededError,
|
|
7091
|
+
storageRejectionError,
|
|
6983
7092
|
timeoutError,
|
|
6984
7093
|
tinyCloudDebugLogger,
|
|
6985
7094
|
utf8Decode,
|
|
@@ -6993,6 +7102,7 @@ export {
|
|
|
6993
7102
|
validateServiceResponseEvent,
|
|
6994
7103
|
validateServiceSession,
|
|
6995
7104
|
validateTelemetrySpanEvent,
|
|
7105
|
+
validatedCapabilityOf,
|
|
6996
7106
|
verifyDecryptResponse,
|
|
6997
7107
|
wrapError
|
|
6998
7108
|
};
|