@tinycloud/cli 1.1.0-beta.11 → 1.1.0-beta.13
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 +103 -21
- package/dist/index.js.map +1 -1
- package/dist/legacy-entry.js +147 -29
- package/dist/legacy-entry.js.map +1 -1
- package/package.json +2 -2
- package/skills/tc-cli/AUTH.md +1 -0
- package/skills/tc-cli/REFERENCE.md +6 -4
package/dist/legacy-entry.js
CHANGED
|
@@ -59,7 +59,9 @@ var init_constants = __esm({
|
|
|
59
59
|
NOT_FOUND: 4,
|
|
60
60
|
PERMISSION_DENIED: 5,
|
|
61
61
|
NETWORK_ERROR: 6,
|
|
62
|
-
NODE_ERROR: 7
|
|
62
|
+
NODE_ERROR: 7,
|
|
63
|
+
/** A write was refused because the owner's TinyCloud storage is full. */
|
|
64
|
+
STORAGE_FULL: 10
|
|
63
65
|
};
|
|
64
66
|
}
|
|
65
67
|
});
|
|
@@ -258,6 +260,86 @@ var init_formatter = __esm({
|
|
|
258
260
|
}
|
|
259
261
|
});
|
|
260
262
|
|
|
263
|
+
// src/output/storage.ts
|
|
264
|
+
function storageRejection(error) {
|
|
265
|
+
let node = error;
|
|
266
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH && typeof node === "object" && node !== null; depth += 1) {
|
|
267
|
+
const record = node;
|
|
268
|
+
let code3;
|
|
269
|
+
if (record.code === "STORAGE_QUOTA_EXCEEDED" || record.code === "STORAGE_LIMIT_REACHED") {
|
|
270
|
+
code3 = record.code;
|
|
271
|
+
} else if (record.code !== void 0) {
|
|
272
|
+
return void 0;
|
|
273
|
+
} else if (isStorageStatus(record)) {
|
|
274
|
+
code3 = storageCodeFromText(record.message);
|
|
275
|
+
}
|
|
276
|
+
if (code3) {
|
|
277
|
+
const account = accountTotals(record) ?? accountTotals(record.meta) ?? accountTotals(record.metadata);
|
|
278
|
+
return account ? { code: code3, account } : { code: code3 };
|
|
279
|
+
}
|
|
280
|
+
node = record.cause;
|
|
281
|
+
}
|
|
282
|
+
return void 0;
|
|
283
|
+
}
|
|
284
|
+
function describeStorageRejection(rejection, progress) {
|
|
285
|
+
const reason = rejection.code === "STORAGE_LIMIT_REACHED" ? "This write is larger than the TinyCloud storage you have left" : "TinyCloud storage is full";
|
|
286
|
+
const message = progress ? `${progress}${reason}.` : `${reason}; nothing was written.`;
|
|
287
|
+
const { account } = rejection;
|
|
288
|
+
const totals = account ? `${formatStorageBytes(account.usedBytes)} used of ${formatStorageBytes(account.limitBytes)}${account.plan ? ` (${account.plan} plan)` : ""}. ` : "";
|
|
289
|
+
return {
|
|
290
|
+
message,
|
|
291
|
+
hint: `${totals}Reading still works.
|
|
292
|
+
Free up space or upgrade: ${MANAGE_STORAGE_URL}`
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
function formatStorageBytes(bytes) {
|
|
296
|
+
const units = ["KiB", "MiB", "GiB", "TiB"];
|
|
297
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
298
|
+
let value = bytes / 1024;
|
|
299
|
+
let unit = 0;
|
|
300
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
301
|
+
value /= 1024;
|
|
302
|
+
unit += 1;
|
|
303
|
+
}
|
|
304
|
+
return `${value.toFixed(1).replace(/\.0$/, "")} ${units[unit]}`;
|
|
305
|
+
}
|
|
306
|
+
function storageCodeFromText(message) {
|
|
307
|
+
if (typeof message !== "string") return void 0;
|
|
308
|
+
if (message.includes("larger than the TinyCloud storage you have left")) return "STORAGE_LIMIT_REACHED";
|
|
309
|
+
if (message.includes("TinyCloud storage is full") || /storage quota exceeded/i.test(message)) {
|
|
310
|
+
return "STORAGE_QUOTA_EXCEEDED";
|
|
311
|
+
}
|
|
312
|
+
return void 0;
|
|
313
|
+
}
|
|
314
|
+
function isStorageStatus(record) {
|
|
315
|
+
const meta = "meta" in record && typeof record.meta === "object" && record.meta !== null ? record.meta : {};
|
|
316
|
+
const statuses = [
|
|
317
|
+
"status" in record ? record.status : void 0,
|
|
318
|
+
"statusCode" in record ? record.statusCode : void 0,
|
|
319
|
+
"status" in meta ? meta.status : void 0
|
|
320
|
+
];
|
|
321
|
+
return statuses.some((value) => value === 402 || value === 413);
|
|
322
|
+
}
|
|
323
|
+
function accountTotals(meta) {
|
|
324
|
+
if (typeof meta !== "object" || meta === null) return void 0;
|
|
325
|
+
const account = meta.account;
|
|
326
|
+
if (typeof account !== "object" || account === null) return void 0;
|
|
327
|
+
const { usedBytes, limitBytes, plan } = account;
|
|
328
|
+
if (!isByteCount(usedBytes) || !isByteCount(limitBytes) || limitBytes === 0) return void 0;
|
|
329
|
+
return typeof plan === "string" && /^[A-Za-z0-9][A-Za-z0-9 _.-]{0,31}$/.test(plan) ? { usedBytes, limitBytes, plan } : { usedBytes, limitBytes };
|
|
330
|
+
}
|
|
331
|
+
function isByteCount(value) {
|
|
332
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
333
|
+
}
|
|
334
|
+
var MANAGE_STORAGE_URL, MAX_CAUSE_DEPTH;
|
|
335
|
+
var init_storage2 = __esm({
|
|
336
|
+
"src/output/storage.ts"() {
|
|
337
|
+
"use strict";
|
|
338
|
+
MANAGE_STORAGE_URL = "https://account.tinycloud.xyz/billing";
|
|
339
|
+
MAX_CAUSE_DEPTH = 4;
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
|
|
261
343
|
// src/output/errors.ts
|
|
262
344
|
import { readFileSync, readdirSync } from "fs";
|
|
263
345
|
import { join as join2 } from "path";
|
|
@@ -268,6 +350,8 @@ function setActiveProfileName(name) {
|
|
|
268
350
|
}
|
|
269
351
|
function cliErrorFromService(error, message = error.message) {
|
|
270
352
|
if (error instanceof CLIError) return error;
|
|
353
|
+
const storageFull = storageFullError(error);
|
|
354
|
+
if (storageFull) return storageFull;
|
|
271
355
|
const meta = { ...error.meta };
|
|
272
356
|
delete meta.hint;
|
|
273
357
|
const status = error.status ?? error.statusCode;
|
|
@@ -286,6 +370,8 @@ function cliErrorFromService(error, message = error.message) {
|
|
|
286
370
|
);
|
|
287
371
|
}
|
|
288
372
|
function wrapError(error) {
|
|
373
|
+
const storageFull = storageFullError(error);
|
|
374
|
+
if (storageFull) return storageFull;
|
|
289
375
|
if (error instanceof CLIError) return error;
|
|
290
376
|
const message = error instanceof Error ? error.message : String(error);
|
|
291
377
|
const verdict = authorizationVerdictOf(error);
|
|
@@ -332,6 +418,13 @@ function missingPrivateKeyError() {
|
|
|
332
418
|
{ hint: `Sign in again with: tc --profile ${profileName} auth login --method openkey` }
|
|
333
419
|
);
|
|
334
420
|
}
|
|
421
|
+
function storageFullError(error, progress) {
|
|
422
|
+
if (error instanceof CLIError && error.exitCode === ExitCode.STORAGE_FULL) return error;
|
|
423
|
+
const rejection = storageRejection(error);
|
|
424
|
+
if (!rejection) return void 0;
|
|
425
|
+
const { message, hint } = describeStorageRejection(rejection, progress);
|
|
426
|
+
return new CLIError(rejection.code, message, ExitCode.STORAGE_FULL, { hint });
|
|
427
|
+
}
|
|
335
428
|
function handleError(error) {
|
|
336
429
|
const cliError = wrapError(error);
|
|
337
430
|
const prebuilt = typeof cliError.metadata?.hint === "string" ? cliError.metadata.hint : void 0;
|
|
@@ -414,6 +507,7 @@ var init_errors = __esm({
|
|
|
414
507
|
"use strict";
|
|
415
508
|
init_constants();
|
|
416
509
|
init_formatter();
|
|
510
|
+
init_storage2();
|
|
417
511
|
CLIError = class extends Error {
|
|
418
512
|
constructor(code3, message, exitCode = ExitCode.ERROR, metadata) {
|
|
419
513
|
super(message);
|
|
@@ -7055,7 +7149,7 @@ function validatedCapabilityOf2(error) {
|
|
|
7055
7149
|
if (verdict !== "unauthenticated" && verdict !== "forbidden") return void 0;
|
|
7056
7150
|
const seen = /* @__PURE__ */ new Set();
|
|
7057
7151
|
let node = error;
|
|
7058
|
-
for (let depth = 0; depth <
|
|
7152
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH2 && typeof node === "object" && node !== null && !seen.has(node); depth += 1) {
|
|
7059
7153
|
seen.add(node);
|
|
7060
7154
|
const record = node;
|
|
7061
7155
|
const status = errorStatusOf(record);
|
|
@@ -7075,7 +7169,7 @@ function validatedCapabilityOf2(error) {
|
|
|
7075
7169
|
}
|
|
7076
7170
|
return void 0;
|
|
7077
7171
|
}
|
|
7078
|
-
var
|
|
7172
|
+
var MAX_CAUSE_DEPTH2 = 8;
|
|
7079
7173
|
function errorStatusOf(node) {
|
|
7080
7174
|
const meta = node.meta;
|
|
7081
7175
|
const candidates = [
|
|
@@ -7094,7 +7188,7 @@ function authorizationVerdictOf2(error) {
|
|
|
7094
7188
|
const seen = /* @__PURE__ */ new Set();
|
|
7095
7189
|
let sawUnauthorizedCode = false;
|
|
7096
7190
|
let node = error;
|
|
7097
|
-
for (let depth = 0; depth <
|
|
7191
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH2 && typeof node === "object" && node !== null && !seen.has(node); depth += 1) {
|
|
7098
7192
|
seen.add(node);
|
|
7099
7193
|
const record = node;
|
|
7100
7194
|
const status = errorStatusOf(record);
|
|
@@ -15117,6 +15211,34 @@ async function commitLogin(profileName, snapshot, commit) {
|
|
|
15117
15211
|
});
|
|
15118
15212
|
}
|
|
15119
15213
|
|
|
15214
|
+
// src/auth/owner-key.ts
|
|
15215
|
+
init_theme();
|
|
15216
|
+
function openKeyPrimaryFlag(delegation) {
|
|
15217
|
+
return typeof delegation.primary === "boolean" ? delegation.primary : void 0;
|
|
15218
|
+
}
|
|
15219
|
+
function withOwnerKeyPrimary(profile, primary) {
|
|
15220
|
+
const { ownerKeyPrimary: _previous, ...rest } = profile;
|
|
15221
|
+
return primary === void 0 ? rest : { ...rest, ownerKeyPrimary: primary };
|
|
15222
|
+
}
|
|
15223
|
+
function nonPrimaryKeyWarning(ownerDid) {
|
|
15224
|
+
const address = ownerDid.split(":")[4] ?? ownerDid;
|
|
15225
|
+
return `${theme.warn("Warning:")} you signed in with OpenKey key ${address} (${ownerDid}), which is not your account's primary OpenKey key. This key is a separate owner with its own spaces and data, so this profile does not see the data stored under your primary key.
|
|
15226
|
+
To use your primary key, log in again and choose the primary key in OpenKey, for example into a new profile: tc init --name <profile>
|
|
15227
|
+
`;
|
|
15228
|
+
}
|
|
15229
|
+
function warnIfNotPrimaryKey(ownerDid, primary) {
|
|
15230
|
+
if (primary !== false || ownerDid === void 0) return;
|
|
15231
|
+
process.stderr.write(nonPrimaryKeyWarning(ownerDid));
|
|
15232
|
+
}
|
|
15233
|
+
function ownerLoginPermissions(owner) {
|
|
15234
|
+
const space = ownerSpaceId("default", owner);
|
|
15235
|
+
return [
|
|
15236
|
+
{ service: "tinycloud.kv", space, path: "", actions: ["tinycloud.kv/put", "tinycloud.kv/get", "tinycloud.kv/del", "tinycloud.kv/list", "tinycloud.kv/metadata"] },
|
|
15237
|
+
{ service: "tinycloud.sql", space, path: "", actions: ["tinycloud.sql/read", "tinycloud.sql/write", "tinycloud.sql/admin"] },
|
|
15238
|
+
{ service: "tinycloud.capabilities", space, path: "", actions: ["tinycloud.capabilities/read"] }
|
|
15239
|
+
];
|
|
15240
|
+
}
|
|
15241
|
+
|
|
15120
15242
|
// src/auth/device-auth.ts
|
|
15121
15243
|
var DEVICE_DELEGATION_MAX_SECONDS = 30 * 24 * 60 * 60;
|
|
15122
15244
|
var DEVICE_APPROVAL_WINDOW_MAX_SECONDS = 60 * 60;
|
|
@@ -15321,7 +15443,8 @@ async function verifyApproval(input) {
|
|
|
15321
15443
|
spaceId: delegation.spaceId,
|
|
15322
15444
|
expiresAt: session.expiresAt,
|
|
15323
15445
|
approved: permissionsFromTuples(signed),
|
|
15324
|
-
declined: declinedPermissions(input.requested, session.permissions, ownerDid)
|
|
15446
|
+
declined: declinedPermissions(input.requested, session.permissions, ownerDid),
|
|
15447
|
+
...openKeyPrimaryFlag(delegation) === void 0 ? {} : { primary: openKeyPrimaryFlag(delegation) }
|
|
15325
15448
|
};
|
|
15326
15449
|
}
|
|
15327
15450
|
function writeApprovalPrompt(prompt) {
|
|
@@ -15498,7 +15621,7 @@ async function loginWithDeviceAuthorization(input) {
|
|
|
15498
15621
|
openkeyHost: input.openkeyHost ?? resolveDeviceApiHost(existing),
|
|
15499
15622
|
expectedOwner
|
|
15500
15623
|
});
|
|
15501
|
-
const profile = {
|
|
15624
|
+
const profile = withOwnerKeyPrimary({
|
|
15502
15625
|
...existing,
|
|
15503
15626
|
name: input.profileName,
|
|
15504
15627
|
host: input.persistHost === true || !existing?.host ? input.nodeOrigin : existing.host,
|
|
@@ -15512,7 +15635,7 @@ async function loginWithDeviceAuthorization(input) {
|
|
|
15512
15635
|
posture: "owner-openkey",
|
|
15513
15636
|
operatorType: existing?.operatorType ?? "human",
|
|
15514
15637
|
authMethod: "openkey"
|
|
15515
|
-
};
|
|
15638
|
+
}, result.primary);
|
|
15516
15639
|
await commitLogin(input.profileName, snapshot, {
|
|
15517
15640
|
key,
|
|
15518
15641
|
session: result.session,
|
|
@@ -15520,6 +15643,7 @@ async function loginWithDeviceAuthorization(input) {
|
|
|
15520
15643
|
// The signed permissions, with their caveats; `approved` is the action summary.
|
|
15521
15644
|
approved: { scope: result.session.permissions, ownerDid: result.ownerDid, replaceSession: input.replaceSession === true }
|
|
15522
15645
|
});
|
|
15646
|
+
warnIfNotPrimaryKey(result.ownerDid, result.primary);
|
|
15523
15647
|
return { profile, result };
|
|
15524
15648
|
}
|
|
15525
15649
|
|
|
@@ -15557,7 +15681,7 @@ async function promptAuthMethod() {
|
|
|
15557
15681
|
}
|
|
15558
15682
|
function registerAuthCommand(program) {
|
|
15559
15683
|
const auth = program.command("auth").description("Authentication management");
|
|
15560
|
-
auth.command("login").description("Authenticate with TinyCloud").option("--device", "Approve on another device (e.g. a phone) through OpenKey device authorization; requires a KV-scoped --manifest (SQL and secret decrypt need browser or --paste login)").option("--paste", "Use manual paste mode instead of browser callback").option("--no-popup", "Print the OpenKey URL without opening a browser").option("--method <method>", "Authentication method: local or openkey").option("--manifest <fileOrBase64>", `Request only this manifest's permissions (one space, plus raw encryption network entries such as a secrets decrypt grant); ${SHARE_PUBLISHING_MANIFEST_REF} covers \`tc share publish\``).option("--expiry <duration>", "OpenKey session lifetime, e.g. 1h or 7d (device login: at most 30d, default 30d)").option("--owner <did>", "
|
|
15684
|
+
auth.command("login").description("Authenticate with TinyCloud").option("--device", "Approve on another device (e.g. a phone) through OpenKey device authorization; requires a KV-scoped --manifest (SQL and secret decrypt need browser or --paste login)").option("--paste", "Use manual paste mode instead of browser callback").option("--no-popup", "Print the OpenKey URL without opening a browser").option("--method <method>", "Authentication method: local or openkey").option("--manifest <fileOrBase64>", `Request only this manifest's permissions (one space, plus raw encryption network entries such as a secrets decrypt grant); ${SHARE_PUBLISHING_MANIFEST_REF} covers \`tc share publish\``).option("--expiry <duration>", "OpenKey session lifetime, e.g. 1h or 7d (device login: at most 30d, default 30d)").option("--owner <did>", "Sign in as this owner (did:pkh:eip155:CHAIN:ADDRESS): OpenKey preselects that key, e.g. one that is not the account's primary key, and an approval by any other identity is refused. With --manifest, also names the secrets owner for a manifest's `secrets` on a profile with no recorded owner").option("--replace-session", "Scoped or device login: replace this profile's live session even though the new scope would narrow, change or shorten it (prefer a new profile)").action(async (options, cmd) => {
|
|
15561
15685
|
try {
|
|
15562
15686
|
if (options.device && options.paste) {
|
|
15563
15687
|
throw new CLIError("INVALID_ARGUMENT", "--device and --paste are mutually exclusive.", ExitCode.USAGE_ERROR);
|
|
@@ -15566,9 +15690,6 @@ function registerAuthCommand(program) {
|
|
|
15566
15690
|
if (scoped && options.method === "local") {
|
|
15567
15691
|
throw new CLIError("INVALID_ARGUMENT", "--device, --manifest, --expiry and --owner require OpenKey login.", ExitCode.USAGE_ERROR);
|
|
15568
15692
|
}
|
|
15569
|
-
if (options.owner && !options.manifest) {
|
|
15570
|
-
throw new CLIError("INVALID_ARGUMENT", "--owner requires --manifest so the signed identity is verified.", ExitCode.USAGE_ERROR);
|
|
15571
|
-
}
|
|
15572
15693
|
if (options.device && !options.manifest) {
|
|
15573
15694
|
throw new CLIError(
|
|
15574
15695
|
"MANIFEST_REQUIRED",
|
|
@@ -15691,6 +15812,7 @@ function registerAuthCommand(program) {
|
|
|
15691
15812
|
did: profile?.did ?? null,
|
|
15692
15813
|
sessionDid: profile?.sessionDid ?? null,
|
|
15693
15814
|
ownerDid: profile?.ownerDid ?? null,
|
|
15815
|
+
ownerKeyPrimary: profile?.ownerKeyPrimary ?? null,
|
|
15694
15816
|
spaceId: profile?.spaceId ?? null,
|
|
15695
15817
|
host: ctx.host,
|
|
15696
15818
|
profile: ctx.profile,
|
|
@@ -15711,6 +15833,7 @@ function registerAuthCommand(program) {
|
|
|
15711
15833
|
process.stdout.write(formatField("DID", profile?.did ?? null) + "\n");
|
|
15712
15834
|
process.stdout.write(formatField("Session DID", profile?.sessionDid ?? null) + "\n");
|
|
15713
15835
|
process.stdout.write(formatField("Owner DID", profile?.ownerDid ?? null) + "\n");
|
|
15836
|
+
process.stdout.write(formatField("Primary Key", profile?.ownerKeyPrimary ?? "unknown") + "\n");
|
|
15714
15837
|
process.stdout.write(formatField("Address", profile?.address ?? null) + "\n");
|
|
15715
15838
|
process.stdout.write(formatField("Space ID", profile?.spaceId ?? null) + "\n");
|
|
15716
15839
|
process.stdout.write(formatField("Has Key", hasKey !== null) + "\n");
|
|
@@ -16783,7 +16906,9 @@ async function refreshOpenKeySession(profileName, host, options = {}) {
|
|
|
16783
16906
|
jwk: key,
|
|
16784
16907
|
host,
|
|
16785
16908
|
openkeyHost: resolveOpenKeyHost(profile),
|
|
16786
|
-
|
|
16909
|
+
// A plain login with --owner names that owner's space, so OpenKey
|
|
16910
|
+
// preselects its key; the signed owner is verified below.
|
|
16911
|
+
permissions: permissions ?? (options.expectedOwner === void 0 ? void 0 : ownerLoginPermissions(expectedOwner)),
|
|
16787
16912
|
expiry: openKeyExpiry,
|
|
16788
16913
|
...permissions ? { reason: "Allow this TinyCloud CLI profile to use the permissions in the requested manifest." } : {}
|
|
16789
16914
|
});
|
|
@@ -16809,7 +16934,8 @@ async function refreshOpenKeySession(profileName, host, options = {}) {
|
|
|
16809
16934
|
sanitizedSession = Object.fromEntries(Object.entries(withoutTrustFields(merged)).filter(([name]) => name !== "siwe" && name !== "signature"));
|
|
16810
16935
|
}
|
|
16811
16936
|
}
|
|
16812
|
-
const
|
|
16937
|
+
const ownerKeyPrimary = verifiedOwner === void 0 ? void 0 : openKeyPrimaryFlag(delegationData);
|
|
16938
|
+
const updatedProfile = withOwnerKeyPrimary({
|
|
16813
16939
|
...profile,
|
|
16814
16940
|
host: options.persistHost === true || !profile.host ? host : profile.host,
|
|
16815
16941
|
sessionDid: profile.sessionDid ?? profile.did,
|
|
@@ -16818,13 +16944,14 @@ async function refreshOpenKeySession(profileName, host, options = {}) {
|
|
|
16818
16944
|
authMethod: "openkey",
|
|
16819
16945
|
...typeof sanitizedSession.spaceId === "string" ? { spaceId: sanitizedSession.spaceId } : {},
|
|
16820
16946
|
...verifiedOwner === void 0 ? {} : { ownerDid: verifiedOwner }
|
|
16821
|
-
};
|
|
16947
|
+
}, ownerKeyPrimary);
|
|
16822
16948
|
await commitLogin(profileName, snapshot, {
|
|
16823
16949
|
key,
|
|
16824
16950
|
session: sanitizedSession,
|
|
16825
16951
|
profile: updatedProfile,
|
|
16826
16952
|
...permissions && verifiedOwner ? { approved: { scope: sanitizedSession.permissions, ownerDid: verifiedOwner, replaceSession: options.replaceSession === true } } : {}
|
|
16827
16953
|
});
|
|
16954
|
+
warnIfNotPrimaryKey(verifiedOwner, ownerKeyPrimary);
|
|
16828
16955
|
return { profile: updatedProfile, delegationData: sanitizedSession, declined, legacyNested };
|
|
16829
16956
|
}
|
|
16830
16957
|
|
|
@@ -17498,15 +17625,6 @@ async function throwKvError(error, spaceUri, profileName) {
|
|
|
17498
17625
|
if (hosted) throw hosted;
|
|
17499
17626
|
throw cliErrorFromService(error);
|
|
17500
17627
|
}
|
|
17501
|
-
function isByteCount(value) {
|
|
17502
|
-
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
17503
|
-
}
|
|
17504
|
-
function storageQuotaError(error) {
|
|
17505
|
-
if (error.code !== "STORAGE_QUOTA_EXCEEDED") return void 0;
|
|
17506
|
-
const { usedBytes, limitBytes } = typeof error.meta === "object" && error.meta !== null ? error.meta : {};
|
|
17507
|
-
const sizes = isByteCount(usedBytes) && isByteCount(limitBytes) ? ` (${formatBytes(usedBytes)} used of ${formatBytes(limitBytes)} limit)` : "";
|
|
17508
|
-
return new CLIError("STORAGE_QUOTA_EXCEEDED", `storage quota exceeded${sizes}; nothing was written`, ExitCode.ERROR);
|
|
17509
|
-
}
|
|
17510
17628
|
function assertAddressableKey(key) {
|
|
17511
17629
|
for (let i = 0; i < key.length; i++) {
|
|
17512
17630
|
const code3 = key.charCodeAt(i);
|
|
@@ -17602,8 +17720,6 @@ function registerKvCommand(program) {
|
|
|
17602
17720
|
const { kv: kv2, spaceUri } = await kvHandle(node, options.space, ctx.profile);
|
|
17603
17721
|
const result = await withSpinner(`Writing ${key}...`, () => kv2.put(key, putValue));
|
|
17604
17722
|
if (!result.ok) {
|
|
17605
|
-
const quota = storageQuotaError(result.error);
|
|
17606
|
-
if (quota) throw quota;
|
|
17607
17723
|
await throwKvError(result.error, spaceUri, ctx.profile);
|
|
17608
17724
|
}
|
|
17609
17725
|
outputJson({ key, written: true });
|
|
@@ -29279,7 +29395,6 @@ var MAX_INLINE_BYTES2 = 256 * 1024;
|
|
|
29279
29395
|
|
|
29280
29396
|
// src/commands/share.ts
|
|
29281
29397
|
import { ProfileLockTimeoutError as ProfileLockTimeoutError3 } from "@tinycloud/operations/state";
|
|
29282
|
-
init_formatter();
|
|
29283
29398
|
init_errors();
|
|
29284
29399
|
|
|
29285
29400
|
// src/share/output.ts
|
|
@@ -29542,9 +29657,8 @@ function shareCliError(error, operation = "publish") {
|
|
|
29542
29657
|
if (failure.kind === "registry-rejected") {
|
|
29543
29658
|
return new CLIError("REGISTRY_REJECTED", "the TinyCloud location registry rejected this session's location record, so nothing was shared; retrying will not help. Log in again, and report the problem if it persists", 6);
|
|
29544
29659
|
}
|
|
29545
|
-
if (failure.kind === "storage-
|
|
29546
|
-
|
|
29547
|
-
return new CLIError("STORAGE_QUOTA_EXCEEDED", `storage quota exceeded${sizes}; nothing was shared`, 4);
|
|
29660
|
+
if (failure.kind === "storage-full") {
|
|
29661
|
+
return storageFullError(failure);
|
|
29548
29662
|
}
|
|
29549
29663
|
if (failure.kind === "upload-failed") {
|
|
29550
29664
|
return new CLIError("UPLOAD_FAILED", "share source upload failed; nothing was shared", 4);
|
|
@@ -29564,6 +29678,8 @@ function shareCliError(error, operation = "publish") {
|
|
|
29564
29678
|
const code3 = error.code === "fetch-failed" ? "NOT_FOUND" : error.code.replaceAll("-", "_").toUpperCase();
|
|
29565
29679
|
return new CLIError(code3, error.message, exit);
|
|
29566
29680
|
}
|
|
29681
|
+
const storageFull = storageFullError(error);
|
|
29682
|
+
if (storageFull) return storageFull;
|
|
29567
29683
|
const message = error instanceof Error ? error.message : String(error);
|
|
29568
29684
|
const nodeCode = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
29569
29685
|
const known = {
|
|
@@ -30021,6 +30137,8 @@ async function dbHandle(node, dbName, spaceInput, profileName) {
|
|
|
30021
30137
|
return { handle: sql.db(dbName), spaceUri };
|
|
30022
30138
|
}
|
|
30023
30139
|
async function throwSqlError(error, spaceUri, profileName, prefix) {
|
|
30140
|
+
const storageFull = storageFullError(error, prefix);
|
|
30141
|
+
if (storageFull) throw storageFull;
|
|
30024
30142
|
const hosted = await unhostedSpaceError(error, spaceUri, profileName);
|
|
30025
30143
|
if (hosted) throw hosted;
|
|
30026
30144
|
const message = prefix ? `${prefix}${error.message}` : error.message;
|