@easybits.cloud/cli 0.15.1 → 0.15.3
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/README.md +3 -0
- package/dist/index.js +98 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,8 +105,11 @@ easybits agents create --from helper.json --name helper-3
|
|
|
105
105
|
# Files, websites, account
|
|
106
106
|
easybits files ls
|
|
107
107
|
easybits files upload ./report.pdf
|
|
108
|
+
easybits files upload ./logo.png --public # open CDN URL; private by default
|
|
108
109
|
easybits files rm FILE_ID --yes
|
|
109
110
|
easybits websites ls
|
|
111
|
+
easybits websites create "My shop" --slug my-shop # slug optional
|
|
112
|
+
easybits websites slug my-shop my-store # change it; the old URL 301s
|
|
110
113
|
easybits providers # storage provider (Tigris by default)
|
|
111
114
|
easybits usage
|
|
112
115
|
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { parseArgs } from "util";
|
|
5
5
|
|
|
6
6
|
// src/commands/account.ts
|
|
7
|
-
import { resolveBaseUrl as
|
|
7
|
+
import { resolveBaseUrl as resolveBaseUrl4 } from "@easybits.cloud/sdk";
|
|
8
8
|
|
|
9
9
|
// src/args.ts
|
|
10
10
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -303,6 +303,9 @@ function maskSecret(v) {
|
|
|
303
303
|
return v.length <= 8 ? "***" : `${v.slice(0, 4)}\u2026***`;
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
+
// src/api.ts
|
|
307
|
+
import { EasybitsError as EasybitsError2, resolveBaseUrl as resolveBaseUrl3 } from "@easybits.cloud/sdk";
|
|
308
|
+
|
|
306
309
|
// src/client.ts
|
|
307
310
|
import { EasybitsClient, resolveBaseUrl as resolveBaseUrl2 } from "@easybits.cloud/sdk";
|
|
308
311
|
|
|
@@ -500,6 +503,32 @@ async function getClient(ctx) {
|
|
|
500
503
|
return new EasybitsClient({ apiKey, baseUrl: await resolveBaseUrl2() });
|
|
501
504
|
}
|
|
502
505
|
|
|
506
|
+
// src/api.ts
|
|
507
|
+
async function api(ctx, method, path, body, opts = {}) {
|
|
508
|
+
const token = await resolveCredential(ctx);
|
|
509
|
+
const base = (await resolveBaseUrl3()).replace(/\/$/, "");
|
|
510
|
+
const headers = { Authorization: `Bearer ${token}` };
|
|
511
|
+
let payload;
|
|
512
|
+
if (body !== void 0) {
|
|
513
|
+
if (opts.raw) {
|
|
514
|
+
payload = body;
|
|
515
|
+
headers["Content-Type"] = "application/octet-stream";
|
|
516
|
+
} else {
|
|
517
|
+
payload = JSON.stringify(body);
|
|
518
|
+
headers["Content-Type"] = "application/json";
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
const res = await fetch(`${base}/api/v2${path}`, { method, headers, body: payload });
|
|
522
|
+
const text = await res.text();
|
|
523
|
+
if (!res.ok) throw new EasybitsError2(res.status, text);
|
|
524
|
+
try {
|
|
525
|
+
return JSON.parse(text);
|
|
526
|
+
} catch {
|
|
527
|
+
return text;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
var encodePath = (p) => p.replace(/^\/+/, "").split("/").map(encodeURIComponent).join("/");
|
|
531
|
+
|
|
503
532
|
// src/commands/account.ts
|
|
504
533
|
var login = {
|
|
505
534
|
name: "login",
|
|
@@ -592,8 +621,8 @@ Webhooks: ${u.counts.webhooks}`
|
|
|
592
621
|
var websites = {
|
|
593
622
|
name: "websites",
|
|
594
623
|
group: "Storage",
|
|
595
|
-
summary: "
|
|
596
|
-
synopsis: "websites",
|
|
624
|
+
summary: "Static websites: list, create, change slug",
|
|
625
|
+
synopsis: "websites <ls|create|slug>",
|
|
597
626
|
subs: {
|
|
598
627
|
ls: {
|
|
599
628
|
aliases: ["list"],
|
|
@@ -613,10 +642,55 @@ var websites = {
|
|
|
613
642
|
)
|
|
614
643
|
);
|
|
615
644
|
}
|
|
645
|
+
},
|
|
646
|
+
create: {
|
|
647
|
+
summary: "Create an empty static website (optionally with your own slug)",
|
|
648
|
+
usage: "easybits websites create <name> [--slug <slug>]",
|
|
649
|
+
options: { slug: { type: "string", value: "slug", description: "Public slug: /s/<slug>/ (a-z, 0-9, hyphens, 3-60 chars)" } },
|
|
650
|
+
examples: ['easybits websites create "Mi tienda" --slug mi-tienda'],
|
|
651
|
+
async run(ctx) {
|
|
652
|
+
const name = need(ctx, 0, "name", this.usage);
|
|
653
|
+
const slug = str(ctx, "slug");
|
|
654
|
+
const { website } = await api(ctx, "POST", "/websites", { name, ...slug ? { slug } : {} });
|
|
655
|
+
emit(ctx, website, () => console.log(t(`Created ${website.slug} \u2192 ${website.url}`, `Creado ${website.slug} \u2192 ${website.url}`)));
|
|
656
|
+
}
|
|
657
|
+
},
|
|
658
|
+
slug: {
|
|
659
|
+
summary: "Change a website's slug (the old URL redirects 301 to the new one)",
|
|
660
|
+
usage: "easybits websites slug <websiteId|slug> <new-slug>",
|
|
661
|
+
examples: ["easybits websites slug rio-durmiente mi-tienda"],
|
|
662
|
+
async run(ctx) {
|
|
663
|
+
const ref = need(ctx, 0, "website", this.usage);
|
|
664
|
+
const slug = need(ctx, 1, "new-slug", this.usage);
|
|
665
|
+
const websiteId = await resolveWebsiteId(ctx, ref);
|
|
666
|
+
const { website } = await api(ctx, "PATCH", `/websites/${websiteId}`, { slug });
|
|
667
|
+
emit(ctx, website, () => console.log(t(`Slug changed \u2192 ${website.url}`, `Slug cambiado \u2192 ${website.url}`)));
|
|
668
|
+
}
|
|
616
669
|
}
|
|
617
670
|
},
|
|
618
671
|
defaultSub: "ls"
|
|
619
672
|
};
|
|
673
|
+
function matchWebsite(ref, items) {
|
|
674
|
+
if (/^[0-9a-f]{24}$/i.test(ref)) return ref;
|
|
675
|
+
const r = ref.trim().toLowerCase();
|
|
676
|
+
return items.find((w) => w.slug === r)?.id ?? null;
|
|
677
|
+
}
|
|
678
|
+
async function resolveWebsiteId(ctx, ref) {
|
|
679
|
+
if (/^[0-9a-f]{24}$/i.test(ref)) return ref;
|
|
680
|
+
for (let offset = 0; ; offset += 100) {
|
|
681
|
+
const page = await api(ctx, "GET", `/websites?limit=100&offset=${offset}`);
|
|
682
|
+
const id = matchWebsite(ref, page.items);
|
|
683
|
+
if (id) return id;
|
|
684
|
+
if (page.items.length < 100 || offset + 100 >= page.total) break;
|
|
685
|
+
}
|
|
686
|
+
throw new CliError(
|
|
687
|
+
t(`No website with id or slug "${ref}".`, `No hay sitio con id o slug "${ref}".`),
|
|
688
|
+
EXIT.API,
|
|
689
|
+
`${t("List them with", "Enl\xEDstalos con")}: easybits websites ls`,
|
|
690
|
+
"not_found",
|
|
691
|
+
404
|
|
692
|
+
);
|
|
693
|
+
}
|
|
620
694
|
var providers = {
|
|
621
695
|
name: "providers",
|
|
622
696
|
group: "Storage",
|
|
@@ -660,7 +734,7 @@ var mcp = {
|
|
|
660
734
|
return;
|
|
661
735
|
}
|
|
662
736
|
const apiKey = resolveApiKey(ctx);
|
|
663
|
-
const baseUrl = await
|
|
737
|
+
const baseUrl = await resolveBaseUrl4();
|
|
664
738
|
const config = {
|
|
665
739
|
mcpServers: {
|
|
666
740
|
easybits: {
|
|
@@ -688,7 +762,7 @@ var whoami = {
|
|
|
688
762
|
const source = process.env.EASYBITS_API_KEY ? "env EASYBITS_API_KEY" : ctx.token ? "--token" : readRc().oauth?.accessToken ? "browser session (~/.easybitsrc)" : readRc().apiKey ? "API key (~/.easybitsrc)" : void 0;
|
|
689
763
|
if (!source) throw notLoggedIn();
|
|
690
764
|
const email = await fetchEmail(await resolveCredential(ctx));
|
|
691
|
-
emit(ctx, { email, source, baseUrl: await
|
|
765
|
+
emit(ctx, { email, source, baseUrl: await resolveBaseUrl4() }, () => console.log(`${email ?? t("(unknown email)", "(correo desconocido)")} ${t("via", "por")} ${source}`));
|
|
692
766
|
}
|
|
693
767
|
}
|
|
694
768
|
};
|
|
@@ -792,22 +866,30 @@ var files = {
|
|
|
792
866
|
},
|
|
793
867
|
upload: {
|
|
794
868
|
summary: "Upload a local file",
|
|
795
|
-
usage: "easybits files upload <path>",
|
|
796
|
-
|
|
869
|
+
usage: "easybits files upload <path> [--public]",
|
|
870
|
+
options: {
|
|
871
|
+
public: { type: "boolean", description: "Public file with an open CDN URL (default: private)" }
|
|
872
|
+
},
|
|
873
|
+
examples: ["easybits files upload ./report.pdf", "easybits files upload ./logo.png --public --json"],
|
|
797
874
|
async run(ctx) {
|
|
798
875
|
const path = need(ctx, 0, "path", this.usage);
|
|
799
876
|
if (!existsSync2(path)) throw usageError(t(`File not found: ${path}`, `No existe el archivo: ${path}`), this.usage);
|
|
800
877
|
const size = statSync(path).size;
|
|
801
878
|
const contentType = MIME[extname(path).slice(1).toLowerCase()] || "application/octet-stream";
|
|
802
879
|
const eb = await getClient(ctx);
|
|
803
|
-
const
|
|
880
|
+
const access = bool(ctx, "public") ? "public" : void 0;
|
|
881
|
+
const data = await eb.uploadFile({ fileName: basename(path), contentType, size, access });
|
|
804
882
|
const res = await fetch(data.putUrl, {
|
|
805
883
|
method: "PUT",
|
|
806
884
|
body: readFileSync3(path),
|
|
807
885
|
headers: { "Content-Type": contentType }
|
|
808
886
|
});
|
|
809
887
|
if (!res.ok) throw new CliError(t(`Upload failed: storage answered ${res.status}`, `Fall\xF3 la subida: el almacenamiento contest\xF3 ${res.status}`), 1, void 0, "upload_failed", res.status);
|
|
810
|
-
|
|
888
|
+
const url = data.file.url;
|
|
889
|
+
emit(ctx, data.file, () => {
|
|
890
|
+
console.log(`${t("Uploaded", "Subido")}: ${data.file.id}`);
|
|
891
|
+
if (url) console.log(`URL: ${url}`);
|
|
892
|
+
});
|
|
811
893
|
}
|
|
812
894
|
},
|
|
813
895
|
rm: {
|
|
@@ -1901,33 +1983,6 @@ function parseLinkStats(columns, row) {
|
|
|
1901
1983
|
return columns.map((column, i) => ({ column, permanent: n(i * 4), expiring: n(i * 4 + 1), external: n(i * 4 + 2), empty: n(i * 4 + 3) })).filter((s) => s.permanent + s.expiring + s.external > 0);
|
|
1902
1984
|
}
|
|
1903
1985
|
|
|
1904
|
-
// src/api.ts
|
|
1905
|
-
import { EasybitsError as EasybitsError2, resolveBaseUrl as resolveBaseUrl4 } from "@easybits.cloud/sdk";
|
|
1906
|
-
async function api(ctx, method, path, body, opts = {}) {
|
|
1907
|
-
const token = await resolveCredential(ctx);
|
|
1908
|
-
const base = (await resolveBaseUrl4()).replace(/\/$/, "");
|
|
1909
|
-
const headers = { Authorization: `Bearer ${token}` };
|
|
1910
|
-
let payload;
|
|
1911
|
-
if (body !== void 0) {
|
|
1912
|
-
if (opts.raw) {
|
|
1913
|
-
payload = body;
|
|
1914
|
-
headers["Content-Type"] = "application/octet-stream";
|
|
1915
|
-
} else {
|
|
1916
|
-
payload = JSON.stringify(body);
|
|
1917
|
-
headers["Content-Type"] = "application/json";
|
|
1918
|
-
}
|
|
1919
|
-
}
|
|
1920
|
-
const res = await fetch(`${base}/api/v2${path}`, { method, headers, body: payload });
|
|
1921
|
-
const text = await res.text();
|
|
1922
|
-
if (!res.ok) throw new EasybitsError2(res.status, text);
|
|
1923
|
-
try {
|
|
1924
|
-
return JSON.parse(text);
|
|
1925
|
-
} catch {
|
|
1926
|
-
return text;
|
|
1927
|
-
}
|
|
1928
|
-
}
|
|
1929
|
-
var encodePath = (p) => p.replace(/^\/+/, "").split("/").map(encodeURIComponent).join("/");
|
|
1930
|
-
|
|
1931
1986
|
// src/commands/agents-config.ts
|
|
1932
1987
|
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync8, readdirSync as readdirSync2, statSync as statSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
1933
1988
|
import { basename as basename3, dirname, join as join4, relative, resolve } from "path";
|
|
@@ -3668,7 +3723,7 @@ async function updateNotice(current2) {
|
|
|
3668
3723
|
}
|
|
3669
3724
|
|
|
3670
3725
|
// src/commands/doctor.ts
|
|
3671
|
-
var VERSION = true ? "0.15.
|
|
3726
|
+
var VERSION = true ? "0.15.3" : "dev";
|
|
3672
3727
|
var doctor2 = {
|
|
3673
3728
|
name: "doctor",
|
|
3674
3729
|
group: "Account",
|
|
@@ -3953,8 +4008,13 @@ var HELP_ES = {
|
|
|
3953
4008
|
"Your files in EasyBits storage": "Tus archivos en el almacenamiento de EasyBits",
|
|
3954
4009
|
"List your files": "Enlista tus archivos",
|
|
3955
4010
|
"Upload a local file": "Sube un archivo local",
|
|
4011
|
+
"Public file with an open CDN URL (default: private)": "Archivo p\xFAblico con URL abierta en el CDN (por defecto: privado)",
|
|
3956
4012
|
"Delete a file (soft delete, 7-day trash)": "Borra un archivo (a la papelera 7 d\xEDas)",
|
|
3957
4013
|
"List your static websites": "Enlista tus sitios est\xE1ticos",
|
|
4014
|
+
"Static websites: list, create, change slug": "Sitios est\xE1ticos: enlistar, crear, cambiar slug",
|
|
4015
|
+
"Create an empty static website (optionally with your own slug)": "Crea un sitio est\xE1tico vac\xEDo (con tu propio slug si quieres)",
|
|
4016
|
+
"Public slug: /s/<slug>/ (a-z, 0-9, hyphens, 3-60 chars)": "Slug p\xFAblico: /s/<slug>/ (a-z, 0-9, guiones, 3-60 caracteres)",
|
|
4017
|
+
"Change a website's slug (the old URL redirects 301 to the new one)": "Cambia el slug de un sitio (la URL vieja redirige 301 a la nueva)",
|
|
3958
4018
|
"Show storage providers": "Muestra los proveedores de almacenamiento",
|
|
3959
4019
|
"MCP": "MCP",
|
|
3960
4020
|
"Print the MCP config JSON for your agent or editor": "Imprime el JSON de configuraci\xF3n MCP para tu agente o editor",
|
|
@@ -4172,7 +4232,7 @@ function normalizeArgs(input) {
|
|
|
4172
4232
|
}
|
|
4173
4233
|
|
|
4174
4234
|
// src/index.ts
|
|
4175
|
-
var VERSION2 = true ? "0.15.
|
|
4235
|
+
var VERSION2 = true ? "0.15.3" : "dev";
|
|
4176
4236
|
var GLOBAL_OPTIONS = {
|
|
4177
4237
|
json: { type: "boolean" },
|
|
4178
4238
|
token: { type: "string" },
|
package/package.json
CHANGED