@tinycloud/cli 1.1.0-beta.8 → 1.1.0-beta.9
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/index.js +59 -36
- package/dist/index.js.map +1 -1
- package/dist/legacy-entry.js +353 -165
- package/dist/legacy-entry.js.map +1 -1
- package/package.json +5 -5
- package/skills/tc-cli/REFERENCE.md +3 -1
package/dist/legacy-entry.js
CHANGED
|
@@ -163,7 +163,7 @@ import ora from "ora";
|
|
|
163
163
|
function outputJson(data) {
|
|
164
164
|
process.stdout.write(JSON.stringify(data, null, 2) + "\n");
|
|
165
165
|
}
|
|
166
|
-
function outputError(code3, message, hint) {
|
|
166
|
+
function outputError(code3, message, hint, meta) {
|
|
167
167
|
if (isInteractive()) {
|
|
168
168
|
process.stderr.write(
|
|
169
169
|
`${theme.error("\u2717")} ${theme.label(code3)}: ${message}
|
|
@@ -180,6 +180,7 @@ function outputError(code3, message, hint) {
|
|
|
180
180
|
error: { code: code3, message }
|
|
181
181
|
};
|
|
182
182
|
if (hint) payload.error.hint = hint;
|
|
183
|
+
if (meta) payload.error.meta = meta;
|
|
183
184
|
process.stderr.write(JSON.stringify(payload, null, 2) + "\n");
|
|
184
185
|
}
|
|
185
186
|
}
|
|
@@ -261,23 +262,42 @@ var init_formatter = __esm({
|
|
|
261
262
|
import { readFileSync, readdirSync } from "fs";
|
|
262
263
|
import { join as join2 } from "path";
|
|
263
264
|
import { ProfileDeletedError, ProfileLockTimeoutError } from "@tinycloud/operations/state";
|
|
265
|
+
import { authorizationVerdictOf, parseCapabilityResource, SERVICE_LONG_TO_SHORT, validatedCapabilityOf } from "@tinycloud/sdk-core";
|
|
264
266
|
function setActiveProfileName(name) {
|
|
265
267
|
activeProfileName = name;
|
|
266
268
|
}
|
|
269
|
+
function cliErrorFromService(error, message = error.message) {
|
|
270
|
+
if (error instanceof CLIError) return error;
|
|
271
|
+
const meta = { ...error.meta };
|
|
272
|
+
delete meta.hint;
|
|
273
|
+
const status = error.status ?? error.statusCode;
|
|
274
|
+
if (typeof status === "number" && Number.isInteger(status) && status >= 400 && status <= 599) meta.status = status;
|
|
275
|
+
const verdict = authorizationVerdictOf({ ...error, meta });
|
|
276
|
+
if (verdict === void 0 && message.includes("Missing private key parameter in JWK")) {
|
|
277
|
+
return missingPrivateKeyError();
|
|
278
|
+
}
|
|
279
|
+
const missingCapability = validatedCapabilityOf({ ...error, meta }) !== void 0;
|
|
280
|
+
const denied = verdict === "forbidden" || verdict === "unauthenticated" && missingCapability;
|
|
281
|
+
return new CLIError(
|
|
282
|
+
denied ? "PERMISSION_DENIED" : verdict === "unauthenticated" ? "AUTH_REQUIRED" : error.code,
|
|
283
|
+
message,
|
|
284
|
+
denied ? ExitCode.PERMISSION_DENIED : verdict === "unauthenticated" ? ExitCode.AUTH_REQUIRED : ExitCode.ERROR,
|
|
285
|
+
meta
|
|
286
|
+
);
|
|
287
|
+
}
|
|
267
288
|
function wrapError(error) {
|
|
289
|
+
if (error instanceof CLIError) return error;
|
|
268
290
|
const message = error instanceof Error ? error.message : String(error);
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
return new CLIError(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
);
|
|
291
|
+
const verdict = authorizationVerdictOf(error);
|
|
292
|
+
if (verdict === "unauthenticated") {
|
|
293
|
+
return new CLIError("AUTH_REQUIRED", message, ExitCode.AUTH_REQUIRED);
|
|
294
|
+
}
|
|
295
|
+
if (verdict === "forbidden") {
|
|
296
|
+
return new CLIError("PERMISSION_DENIED", message, ExitCode.PERMISSION_DENIED);
|
|
297
|
+
}
|
|
298
|
+
if (verdict === void 0 && message.includes("Missing private key parameter in JWK")) {
|
|
299
|
+
return missingPrivateKeyError();
|
|
279
300
|
}
|
|
280
|
-
if (error instanceof CLIError) return error;
|
|
281
301
|
if (error instanceof ProfileLockTimeoutError) {
|
|
282
302
|
return new CLIError(
|
|
283
303
|
"PROFILE_LOCK_TIMEOUT",
|
|
@@ -289,13 +309,13 @@ function wrapError(error) {
|
|
|
289
309
|
if (error instanceof ProfileDeletedError) {
|
|
290
310
|
return new CLIError("PROFILE_NOT_FOUND", message);
|
|
291
311
|
}
|
|
292
|
-
if (message.includes("Not signed in") || message.includes("AUTH_EXPIRED") || message.includes("Session expired")) {
|
|
312
|
+
if (verdict === void 0 && (message.includes("Not signed in") || message.includes("AUTH_EXPIRED") || message.includes("Session expired"))) {
|
|
293
313
|
return new CLIError("AUTH_REQUIRED", message, ExitCode.AUTH_REQUIRED);
|
|
294
314
|
}
|
|
295
315
|
if (message.includes("NOT_FOUND") || message.includes("KV_NOT_FOUND")) {
|
|
296
316
|
return new CLIError("NOT_FOUND", message, ExitCode.NOT_FOUND);
|
|
297
317
|
}
|
|
298
|
-
if (message.includes("PERMISSION_DENIED")) {
|
|
318
|
+
if (verdict === void 0 && message.includes("PERMISSION_DENIED")) {
|
|
299
319
|
return new CLIError("PERMISSION_DENIED", message, ExitCode.PERMISSION_DENIED);
|
|
300
320
|
}
|
|
301
321
|
if (message.includes("ECONNREFUSED") || message.includes("ETIMEDOUT") || message.includes("fetch failed")) {
|
|
@@ -303,39 +323,51 @@ function wrapError(error) {
|
|
|
303
323
|
}
|
|
304
324
|
return new CLIError("ERROR", message, ExitCode.ERROR);
|
|
305
325
|
}
|
|
326
|
+
function missingPrivateKeyError() {
|
|
327
|
+
const profileName = activeProfileName ?? process.env.TC_PROFILE ?? DEFAULT_PROFILE;
|
|
328
|
+
return new CLIError(
|
|
329
|
+
"AUTH_REQUIRED",
|
|
330
|
+
`Profile "${profileName}" cannot restore its session because its private key material is missing.`,
|
|
331
|
+
ExitCode.AUTH_REQUIRED,
|
|
332
|
+
{ hint: `Sign in again with: tc --profile ${profileName} auth login --method openkey` }
|
|
333
|
+
);
|
|
334
|
+
}
|
|
306
335
|
function handleError(error) {
|
|
307
336
|
const cliError = wrapError(error);
|
|
308
337
|
const prebuilt = typeof cliError.metadata?.hint === "string" ? cliError.metadata.hint : void 0;
|
|
309
338
|
const hint = prebuilt ?? buildAuthHint(cliError) ?? (cliError.code === "NETWORK_ERROR" ? buildNetworkHint() : void 0);
|
|
310
|
-
|
|
339
|
+
const authMeta = cliError.code === "AUTH_REQUIRED" || cliError.code === "PERMISSION_DENIED" ? cliError.metadata : void 0;
|
|
340
|
+
const meta = {};
|
|
341
|
+
if (cliError.status !== void 0 && authMeta !== void 0) meta.status = cliError.status;
|
|
342
|
+
const capability = validatedCapabilityOf({ meta: authMeta });
|
|
343
|
+
if (capability) {
|
|
344
|
+
meta.resource = capability.resource;
|
|
345
|
+
meta.requiredAction = capability.requiredAction;
|
|
346
|
+
}
|
|
347
|
+
outputError(cliError.code, cliError.message, hint, Object.keys(meta).length ? meta : void 0);
|
|
311
348
|
process.exit(cliError.exitCode);
|
|
312
349
|
}
|
|
313
350
|
function buildAuthHint(error) {
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
return void 0;
|
|
318
|
-
}
|
|
319
|
-
const spec = capSpecFromAuthMeta(resource, requiredAction);
|
|
351
|
+
const capability = validatedCapabilityOf({ meta: error.metadata });
|
|
352
|
+
if (!capability) return void 0;
|
|
353
|
+
const spec = capSpecFromAuthMeta(capability.resource, capability.requiredAction);
|
|
320
354
|
if (!spec) return void 0;
|
|
321
355
|
return [
|
|
322
356
|
"The active session is missing a TinyCloud capability.",
|
|
323
|
-
`Request it with: tc auth request --cap
|
|
357
|
+
`Request it with: tc auth request --cap '${spec.replaceAll("'", "'\\''")}'`,
|
|
324
358
|
"Then retry the original command."
|
|
325
359
|
].join("\n");
|
|
326
360
|
}
|
|
327
361
|
function capSpecFromAuthMeta(resource, action) {
|
|
328
|
-
const slash =
|
|
329
|
-
if (slash
|
|
330
|
-
const
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
const spaceName = spaceUri.startsWith("tinycloud:") ? spaceUri.slice(spaceUri.lastIndexOf(":") + 1) : spaceUri;
|
|
338
|
-
return `tinycloud.${serviceShort}:${spaceName}:${path}:${actionName}`;
|
|
362
|
+
const slash = action.indexOf("/");
|
|
363
|
+
if (slash < 0) return void 0;
|
|
364
|
+
const longService = action.slice(0, slash);
|
|
365
|
+
const serviceShort = SERVICE_LONG_TO_SHORT[longService];
|
|
366
|
+
if (!serviceShort) return void 0;
|
|
367
|
+
const parsed = parseCapabilityResource(resource, serviceShort);
|
|
368
|
+
if (!parsed) return void 0;
|
|
369
|
+
const spaceName = parsed.space.slice(parsed.space.lastIndexOf(":") + 1);
|
|
370
|
+
return `${longService}:${spaceName}:${parsed.path}:${action.slice(slash + 1)}`;
|
|
339
371
|
}
|
|
340
372
|
function buildNetworkHint() {
|
|
341
373
|
const readHost = (name) => {
|
|
@@ -389,7 +421,9 @@ var init_errors = __esm({
|
|
|
389
421
|
this.exitCode = exitCode;
|
|
390
422
|
this.metadata = metadata;
|
|
391
423
|
this.name = "CLIError";
|
|
424
|
+
if (typeof metadata?.status === "number" && Number.isInteger(metadata.status) && metadata.status >= 400 && metadata.status <= 599) this.status = metadata.status;
|
|
392
425
|
}
|
|
426
|
+
status;
|
|
393
427
|
};
|
|
394
428
|
}
|
|
395
429
|
});
|
|
@@ -1880,6 +1914,7 @@ var CAPABILITIES2 = deriveServiceConstants("capabilities");
|
|
|
1880
1914
|
var HOOKS = deriveServiceConstants("hooks");
|
|
1881
1915
|
var ENCRYPTION = deriveServiceConstants("encryption");
|
|
1882
1916
|
var SPACE = deriveServiceConstants("space");
|
|
1917
|
+
var CAPABILITY_REGISTRY = CAPABILITIES;
|
|
1883
1918
|
var DEFAULT_MANIFEST_SPACE = "applications";
|
|
1884
1919
|
var ACCOUNT_REGISTRY_SPACE = "account";
|
|
1885
1920
|
var ACCOUNT_REGISTRY_PATH = "applications/";
|
|
@@ -6820,6 +6855,75 @@ var ServiceSessionSchema = external_exports.object({
|
|
|
6820
6855
|
/** The session key JWK (required for invoke) */
|
|
6821
6856
|
jwk: external_exports.object({}).passthrough()
|
|
6822
6857
|
});
|
|
6858
|
+
var URN_PREFIX = "urn:tinycloud:encryption:";
|
|
6859
|
+
var NETWORK_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
6860
|
+
var PKH_EIP155_DID_RE = /^did:pkh:eip155:(\d+):(0x[a-fA-F0-9]{40})$/;
|
|
6861
|
+
var NetworkIdError = class extends Error {
|
|
6862
|
+
constructor(message) {
|
|
6863
|
+
super(message);
|
|
6864
|
+
this.name = "NetworkIdError";
|
|
6865
|
+
}
|
|
6866
|
+
};
|
|
6867
|
+
function parseNetworkId(networkId) {
|
|
6868
|
+
if (typeof networkId !== "string" || networkId.length === 0) {
|
|
6869
|
+
throw new NetworkIdError("networkId must be a non-empty string");
|
|
6870
|
+
}
|
|
6871
|
+
if (!networkId.startsWith(URN_PREFIX)) {
|
|
6872
|
+
throw new NetworkIdError(
|
|
6873
|
+
`networkId must start with ${URN_PREFIX} (got ${JSON.stringify(networkId)})`
|
|
6874
|
+
);
|
|
6875
|
+
}
|
|
6876
|
+
const body = networkId.slice(URN_PREFIX.length);
|
|
6877
|
+
const lastColon = body.lastIndexOf(":");
|
|
6878
|
+
if (lastColon <= 0 || lastColon === body.length - 1) {
|
|
6879
|
+
throw new NetworkIdError(
|
|
6880
|
+
`networkId missing ownerDid or name segment (got ${JSON.stringify(networkId)})`
|
|
6881
|
+
);
|
|
6882
|
+
}
|
|
6883
|
+
const ownerDid = body.slice(0, lastColon);
|
|
6884
|
+
const name = body.slice(lastColon + 1);
|
|
6885
|
+
if (!ownerDid.startsWith("did:")) {
|
|
6886
|
+
throw new NetworkIdError(
|
|
6887
|
+
`networkId ownerDid must be a DID (got ${JSON.stringify(ownerDid)})`
|
|
6888
|
+
);
|
|
6889
|
+
}
|
|
6890
|
+
const didParts = ownerDid.split(":");
|
|
6891
|
+
if (didParts.length < 3 || didParts.some((p) => p.length === 0)) {
|
|
6892
|
+
throw new NetworkIdError(
|
|
6893
|
+
`networkId ownerDid is not a well-formed DID (got ${JSON.stringify(ownerDid)})`
|
|
6894
|
+
);
|
|
6895
|
+
}
|
|
6896
|
+
if (!NETWORK_NAME_RE.test(name)) {
|
|
6897
|
+
throw new NetworkIdError(
|
|
6898
|
+
`networkId name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
6899
|
+
);
|
|
6900
|
+
}
|
|
6901
|
+
return { networkId, ownerDid, name };
|
|
6902
|
+
}
|
|
6903
|
+
function parsePkhOwnerDid(ownerDid) {
|
|
6904
|
+
const match = ownerDid.match(PKH_EIP155_DID_RE);
|
|
6905
|
+
if (!match) return null;
|
|
6906
|
+
return {
|
|
6907
|
+
chainId: match[1],
|
|
6908
|
+
address: match[2].toLowerCase()
|
|
6909
|
+
};
|
|
6910
|
+
}
|
|
6911
|
+
function ownerDidMatches(a, b) {
|
|
6912
|
+
const aPkh = parsePkhOwnerDid(a);
|
|
6913
|
+
const bPkh = parsePkhOwnerDid(b);
|
|
6914
|
+
if (aPkh && bPkh) {
|
|
6915
|
+
return aPkh.chainId === bPkh.chainId && aPkh.address === bPkh.address;
|
|
6916
|
+
}
|
|
6917
|
+
return a === b;
|
|
6918
|
+
}
|
|
6919
|
+
function networkDiscoveryKey(name) {
|
|
6920
|
+
if (!NETWORK_NAME_RE.test(name)) {
|
|
6921
|
+
throw new NetworkIdError(
|
|
6922
|
+
`network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
6923
|
+
);
|
|
6924
|
+
}
|
|
6925
|
+
return `.well-known/encryption/network/${name}`;
|
|
6926
|
+
}
|
|
6823
6927
|
function parsePermissionHint(value) {
|
|
6824
6928
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
6825
6929
|
const candidate = value;
|
|
@@ -6887,6 +6991,101 @@ function parseAuthError(responseText) {
|
|
|
6887
6991
|
function authUnauthorizedError(service, message, meta) {
|
|
6888
6992
|
return serviceError(ErrorCodes.AUTH_UNAUTHORIZED, message, service, { meta });
|
|
6889
6993
|
}
|
|
6994
|
+
var grantableActions = new Set(
|
|
6995
|
+
CAPABILITY_REGISTRY.map(({ urn }) => urn).filter((urn) => !urn.endsWith("/*"))
|
|
6996
|
+
);
|
|
6997
|
+
var capabilityServices = new Set(
|
|
6998
|
+
CAPABILITY_REGISTRY.map(({ service }) => service.slice("tinycloud.".length))
|
|
6999
|
+
);
|
|
7000
|
+
function parseCapabilityResource2(resource, service) {
|
|
7001
|
+
if (resource.length === 0 || resource.length > 1024 || !capabilityServices.has(service) || /[\s\p{C}*#]/u.test(resource) || resource.includes("://")) return void 0;
|
|
7002
|
+
const segments = resource.split("/");
|
|
7003
|
+
if (!/^tinycloud:[A-Za-z0-9][A-Za-z0-9:._-]*$/.test(segments[0])) return void 0;
|
|
7004
|
+
const serviceIndex = segments.findIndex(
|
|
7005
|
+
(segment, index) => index > 0 && capabilityServices.has(segment)
|
|
7006
|
+
);
|
|
7007
|
+
if (serviceIndex < 1 || segments[serviceIndex] !== service) return void 0;
|
|
7008
|
+
if (segments.slice(1, serviceIndex).some(
|
|
7009
|
+
(segment) => segment.length === 0 || segment === "." || segment === ".."
|
|
7010
|
+
)) return void 0;
|
|
7011
|
+
const pathSegments = segments.slice(serviceIndex + 1);
|
|
7012
|
+
if (pathSegments.some((segment) => segment === "." || segment === "..")) return void 0;
|
|
7013
|
+
if (service !== "kv" && (pathSegments.length === 0 || pathSegments[pathSegments.length - 1] === "")) return void 0;
|
|
7014
|
+
return {
|
|
7015
|
+
space: segments.slice(0, serviceIndex).join("/"),
|
|
7016
|
+
path: pathSegments.join("/")
|
|
7017
|
+
};
|
|
7018
|
+
}
|
|
7019
|
+
function safeCapabilityResource(value, service, action) {
|
|
7020
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 1024) return false;
|
|
7021
|
+
if (service === "encryption" && value.startsWith("urn:tinycloud:encryption:")) {
|
|
7022
|
+
if (!/^[A-Za-z0-9_][A-Za-z0-9_.:/-]*$/.test(value) || value.includes("//") || value.split("/").some((segment) => segment === "." || segment === "..")) return false;
|
|
7023
|
+
try {
|
|
7024
|
+
parseNetworkId(value);
|
|
7025
|
+
return true;
|
|
7026
|
+
} catch {
|
|
7027
|
+
return false;
|
|
7028
|
+
}
|
|
7029
|
+
}
|
|
7030
|
+
const parsed = parseCapabilityResource2(value, service);
|
|
7031
|
+
return parsed !== void 0 && (!parsed.path.endsWith("/") || service === "kv" && action === "tinycloud.kv/list") && (parsed.path !== "" || service === "kv" && action === "tinycloud.kv/list");
|
|
7032
|
+
}
|
|
7033
|
+
function validatedCapabilityOf2(error) {
|
|
7034
|
+
const verdict = authorizationVerdictOf2(error);
|
|
7035
|
+
if (verdict !== "unauthenticated" && verdict !== "forbidden") return void 0;
|
|
7036
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7037
|
+
let node = error;
|
|
7038
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH && typeof node === "object" && node !== null && !seen.has(node); depth += 1) {
|
|
7039
|
+
seen.add(node);
|
|
7040
|
+
const record = node;
|
|
7041
|
+
const status = errorStatusOf(record);
|
|
7042
|
+
const meta = record.meta;
|
|
7043
|
+
if ((status === 401 || status === 403 || status === void 0 && record.code === ErrorCodes.AUTH_UNAUTHORIZED) && typeof meta === "object" && meta !== null && !Array.isArray(meta)) {
|
|
7044
|
+
const metadata = meta;
|
|
7045
|
+
const { resource, requiredAction } = metadata;
|
|
7046
|
+
if (typeof requiredAction === "string" && grantableActions.has(requiredAction)) {
|
|
7047
|
+
const actionService = requiredAction.slice("tinycloud.".length, requiredAction.indexOf("/"));
|
|
7048
|
+
const explicitService = record.service === void 0 ? metadata.service : record.service;
|
|
7049
|
+
if (safeCapabilityResource(resource, actionService, requiredAction) && (explicitService === void 0 || explicitService === actionService || explicitService === `tinycloud.${actionService}`)) {
|
|
7050
|
+
return { resource, requiredAction };
|
|
7051
|
+
}
|
|
7052
|
+
}
|
|
7053
|
+
}
|
|
7054
|
+
node = record.cause;
|
|
7055
|
+
}
|
|
7056
|
+
return void 0;
|
|
7057
|
+
}
|
|
7058
|
+
var MAX_CAUSE_DEPTH = 8;
|
|
7059
|
+
function errorStatusOf(node) {
|
|
7060
|
+
const meta = node.meta;
|
|
7061
|
+
const candidates = [
|
|
7062
|
+
node.status,
|
|
7063
|
+
node.statusCode,
|
|
7064
|
+
typeof meta === "object" && meta !== null ? meta.status : void 0
|
|
7065
|
+
];
|
|
7066
|
+
for (const candidate of candidates) {
|
|
7067
|
+
if (typeof candidate === "number" && Number.isInteger(candidate) && candidate >= 400 && candidate <= 599) {
|
|
7068
|
+
return candidate;
|
|
7069
|
+
}
|
|
7070
|
+
}
|
|
7071
|
+
return void 0;
|
|
7072
|
+
}
|
|
7073
|
+
function authorizationVerdictOf2(error) {
|
|
7074
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7075
|
+
let sawUnauthorizedCode = false;
|
|
7076
|
+
let node = error;
|
|
7077
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH && typeof node === "object" && node !== null && !seen.has(node); depth += 1) {
|
|
7078
|
+
seen.add(node);
|
|
7079
|
+
const record = node;
|
|
7080
|
+
const status = errorStatusOf(record);
|
|
7081
|
+
if (status === 401) return "unauthenticated";
|
|
7082
|
+
if (status === 403) return "forbidden";
|
|
7083
|
+
if (status !== void 0) return "other";
|
|
7084
|
+
if (record.code === ErrorCodes.AUTH_UNAUTHORIZED) sawUnauthorizedCode = true;
|
|
7085
|
+
node = record.cause;
|
|
7086
|
+
}
|
|
7087
|
+
return sawUnauthorizedCode ? "forbidden" : void 0;
|
|
7088
|
+
}
|
|
6890
7089
|
function storageQuotaExceededError(service, message, meta) {
|
|
6891
7090
|
return {
|
|
6892
7091
|
code: ErrorCodes.STORAGE_QUOTA_EXCEEDED,
|
|
@@ -7582,12 +7781,14 @@ var KVService = class extends BaseService {
|
|
|
7582
7781
|
signal: this.combineSignals(options?.signal)
|
|
7583
7782
|
});
|
|
7584
7783
|
if (!response.ok) {
|
|
7585
|
-
const errorText = await response.text();
|
|
7784
|
+
const errorText = response.status === 401 || response.status === 403 ? await this.readAuthorizationText(response) : await response.text();
|
|
7586
7785
|
if (response.status === 401 || response.status === 403) {
|
|
7587
7786
|
return this.authorizationFailure(
|
|
7588
7787
|
`Failed to batch read ${keys.length} key(s)`,
|
|
7589
7788
|
response,
|
|
7590
|
-
errorText
|
|
7789
|
+
errorText,
|
|
7790
|
+
paths,
|
|
7791
|
+
action
|
|
7591
7792
|
);
|
|
7592
7793
|
}
|
|
7593
7794
|
if (response.status === 413) {
|
|
@@ -7677,7 +7878,7 @@ var KVService = class extends BaseService {
|
|
|
7677
7878
|
return text;
|
|
7678
7879
|
}
|
|
7679
7880
|
}
|
|
7680
|
-
async createSignedReadUrlError(response, key) {
|
|
7881
|
+
async createSignedReadUrlError(response, key, path) {
|
|
7681
7882
|
let errorText = response.statusText;
|
|
7682
7883
|
try {
|
|
7683
7884
|
const text = await response.text();
|
|
@@ -7690,7 +7891,9 @@ var KVService = class extends BaseService {
|
|
|
7690
7891
|
return this.authorizationFailure(
|
|
7691
7892
|
`Failed to create signed read URL for key ${JSON.stringify(key)}`,
|
|
7692
7893
|
response,
|
|
7693
|
-
errorText
|
|
7894
|
+
errorText,
|
|
7895
|
+
[path],
|
|
7896
|
+
KVAction.GET
|
|
7694
7897
|
);
|
|
7695
7898
|
}
|
|
7696
7899
|
const code3 = response.status === 400 ? ErrorCodes.INVALID_INPUT : ErrorCodes.NETWORK_ERROR;
|
|
@@ -7703,21 +7906,42 @@ var KVService = class extends BaseService {
|
|
|
7703
7906
|
)
|
|
7704
7907
|
);
|
|
7705
7908
|
}
|
|
7909
|
+
/** A known 401/403 keeps its typed status even if reading its body fails. */
|
|
7910
|
+
async readAuthorizationText(response) {
|
|
7911
|
+
try {
|
|
7912
|
+
return await response.text();
|
|
7913
|
+
} catch {
|
|
7914
|
+
return "";
|
|
7915
|
+
}
|
|
7916
|
+
}
|
|
7706
7917
|
/**
|
|
7707
7918
|
* AUTH_UNAUTHORIZED for a 401/403 response. The message keeps the HTTP
|
|
7708
7919
|
* status and the server text (`<context>: <status> - <text>`, the same
|
|
7709
7920
|
* shape as every other KV failure) so callers that rethrow only the message
|
|
7710
7921
|
* still see the status; `meta.status` carries it for typed callers.
|
|
7711
|
-
*
|
|
7922
|
+
* Server hints must match the requested path/action (whether the node sends
|
|
7923
|
+
* a relative path or full resource); metadata uses only the request-derived
|
|
7924
|
+
* canonical resource under the authenticated session's space.
|
|
7712
7925
|
*/
|
|
7713
|
-
authorizationFailure(context, response, errorText, extraMeta = {}) {
|
|
7926
|
+
authorizationFailure(context, response, errorText, paths, expectedAction, extraMeta = {}) {
|
|
7714
7927
|
const { resource, action } = parseAuthError(errorText);
|
|
7928
|
+
const requestedPath = paths.find(
|
|
7929
|
+
(path) => resource === path || resource === `${this.context.session.spaceId}/kv/${path}`
|
|
7930
|
+
);
|
|
7931
|
+
const capability = requestedPath !== void 0 && action === expectedAction ? validatedCapabilityOf2({
|
|
7932
|
+
service: "kv",
|
|
7933
|
+
code: ErrorCodes.AUTH_UNAUTHORIZED,
|
|
7934
|
+
meta: {
|
|
7935
|
+
status: response.status,
|
|
7936
|
+
resource: `${this.context.session.spaceId}/kv/${requestedPath}`,
|
|
7937
|
+
requiredAction: action
|
|
7938
|
+
}
|
|
7939
|
+
}) : void 0;
|
|
7715
7940
|
const detail = errorText.trim().length > 0 ? errorText : response.statusText || "authorization failed";
|
|
7716
7941
|
return err(authUnauthorizedError("kv", `${context}: ${response.status} - ${detail}`, {
|
|
7717
7942
|
status: response.status,
|
|
7718
|
-
...
|
|
7719
|
-
...
|
|
7720
|
-
...extraMeta
|
|
7943
|
+
...extraMeta,
|
|
7944
|
+
...capability
|
|
7721
7945
|
}));
|
|
7722
7946
|
}
|
|
7723
7947
|
normalizeSignedReadUrlResponse(data) {
|
|
@@ -7761,13 +7985,24 @@ var KVService = class extends BaseService {
|
|
|
7761
7985
|
);
|
|
7762
7986
|
if (!response.ok) {
|
|
7763
7987
|
if (response.status === 401 || response.status === 403) {
|
|
7764
|
-
const errorText2 = await
|
|
7988
|
+
const errorText2 = await this.readAuthorizationText(response);
|
|
7765
7989
|
const permissionHint = parsePermissionHintFromErrorText(errorText2);
|
|
7990
|
+
const structuredCapability = permissionHint?.service === "tinycloud.kv" && permissionHint.space === this.context.session.spaceId && permissionHint.path === path ? validatedCapabilityOf2({
|
|
7991
|
+
service: "kv",
|
|
7992
|
+
code: ErrorCodes.AUTH_UNAUTHORIZED,
|
|
7993
|
+
meta: {
|
|
7994
|
+
status: response.status,
|
|
7995
|
+
resource: `${this.context.session.spaceId}/kv/${path}`,
|
|
7996
|
+
requiredAction: KVAction.GET
|
|
7997
|
+
}
|
|
7998
|
+
}) : void 0;
|
|
7766
7999
|
return this.authorizationFailure(
|
|
7767
8000
|
`Failed to get key ${JSON.stringify(key)}`,
|
|
7768
8001
|
response,
|
|
7769
8002
|
errorText2,
|
|
7770
|
-
|
|
8003
|
+
[path],
|
|
8004
|
+
KVAction.GET,
|
|
8005
|
+
structuredCapability ? { permissionHint, ...structuredCapability } : {}
|
|
7771
8006
|
);
|
|
7772
8007
|
}
|
|
7773
8008
|
if (response.status === 404) {
|
|
@@ -7844,7 +8079,9 @@ var KVService = class extends BaseService {
|
|
|
7844
8079
|
return this.authorizationFailure(
|
|
7845
8080
|
`Failed to put key ${JSON.stringify(key)}`,
|
|
7846
8081
|
response,
|
|
7847
|
-
await
|
|
8082
|
+
await this.readAuthorizationText(response),
|
|
8083
|
+
[path],
|
|
8084
|
+
KVAction.PUT
|
|
7848
8085
|
);
|
|
7849
8086
|
}
|
|
7850
8087
|
if (!response.ok) {
|
|
@@ -7973,7 +8210,9 @@ var KVService = class extends BaseService {
|
|
|
7973
8210
|
return this.authorizationFailure(
|
|
7974
8211
|
`Failed to batch put ${items.length} key(s)`,
|
|
7975
8212
|
response,
|
|
7976
|
-
errorText
|
|
8213
|
+
errorText,
|
|
8214
|
+
paths,
|
|
8215
|
+
KVAction.PUT
|
|
7977
8216
|
);
|
|
7978
8217
|
}
|
|
7979
8218
|
const quotaError = this.handleQuotaErrorResponse(
|
|
@@ -8094,11 +8333,13 @@ var KVService = class extends BaseService {
|
|
|
8094
8333
|
}
|
|
8095
8334
|
);
|
|
8096
8335
|
if (!response.ok) {
|
|
8097
|
-
if (response.status === 401) {
|
|
8336
|
+
if (response.status === 401 || response.status === 403) {
|
|
8098
8337
|
return this.authorizationFailure(
|
|
8099
8338
|
"Failed to list keys",
|
|
8100
8339
|
response,
|
|
8101
|
-
await
|
|
8340
|
+
await this.readAuthorizationText(response),
|
|
8341
|
+
[listPath],
|
|
8342
|
+
KVAction.LIST
|
|
8102
8343
|
);
|
|
8103
8344
|
}
|
|
8104
8345
|
const errorText = await response.text();
|
|
@@ -8147,11 +8388,13 @@ var KVService = class extends BaseService {
|
|
|
8147
8388
|
options?.ifMatch === void 0 ? void 0 : { "if-match": options.ifMatch }
|
|
8148
8389
|
);
|
|
8149
8390
|
if (!response.ok) {
|
|
8150
|
-
if (response.status === 401) {
|
|
8391
|
+
if (response.status === 401 || response.status === 403) {
|
|
8151
8392
|
return this.authorizationFailure(
|
|
8152
8393
|
`Failed to delete key ${JSON.stringify(key)}`,
|
|
8153
8394
|
response,
|
|
8154
|
-
await
|
|
8395
|
+
await this.readAuthorizationText(response),
|
|
8396
|
+
[path],
|
|
8397
|
+
KVAction.DELETE
|
|
8155
8398
|
);
|
|
8156
8399
|
}
|
|
8157
8400
|
if (response.status === 404) {
|
|
@@ -8209,11 +8452,13 @@ var KVService = class extends BaseService {
|
|
|
8209
8452
|
options?.signal
|
|
8210
8453
|
);
|
|
8211
8454
|
if (!response.ok) {
|
|
8212
|
-
if (response.status === 401) {
|
|
8455
|
+
if (response.status === 401 || response.status === 403) {
|
|
8213
8456
|
return this.authorizationFailure(
|
|
8214
8457
|
`Failed to get metadata for key ${JSON.stringify(key)}`,
|
|
8215
8458
|
response,
|
|
8216
|
-
await
|
|
8459
|
+
await this.readAuthorizationText(response),
|
|
8460
|
+
[path],
|
|
8461
|
+
KVAction.HEAD
|
|
8217
8462
|
);
|
|
8218
8463
|
}
|
|
8219
8464
|
if (response.status === 404) {
|
|
@@ -8280,7 +8525,7 @@ var KVService = class extends BaseService {
|
|
|
8280
8525
|
signal: this.combineSignals(options?.signal)
|
|
8281
8526
|
});
|
|
8282
8527
|
if (!response.ok) {
|
|
8283
|
-
return this.createSignedReadUrlError(response, key);
|
|
8528
|
+
return this.createSignedReadUrlError(response, key, path);
|
|
8284
8529
|
}
|
|
8285
8530
|
const signedUrl = this.normalizeSignedReadUrlResponse(
|
|
8286
8531
|
await response.json()
|
|
@@ -8504,14 +8749,15 @@ var SQLService = class extends BaseService {
|
|
|
8504
8749
|
};
|
|
8505
8750
|
if (options?.maxRows !== void 0) body.maxRows = options.maxRows;
|
|
8506
8751
|
if (options?.maxBytes !== void 0) body.maxBytes = options.maxBytes;
|
|
8752
|
+
const action = this.actionForSql(sql, SQLAction.READ);
|
|
8507
8753
|
const response = await this.invokeSQL(
|
|
8508
8754
|
dbName,
|
|
8509
|
-
|
|
8755
|
+
action,
|
|
8510
8756
|
body,
|
|
8511
8757
|
options?.signal
|
|
8512
8758
|
);
|
|
8513
8759
|
if (!response.ok) {
|
|
8514
|
-
return this.handleErrorResponse(response, "query");
|
|
8760
|
+
return this.handleErrorResponse(response, "query", dbName, [action]);
|
|
8515
8761
|
}
|
|
8516
8762
|
const data = await response.json();
|
|
8517
8763
|
return ok(data);
|
|
@@ -8540,14 +8786,15 @@ var SQLService = class extends BaseService {
|
|
|
8540
8786
|
(statement) => this.actionForSql(statement, SQLAction.SCHEMA)
|
|
8541
8787
|
)
|
|
8542
8788
|
];
|
|
8789
|
+
const requestedActions2 = this.dedupeActions(actions);
|
|
8543
8790
|
const response = await this.invokeSQL(
|
|
8544
8791
|
dbName,
|
|
8545
|
-
|
|
8792
|
+
requestedActions2,
|
|
8546
8793
|
body,
|
|
8547
8794
|
options?.signal
|
|
8548
8795
|
);
|
|
8549
8796
|
if (!response.ok) {
|
|
8550
|
-
return this.handleErrorResponse(response, "execute");
|
|
8797
|
+
return this.handleErrorResponse(response, "execute", dbName, requestedActions2);
|
|
8551
8798
|
}
|
|
8552
8799
|
const data = await response.json();
|
|
8553
8800
|
return ok(data);
|
|
@@ -8562,14 +8809,15 @@ var SQLService = class extends BaseService {
|
|
|
8562
8809
|
return err(authRequiredError("sql"));
|
|
8563
8810
|
}
|
|
8564
8811
|
try {
|
|
8812
|
+
const requestedActions2 = this.actionsForSqlBatch(statements);
|
|
8565
8813
|
const response = await this.invokeSQL(
|
|
8566
8814
|
dbName,
|
|
8567
|
-
|
|
8815
|
+
requestedActions2,
|
|
8568
8816
|
{ action: "batch", statements },
|
|
8569
8817
|
options?.signal
|
|
8570
8818
|
);
|
|
8571
8819
|
if (!response.ok) {
|
|
8572
|
-
return this.handleErrorResponse(response, "batch");
|
|
8820
|
+
return this.handleErrorResponse(response, "batch", dbName, requestedActions2);
|
|
8573
8821
|
}
|
|
8574
8822
|
const data = await response.json();
|
|
8575
8823
|
return ok(data);
|
|
@@ -8591,7 +8839,7 @@ var SQLService = class extends BaseService {
|
|
|
8591
8839
|
options?.signal
|
|
8592
8840
|
);
|
|
8593
8841
|
if (!response.ok) {
|
|
8594
|
-
return this.handleErrorResponse(response, "executeStatement");
|
|
8842
|
+
return this.handleErrorResponse(response, "executeStatement", dbName, [SQLAction.WRITE]);
|
|
8595
8843
|
}
|
|
8596
8844
|
const data = await response.json();
|
|
8597
8845
|
return ok(data);
|
|
@@ -8613,7 +8861,7 @@ var SQLService = class extends BaseService {
|
|
|
8613
8861
|
options?.signal
|
|
8614
8862
|
);
|
|
8615
8863
|
if (!response.ok) {
|
|
8616
|
-
return this.handleErrorResponse(response, "export");
|
|
8864
|
+
return this.handleErrorResponse(response, "export", dbName, [SQLAction.READ]);
|
|
8617
8865
|
}
|
|
8618
8866
|
const resp = response;
|
|
8619
8867
|
if (typeof resp.blob === "function") {
|
|
@@ -8747,7 +8995,7 @@ var SQLService = class extends BaseService {
|
|
|
8747
8995
|
}))
|
|
8748
8996
|
);
|
|
8749
8997
|
}
|
|
8750
|
-
async handleErrorResponse(response, operation) {
|
|
8998
|
+
async handleErrorResponse(response, operation, dbName, requestedActions2) {
|
|
8751
8999
|
const errorText = await response.text();
|
|
8752
9000
|
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
8753
9001
|
if (response.status === 402) {
|
|
@@ -8766,9 +9014,11 @@ var SQLService = class extends BaseService {
|
|
|
8766
9014
|
errorBody
|
|
8767
9015
|
);
|
|
8768
9016
|
if (response.status === 401) {
|
|
8769
|
-
const {
|
|
8770
|
-
if (action
|
|
8771
|
-
|
|
9017
|
+
const { action } = parseAuthError(errorText);
|
|
9018
|
+
if (action && requestedActions2.includes(action)) {
|
|
9019
|
+
meta.requiredAction = action;
|
|
9020
|
+
meta.resource = `${this.context.session.spaceId}/sql/${dbName}`;
|
|
9021
|
+
}
|
|
8772
9022
|
}
|
|
8773
9023
|
return err(
|
|
8774
9024
|
serviceError(errorCode2, message, "sql", { meta })
|
|
@@ -11517,75 +11767,6 @@ function canonicalHashHex(sha2563, value) {
|
|
|
11517
11767
|
const canonical = canonicalize(value);
|
|
11518
11768
|
return hexEncode2(sha2563(utf8Encode(canonical)));
|
|
11519
11769
|
}
|
|
11520
|
-
var URN_PREFIX = "urn:tinycloud:encryption:";
|
|
11521
|
-
var NETWORK_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
11522
|
-
var PKH_EIP155_DID_RE = /^did:pkh:eip155:(\d+):(0x[a-fA-F0-9]{40})$/;
|
|
11523
|
-
var NetworkIdError = class extends Error {
|
|
11524
|
-
constructor(message) {
|
|
11525
|
-
super(message);
|
|
11526
|
-
this.name = "NetworkIdError";
|
|
11527
|
-
}
|
|
11528
|
-
};
|
|
11529
|
-
function parseNetworkId(networkId) {
|
|
11530
|
-
if (typeof networkId !== "string" || networkId.length === 0) {
|
|
11531
|
-
throw new NetworkIdError("networkId must be a non-empty string");
|
|
11532
|
-
}
|
|
11533
|
-
if (!networkId.startsWith(URN_PREFIX)) {
|
|
11534
|
-
throw new NetworkIdError(
|
|
11535
|
-
`networkId must start with ${URN_PREFIX} (got ${JSON.stringify(networkId)})`
|
|
11536
|
-
);
|
|
11537
|
-
}
|
|
11538
|
-
const body = networkId.slice(URN_PREFIX.length);
|
|
11539
|
-
const lastColon = body.lastIndexOf(":");
|
|
11540
|
-
if (lastColon <= 0 || lastColon === body.length - 1) {
|
|
11541
|
-
throw new NetworkIdError(
|
|
11542
|
-
`networkId missing ownerDid or name segment (got ${JSON.stringify(networkId)})`
|
|
11543
|
-
);
|
|
11544
|
-
}
|
|
11545
|
-
const ownerDid = body.slice(0, lastColon);
|
|
11546
|
-
const name = body.slice(lastColon + 1);
|
|
11547
|
-
if (!ownerDid.startsWith("did:")) {
|
|
11548
|
-
throw new NetworkIdError(
|
|
11549
|
-
`networkId ownerDid must be a DID (got ${JSON.stringify(ownerDid)})`
|
|
11550
|
-
);
|
|
11551
|
-
}
|
|
11552
|
-
const didParts = ownerDid.split(":");
|
|
11553
|
-
if (didParts.length < 3 || didParts.some((p) => p.length === 0)) {
|
|
11554
|
-
throw new NetworkIdError(
|
|
11555
|
-
`networkId ownerDid is not a well-formed DID (got ${JSON.stringify(ownerDid)})`
|
|
11556
|
-
);
|
|
11557
|
-
}
|
|
11558
|
-
if (!NETWORK_NAME_RE.test(name)) {
|
|
11559
|
-
throw new NetworkIdError(
|
|
11560
|
-
`networkId name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
11561
|
-
);
|
|
11562
|
-
}
|
|
11563
|
-
return { networkId, ownerDid, name };
|
|
11564
|
-
}
|
|
11565
|
-
function parsePkhOwnerDid(ownerDid) {
|
|
11566
|
-
const match = ownerDid.match(PKH_EIP155_DID_RE);
|
|
11567
|
-
if (!match) return null;
|
|
11568
|
-
return {
|
|
11569
|
-
chainId: match[1],
|
|
11570
|
-
address: match[2].toLowerCase()
|
|
11571
|
-
};
|
|
11572
|
-
}
|
|
11573
|
-
function ownerDidMatches(a, b) {
|
|
11574
|
-
const aPkh = parsePkhOwnerDid(a);
|
|
11575
|
-
const bPkh = parsePkhOwnerDid(b);
|
|
11576
|
-
if (aPkh && bPkh) {
|
|
11577
|
-
return aPkh.chainId === bPkh.chainId && aPkh.address === bPkh.address;
|
|
11578
|
-
}
|
|
11579
|
-
return a === b;
|
|
11580
|
-
}
|
|
11581
|
-
function networkDiscoveryKey(name) {
|
|
11582
|
-
if (!NETWORK_NAME_RE.test(name)) {
|
|
11583
|
-
throw new NetworkIdError(
|
|
11584
|
-
`network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
11585
|
-
);
|
|
11586
|
-
}
|
|
11587
|
-
return `.well-known/encryption/network/${name}`;
|
|
11588
|
-
}
|
|
11589
11770
|
var DEFAULT_ENCRYPTION_ALG = "x25519-aes256gcm/v1";
|
|
11590
11771
|
var ENVELOPE_VERSION = 1;
|
|
11591
11772
|
var DEFAULT_KEY_VERSION = 1;
|
|
@@ -12421,7 +12602,7 @@ var SERVICE_SHORT_TO_LONG = Object.freeze({
|
|
|
12421
12602
|
});
|
|
12422
12603
|
var ENCRYPTION_PERMISSION_SERVICE2 = "tinycloud.encryption";
|
|
12423
12604
|
var ENCRYPTION_MANIFEST_SPACE2 = "encryption";
|
|
12424
|
-
var
|
|
12605
|
+
var SERVICE_LONG_TO_SHORT2 = Object.freeze(
|
|
12425
12606
|
Object.fromEntries(
|
|
12426
12607
|
Object.entries(SERVICE_SHORT_TO_LONG).map(([s, l]) => [l, s])
|
|
12427
12608
|
)
|
|
@@ -13955,7 +14136,7 @@ async function authenticatedNode(cmd) {
|
|
|
13955
14136
|
}
|
|
13956
14137
|
function assertOk(result) {
|
|
13957
14138
|
if (!result.ok) {
|
|
13958
|
-
throw
|
|
14139
|
+
throw cliErrorFromService(result.error);
|
|
13959
14140
|
}
|
|
13960
14141
|
}
|
|
13961
14142
|
async function loadManifestSource(source) {
|
|
@@ -15967,7 +16148,7 @@ async function importRequestBoundDelegation(ctx, artifact) {
|
|
|
15967
16148
|
ExitCode.ERROR
|
|
15968
16149
|
);
|
|
15969
16150
|
case "error":
|
|
15970
|
-
throw
|
|
16151
|
+
throw cliErrorFromService(result.error);
|
|
15971
16152
|
}
|
|
15972
16153
|
}
|
|
15973
16154
|
function isStoredDelegationLike(value) {
|
|
@@ -16702,7 +16883,7 @@ function registerDelegationCommand(program) {
|
|
|
16702
16883
|
expiry
|
|
16703
16884
|
});
|
|
16704
16885
|
if (!result.ok) {
|
|
16705
|
-
throw
|
|
16886
|
+
throw cliErrorFromService(result.error);
|
|
16706
16887
|
}
|
|
16707
16888
|
outputJson({
|
|
16708
16889
|
cid: result.data.cid,
|
|
@@ -16722,7 +16903,7 @@ function registerDelegationCommand(program) {
|
|
|
16722
16903
|
const node = await ensureAuthenticated(ctx);
|
|
16723
16904
|
const result = await node.delegationManager.list();
|
|
16724
16905
|
if (!result.ok) {
|
|
16725
|
-
throw
|
|
16906
|
+
throw cliErrorFromService(result.error);
|
|
16726
16907
|
}
|
|
16727
16908
|
let delegations = result.data;
|
|
16728
16909
|
if (options.granted) {
|
|
@@ -16768,7 +16949,7 @@ function registerDelegationCommand(program) {
|
|
|
16768
16949
|
const node = await ensureAuthenticated(ctx);
|
|
16769
16950
|
const result = await node.delegationManager.revoke(cid);
|
|
16770
16951
|
if (!result.ok) {
|
|
16771
|
-
throw
|
|
16952
|
+
throw cliErrorFromService(result.error);
|
|
16772
16953
|
}
|
|
16773
16954
|
outputJson({ cid, revoked: true });
|
|
16774
16955
|
} catch (error) {
|
|
@@ -16893,7 +17074,6 @@ function registerDoctorCommand(program) {
|
|
|
16893
17074
|
init_profiles();
|
|
16894
17075
|
init_formatter();
|
|
16895
17076
|
init_errors();
|
|
16896
|
-
init_constants();
|
|
16897
17077
|
import { readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
|
|
16898
17078
|
import { resolve } from "path";
|
|
16899
17079
|
init_theme();
|
|
@@ -16910,7 +17090,7 @@ function registerDuckdbCommand(program) {
|
|
|
16910
17090
|
() => node.duckdb.db(options.db).query(sqlStr, params)
|
|
16911
17091
|
);
|
|
16912
17092
|
if (!result.ok) {
|
|
16913
|
-
throw
|
|
17093
|
+
throw cliErrorFromService(result.error);
|
|
16914
17094
|
}
|
|
16915
17095
|
const { columns, rows, rowCount } = result.data;
|
|
16916
17096
|
if (shouldOutputJson()) {
|
|
@@ -16942,7 +17122,7 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
|
|
|
16942
17122
|
() => node.duckdb.db(options.db).execute(sqlStr, params)
|
|
16943
17123
|
);
|
|
16944
17124
|
if (!result.ok) {
|
|
16945
|
-
throw
|
|
17125
|
+
throw cliErrorFromService(result.error);
|
|
16946
17126
|
}
|
|
16947
17127
|
outputJson({ changes: result.data.changes });
|
|
16948
17128
|
} catch (error) {
|
|
@@ -16959,7 +17139,7 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
|
|
|
16959
17139
|
() => node.duckdb.db(options.db).describe()
|
|
16960
17140
|
);
|
|
16961
17141
|
if (!result.ok) {
|
|
16962
|
-
throw
|
|
17142
|
+
throw cliErrorFromService(result.error);
|
|
16963
17143
|
}
|
|
16964
17144
|
const schema = result.data;
|
|
16965
17145
|
if (shouldOutputJson()) {
|
|
@@ -17004,7 +17184,7 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
|
|
|
17004
17184
|
() => node.duckdb.db(options.db).export()
|
|
17005
17185
|
);
|
|
17006
17186
|
if (!result.ok) {
|
|
17007
|
-
throw
|
|
17187
|
+
throw cliErrorFromService(result.error);
|
|
17008
17188
|
}
|
|
17009
17189
|
const blob = result.data;
|
|
17010
17190
|
const buffer = Buffer.from(await blob.arrayBuffer());
|
|
@@ -17031,7 +17211,7 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
|
|
|
17031
17211
|
() => node.duckdb.db(options.db).import(bytes)
|
|
17032
17212
|
);
|
|
17033
17213
|
if (!result.ok) {
|
|
17034
|
-
throw
|
|
17214
|
+
throw cliErrorFromService(result.error);
|
|
17035
17215
|
}
|
|
17036
17216
|
outputJson({
|
|
17037
17217
|
file: filePath,
|
|
@@ -17168,7 +17348,7 @@ init_theme();
|
|
|
17168
17348
|
async function throwKvError(error, spaceUri, profileName) {
|
|
17169
17349
|
const hosted = await unhostedSpaceError(error, spaceUri, profileName);
|
|
17170
17350
|
if (hosted) throw hosted;
|
|
17171
|
-
throw
|
|
17351
|
+
throw cliErrorFromService(error);
|
|
17172
17352
|
}
|
|
17173
17353
|
function isByteCount(value) {
|
|
17174
17354
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
@@ -18685,7 +18865,7 @@ function registerSecretsCommand(program, openKeyAcquisition) {
|
|
|
18685
18865
|
operation: () => secrets2.list(scopeOptions)
|
|
18686
18866
|
});
|
|
18687
18867
|
if (!result.ok) {
|
|
18688
|
-
throw
|
|
18868
|
+
throw cliErrorFromService(result.error);
|
|
18689
18869
|
}
|
|
18690
18870
|
const secretNames = Array.isArray(result.data) ? result.data : [];
|
|
18691
18871
|
outputJson({
|
|
@@ -18802,7 +18982,7 @@ function registerSecretsCommand(program, openKeyAcquisition) {
|
|
|
18802
18982
|
operation: () => secrets2.put(name, secretValue, scopeOptions)
|
|
18803
18983
|
});
|
|
18804
18984
|
if (!result.ok) {
|
|
18805
|
-
throw
|
|
18985
|
+
throw cliErrorFromService(result.error);
|
|
18806
18986
|
}
|
|
18807
18987
|
outputJson({ name, written: true });
|
|
18808
18988
|
} catch (error) {
|
|
@@ -18828,7 +19008,7 @@ function registerSecretsCommand(program, openKeyAcquisition) {
|
|
|
18828
19008
|
operation: () => secrets2.delete(name, scopeOptions)
|
|
18829
19009
|
});
|
|
18830
19010
|
if (!result.ok) {
|
|
18831
|
-
throw
|
|
19011
|
+
throw cliErrorFromService(result.error);
|
|
18832
19012
|
}
|
|
18833
19013
|
outputJson({ name, deleted: true });
|
|
18834
19014
|
} catch (error) {
|
|
@@ -27511,7 +27691,6 @@ async function notifyShare(input) {
|
|
|
27511
27691
|
};
|
|
27512
27692
|
}
|
|
27513
27693
|
let attempts = 0;
|
|
27514
|
-
let lastError;
|
|
27515
27694
|
while (attempts < attemptsLimit) {
|
|
27516
27695
|
if (input.signal?.aborted) throw new ShareNotifyError("share delivery was cancelled");
|
|
27517
27696
|
attempts += 1;
|
|
@@ -27538,10 +27717,19 @@ async function notifyShare(input) {
|
|
|
27538
27717
|
reason: "delivery-window-expired"
|
|
27539
27718
|
};
|
|
27540
27719
|
}
|
|
27541
|
-
|
|
27720
|
+
if (error !== null && typeof error === "object" && "status" in error && (error.status === 401 || error.status === 403)) {
|
|
27721
|
+
return {
|
|
27722
|
+
protocol: "tinycloud-share",
|
|
27723
|
+
version: 1,
|
|
27724
|
+
shareId: input.shareId,
|
|
27725
|
+
state: "partial-failure",
|
|
27726
|
+
idempotencyKey,
|
|
27727
|
+
attempts,
|
|
27728
|
+
retryable: false
|
|
27729
|
+
};
|
|
27730
|
+
}
|
|
27542
27731
|
}
|
|
27543
27732
|
}
|
|
27544
|
-
void lastError;
|
|
27545
27733
|
return { protocol: "tinycloud-share", version: 1, shareId: input.shareId, state: "partial-failure", idempotencyKey, attempts, retryable: true };
|
|
27546
27734
|
}
|
|
27547
27735
|
async function defaultIdempotencyKey(shareId, recipient) {
|
|
@@ -29543,7 +29731,7 @@ function registerSpaceCommand(program) {
|
|
|
29543
29731
|
const node = await ensureAuthenticated(ctx);
|
|
29544
29732
|
const result = await node.spaces.list();
|
|
29545
29733
|
if (!result.ok) {
|
|
29546
|
-
throw
|
|
29734
|
+
throw cliErrorFromService(result.error);
|
|
29547
29735
|
}
|
|
29548
29736
|
if (shouldOutputJson()) {
|
|
29549
29737
|
outputJson({ spaces: result.data, count: result.data.length });
|
|
@@ -29688,7 +29876,7 @@ async function throwSqlError(error, spaceUri, profileName, prefix) {
|
|
|
29688
29876
|
const hosted = await unhostedSpaceError(error, spaceUri, profileName);
|
|
29689
29877
|
if (hosted) throw hosted;
|
|
29690
29878
|
const message = prefix ? `${prefix}${error.message}` : error.message;
|
|
29691
|
-
throw
|
|
29879
|
+
throw cliErrorFromService(error, message);
|
|
29692
29880
|
}
|
|
29693
29881
|
function registerSqlCommand(program) {
|
|
29694
29882
|
const sql = program.command("sql").description("SQLite database operations for your TinyCloud space").addHelpText("after", `
|
|
@@ -30400,7 +30588,7 @@ async function unlockVault(node, privateKey) {
|
|
|
30400
30588
|
const signer = new PrivateKeySigner2(privateKey);
|
|
30401
30589
|
const result = await node.vault.unlock(signer);
|
|
30402
30590
|
if (result && !result.ok) {
|
|
30403
|
-
throw
|
|
30591
|
+
throw cliErrorFromService(result.error);
|
|
30404
30592
|
}
|
|
30405
30593
|
}
|
|
30406
30594
|
function registerVaultCommand(program) {
|
|
@@ -30441,7 +30629,7 @@ function registerVaultCommand(program) {
|
|
|
30441
30629
|
}
|
|
30442
30630
|
const result = await withSpinner(`Writing ${key}...`, () => node.vault.put(key, putValue));
|
|
30443
30631
|
if (!result.ok) {
|
|
30444
|
-
throw
|
|
30632
|
+
throw cliErrorFromService(result.error);
|
|
30445
30633
|
}
|
|
30446
30634
|
outputJson({ key, written: true });
|
|
30447
30635
|
} catch (error) {
|
|
@@ -30460,7 +30648,7 @@ function registerVaultCommand(program) {
|
|
|
30460
30648
|
if (result.error.code === "NOT_FOUND") {
|
|
30461
30649
|
throw new CLIError("NOT_FOUND", `Key "${key}" not found`, ExitCode.NOT_FOUND);
|
|
30462
30650
|
}
|
|
30463
|
-
throw
|
|
30651
|
+
throw cliErrorFromService(result.error);
|
|
30464
30652
|
}
|
|
30465
30653
|
const data = result.data.data ?? result.data;
|
|
30466
30654
|
if (options.output) {
|
|
@@ -30491,7 +30679,7 @@ function registerVaultCommand(program) {
|
|
|
30491
30679
|
await withSpinner("Unlocking vault...", () => unlockVault(node, privateKey));
|
|
30492
30680
|
const result = await withSpinner(`Deleting ${key}...`, () => node.vault.delete(key));
|
|
30493
30681
|
if (!result.ok) {
|
|
30494
|
-
throw
|
|
30682
|
+
throw cliErrorFromService(result.error);
|
|
30495
30683
|
}
|
|
30496
30684
|
outputJson({ key, deleted: true });
|
|
30497
30685
|
} catch (error) {
|
|
@@ -30508,7 +30696,7 @@ function registerVaultCommand(program) {
|
|
|
30508
30696
|
const listOptions = options.prefix ? { prefix: options.prefix } : void 0;
|
|
30509
30697
|
const result = await withSpinner("Listing vault keys...", () => node.vault.list(listOptions));
|
|
30510
30698
|
if (!result.ok) {
|
|
30511
|
-
throw
|
|
30699
|
+
throw cliErrorFromService(result.error);
|
|
30512
30700
|
}
|
|
30513
30701
|
const keys = result.data.data ?? result.data;
|
|
30514
30702
|
const keyList = Array.isArray(keys) ? keys : [];
|
|
@@ -30534,7 +30722,7 @@ function registerVaultCommand(program) {
|
|
|
30534
30722
|
outputJson({ key, exists: false, metadata: {} });
|
|
30535
30723
|
return;
|
|
30536
30724
|
}
|
|
30537
|
-
throw
|
|
30725
|
+
throw cliErrorFromService(result.error);
|
|
30538
30726
|
}
|
|
30539
30727
|
outputJson({
|
|
30540
30728
|
key,
|
|
@@ -30584,7 +30772,7 @@ function registerVarsCommand(program) {
|
|
|
30584
30772
|
const prefixedKv = node.kv.withPrefix(VARIABLES_PREFIX);
|
|
30585
30773
|
const result = await withSpinner("Listing variables...", () => prefixedKv.list());
|
|
30586
30774
|
if (!result.ok) {
|
|
30587
|
-
throw
|
|
30775
|
+
throw cliErrorFromService(result.error);
|
|
30588
30776
|
}
|
|
30589
30777
|
const rawData = result.data.data ?? result.data;
|
|
30590
30778
|
const keyList = Array.isArray(rawData) ? rawData : rawData?.keys ?? [];
|
|
@@ -30608,7 +30796,7 @@ function registerVarsCommand(program) {
|
|
|
30608
30796
|
if (result.error.code === "KV_NOT_FOUND" || result.error.code === "NOT_FOUND") {
|
|
30609
30797
|
throw new CLIError("NOT_FOUND", `Variable "${name}" not found`, ExitCode.NOT_FOUND);
|
|
30610
30798
|
}
|
|
30611
|
-
throw
|
|
30799
|
+
throw cliErrorFromService(result.error);
|
|
30612
30800
|
}
|
|
30613
30801
|
const data = result.data.data;
|
|
30614
30802
|
let value;
|
|
@@ -30666,7 +30854,7 @@ function registerVarsCommand(program) {
|
|
|
30666
30854
|
const prefixedKv = node.kv.withPrefix(VARIABLES_PREFIX);
|
|
30667
30855
|
const result = await withSpinner(`Setting variable ${name}...`, () => prefixedKv.put(name, payload));
|
|
30668
30856
|
if (!result.ok) {
|
|
30669
|
-
throw
|
|
30857
|
+
throw cliErrorFromService(result.error);
|
|
30670
30858
|
}
|
|
30671
30859
|
outputJson({ name, written: true });
|
|
30672
30860
|
} catch (error) {
|
|
@@ -30682,7 +30870,7 @@ function registerVarsCommand(program) {
|
|
|
30682
30870
|
const prefixedKv = node.kv.withPrefix(VARIABLES_PREFIX);
|
|
30683
30871
|
const result = await withSpinner(`Deleting variable ${name}...`, () => prefixedKv.delete(name));
|
|
30684
30872
|
if (!result.ok) {
|
|
30685
|
-
throw
|
|
30873
|
+
throw cliErrorFromService(result.error);
|
|
30686
30874
|
}
|
|
30687
30875
|
outputJson({ name, deleted: true });
|
|
30688
30876
|
} catch (error) {
|