@tinycloud/cli 1.1.0-beta.12 → 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 +104 -19
- package/dist/legacy-entry.js.map +1 -1
- package/package.json +2 -2
- package/skills/tc-cli/REFERENCE.md +5 -3
package/dist/index.js
CHANGED
|
@@ -32,7 +32,9 @@ var init_constants = __esm({
|
|
|
32
32
|
NOT_FOUND: 4,
|
|
33
33
|
PERMISSION_DENIED: 5,
|
|
34
34
|
NETWORK_ERROR: 6,
|
|
35
|
-
NODE_ERROR: 7
|
|
35
|
+
NODE_ERROR: 7,
|
|
36
|
+
/** A write was refused because the owner's TinyCloud storage is full. */
|
|
37
|
+
STORAGE_FULL: 10
|
|
36
38
|
};
|
|
37
39
|
}
|
|
38
40
|
});
|
|
@@ -96,11 +98,6 @@ function outputError(code3, message, hint, meta) {
|
|
|
96
98
|
function isInteractive() {
|
|
97
99
|
return Boolean(process.stdout.isTTY);
|
|
98
100
|
}
|
|
99
|
-
function formatBytes(bytes) {
|
|
100
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
101
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
102
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
103
|
-
}
|
|
104
101
|
var init_formatter = __esm({
|
|
105
102
|
"src/output/formatter.ts"() {
|
|
106
103
|
"use strict";
|
|
@@ -108,6 +105,86 @@ var init_formatter = __esm({
|
|
|
108
105
|
}
|
|
109
106
|
});
|
|
110
107
|
|
|
108
|
+
// src/output/storage.ts
|
|
109
|
+
function storageRejection(error) {
|
|
110
|
+
let node = error;
|
|
111
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH && typeof node === "object" && node !== null; depth += 1) {
|
|
112
|
+
const record = node;
|
|
113
|
+
let code3;
|
|
114
|
+
if (record.code === "STORAGE_QUOTA_EXCEEDED" || record.code === "STORAGE_LIMIT_REACHED") {
|
|
115
|
+
code3 = record.code;
|
|
116
|
+
} else if (record.code !== void 0) {
|
|
117
|
+
return void 0;
|
|
118
|
+
} else if (isStorageStatus(record)) {
|
|
119
|
+
code3 = storageCodeFromText(record.message);
|
|
120
|
+
}
|
|
121
|
+
if (code3) {
|
|
122
|
+
const account = accountTotals(record) ?? accountTotals(record.meta) ?? accountTotals(record.metadata);
|
|
123
|
+
return account ? { code: code3, account } : { code: code3 };
|
|
124
|
+
}
|
|
125
|
+
node = record.cause;
|
|
126
|
+
}
|
|
127
|
+
return void 0;
|
|
128
|
+
}
|
|
129
|
+
function describeStorageRejection(rejection, progress) {
|
|
130
|
+
const reason = rejection.code === "STORAGE_LIMIT_REACHED" ? "This write is larger than the TinyCloud storage you have left" : "TinyCloud storage is full";
|
|
131
|
+
const message = progress ? `${progress}${reason}.` : `${reason}; nothing was written.`;
|
|
132
|
+
const { account } = rejection;
|
|
133
|
+
const totals = account ? `${formatStorageBytes(account.usedBytes)} used of ${formatStorageBytes(account.limitBytes)}${account.plan ? ` (${account.plan} plan)` : ""}. ` : "";
|
|
134
|
+
return {
|
|
135
|
+
message,
|
|
136
|
+
hint: `${totals}Reading still works.
|
|
137
|
+
Free up space or upgrade: ${MANAGE_STORAGE_URL}`
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function formatStorageBytes(bytes) {
|
|
141
|
+
const units = ["KiB", "MiB", "GiB", "TiB"];
|
|
142
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
143
|
+
let value = bytes / 1024;
|
|
144
|
+
let unit = 0;
|
|
145
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
146
|
+
value /= 1024;
|
|
147
|
+
unit += 1;
|
|
148
|
+
}
|
|
149
|
+
return `${value.toFixed(1).replace(/\.0$/, "")} ${units[unit]}`;
|
|
150
|
+
}
|
|
151
|
+
function storageCodeFromText(message) {
|
|
152
|
+
if (typeof message !== "string") return void 0;
|
|
153
|
+
if (message.includes("larger than the TinyCloud storage you have left")) return "STORAGE_LIMIT_REACHED";
|
|
154
|
+
if (message.includes("TinyCloud storage is full") || /storage quota exceeded/i.test(message)) {
|
|
155
|
+
return "STORAGE_QUOTA_EXCEEDED";
|
|
156
|
+
}
|
|
157
|
+
return void 0;
|
|
158
|
+
}
|
|
159
|
+
function isStorageStatus(record) {
|
|
160
|
+
const meta = "meta" in record && typeof record.meta === "object" && record.meta !== null ? record.meta : {};
|
|
161
|
+
const statuses = [
|
|
162
|
+
"status" in record ? record.status : void 0,
|
|
163
|
+
"statusCode" in record ? record.statusCode : void 0,
|
|
164
|
+
"status" in meta ? meta.status : void 0
|
|
165
|
+
];
|
|
166
|
+
return statuses.some((value) => value === 402 || value === 413);
|
|
167
|
+
}
|
|
168
|
+
function accountTotals(meta) {
|
|
169
|
+
if (typeof meta !== "object" || meta === null) return void 0;
|
|
170
|
+
const account = meta.account;
|
|
171
|
+
if (typeof account !== "object" || account === null) return void 0;
|
|
172
|
+
const { usedBytes, limitBytes, plan } = account;
|
|
173
|
+
if (!isByteCount(usedBytes) || !isByteCount(limitBytes) || limitBytes === 0) return void 0;
|
|
174
|
+
return typeof plan === "string" && /^[A-Za-z0-9][A-Za-z0-9 _.-]{0,31}$/.test(plan) ? { usedBytes, limitBytes, plan } : { usedBytes, limitBytes };
|
|
175
|
+
}
|
|
176
|
+
function isByteCount(value) {
|
|
177
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
178
|
+
}
|
|
179
|
+
var MANAGE_STORAGE_URL, MAX_CAUSE_DEPTH;
|
|
180
|
+
var init_storage = __esm({
|
|
181
|
+
"src/output/storage.ts"() {
|
|
182
|
+
"use strict";
|
|
183
|
+
MANAGE_STORAGE_URL = "https://account.tinycloud.xyz/billing";
|
|
184
|
+
MAX_CAUSE_DEPTH = 4;
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
111
188
|
// src/output/errors.ts
|
|
112
189
|
import { readFileSync, readdirSync } from "fs";
|
|
113
190
|
import { join } from "path";
|
|
@@ -117,6 +194,8 @@ function setActiveProfileName(name) {
|
|
|
117
194
|
activeProfileName = name;
|
|
118
195
|
}
|
|
119
196
|
function wrapError(error) {
|
|
197
|
+
const storageFull = storageFullError(error);
|
|
198
|
+
if (storageFull) return storageFull;
|
|
120
199
|
if (error instanceof CLIError) return error;
|
|
121
200
|
const message = error instanceof Error ? error.message : String(error);
|
|
122
201
|
const verdict = authorizationVerdictOf(error);
|
|
@@ -163,6 +242,13 @@ function missingPrivateKeyError() {
|
|
|
163
242
|
{ hint: `Sign in again with: tc --profile ${profileName} auth login --method openkey` }
|
|
164
243
|
);
|
|
165
244
|
}
|
|
245
|
+
function storageFullError(error, progress) {
|
|
246
|
+
if (error instanceof CLIError && error.exitCode === ExitCode.STORAGE_FULL) return error;
|
|
247
|
+
const rejection = storageRejection(error);
|
|
248
|
+
if (!rejection) return void 0;
|
|
249
|
+
const { message, hint } = describeStorageRejection(rejection, progress);
|
|
250
|
+
return new CLIError(rejection.code, message, ExitCode.STORAGE_FULL, { hint });
|
|
251
|
+
}
|
|
166
252
|
function handleError(error) {
|
|
167
253
|
const cliError = wrapError(error);
|
|
168
254
|
const prebuilt = typeof cliError.metadata?.hint === "string" ? cliError.metadata.hint : void 0;
|
|
@@ -245,6 +331,7 @@ var init_errors = __esm({
|
|
|
245
331
|
"use strict";
|
|
246
332
|
init_constants();
|
|
247
333
|
init_formatter();
|
|
334
|
+
init_storage();
|
|
248
335
|
CLIError = class extends Error {
|
|
249
336
|
constructor(code3, message, exitCode = ExitCode.ERROR, metadata) {
|
|
250
337
|
super(message);
|
|
@@ -312,7 +399,7 @@ async function listDirs(dirPath) {
|
|
|
312
399
|
}
|
|
313
400
|
}
|
|
314
401
|
var PRIVATE_FILE_MODE, PRIVATE_DIR_MODE;
|
|
315
|
-
var
|
|
402
|
+
var init_storage2 = __esm({
|
|
316
403
|
"src/config/storage.ts"() {
|
|
317
404
|
"use strict";
|
|
318
405
|
PRIVATE_FILE_MODE = 384;
|
|
@@ -570,7 +657,7 @@ var init_profiles = __esm({
|
|
|
570
657
|
"src/config/profiles.ts"() {
|
|
571
658
|
"use strict";
|
|
572
659
|
init_constants();
|
|
573
|
-
|
|
660
|
+
init_storage2();
|
|
574
661
|
init_errors();
|
|
575
662
|
ProfileManager = class _ProfileManager {
|
|
576
663
|
// ── Initialization ──────────────────────────────────────────────────
|
|
@@ -5750,7 +5837,7 @@ var init_permissions = __esm({
|
|
|
5750
5837
|
"src/lib/permissions.ts"() {
|
|
5751
5838
|
"use strict";
|
|
5752
5839
|
init_constants();
|
|
5753
|
-
|
|
5840
|
+
init_storage2();
|
|
5754
5841
|
init_profiles();
|
|
5755
5842
|
init_errors();
|
|
5756
5843
|
init_constants();
|
|
@@ -16699,7 +16786,6 @@ function parseDuration(input) {
|
|
|
16699
16786
|
}
|
|
16700
16787
|
|
|
16701
16788
|
// src/commands/share.ts
|
|
16702
|
-
init_formatter();
|
|
16703
16789
|
init_errors();
|
|
16704
16790
|
|
|
16705
16791
|
// src/share/output.ts
|
|
@@ -16965,9 +17051,8 @@ function shareCliError(error, operation = "publish") {
|
|
|
16965
17051
|
if (failure.kind === "registry-rejected") {
|
|
16966
17052
|
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);
|
|
16967
17053
|
}
|
|
16968
|
-
if (failure.kind === "storage-
|
|
16969
|
-
|
|
16970
|
-
return new CLIError("STORAGE_QUOTA_EXCEEDED", `storage quota exceeded${sizes}; nothing was shared`, 4);
|
|
17054
|
+
if (failure.kind === "storage-full") {
|
|
17055
|
+
return storageFullError(failure);
|
|
16971
17056
|
}
|
|
16972
17057
|
if (failure.kind === "upload-failed") {
|
|
16973
17058
|
return new CLIError("UPLOAD_FAILED", "share source upload failed; nothing was shared", 4);
|
|
@@ -16987,6 +17072,8 @@ function shareCliError(error, operation = "publish") {
|
|
|
16987
17072
|
const code3 = error.code === "fetch-failed" ? "NOT_FOUND" : error.code.replaceAll("-", "_").toUpperCase();
|
|
16988
17073
|
return new CLIError(code3, error.message, exit);
|
|
16989
17074
|
}
|
|
17075
|
+
const storageFull = storageFullError(error);
|
|
17076
|
+
if (storageFull) return storageFull;
|
|
16990
17077
|
const message = error instanceof Error ? error.message : String(error);
|
|
16991
17078
|
const nodeCode = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
16992
17079
|
const known = {
|
|
@@ -17280,6 +17367,7 @@ function registerShareCommand(program2) {
|
|
|
17280
17367
|
}
|
|
17281
17368
|
|
|
17282
17369
|
// src/share/adapters.ts
|
|
17370
|
+
init_storage();
|
|
17283
17371
|
init_profiles();
|
|
17284
17372
|
init_constants();
|
|
17285
17373
|
import { readFile as readFile4 } from "fs/promises";
|
|
@@ -17293,15 +17381,9 @@ function requiredKvAction(meta) {
|
|
|
17293
17381
|
const action = meta.requiredAction;
|
|
17294
17382
|
return action === "tinycloud.kv/put" || action === "tinycloud.kv/get" ? action : void 0;
|
|
17295
17383
|
}
|
|
17296
|
-
function isByteCount(value) {
|
|
17297
|
-
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
17298
|
-
}
|
|
17299
17384
|
function throwKvUploadFailure(error) {
|
|
17300
|
-
|
|
17301
|
-
|
|
17302
|
-
const { usedBytes, limitBytes } = meta;
|
|
17303
|
-
throw new SharePublishAuthorityError(isByteCount(usedBytes) && isByteCount(limitBytes) ? { kind: "storage-quota-exceeded", usedBytes, limitBytes } : { kind: "storage-quota-exceeded" });
|
|
17304
|
-
}
|
|
17385
|
+
const rejection = storageRejection(error);
|
|
17386
|
+
if (rejection) throw new SharePublishAuthorityError({ kind: "storage-full", ...rejection });
|
|
17305
17387
|
throw new SharePublishAuthorityError({ kind: "upload-failed" });
|
|
17306
17388
|
}
|
|
17307
17389
|
var DEFAULT_SHARE_ORIGIN = "https://share.tinycloud.xyz";
|