deploro 0.6.2 → 0.7.0

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.
Files changed (2) hide show
  1. package/dist/index.js +306 -4
  2. package/package.json +44 -44
package/dist/index.js CHANGED
@@ -359,9 +359,10 @@ async function dbTablesCommand() {
359
359
  }
360
360
  async function dbQueryCommand(sql, opts) {
361
361
  requireProject();
362
+ const params = opts.param?.length ? opts.param : void 0;
362
363
  const data = await apiRequest(
363
364
  "/api/db/query",
364
- { method: "POST", body: JSON.stringify({ sql }) }
365
+ { method: "POST", body: JSON.stringify({ sql, params }) }
365
366
  );
366
367
  if (opts.json) {
367
368
  json(data.rows);
@@ -593,6 +594,23 @@ async function tokenRevokeCommand(id, opts) {
593
594
  await apiRequestNoProject(`/api/auth/tokens/${encodeURIComponent(id)}`, { method: "DELETE" });
594
595
  console.log(`\u2713 Token ${id} revoked`);
595
596
  }
597
+ async function tokenRotateCommand(id, opts) {
598
+ const config = requireConfig();
599
+ requireSessionAuth(config);
600
+ const graceHours = Number(opts.graceHours ?? 0);
601
+ const body = { graceHours };
602
+ if (opts.days !== void 0) body.expiresInDays = Number(opts.days);
603
+ const data = await apiRequestNoProject(
604
+ `/api/auth/tokens/${encodeURIComponent(id)}/rotate`,
605
+ { method: "POST", body: JSON.stringify(body) }
606
+ );
607
+ console.log("\u2713 Token rotated. Copy the new one now, it will not be shown again:");
608
+ console.log(`
609
+ ${data.token}
610
+ `);
611
+ console.log(` Expires : in ${data.expiresInDays} days`);
612
+ console.log(data.oldTokenValidForHours ? ` The old token keeps working for ${data.oldTokenValidForHours} hour(s).` : " The old token no longer works.");
613
+ }
596
614
  function isEmailProvider(provider) {
597
615
  return provider === "email" || provider === "email_password";
598
616
  }
@@ -886,8 +904,273 @@ async function resolveDomainId(projectId, idOrHostname) {
886
904
  return match.id;
887
905
  }
888
906
 
907
+ // src/commands/zones.ts
908
+ import { writeFileSync as writeFileSync3 } from "fs";
909
+ function zonesPath() {
910
+ return `/api/projects/${requireProject().projectId}/zones`;
911
+ }
912
+ async function findZone(name) {
913
+ const { zones: zones2 } = await apiRequest(zonesPath());
914
+ const n = name.trim().toLowerCase();
915
+ const match = zones2.filter((z) => n === z.name || n.endsWith(`.${z.name}`)).sort((a, b) => b.name.length - a.name.length)[0];
916
+ if (!match) {
917
+ console.error(`This project has no managed domain matching "${name}". Run: deploro zones list`);
918
+ process.exit(1);
919
+ }
920
+ return match;
921
+ }
922
+ function printNameservers(z) {
923
+ console.log(`
924
+ At your registrar, replace every nameserver for ${z.name} with:
925
+ `);
926
+ for (const ns of z.name_servers) console.log(` ${ns}`);
927
+ if (z.original_name_servers.length) console.log(`
928
+ (currently: ${z.original_name_servers.join(", ")})`);
929
+ console.log(`
930
+ Then run: deploro zones check ${z.name}`);
931
+ }
932
+ async function zonesListCommand() {
933
+ const { zones: zones2 } = await apiRequest(zonesPath());
934
+ if (!zones2.length) {
935
+ console.log("This project has no managed domains. Add one with: deploro zones add <domain>");
936
+ return;
937
+ }
938
+ table(zones2.map((z) => ({ domain: z.name, status: z.status, serving: z.hostname_count ?? 0 })));
939
+ }
940
+ async function zonesAddCommand(domain) {
941
+ const data = await apiRequest(zonesPath(), { method: "POST", body: JSON.stringify({ name: domain }) });
942
+ console.log(`\u2713 ${data.zone.name} added.
943
+ `);
944
+ console.log(`Copied ${data.imported_records.length} existing record(s) \u2014 check nothing you use is missing:`);
945
+ for (const r of data.imported_records) console.log(` ${r.type.padEnd(6)} ${r.name} \u2192 ${r.priority ?? ""} ${r.content}`);
946
+ for (const f of data.import_failed ?? []) console.log(` \u2717 ${f.record.type} ${f.record.name}: ${f.error}`);
947
+ console.log("DNS can't list every name a domain has \u2014 add anything else with 'deploro zones records add' before switching.");
948
+ if (data.legacy_hostnames.length) {
949
+ console.log(`
950
+ Already connected via CNAME: ${data.legacy_hostnames.join(", ")} \u2014 move them over with 'deploro zones attach' once live.`);
951
+ }
952
+ printNameservers(data.zone);
953
+ }
954
+ async function zonesStatusCommand(domain) {
955
+ const z = await findZone(domain);
956
+ const { zone } = await apiRequest(`${zonesPath()}/${z.id}`);
957
+ console.log(`${zone.name}: ${zone.status}`);
958
+ if (zone.status !== "active") printNameservers(zone);
959
+ }
960
+ async function zonesCheckCommand(domain) {
961
+ const z = await findZone(domain);
962
+ const { zone } = await apiRequest(`${zonesPath()}/${z.id}/check`, { method: "POST" });
963
+ if (zone.status === "active") console.log(`\u2713 ${zone.name} is live on Deploro`);
964
+ else console.log(`Not switched yet \u2014 nameserver changes can take a few hours. Deploro keeps checking and emails you when it's live.`);
965
+ }
966
+ async function zonesRemoveCommand(domain, opts) {
967
+ const z = await findZone(domain);
968
+ await confirmOrDie(
969
+ `Remove ${z.name}? If its nameservers still point at Deploro, its website AND email stop resolving immediately.`,
970
+ opts.yes
971
+ );
972
+ const data = await apiRequest(`${zonesPath()}/${z.id}`, {
973
+ method: "DELETE",
974
+ body: JSON.stringify({ confirm: z.name })
975
+ });
976
+ if (data.zone_file) {
977
+ const file = `${z.name}.zone.txt`;
978
+ writeFileSync3(file, data.zone_file);
979
+ console.log(`Saved its records to ${file}`);
980
+ }
981
+ console.log(`\u2713 ${z.name} removed`);
982
+ }
983
+ async function zonesRecordsListCommand(domain) {
984
+ const z = await findZone(domain);
985
+ const { records } = await apiRequest(`${zonesPath()}/${z.id}/records`);
986
+ table(
987
+ records.map((r) => ({
988
+ id: r.id,
989
+ type: r.type,
990
+ name: r.name,
991
+ content: r.priority !== null && r.type === "MX" ? `${r.priority} ${r.content}` : r.content,
992
+ proxied: r.proxied ? "yes" : "",
993
+ managed: r.managed_by ?? ""
994
+ }))
995
+ );
996
+ }
997
+ async function zonesRecordsAddCommand(domain, type, name, content, opts) {
998
+ const z = await findZone(domain);
999
+ const { record } = await apiRequest(`${zonesPath()}/${z.id}/records`, {
1000
+ method: "POST",
1001
+ body: JSON.stringify({
1002
+ type,
1003
+ name,
1004
+ content,
1005
+ ...opts.ttl ? { ttl: Number(opts.ttl) } : {},
1006
+ ...opts.priority ? { priority: Number(opts.priority) } : {},
1007
+ ...opts.proxied ? { proxied: true } : {}
1008
+ })
1009
+ });
1010
+ console.log(`\u2713 Added ${record.type} ${record.name} \u2192 ${record.content} (id: ${record.id})`);
1011
+ }
1012
+ async function zonesRecordsRemoveCommand(domain, recordId, opts) {
1013
+ const z = await findZone(domain);
1014
+ await confirmOrDie(`Delete record ${recordId} from ${z.name}?`, opts.yes);
1015
+ await apiRequest(`${zonesPath()}/${z.id}/records/${recordId}`, { method: "DELETE" });
1016
+ console.log("\u2713 Record deleted");
1017
+ }
1018
+ async function zonesAttachCommand(hostname, opts) {
1019
+ const z = await findZone(hostname);
1020
+ const h = hostname.trim().toLowerCase();
1021
+ try {
1022
+ const data = await apiRequest(
1023
+ `${zonesPath()}/${z.id}/hostnames`,
1024
+ { method: "POST", body: JSON.stringify({ hostname: h, replace: !!opts.replace }) }
1025
+ );
1026
+ if (data.attached) console.log(`\u2713 https://${data.hostname.hostname} now serves this project`);
1027
+ else console.log(`Saved, but not attached yet: ${data.error}`);
1028
+ } catch (err) {
1029
+ const msg = err.message;
1030
+ if (msg.includes("already points somewhere")) {
1031
+ console.error(`${h} already has DNS records or a CNAME connection. Re-run with --replace to point it at this project instead.`);
1032
+ process.exit(1);
1033
+ }
1034
+ throw err;
1035
+ }
1036
+ }
1037
+ async function zonesDetachCommand(hostname, opts) {
1038
+ const z = await findZone(hostname);
1039
+ const h = hostname.trim().toLowerCase();
1040
+ const { hostnames } = await apiRequest(`${zonesPath()}/${z.id}/hostnames`);
1041
+ const match = hostnames.find((x) => x.hostname === h);
1042
+ if (!match) {
1043
+ console.error(`${h} isn't serving this project.`);
1044
+ process.exit(1);
1045
+ }
1046
+ await confirmOrDie(`Stop serving this project on ${h}? It stops immediately.`, opts.yes);
1047
+ await apiRequest(`${zonesPath()}/${z.id}/hostnames/${match.id}`, { method: "DELETE" });
1048
+ console.log(`\u2713 ${h} detached`);
1049
+ }
1050
+ var FORWARDING = "cf_routing";
1051
+ async function zonesEmailStatusCommand(domain) {
1052
+ const z = await findZone(domain);
1053
+ const s = await apiRequest(`${zonesPath()}/${z.id}/email`);
1054
+ const names = new Map(s.presets.map((p) => [p.kind, p.name]));
1055
+ const active = s.services.map((x) => x.kind === FORWARDING ? "Forwarding" : names.get(x.kind) ?? x.kind);
1056
+ console.log(`Email on ${z.name}: ${active.length ? active.join(", ") : "nothing set up"}`);
1057
+ if (s.forwarding.enabled) {
1058
+ console.log("\nForwarding:");
1059
+ for (const r of s.forwarding.rules) {
1060
+ console.log(` ${r.address} \u2192 ${r.destination}${r.enabled ? "" : " (paused until the inbox confirms)"}`);
1061
+ }
1062
+ const ca = s.forwarding.catch_all;
1063
+ console.log(` everything else \u2192 ${ca?.enabled ? ca.destination : "rejected"}`);
1064
+ }
1065
+ if (s.destinations.length) {
1066
+ console.log("\nInboxes:");
1067
+ for (const d of s.destinations) {
1068
+ const state = d.usable ? "confirmed" : `waiting for them to click the ${d.waiting_for === "deploro" ? "Deploro" : "Cloudflare"} email`;
1069
+ console.log(` ${d.email} ${state}`);
1070
+ }
1071
+ }
1072
+ console.log(`
1073
+ Providers: ${s.presets.map((p) => p.kind).join(", ")} \u2014 or 'deploro zones email-forwarding on ${z.name}'`);
1074
+ }
1075
+ async function zonesEmailSetupCommand(domain, provider, opts) {
1076
+ const z = await findZone(domain);
1077
+ const config = {};
1078
+ for (const kv of opts.set ?? []) {
1079
+ const i = kv.indexOf("=");
1080
+ if (i < 1) {
1081
+ console.error(`--set expects key=value, got "${kv}"`);
1082
+ process.exit(1);
1083
+ }
1084
+ config[kv.slice(0, i)] = kv.slice(i + 1);
1085
+ }
1086
+ try {
1087
+ await apiRequest(`${zonesPath()}/${z.id}/email/presets/${provider}`, {
1088
+ method: "POST",
1089
+ body: JSON.stringify({ config, replace: !!opts.replace })
1090
+ });
1091
+ console.log(`\u2713 ${provider} is set up on ${z.name}`);
1092
+ } catch (err) {
1093
+ if (err.message.includes("replaces existing records")) {
1094
+ console.error(
1095
+ `${z.name} already has mail records this would replace \u2014 see 'deploro zones records list ${z.name}'. Re-run with --replace to replace them.`
1096
+ );
1097
+ process.exit(1);
1098
+ }
1099
+ throw err;
1100
+ }
1101
+ }
1102
+ async function zonesEmailRemoveCommand(domain, provider, opts) {
1103
+ const z = await findZone(domain);
1104
+ await confirmOrDie(`Remove ${provider} from ${z.name}? Its DNS records are deleted and mail stops arriving there.`, opts.yes);
1105
+ await apiRequest(`${zonesPath()}/${z.id}/email/presets/${provider}`, { method: "DELETE" });
1106
+ console.log(`\u2713 ${provider} removed`);
1107
+ }
1108
+ async function zonesEmailForwardingCommand(mode, domain, opts) {
1109
+ const z = await findZone(domain);
1110
+ if (mode === "on") {
1111
+ try {
1112
+ await apiRequest(`${zonesPath()}/${z.id}/email/forwarding`, {
1113
+ method: "POST",
1114
+ body: JSON.stringify({ replace: !!opts.replace })
1115
+ });
1116
+ } catch (err) {
1117
+ if (err.message.includes("replaces the domain's existing mail servers")) {
1118
+ console.error(`${z.name} already has MX records. Re-run with --replace to replace them with forwarding.`);
1119
+ process.exit(1);
1120
+ }
1121
+ throw err;
1122
+ }
1123
+ console.log(`\u2713 Forwarding is on for ${z.name}. Next: deploro zones forward hello@${z.name} you@gmail.com`);
1124
+ } else if (mode === "off") {
1125
+ await confirmOrDie(`Turn off forwarding for ${z.name}? Mail to it will bounce.`, opts.yes);
1126
+ await apiRequest(`${zonesPath()}/${z.id}/email/forwarding`, { method: "DELETE" });
1127
+ console.log("\u2713 Forwarding is off");
1128
+ } else {
1129
+ console.error("Use: deploro zones email-forwarding on|off <domain>");
1130
+ process.exit(1);
1131
+ }
1132
+ }
1133
+ async function zonesForwardCommand(address, inbox) {
1134
+ const [local, domain] = address.toLowerCase().split("@");
1135
+ if (!local || !domain) {
1136
+ console.error("The first argument is the address to forward, like hello@yourdomain.com");
1137
+ process.exit(1);
1138
+ }
1139
+ const z = await findZone(domain);
1140
+ const { projectId } = requireProject();
1141
+ const email = inbox.trim().toLowerCase();
1142
+ let s = await apiRequest(`${zonesPath()}/${z.id}/email`);
1143
+ let dest = s.destinations.find((d) => d.email === email);
1144
+ if (!dest) {
1145
+ await apiRequest(`/api/projects/${projectId}/email-destinations`, { method: "POST", body: JSON.stringify({ email }) });
1146
+ s = await apiRequest(`${zonesPath()}/${z.id}/email`);
1147
+ dest = s.destinations.find((d) => d.email === email);
1148
+ }
1149
+ if (!dest?.usable) {
1150
+ console.log(`${email} has been sent a confirmation email. Once they click it, run this command again.`);
1151
+ return;
1152
+ }
1153
+ await apiRequest(`${zonesPath()}/${z.id}/email/rules`, {
1154
+ method: "POST",
1155
+ body: JSON.stringify({ local, destination_id: dest.id })
1156
+ });
1157
+ console.log(`\u2713 ${local}@${z.name} \u2192 ${email}`);
1158
+ }
1159
+ async function zonesUnforwardCommand(address) {
1160
+ const domain = address.toLowerCase().split("@")[1] ?? "";
1161
+ const z = await findZone(domain);
1162
+ const s = await apiRequest(`${zonesPath()}/${z.id}/email`);
1163
+ const rule = s.forwarding.rules.find((r) => r.address === address.toLowerCase());
1164
+ if (!rule) {
1165
+ console.error(`${address} isn't forwarded.`);
1166
+ process.exit(1);
1167
+ }
1168
+ await apiRequest(`${zonesPath()}/${z.id}/email/rules/${rule.id}`, { method: "DELETE" });
1169
+ console.log(`\u2713 ${address} no longer forwards`);
1170
+ }
1171
+
889
1172
  // src/commands/storage.ts
890
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "fs";
1173
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync4 } from "fs";
891
1174
  import { basename } from "path";
892
1175
  function authHeaders2(config) {
893
1176
  return { Authorization: `Bearer ${config.accessToken}` };
@@ -939,7 +1222,7 @@ async function storageDownloadCommand(key, opts) {
939
1222
  await throwOnError2(res);
940
1223
  const bytes = new Uint8Array(await res.arrayBuffer());
941
1224
  const outPath = opts.out ?? basename(key);
942
- writeFileSync3(outPath, bytes);
1225
+ writeFileSync4(outPath, bytes);
943
1226
  console.log(`\u2713 Saved to ${outPath} (${bytes.length} bytes)`);
944
1227
  }
945
1228
  async function storageDeleteCommand(key, opts) {
@@ -1808,7 +2091,7 @@ db.command("create").description("Provision the active project's database (idemp
1808
2091
  db.command("info").description("Show database status and how to reach it from a deployed app").action(dbInfoCommand);
1809
2092
  db.command("tables").description("List tables in the active project").action(dbTablesCommand);
1810
2093
  db.command("rows <table>").description("List rows in a table").option("--limit <n>", "Rows per page (max 200)", "20").option("--page <n>", "Page number", "1").option("--json", "Output raw JSON").action(dbRowsCommand);
1811
- db.command("query <sql>").description("Run a SQL query (project admin)").option("--json", "Output raw JSON").action(dbQueryCommand);
2094
+ db.command("query <sql>").description("Run a read-only SQL query (project admin)").option("--param <value>", "Bind a value to $1, $2, ... in order (repeatable)", (v, prev) => [...prev, v], []).option("--json", "Output raw JSON").action(dbQueryCommand);
1812
2095
  db.command("schema <table>").description("Show schema for a table").action(dbSchemaCommand);
1813
2096
  db.command("insert <table>").description("Insert a row").requiredOption("--data <json>", "Row data as a JSON object").action(dbInsertCommand);
1814
2097
  db.command("update <table> <id>").description("Update a row by id").requiredOption("--data <json>", "Fields to update as a JSON object").action(dbUpdateCommand);
@@ -1840,6 +2123,7 @@ authEndUsers.command("delete <id>").description("Delete an end user and all thei
1840
2123
  var token = program.command("token").description("Personal access token commands");
1841
2124
  token.command("list").description("List your personal access tokens").action(tokenListCommand);
1842
2125
  token.command("create <name>").description("Create a new project-scoped personal access token").option("--read", "Grant read scope").option("--write", "Grant write scope").option("--project <slugs>", "Comma-separated project slugs/ids/names (defaults to the active project)").option("--days <n>", "Expiry in days (1-365)", "90").action(tokenCreateCommand);
2126
+ token.command("rotate <id>").description("Replace a token with a new one (same name, scopes and projects)").option("--grace-hours <n>", "Keep the old token working for this many hours (0-72)", "0").option("--days <n>", "Expiry of the new token in days (1-365, default: the old token's lifetime)").action(tokenRotateCommand);
1843
2127
  token.command("revoke <id>").description("Revoke a personal access token").option("--yes", "Skip confirmation prompt").action(tokenRevokeCommand);
1844
2128
  var hosting = program.command("hosting").description("Hosting commands");
1845
2129
  hosting.command("status").description("Show Worker and VPS health").action(hostingStatusCommand);
@@ -1889,6 +2173,24 @@ domains.command("add <hostname>").description("Add a domain \u2014 prints the CN
1889
2173
  domains.command("verify <id-or-hostname>").description("Verify DNS ownership and register SSL").action(domainsVerifyCommand);
1890
2174
  domains.command("status <id-or-hostname>").description("Poll domain verification/SSL status").action(domainsStatusCommand);
1891
2175
  domains.command("remove <id-or-hostname>").description("Remove a domain").option("-y, --yes", "Skip confirmation prompt").action(domainsRemoveCommand);
2176
+ var zones = program.command("zones").description("The active project's domains whose DNS Deploro manages (switch nameservers once, then manage everything)");
2177
+ zones.command("list").description("List the project's managed domains").action(zonesListCommand);
2178
+ zones.command("add <domain>").description("Add a domain \u2014 copies its current records and prints the nameservers to switch to").action(zonesAddCommand);
2179
+ zones.command("status <domain>").description("Show whether the nameserver switch has taken effect").action(zonesStatusCommand);
2180
+ zones.command("check <domain>").description("Ask Deploro to re-check the nameservers now").action(zonesCheckCommand);
2181
+ zones.command("remove <domain>").description("Remove a domain (saves its records to a zone file first)").option("-y, --yes", "Skip confirmation prompt").action(zonesRemoveCommand);
2182
+ var zoneRecords = zones.command("records").description("DNS records of a managed domain");
2183
+ zoneRecords.command("list <domain>").description("List records").action(zonesRecordsListCommand);
2184
+ zoneRecords.command("add <domain> <type> <name> <content>").description("Add a record (name: @ for the root, or e.g. www)").option("--ttl <seconds>", "TTL (default auto)").option("--priority <n>", "MX priority (default 10)").option("--proxied", "Proxy through Cloudflare (A/AAAA/CNAME only)").action(zonesRecordsAddCommand);
2185
+ zoneRecords.command("rm <domain> <record-id>").description("Delete a record").option("-y, --yes", "Skip confirmation prompt").action(zonesRecordsRemoveCommand);
2186
+ zones.command("attach <hostname>").description("Serve the active project on a managed domain or subdomain").option("--replace", "Replace records or a CNAME connection already at that hostname").action(zonesAttachCommand);
2187
+ zones.command("detach <hostname>").description("Stop serving the active project on that hostname").option("-y, --yes", "Skip confirmation prompt").action(zonesDetachCommand);
2188
+ zones.command("email <domain>").description("Show email setup: providers, forwarding, inboxes").action(zonesEmailStatusCommand);
2189
+ zones.command("email-setup <domain> <provider>").description("Set up google_workspace | microsoft_365 | zoho | fastmail | resend").option("--set <key=value...>", "Provider values, e.g. --set region=eu dkim_selector=zmail").option("--replace", "Replace existing mail records").action(zonesEmailSetupCommand);
2190
+ zones.command("email-remove <domain> <provider>").description("Remove a provider and its records").option("-y, --yes", "Skip confirmation prompt").action(zonesEmailRemoveCommand);
2191
+ zones.command("email-forwarding <mode> <domain>").description("Turn free email forwarding on or off (mode: on|off)").option("--replace", "Replace existing MX records").option("-y, --yes", "Skip confirmation prompt").action(zonesEmailForwardingCommand);
2192
+ zones.command("forward <address> <inbox>").description("Forward e.g. hello@yourdomain.com to you@gmail.com (the inbox confirms once)").action(zonesForwardCommand);
2193
+ zones.command("unforward <address>").description("Stop forwarding an address").action(zonesUnforwardCommand);
1892
2194
  var storage = program.command("storage").description("R2 file storage for the active project");
1893
2195
  storage.command("list").description("List stored files").action(storageListCommand);
1894
2196
  storage.command("upload <file>").description("Upload a local file").option("--key <name>", "Stored file name (defaults to the local file's name)").option("--bucket <name>", "Upload into an existing bucket instead of the project root").action(storageUploadCommand);
package/package.json CHANGED
@@ -1,44 +1,44 @@
1
- {
2
- "name": "deploro",
3
- "version": "0.6.2",
4
- "description": "Command-line interface for the Deploro developer platform — manage projects, databases, deployments, and hosting from your terminal.",
5
- "type": "module",
6
- "bin": {
7
- "deploro": "dist/index.js"
8
- },
9
- "files": [
10
- "dist"
11
- ],
12
- "engines": {
13
- "node": ">=18"
14
- },
15
- "keywords": [
16
- "deploro",
17
- "cli",
18
- "cloudflare",
19
- "postgres",
20
- "deployment"
21
- ],
22
- "license": "MIT",
23
- "repository": {
24
- "type": "git",
25
- "url": "git+https://github.com/yawdeals1/deploro.git",
26
- "directory": "packages/cli"
27
- },
28
- "homepage": "https://deploro.com",
29
- "publishConfig": {
30
- "access": "public"
31
- },
32
- "scripts": {
33
- "build": "tsup src/index.ts --format esm --no-splitting --target node18 --out-dir dist",
34
- "dev": "tsup src/index.ts --format esm --no-splitting --target node18 --out-dir dist --watch"
35
- },
36
- "dependencies": {
37
- "commander": "^13.0.0"
38
- },
39
- "devDependencies": {
40
- "@types/node": "^22.0.0",
41
- "tsup": "^8.0.0",
42
- "typescript": "^5.5.0"
43
- }
44
- }
1
+ {
2
+ "name": "deploro",
3
+ "version": "0.7.0",
4
+ "description": "Command-line interface for the Deploro developer platform — manage projects, databases, deployments, and hosting from your terminal.",
5
+ "type": "module",
6
+ "bin": {
7
+ "deploro": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "engines": {
13
+ "node": ">=18"
14
+ },
15
+ "keywords": [
16
+ "deploro",
17
+ "cli",
18
+ "cloudflare",
19
+ "postgres",
20
+ "deployment"
21
+ ],
22
+ "license": "MIT",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/yawdeals1/deploro.git",
26
+ "directory": "packages/cli"
27
+ },
28
+ "homepage": "https://deploro.com",
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "scripts": {
33
+ "build": "tsup src/index.ts --format esm --no-splitting --target node18 --out-dir dist",
34
+ "dev": "tsup src/index.ts --format esm --no-splitting --target node18 --out-dir dist --watch"
35
+ },
36
+ "dependencies": {
37
+ "commander": "^13.0.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "^22.0.0",
41
+ "tsup": "^8.0.0",
42
+ "typescript": "^5.5.0"
43
+ }
44
+ }