@tinycloud/sdk-services 3.12.0-beta.7 → 3.12.0-beta.8
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.d.cts +2 -2
- package/dist/encryption/index.d.ts +2 -2
- package/dist/encryption/index.js.map +1 -1
- package/dist/encryption/named-keys.d.cts +1 -1
- package/dist/encryption/named-keys.d.ts +1 -1
- package/dist/index.cjs +97 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +94 -50
- package/dist/index.js.map +1 -1
- package/dist/kv/index.cjs.map +1 -1
- package/dist/kv/index.js.map +1 -1
- package/dist/kv/replication/index.cjs.map +1 -1
- package/dist/kv/replication/index.js.map +1 -1
- package/dist/sql/index.cjs.map +1 -1
- package/dist/sql/index.js.map +1 -1
- package/dist/{types-XE4tyBLH.d.ts → types-Ceti5xVp.d.ts} +39 -4
- package/dist/{types-cWtQmCCw.d.cts → types-CoZ0vXo8.d.cts} +39 -4
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { E as EncryptionCrypto, I as InlineEncryptedEnvelope, J as Json } from '../types-
|
|
1
|
+
import { E as EncryptionCrypto, I as InlineEncryptedEnvelope, J as Json } from '../types-CoZ0vXo8.cjs';
|
|
2
2
|
import { ParsedKeyResource } from './resource.cjs';
|
|
3
3
|
import '../types-DjAP8dve.cjs';
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { E as EncryptionCrypto, I as InlineEncryptedEnvelope, J as Json } from '../types-
|
|
1
|
+
import { E as EncryptionCrypto, I as InlineEncryptedEnvelope, J as Json } from '../types-Ceti5xVp.js';
|
|
2
2
|
import { ParsedKeyResource } from './resource.js';
|
|
3
3
|
import '../types-DjAP8dve.js';
|
|
4
4
|
|
package/dist/index.cjs
CHANGED
|
@@ -104,6 +104,7 @@ __export(src_exports, {
|
|
|
104
104
|
clearTinyCloudDebugLogs: () => clearTinyCloudDebugLogs,
|
|
105
105
|
createKVResponseSchema: () => createKVResponseSchema,
|
|
106
106
|
createResourceRoutingFetch: () => createResourceRoutingFetch,
|
|
107
|
+
createResourceTransportInvocationFetch: () => createResourceTransportInvocationFetch,
|
|
107
108
|
createResultSchema: () => createResultSchema,
|
|
108
109
|
createVaultCrypto: () => createVaultCrypto,
|
|
109
110
|
decryptEnvelopeWithKey: () => decryptEnvelopeWithKey,
|
|
@@ -146,7 +147,9 @@ __export(src_exports, {
|
|
|
146
147
|
requiresSecretsOptIn: () => requiresSecretsOptIn,
|
|
147
148
|
resolveSecretListPrefix: () => resolveSecretListPrefix,
|
|
148
149
|
resolveSecretPath: () => resolveSecretPath,
|
|
150
|
+
routeResourceRequest: () => routeResourceRequest,
|
|
149
151
|
routingFailure: () => routingFailure,
|
|
152
|
+
routingResourceOf: () => routingResourceOf,
|
|
150
153
|
serviceError: () => serviceError,
|
|
151
154
|
storageLimitReachedError: () => storageLimitReachedError,
|
|
152
155
|
storageQuotaExceededError: () => storageQuotaExceededError,
|
|
@@ -989,6 +992,7 @@ async function verifyResourceDestination(target, fetchFn) {
|
|
|
989
992
|
if (infoDid !== target.nodeDid || keysDid !== target.nodeDid) {
|
|
990
993
|
throw new NodeIdentityMismatchError(target.url, target.nodeDid, infoDid !== target.nodeDid ? infoDid : keysDid);
|
|
991
994
|
}
|
|
995
|
+
return info;
|
|
992
996
|
}
|
|
993
997
|
var NodeNotRespondingError = class extends Error {
|
|
994
998
|
constructor(hosts, cause) {
|
|
@@ -1056,6 +1060,17 @@ function authorizationOf(headers) {
|
|
|
1056
1060
|
if (headers === void 0) return void 0;
|
|
1057
1061
|
return (Array.isArray(headers) ? headers : Object.entries(headers)).find(([name]) => name.toLowerCase() === "authorization")?.[1];
|
|
1058
1062
|
}
|
|
1063
|
+
function routingResourceOf(uri) {
|
|
1064
|
+
if (uri.startsWith("tinycloud://")) {
|
|
1065
|
+
const resource = uri.slice("tinycloud://".length).split("/", 1)[0];
|
|
1066
|
+
if (resource) return resource;
|
|
1067
|
+
} else if (uri.startsWith("urn:tinycloud:encryption:")) {
|
|
1068
|
+
return uri;
|
|
1069
|
+
} else if (uri.startsWith("tinycloud:")) {
|
|
1070
|
+
return uri.split("/", 1)[0];
|
|
1071
|
+
}
|
|
1072
|
+
throw new ResourceNotRoutedError(uri);
|
|
1073
|
+
}
|
|
1059
1074
|
function invocationResources(authorization) {
|
|
1060
1075
|
const encoded = authorization.split(".")[1];
|
|
1061
1076
|
if (!encoded) throw new ResourceNotRoutedError("invalid invocation");
|
|
@@ -1067,8 +1082,7 @@ function invocationResources(authorization) {
|
|
|
1067
1082
|
for (const [uri, abilities] of Object.entries(payload.att)) {
|
|
1068
1083
|
if (typeof abilities !== "object" || abilities === null || Array.isArray(abilities)) throw new ResourceNotRoutedError(uri);
|
|
1069
1084
|
for (const action of Object.keys(abilities)) {
|
|
1070
|
-
const resource =
|
|
1071
|
-
if (!resource.startsWith("tinycloud:") && !resource.startsWith("urn:tinycloud:encryption:")) throw new ResourceNotRoutedError(uri);
|
|
1085
|
+
const resource = routingResourceOf(uri);
|
|
1072
1086
|
const read2 = /^(tinycloud\.(kv\/(get|list|metadata|head|sync)|sql\/(read|export)|duckdb\/(read|describe|export)|capabilities\/read|space\/(list|info)|hooks\/list))$/.test(action);
|
|
1073
1087
|
const access = resource.startsWith("urn:tinycloud:encryption:") ? "encryption" : action === "tinycloud.space/host" ? "host" : read2 ? "read" : "write";
|
|
1074
1088
|
if (!resources.some((entry) => entry.resource === resource && entry.access === access)) resources.push({ resource, access });
|
|
@@ -1077,6 +1091,83 @@ function invocationResources(authorization) {
|
|
|
1077
1091
|
if (resources.length === 0) throw new ResourceNotRoutedError("empty invocation");
|
|
1078
1092
|
return resources;
|
|
1079
1093
|
}
|
|
1094
|
+
async function routeResourceRequest(resources, routing, send, options) {
|
|
1095
|
+
if (resources.length === 0) throw new ResourceNotRoutedError("empty request");
|
|
1096
|
+
const routes = await Promise.all(resources.map(({ resource, access }) => routing.resolveResource(resource, access)));
|
|
1097
|
+
if (routes.some((route) => route.length === 0)) throw new ResourceNotRoutedError(resources[routes.findIndex((route) => route.length === 0)].resource);
|
|
1098
|
+
const write = options?.independentResources === true || resources.some(({ access }) => access === "write" || access === "host");
|
|
1099
|
+
let targets;
|
|
1100
|
+
if (options?.independentResources) {
|
|
1101
|
+
targets = routes.flat();
|
|
1102
|
+
const identities = /* @__PURE__ */ new Map();
|
|
1103
|
+
for (const target of targets) {
|
|
1104
|
+
if (identities.has(target.url) && identities.get(target.url) !== target.nodeDid) throw new ResourceNotRoutedError(target.url);
|
|
1105
|
+
identities.set(target.url, target.nodeDid);
|
|
1106
|
+
}
|
|
1107
|
+
} else {
|
|
1108
|
+
targets = routes[0].filter((target) => routes.every((route) => route.some((other) => other.url === target.url && other.nodeDid === target.nodeDid)));
|
|
1109
|
+
if (targets.length === 0 || write && routes.some((route) => route.length !== targets.length)) throw new ResourceNotRoutedError(resources.map(({ resource }) => resource).join(", "));
|
|
1110
|
+
}
|
|
1111
|
+
targets = targets.filter((target, index) => targets.findIndex((other) => other.url === target.url) === index);
|
|
1112
|
+
if (options?.nodeDid) targets = targets.filter((target) => target.nodeDid === options.nodeDid || target.nodeDid === void 0);
|
|
1113
|
+
if (targets.length === 0 || options?.nodeLocal && targets.length !== 1) throw new ResourceNotRoutedError(resources.map(({ resource }) => resource).join(", "));
|
|
1114
|
+
if (!write) {
|
|
1115
|
+
let response2;
|
|
1116
|
+
let failure;
|
|
1117
|
+
for (const target of targets) {
|
|
1118
|
+
try {
|
|
1119
|
+
response2 = await send(target);
|
|
1120
|
+
if (response2.ok || response2.status !== 404) return response2;
|
|
1121
|
+
} catch (error) {
|
|
1122
|
+
if (!(error instanceof NodeNotRespondingError)) throw error;
|
|
1123
|
+
failure = error;
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
if (failure) throw new NodeNotRespondingError(targets.map(({ url }) => url), failure);
|
|
1127
|
+
if (response2) return response2;
|
|
1128
|
+
throw new NodeNotRespondingError(targets.map(({ url }) => url), failure);
|
|
1129
|
+
}
|
|
1130
|
+
const succeeded = [];
|
|
1131
|
+
const failed = [];
|
|
1132
|
+
let response;
|
|
1133
|
+
let failureResponse;
|
|
1134
|
+
for (const target of targets) {
|
|
1135
|
+
try {
|
|
1136
|
+
const result = await send(target);
|
|
1137
|
+
if (result.ok) {
|
|
1138
|
+
succeeded.push(target.url);
|
|
1139
|
+
response ?? (response = result);
|
|
1140
|
+
} else {
|
|
1141
|
+
failed.push({ url: target.url, status: result.status });
|
|
1142
|
+
failureResponse ?? (failureResponse = result);
|
|
1143
|
+
}
|
|
1144
|
+
} catch (error) {
|
|
1145
|
+
if (!routingFailure(error) && succeeded.length === 0) throw error;
|
|
1146
|
+
failed.push({ url: target.url, cause: error });
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
if (failed.length > 0) {
|
|
1150
|
+
if (succeeded.length > 0 || targets.length > 1) throw new PartialNodeWriteError(succeeded, failed);
|
|
1151
|
+
if (failureResponse) return failureResponse;
|
|
1152
|
+
if (failed[0]?.cause && !(failed[0].cause instanceof NodeNotRespondingError)) throw failed[0].cause;
|
|
1153
|
+
throw new NodeNotRespondingError(targets.map(({ url }) => url), failed[0]?.cause);
|
|
1154
|
+
}
|
|
1155
|
+
return response;
|
|
1156
|
+
}
|
|
1157
|
+
function createResourceTransportInvocationFetch(transport, session) {
|
|
1158
|
+
return async (url, init) => {
|
|
1159
|
+
const parsed = new URL(url);
|
|
1160
|
+
if (parsed.pathname !== "/invoke") throw new ResourceNotRoutedError(parsed.pathname);
|
|
1161
|
+
const authorization = authorizationOf(init?.headers);
|
|
1162
|
+
if (!authorization) throw new ResourceNotRoutedError("unsigned invocation");
|
|
1163
|
+
return transport(invocationResources(authorization), async (target) => {
|
|
1164
|
+
const signed = await target.bindAudience(authorization);
|
|
1165
|
+
const headers = (Array.isArray(init?.headers) ? init.headers : Object.entries(init?.headers ?? {})).filter(([name]) => name.toLowerCase() !== "authorization");
|
|
1166
|
+
headers.push(["Authorization", signed]);
|
|
1167
|
+
return target.fetch(`${target.url}${parsed.pathname}${parsed.search}`, { ...init, headers });
|
|
1168
|
+
}, { invocationSession: session });
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1080
1171
|
function createResourceRoutingFetch(fetchFn, routing) {
|
|
1081
1172
|
return async (url, init) => {
|
|
1082
1173
|
const parsed = new URL(url);
|
|
@@ -1084,12 +1175,6 @@ function createResourceRoutingFetch(fetchFn, routing) {
|
|
|
1084
1175
|
const authorization = authorizationOf(init?.headers);
|
|
1085
1176
|
if (!authorization) throw new ResourceNotRoutedError("unsigned invocation");
|
|
1086
1177
|
const resources = invocationResources(authorization);
|
|
1087
|
-
const routes = await Promise.all(resources.map(({ resource, access }) => routing.resolveResource(resource, access)));
|
|
1088
|
-
if (routes.some((route) => route.length === 0)) throw new ResourceNotRoutedError(resources[routes.findIndex((route) => route.length === 0)].resource);
|
|
1089
|
-
const write = resources.some(({ access }) => access === "write" || access === "host");
|
|
1090
|
-
let targets = routes[0].filter((target) => routes.every((route) => route.some((other) => other.url === target.url && other.nodeDid === target.nodeDid)));
|
|
1091
|
-
if (targets.length === 0 || write && routes.some((route) => route.length !== targets.length)) throw new ResourceNotRoutedError(resources.map(({ resource }) => resource).join(", "));
|
|
1092
|
-
targets = targets.filter((target, index) => targets.findIndex((other) => other.url === target.url) === index);
|
|
1093
1178
|
const send = async (target) => {
|
|
1094
1179
|
init?.signal?.throwIfAborted();
|
|
1095
1180
|
if (routing.verifyDestination) await routing.verifyDestination(target);
|
|
@@ -1107,48 +1192,7 @@ function createResourceRoutingFetch(fetchFn, routing) {
|
|
|
1107
1192
|
throw new NodeNotRespondingError([target.url], error);
|
|
1108
1193
|
}
|
|
1109
1194
|
};
|
|
1110
|
-
|
|
1111
|
-
let response2;
|
|
1112
|
-
let failure;
|
|
1113
|
-
for (const target of targets) {
|
|
1114
|
-
try {
|
|
1115
|
-
response2 = await send(target);
|
|
1116
|
-
if (response2.ok || response2.status !== 404) return response2;
|
|
1117
|
-
} catch (error) {
|
|
1118
|
-
if (!(error instanceof NodeNotRespondingError)) throw error;
|
|
1119
|
-
failure = error;
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1122
|
-
if (failure) throw new NodeNotRespondingError(targets.map(({ url: url2 }) => url2), failure);
|
|
1123
|
-
if (response2) return response2;
|
|
1124
|
-
throw new NodeNotRespondingError(targets.map(({ url: url2 }) => url2), failure);
|
|
1125
|
-
}
|
|
1126
|
-
const succeeded = [];
|
|
1127
|
-
const failed = [];
|
|
1128
|
-
let response;
|
|
1129
|
-
let failureResponse;
|
|
1130
|
-
for (const target of targets) {
|
|
1131
|
-
try {
|
|
1132
|
-
const result = await send(target);
|
|
1133
|
-
if (result.ok) {
|
|
1134
|
-
succeeded.push(target.url);
|
|
1135
|
-
response ?? (response = result);
|
|
1136
|
-
} else {
|
|
1137
|
-
failed.push({ url: target.url, status: result.status });
|
|
1138
|
-
failureResponse ?? (failureResponse = result);
|
|
1139
|
-
}
|
|
1140
|
-
} catch (error) {
|
|
1141
|
-
if (!routingFailure(error) && succeeded.length === 0) throw error;
|
|
1142
|
-
failed.push({ url: target.url, cause: error });
|
|
1143
|
-
}
|
|
1144
|
-
}
|
|
1145
|
-
if (failed.length > 0) {
|
|
1146
|
-
if (succeeded.length > 0 || targets.length > 1) throw new PartialNodeWriteError(succeeded, failed);
|
|
1147
|
-
if (failureResponse) return failureResponse;
|
|
1148
|
-
if (failed[0]?.cause && !(failed[0].cause instanceof NodeNotRespondingError)) throw failed[0].cause;
|
|
1149
|
-
throw new NodeNotRespondingError(targets.map(({ url: url2 }) => url2), failed[0]?.cause);
|
|
1150
|
-
}
|
|
1151
|
-
return response;
|
|
1195
|
+
return routeResourceRequest(resources, routing, send);
|
|
1152
1196
|
};
|
|
1153
1197
|
}
|
|
1154
1198
|
|
|
@@ -9080,6 +9124,7 @@ var import_decrypt_transport_response_error3 = require("@tinycloud/sdk-services/
|
|
|
9080
9124
|
clearTinyCloudDebugLogs,
|
|
9081
9125
|
createKVResponseSchema,
|
|
9082
9126
|
createResourceRoutingFetch,
|
|
9127
|
+
createResourceTransportInvocationFetch,
|
|
9083
9128
|
createResultSchema,
|
|
9084
9129
|
createVaultCrypto,
|
|
9085
9130
|
decryptEnvelopeWithKey,
|
|
@@ -9122,7 +9167,9 @@ var import_decrypt_transport_response_error3 = require("@tinycloud/sdk-services/
|
|
|
9122
9167
|
requiresSecretsOptIn,
|
|
9123
9168
|
resolveSecretListPrefix,
|
|
9124
9169
|
resolveSecretPath,
|
|
9170
|
+
routeResourceRequest,
|
|
9125
9171
|
routingFailure,
|
|
9172
|
+
routingResourceOf,
|
|
9126
9173
|
serviceError,
|
|
9127
9174
|
storageLimitReachedError,
|
|
9128
9175
|
storageQuotaExceededError,
|