@dashnex/cli 0.5.2 → 0.5.23

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 (61) hide show
  1. package/README.md +2 -1
  2. package/dist/cli.js +1 -161
  3. package/dist/client.js +1 -12
  4. package/dist/commands/create.js +1 -134
  5. package/dist/commands/delete.js +1 -51
  6. package/dist/commands/deploy.js +1 -0
  7. package/dist/commands/dev.js +1 -0
  8. package/dist/commands/index.js +1 -68
  9. package/dist/commands/install.js +1 -0
  10. package/dist/commands/login.js +1 -262
  11. package/dist/commands/logout.js +1 -16
  12. package/dist/commands/pull.js +1 -102
  13. package/dist/commands/push.js +1 -108
  14. package/dist/commands/version.js +1 -10
  15. package/dist/commands/whoami.js +1 -52
  16. package/dist/dashnex.json.js +1 -5
  17. package/dist/lib/api.js +1 -23
  18. package/dist/lib/debug.js +1 -45
  19. package/dist/lib/errors.js +1 -0
  20. package/dist/lib/spinner.js +1 -0
  21. package/dist/package.json.js +1 -15
  22. package/dist/server.js +1 -12
  23. package/dist/services/auth.js +1 -116
  24. package/dist/src/cli.d.ts +2 -0
  25. package/dist/src/client.d.ts +3 -0
  26. package/dist/src/commands/create.d.ts +11 -0
  27. package/dist/src/commands/delete.d.ts +4 -0
  28. package/dist/src/commands/deploy.d.ts +4 -0
  29. package/dist/src/commands/dev.d.ts +4 -0
  30. package/dist/src/commands/index.d.ts +3 -0
  31. package/dist/src/commands/install.d.ts +4 -0
  32. package/dist/src/commands/login.d.ts +8 -0
  33. package/dist/src/commands/logout.d.ts +4 -0
  34. package/dist/src/commands/pull.d.ts +6 -0
  35. package/dist/src/commands/push.d.ts +4 -0
  36. package/dist/src/commands/version.d.ts +5 -0
  37. package/dist/src/commands/whoami.d.ts +4 -0
  38. package/dist/src/lib/api.d.ts +8 -0
  39. package/dist/src/lib/debug.d.ts +3 -0
  40. package/dist/src/lib/errors.d.ts +2 -0
  41. package/dist/src/lib/spinner.d.ts +6 -0
  42. package/dist/src/server.d.ts +3 -0
  43. package/dist/src/services/auth.d.ts +10 -0
  44. package/package.json +5 -6
  45. package/dist/cli.js.map +0 -1
  46. package/dist/client.js.map +0 -1
  47. package/dist/commands/create.js.map +0 -1
  48. package/dist/commands/delete.js.map +0 -1
  49. package/dist/commands/index.js.map +0 -1
  50. package/dist/commands/login.js.map +0 -1
  51. package/dist/commands/logout.js.map +0 -1
  52. package/dist/commands/pull.js.map +0 -1
  53. package/dist/commands/push.js.map +0 -1
  54. package/dist/commands/version.js.map +0 -1
  55. package/dist/commands/whoami.js.map +0 -1
  56. package/dist/dashnex.json.js.map +0 -1
  57. package/dist/lib/api.js.map +0 -1
  58. package/dist/lib/debug.js.map +0 -1
  59. package/dist/package.json.js.map +0 -1
  60. package/dist/server.js.map +0 -1
  61. package/dist/services/auth.js.map +0 -1
package/README.md CHANGED
@@ -30,6 +30,7 @@ npx @dashnex/cli <command> [options]
30
30
  | `delete` | Delete application from DashNex |
31
31
  | `whoami` | Show current logged-in business and user |
32
32
 
33
+
33
34
  ### Options
34
35
 
35
- - **create**: `-t, --template <template>` — Template (name@branch-or-tag, default: webapp-base@live)
36
+ - **create**: `-t, --template <template>` — Template (name@branch-or-tag, default: webapp-base@live)
package/dist/cli.js CHANGED
@@ -1,162 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import { Command } from "commander";
3
- import chalk from "chalk";
4
- import fs from "fs-extra";
5
- import path from "path";
6
- import dotenv from "dotenv";
7
- import packageJson from "./package.json.js";
8
- const program = new Command();
9
- const { name, version, description } = packageJson;
10
- program.name(name).description(description).version(version);
11
- function getModuleRoot(module, appDir) {
12
- const appPackageJsonPath = path.join(appDir, "package.json");
13
- if (fs.existsSync(appPackageJsonPath)) {
14
- try {
15
- const appPackageJson = JSON.parse(fs.readFileSync(appPackageJsonPath, "utf8"));
16
- if (appPackageJson.name === module) {
17
- return appDir;
18
- }
19
- } catch {
20
- }
21
- }
22
- return path.join(appDir, "node_modules", module);
23
- }
24
- async function discoverModuleCommands(module, appDir) {
25
- const discoveredCommands = [];
26
- try {
27
- const moduleRoot = getModuleRoot(module, appDir);
28
- const modulePath = path.join(moduleRoot, "dist", "commands", "index.js");
29
- if (fs.existsSync(modulePath)) {
30
- const module2 = await import(modulePath);
31
- let moduleCommands = [];
32
- if (module2.default) {
33
- moduleCommands = Array.isArray(module2.default) ? module2.default : [];
34
- } else if (module2.commands) {
35
- moduleCommands = Array.isArray(module2.commands) ? module2.commands : [];
36
- }
37
- if (moduleCommands.length > 0) {
38
- discoveredCommands.push(...moduleCommands);
39
- }
40
- }
41
- } catch (error) {
42
- if (process.env.DEBUG) {
43
- const errorMessage = error instanceof Error ? error.message : String(error);
44
- console.log(chalk.yellow(`Module ${module} has no commands or failed to load: ${errorMessage}`));
45
- }
46
- }
47
- return discoveredCommands;
48
- }
49
- async function discoverDashnexModules(appDir) {
50
- try {
51
- const dashnexModules = [];
52
- const seen = /* @__PURE__ */ new Set();
53
- const addIfNew = (name2) => {
54
- if (!seen.has(name2)) {
55
- seen.add(name2);
56
- dashnexModules.push(name2);
57
- }
58
- };
59
- const appDashnexPath = path.join(appDir, "dashnex.json");
60
- if (fs.existsSync(appDashnexPath)) {
61
- const appPackageJsonPath2 = path.join(appDir, "package.json");
62
- if (fs.existsSync(appPackageJsonPath2)) {
63
- const appPackageJson2 = JSON.parse(fs.readFileSync(appPackageJsonPath2, "utf8"));
64
- if (appPackageJson2.name) {
65
- addIfNew(appPackageJson2.name);
66
- }
67
- }
68
- }
69
- const appPackageJsonPath = path.join(appDir, "package.json");
70
- if (!fs.existsSync(appPackageJsonPath)) {
71
- return dashnexModules;
72
- }
73
- const appPackageJson = JSON.parse(fs.readFileSync(appPackageJsonPath, "utf8"));
74
- const allDependencies = {
75
- ...appPackageJson.dependencies,
76
- ...appPackageJson.devDependencies,
77
- ...appPackageJson.optionalDependencies
78
- };
79
- for (const [module] of Object.entries(allDependencies)) {
80
- const moduleRoot = path.join(appDir, "node_modules", module);
81
- if (fs.existsSync(path.join(moduleRoot, "dashnex.json"))) {
82
- addIfNew(module);
83
- }
84
- }
85
- return dashnexModules;
86
- } catch (error) {
87
- if (process.env.DEBUG) {
88
- const errorMessage = error instanceof Error ? error.message : String(error);
89
- console.log("⚠ Error reading app package.json:", errorMessage);
90
- }
91
- return [];
92
- }
93
- }
94
- function registerCommand(parentCommand, dashnexCommand, parentOptions = {}) {
95
- const cmd = parentCommand.command(dashnexCommand.name).description(dashnexCommand.description);
96
- if (dashnexCommand.options) {
97
- dashnexCommand.options.forEach((option) => {
98
- if (option.defaultValue !== void 0) {
99
- if (typeof option.defaultValue === "number") {
100
- cmd.option(option.flags, option.description, String(option.defaultValue));
101
- } else {
102
- cmd.option(option.flags, option.description, option.defaultValue);
103
- }
104
- } else {
105
- cmd.option(option.flags, option.description);
106
- }
107
- });
108
- }
109
- if (dashnexCommand.subcommands) {
110
- dashnexCommand.subcommands.forEach((subcommand) => {
111
- registerCommand(cmd, subcommand, { ...parentOptions, ...dashnexCommand.options });
112
- });
113
- }
114
- cmd.action(async (options, actionCommand) => {
115
- try {
116
- const mergedOptions = { ...parentOptions, ...options };
117
- await dashnexCommand.handler.execute(mergedOptions);
118
- } catch (error) {
119
- console.error(chalk.red(`❌ Command failed in ${dashnexCommand.name}:`), error);
120
- process.exit(1);
121
- }
122
- });
123
- }
124
- async function main() {
125
- dotenv.config({ quiet: true });
126
- process.env.DASHNEX_CLI = "1";
127
- let appDir = process.cwd();
128
- if (process.env.DEBUG) {
129
- console.log(`CLI started from directory: ${appDir}`);
130
- }
131
- const moduleNames = await discoverDashnexModules(appDir);
132
- if (process.env.DEBUG) {
133
- console.log(`Discovered modules: ${moduleNames.join(", ")}`);
134
- }
135
- for (const moduleName of moduleNames) {
136
- const moduleCommands = await discoverModuleCommands(moduleName, appDir);
137
- for (const command of moduleCommands) {
138
- registerCommand(program, command);
139
- }
140
- }
141
- try {
142
- const { default: applicationCommands } = await import(path.join(appDir, "dist", "commands", "index.js"));
143
- if (applicationCommands && Array.isArray(applicationCommands)) {
144
- for (const command of applicationCommands) {
145
- registerCommand(program, command);
146
- }
147
- }
148
- } catch (error) {
149
- if (process.env.DEBUG) {
150
- console.error(chalk.yellow("⚠ Failed to discover application commands"));
151
- }
152
- }
153
- program.parse(process.argv);
154
- if (!process.argv.slice(2).length) {
155
- program.outputHelp();
156
- }
157
- }
158
- main().catch((error) => {
159
- console.error(chalk.red("❌ CLI failed:"), error);
160
- process.exit(1);
161
- });
162
- //# sourceMappingURL=cli.js.map
2
+ import{Command as o}from"commander";import e from"chalk";import n from"fs-extra";import s from"path";import{fileURLToPath as a}from"url";import c from"dotenv";import r from"./package.json.js";import{isUserInterrupt as t,INTERRUPTED_MESSAGE as i}from"./lib/errors.js";const l=new o,{name:d,version:m,description:p}=r;async function f(o,a){const c=[];try{const e=function(o,e){const a=s.join(e,"package.json");if(n.existsSync(a))try{if(JSON.parse(n.readFileSync(a,"utf8")).name===o)return e}catch{}return s.join(e,"node_modules",o)}(o,a),r=s.join(e,"dist","commands","index.js");if(n.existsSync(r)){const o=await import(r);let e=[];o.default?e=Array.isArray(o.default)?o.default:[]:o.commands&&(e=Array.isArray(o.commands)?o.commands:[]),e.length>0&&c.push(...e)}}catch(r){if(process.env.DEBUG){const n=r instanceof Error?r.message:String(r);console.log(e.yellow(`Module ${o} has no commands or failed to load: ${n}`))}}return c}function u(o,n,s={}){const a=o.command(n.name).description(n.description);"pull"===n.name&&a.arguments("[folder]"),n.options&&n.options.forEach(o=>{void 0!==o.defaultValue?"number"==typeof o.defaultValue?a.option(o.flags,o.description,String(o.defaultValue)):a.option(o.flags,o.description,o.defaultValue):a.option(o.flags,o.description)}),n.subcommands&&n.subcommands.forEach(o=>{u(a,o,{...s,...n.options})}),"pull"===n.name?a.action(async(o,a,c)=>{try{const e={...s,...a};o&&(e.folder=o),await n.handler.execute(e)}catch(r){if(t(r))return void console.log(e.yellow(i));console.error(e.red(`❌ Command failed in ${n.name}:`),r),process.exit(1)}}):a.action(async(o,a)=>{try{const e={...s,...o};await n.handler.execute(e)}catch(c){if(t(c))return void console.log(e.yellow(i));console.error(e.red(`❌ Command failed in ${n.name}:`),c),process.exit(1)}})}l.name(d).description(p).version(m),async function(){c.config({quiet:!0}),process.env.DASHNEX_CLI="1";let o=process.cwd();const r=s.dirname(a(import.meta.url)),t=s.resolve(r,"..");process.env.DEBUG&&(console.log(`CLI started from directory: ${o}`),console.log(`CLI package directory: ${t}`));const i=await async function(o){try{const e=[],a=/* @__PURE__ */new Set,c=o=>{a.has(o)||(a.add(o),e.push(o))},r=s.join(o,"dashnex.json");if(n.existsSync(r)){const e=s.join(o,"package.json");if(n.existsSync(e)){const o=JSON.parse(n.readFileSync(e,"utf8"));o.name&&c(o.name)}}const t=s.join(o,"package.json");if(!n.existsSync(t))return e;const i=JSON.parse(n.readFileSync(t,"utf8")),l={...i.dependencies,...i.devDependencies,...i.optionalDependencies};for(const[d]of Object.entries(l)){const e=s.join(o,"node_modules",d);n.existsSync(s.join(e,"dashnex.json"))&&c(d)}return e}catch(e){if(process.env.DEBUG){const o=e instanceof Error?e.message:String(e);console.log("⚠ Error reading app package.json:",o)}return[]}}(o),d=t.includes("node_modules");let m=!1;try{const e=s.join(o,"package.json");if(await n.pathExists(e)){const o=JSON.parse(await n.readFile(e,"utf8"));m="@dashnex/cli"in{...o.dependencies,...o.devDependencies,...o.optionalDependencies}}}catch{}!d&&!m||i.includes("@dashnex/cli")||i.push("@dashnex/cli"),process.env.DEBUG&&(console.log(`CLI package directory: ${t}`),console.log(`Is installed package: ${d}`),console.log(`CLI in dependencies: ${m}`),console.log(`Discovered modules: ${i.join(", ")}`));for(const a of i){let c=[];if("@dashnex/cli"===a&&(d||m))try{const o=s.join(t,"dist","commands","index.js");if(process.env.DEBUG&&console.log(`Loading @dashnex/cli commands from: ${o}`),await n.pathExists(o)){const e=await import(o);e.default?c=Array.isArray(e.default)?e.default:[]:e.commands&&(c=Array.isArray(e.commands)?e.commands:[]),process.env.DEBUG&&console.log(`Loaded ${c.length} commands from @dashnex/cli`)}}catch(p){if(process.env.DEBUG){const o=p instanceof Error?p.message:String(p);console.log(e.yellow(`Failed to load @dashnex/cli commands: ${o}`))}}else c=await f(a,o);for(const o of c)u(l,o)}try{const{default:e}=await import(s.join(o,"dist","commands","index.js"));if(e&&Array.isArray(e))for(const o of e)u(l,o)}catch(p){process.env.DEBUG&&console.error(e.yellow("⚠ Failed to discover application commands"))}l.parse(process.argv),process.argv.slice(2).length||l.outputHelp()}().catch(o=>{t(o)&&(console.log(e.yellow(i)),process.exit(0)),console.error(e.red("❌ CLI failed:"),o),process.exit(1)});
package/dist/client.js CHANGED
@@ -1,12 +1 @@
1
- import packageJson from "./package.json.js";
2
- import dashnexConfig from "./dashnex.json.js";
3
- const client = {
4
- name: packageJson.name,
5
- version: packageJson.version,
6
- description: packageJson.description,
7
- ...dashnexConfig
8
- };
9
- export {
10
- client as default
11
- };
12
- //# sourceMappingURL=client.js.map
1
+ import o from"./package.json.js";import s from"./dashnex.json.js";const e={name:o.name,version:o.version,description:o.description,...s};export{e as default};
@@ -1,134 +1 @@
1
- import inquirer from "inquirer";
2
- import chalk from "chalk";
3
- import { debug, debugError } from "../lib/debug.js";
4
- import { getBusinessApiBase } from "../lib/api.js";
5
- import { ensureLoggedIn } from "../services/auth.js";
6
- const extractErrorMessage = (body) => {
7
- if (Array.isArray(body.message) && body.message.length > 0) {
8
- return body.message.join(" ");
9
- }
10
- if (typeof body.message === "string") return body.message;
11
- if (typeof body.error === "string") return body.error;
12
- return void 0;
13
- };
14
- const SUCCESS_MESSAGE = "Application is created successfully. Use 'npx dashnex pull' to pull it to your computer or 'npx dashnex deploy' to deploy it to the cloud.";
15
- class CreateCommand {
16
- async execute(options = {}) {
17
- debug("Create flow started");
18
- const session = await ensureLoggedIn();
19
- if (!session) return;
20
- debug("Auth valid, checking if business already has application");
21
- const applicationsUrl = `${getBusinessApiBase()}/business/v1/applications`;
22
- debug(`GET ${applicationsUrl}`);
23
- try {
24
- const appsResponse = await fetch(applicationsUrl, {
25
- headers: { Authorization: `Bearer ${session.token}` }
26
- });
27
- debug(`Applications response: ${appsResponse.status}`);
28
- if (appsResponse.status !== 404) {
29
- console.error(
30
- chalk.red(
31
- "Business already has an application. Run 'npx dashnex pull' to pull the existing one."
32
- )
33
- );
34
- process.exit(1);
35
- }
36
- } catch (error) {
37
- debugError(error);
38
- if (error instanceof Error && error.message.startsWith("EXIT:")) throw error;
39
- console.error(chalk.red("Could not reach DashNex API. Check your connection and try again."));
40
- process.exit(1);
41
- }
42
- debug("No existing application, proceeding to subdomain prompt");
43
- let subdomain;
44
- const checkSubdomainUrl = (sub) => `${getBusinessApiBase()}/business/v1/applications/check-subdomain?subdomain=${encodeURIComponent(sub)}`;
45
- while (true) {
46
- const { sub } = await inquirer.prompt([
47
- {
48
- type: "input",
49
- name: "sub",
50
- message: "Pick your subdomain:",
51
- validate: (input) => input.trim() ? true : "Subdomain is required"
52
- }
53
- ]);
54
- subdomain = sub.trim();
55
- debug(`Checking subdomain: ${subdomain}`);
56
- try {
57
- const checkResponse = await fetch(checkSubdomainUrl(subdomain), {
58
- headers: { Authorization: `Bearer ${session.token}` }
59
- });
60
- debug(`Check subdomain response: ${checkResponse.status}`);
61
- if (!checkResponse.ok) {
62
- const contentType = checkResponse.headers.get("content-type") ?? "";
63
- let message = "Failed to check subdomain availability.";
64
- if (checkResponse.status === 401 || checkResponse.status === 403) {
65
- message = "Please run 'npx dashnex login' to authenticate.";
66
- console.error(chalk.red(message));
67
- process.exit(1);
68
- }
69
- if (contentType.includes("application/json")) {
70
- const body = await checkResponse.json().catch(() => ({}));
71
- const apiMessage = extractErrorMessage(body);
72
- if (apiMessage) message = apiMessage;
73
- }
74
- console.error(chalk.red(message));
75
- continue;
76
- }
77
- const checkBody = await checkResponse.json();
78
- if (checkBody.available) {
79
- debug(`Subdomain ${subdomain} is available`);
80
- break;
81
- }
82
- console.error(chalk.red("Subdomain is not available. Please choose a different one."));
83
- } catch (error) {
84
- debugError(error);
85
- if (error instanceof Error && error.message.startsWith("EXIT:")) throw error;
86
- console.error(chalk.red("Could not reach DashNex API. Check your connection and try again."));
87
- process.exit(1);
88
- }
89
- }
90
- const createUrl = `${getBusinessApiBase()}/business/v1/cli/create`;
91
- debug(`POST ${createUrl}`);
92
- const createBody = { subdomain };
93
- if (options.template) {
94
- createBody.template = options.template;
95
- debug(`Template: ${options.template}`);
96
- }
97
- try {
98
- const createResponse = await fetch(createUrl, {
99
- method: "POST",
100
- headers: {
101
- Authorization: `Bearer ${session.token}`,
102
- "Content-Type": "application/json"
103
- },
104
- body: JSON.stringify(createBody)
105
- });
106
- debug(`Create response: ${createResponse.status}`);
107
- if (!createResponse.ok) {
108
- const contentType = createResponse.headers.get("content-type") ?? "";
109
- let message = "Failed to create application.";
110
- if (createResponse.status === 401 || createResponse.status === 403) {
111
- message = "Please run 'npx dashnex login' to authenticate.";
112
- } else if (contentType.includes("application/json")) {
113
- const body = await createResponse.json().catch(() => ({}));
114
- debug(`Create response body: ${JSON.stringify(body)}`);
115
- const apiMessage = extractErrorMessage(body);
116
- if (apiMessage) message = apiMessage;
117
- }
118
- console.error(chalk.red(message));
119
- process.exit(1);
120
- }
121
- debug("Application created successfully");
122
- console.log(chalk.green(SUCCESS_MESSAGE));
123
- } catch (error) {
124
- debugError(error);
125
- if (error instanceof Error && error.message.startsWith("EXIT:")) throw error;
126
- console.error(chalk.red("Could not reach DashNex API. Check your connection and try again."));
127
- process.exit(1);
128
- }
129
- }
130
- }
131
- export {
132
- CreateCommand
133
- };
134
- //# sourceMappingURL=create.js.map
1
+ import e from"inquirer";import t from"chalk";import{debug as o,debugError as s}from"../lib/debug.js";import{getBusinessApiBase as a}from"../lib/api.js";import{ensureLoggedIn as i}from"../services/auth.js";import{createSpinner as r}from"../lib/spinner.js";import{isUserInterrupt as n,INTERRUPTED_MESSAGE as l}from"../lib/errors.js";import{PullCommand as c}from"./pull.js";const p=e=>Array.isArray(e.message)&&e.message.length>0?e.message.join("\n"):"string"==typeof e.message?e.message:"string"==typeof e.error?e.error:void 0,u=e=>new Promise(t=>setTimeout(t,e));class d{async pollApplicationCreated(e,t,a=5e3,i=6e4){const r=Date.now();let n=0;for(;Date.now()-r<i;){n++,o(`Polling application status (attempt ${n})...`);try{const s=await fetch(e,{headers:{Authorization:`Bearer ${t}`}});if(o(`Poll response: ${s.status}`),200===s.status){const e=await s.json();if(o(`Poll response body status: ${e.status}`),"creating"!==e.status)return o(`Application status is "${e.status}", creation complete`),{ready:!0,status:e.status};o('Application status is still "creating", continuing to poll...')}}catch(l){s(l),o(`Poll attempt ${n} failed with network error`)}await u(a)}return{ready:!1}}async execute(u={}){o("Create flow started");const d=await i();if(!d)return;o("Auth valid, checking if business already has application");const h=r(),m=`${a()}/business/v1/applications`;o(`GET ${m}`),h.start("Checking application status...");try{const e=await fetch(m,{headers:{Authorization:`Bearer ${d.token}`}});h.stop(),o(`Applications response: ${e.status}`);const s=await e.text();o(`Applications response body: ${s}`),404!==e.status&&(console.error(t.red("Business already has an application. Run 'npx dashnex pull' to pull the existing one.")),process.exit(1))}catch($){if(h.stop(),s($),$ instanceof Error&&$.message.startsWith("EXIT:"))throw $;if(n($))return void console.log(t.yellow(l));console.error(t.red("Could not reach DashNex API. Check your connection and try again.")),process.exit(1)}let f;o("No existing application, proceeding to subdomain prompt");const y=e=>`${a()}/business/v1/applications/check-subdomain?subdomain=${encodeURIComponent(e)}`;for(;;){const{sub:a}=await e.prompt([{type:"input",name:"sub",message:"Pick your subdomain:",validate:e=>!!e.trim()||"Subdomain is required"}]);f=a.trim(),o(`Checking subdomain: ${f}`);const i=y(f);o(`GET ${i}`),h.start("Checking subdomain...");try{const e=await fetch(i,{headers:{Authorization:`Bearer ${d.token}`}});h.stop(),o(`Check subdomain response: ${e.status}`);const s=await e.text();if(o(`Check subdomain response body: ${s}`),!e.ok){const a=e.headers.get("content-type")??"";let i="Failed to check subdomain availability.";if(401!==e.status&&403!==e.status||(i="Please run 'npx dashnex login' to authenticate.",console.error(t.red(i)),process.exit(1)),a.includes("application/json")){const e=JSON.parse(s);o(`Check subdomain error body: ${JSON.stringify(e)}`);const t=p(e);t&&(i=t)}console.error(t.red(i));continue}const a=JSON.parse(s);if(o(`Check subdomain parsed body: ${JSON.stringify(a)}`),a.available){o(`Subdomain ${f} is available`);break}console.error(t.red("Subdomain is not available. Please choose a different one."))}catch($){if(h.stop(),s($),$ instanceof Error&&$.message.startsWith("EXIT:"))throw $;if(n($))return void console.log(t.yellow(l));console.error(t.red("Could not reach DashNex API. Check your connection and try again.")),process.exit(1)}}const g=`${a()}/business/v1/cli/create`;o(`POST ${g}`);const b={subdomain:f};u.template&&(b.template=u.template,o(`Template: ${u.template}`));const w=JSON.stringify(b);o(`Create request body: ${w}`),h.start("Creating application...");try{const i=await fetch(g,{method:"POST",headers:{Authorization:`Bearer ${d.token}`,"Content-Type":"application/json"},body:w});h.stop(),o(`Create response: ${i.status}`);const r=await i.text();if(o(`Create response body: ${r}`),503===i.status){o("Create returned 503, polling for application creation..."),console.log(t.yellow("Application is being created, please wait..."));const e=`${a()}/business/v1/applications`,s=await this.pollApplicationCreated(e,d.token);s.ready||(console.error(t.red("Application creation is taking longer than expected. Try again later or run 'npx dashnex pull' to check.")),process.exit(1)),"failed"===s.status&&(console.error(t.red("Application creation failed. Please try again.")),process.exit(1)),o("Application found after polling")}else if(!i.ok){const e=i.headers.get("content-type")??"";let s="Failed to create application.";if(401===i.status||403===i.status)s="Please run 'npx dashnex login' to authenticate.";else if(e.includes("application/json")){const e=JSON.parse(r);o(`Create error body parsed: ${JSON.stringify(e)}`);const t=p(e);t&&(s=t)}console.error(t.red(s)),process.exit(1)}o("Application created successfully");const{pull:u}=await e.prompt([{type:"confirm",name:"pull",message:"Pull the application locally?",default:!0}]);if(o(`User chose to pull: ${u}`),u){o("Running pull flow");try{const e=new c;await e.execute()}catch($){if(s($),$ instanceof Error&&$.message.startsWith("EXIT:"))throw $;if(n($))return void console.log(t.yellow(l));console.error(t.red("Failed to pull application."))}}else console.log(t.green("Application is created successfully. Run 'dashnex pull' to pull it to your computer or 'dashnex deploy' to deploy it to the cloud."))}catch($){if(h.stop(),s($),$ instanceof Error&&$.message.startsWith("EXIT:"))throw $;if(n($))return void console.log(t.yellow(l));console.error(t.red("Could not reach DashNex API. Check your connection and try again.")),process.exit(1)}}}export{d as CreateCommand};
@@ -1,51 +1 @@
1
- import chalk from "chalk";
2
- import { debug, debugError } from "../lib/debug.js";
3
- import { getBusinessApiBase } from "../lib/api.js";
4
- import { ensureLoggedIn } from "../services/auth.js";
5
- const extractErrorMessage = (body) => {
6
- if (typeof body.error === "string") return body.error;
7
- if (typeof body.message === "string") return body.message;
8
- return void 0;
9
- };
10
- class DeleteCommand {
11
- async execute() {
12
- debug("Delete flow started");
13
- const session = await ensureLoggedIn();
14
- if (!session) return;
15
- const url = `${getBusinessApiBase()}/business/v1/applications`;
16
- debug(`DELETE ${url}`);
17
- try {
18
- const response = await fetch(url, {
19
- method: "DELETE",
20
- headers: { Authorization: `Bearer ${session.token}` }
21
- });
22
- debug(`Response: ${response.status}`);
23
- if (!response.ok) {
24
- const contentType = response.headers.get("content-type") ?? "";
25
- let message = "Failed to delete application.";
26
- if (response.status === 401 || response.status === 403) {
27
- message = "Please run 'npx dashnex login' to authenticate.";
28
- } else if (contentType.includes("application/json")) {
29
- const body2 = await response.json().catch(() => ({}));
30
- const apiMessage = extractErrorMessage(body2);
31
- if (apiMessage) message = apiMessage;
32
- }
33
- console.error(chalk.red(message));
34
- process.exit(1);
35
- }
36
- const body = await response.json().catch(() => ({}));
37
- const successMessage = typeof body.message === "string" ? body.message : "Application deleted successfully.";
38
- debug("Application deleted successfully");
39
- console.log(chalk.green(successMessage));
40
- } catch (error) {
41
- debugError(error);
42
- if (error instanceof Error && error.message.startsWith("EXIT:")) throw error;
43
- console.error(chalk.red("Could not reach DashNex API. Check your connection and try again."));
44
- process.exit(1);
45
- }
46
- }
47
- }
48
- export {
49
- DeleteCommand
50
- };
51
- //# sourceMappingURL=delete.js.map
1
+ import e from"inquirer";import t from"chalk";import{debug as o,debugError as s}from"../lib/debug.js";import{getBusinessApiBase as r}from"../lib/api.js";import{ensureLoggedIn as i}from"../services/auth.js";import{createSpinner as n}from"../lib/spinner.js";import{isUserInterrupt as a,INTERRUPTED_MESSAGE as c}from"../lib/errors.js";class l{async execute(){o("Delete flow started");const{confirm:l}=await e.prompt([{type:"confirm",name:"confirm",message:"Are you sure you want to delete this application? This action cannot be undone.",default:!1}]);if(!l)return o("User cancelled deletion"),void console.log(t.yellow("Deletion cancelled."));const p=await i();if(!p)return;const d=`${r()}/business/v1/applications`;o(`DELETE ${d}`);const f=n();f.start("Deleting application...");try{const e=await fetch(d,{method:"DELETE",headers:{Authorization:`Bearer ${p.token}`}});if(f.stop(),o(`Response: ${e.status}`),!e.ok){const o=e.headers.get("content-type")??"";let s="Failed to delete application.";if(401===e.status||403===e.status)s="Please run 'npx dashnex login' to authenticate.";else if(o.includes("application/json")){const t=(e=>"string"==typeof e.error?e.error:"string"==typeof e.message?e.message:void 0)(await e.json().catch(()=>({})));t&&(s=t)}console.error(t.red(s)),process.exit(1)}const s=await e.json().catch(()=>({})),r="string"==typeof s.message?s.message:"Application deleted successfully.";o("Application deleted successfully"),console.log(t.green(r))}catch(m){if(f.stop(),s(m),m instanceof Error&&m.message.startsWith("EXIT:"))throw m;if(a(m))return void console.log(t.yellow(c));console.error(t.red("Could not reach DashNex API. Check your connection and try again.")),process.exit(1)}}}export{l as DeleteCommand};
@@ -0,0 +1 @@
1
+ import e from"chalk";import{debug as t,debugError as o}from"../lib/debug.js";import{getDeployerBase as s}from"../lib/api.js";import{ensureLoggedIn as r}from"../services/auth.js";import{createSpinner as n}from"../lib/spinner.js";import{isUserInterrupt as a,INTERRUPTED_MESSAGE as i}from"../lib/errors.js";const c=3e5,l=99,p=e=>new Promise(t=>setTimeout(t,e)),d=async(s,r,n,a)=>{const i=await fetch(s,{method:"GET",headers:{Authorization:`Bearer ${r}`,Accept:"text/event-stream"}});if(t(`SSE connection opened: ${i.status}`),!i.ok){const t=i.status;let o="Failed to start deployment.";if(401===t||403===t)o="Please run 'npx dashnex login' to authenticate.";else try{const e=await i.text(),t=JSON.parse(e);"string"==typeof t.error?o=t.error:"string"==typeof t.message&&(o=t.message)}catch{}throw console.error(e.red(o)),new Error(`HTTP ${t}: ${o}`)}if(!i.body)throw new Error("Response body is null");t("SSE connection established successfully"),a?.();const c=i.body.getReader();try{for await(const e of async function*(e){const t=new TextDecoder("utf-8");let o="";for(;;){const{value:s,done:r}=await e.read();if(r)break;o+=t.decode(s,{stream:!0});const n=o.split("\n");o=n.pop()||"";let a="";for(const e of n)e.startsWith("data: ")?a=e.slice(6):""===e&&a&&(yield{data:a},a="")}if(o.startsWith("data: ")){const e=o.slice(6);e&&(yield{data:e})}}(c))try{if(!e.data){t("Received empty SSE event");continue}const o=JSON.parse(e.data);t(`SSE message received: ${JSON.stringify(o)}`),n(o)}catch(l){o(l),t(`Failed to parse SSE event data: ${e.data}`)}}finally{c.releaseLock()}};class f{async execute(){t("Deploy flow started");const f=await r();if(!f)return;const m=`${s()}/business/v1/applications/deploy`;t(`GET ${m} (SSE)`);let y=0,u="",g=!1,h=0,w=!1;const S=n();let x=0,$=0,v=null;const b=(e,t)=>{const o=Math.round(e);S.text(`[${o}%] ${t}`)},E=()=>{D();const e=y,t=Date.now(),o=c*((l-e)/l);v=setInterval(()=>{const s=Date.now()-t;let r;if($>t){const e=Date.now()-$,t=l-x,o=t*3030.3030303030305;r=Math.min(x+e/o*t,l)}else r=Math.min(e+s/o*(l-e),l);r>y&&(y=r,b(y,u))},200)},D=()=>{v&&(clearInterval(v),v=null)};let T=!1;const M=t=>{if(w=!0,"string"==typeof t.error)return D(),S.stop(),console.error(e.red(t.error)),g=!0,void(T=!0);if("string"==typeof t.message&&(u=t.message),"number"==typeof t.progress&&(x=t.progress,$=Date.now(),t.progress>y&&(y=t.progress)),"string"==typeof t.message||"number"==typeof t.progress)if(y>=100){D(),S.stop();const t=u||"Application is deployed";process.stdout.write(`${e.green(t)}\n`),g=!0}else b(y,u)};for(;h<=5;)try{return w?b(y,u):S.start("Connecting..."),E(),await d(m,f.token,M,()=>{w||(S.text(`[${Math.round(y)}%] Deployment in progress...`),u="Deployment in progress...")}),D(),S.stop(),t("SSE connection closed"),void(T&&process.exit(1))}catch(k){if(D(),o(k),t(`SSE connection error: ${k}`),g)return S.stop(),void(T&&process.exit(1));if(a(k))return S.stop(),void console.log(e.yellow(i));k instanceof Error&&k.message.startsWith("HTTP")&&(S.stop(),console.error(e.red("Could not complete deployment. Check your connection and try again.")),process.exit(1)),h++,h>5&&(S.stop(),console.error(e.red("Deployment failed. Maximum reconnection attempts exceeded.")),process.exit(1));const s=Math.min(1e3*Math.pow(2,h-1),3e4);t(`Connection error. Reconnecting in ${s/1e3}s... (attempt ${h}/5)`),await p(s)}}}export{f as DeployCommand};
@@ -0,0 +1 @@
1
+ import{spawn as e}from"child_process";import o from"path";import s from"fs-extra";import r from"chalk";import{debug as n,debugError as a}from"../lib/debug.js";class i{async execute(){n("Dev flow started");const i=process.cwd(),c=o.join(i,"dashnex.json"),t=o.join(i,"package.json");let p;n(`Checking for dashnex.json at: ${c}`),await s.pathExists(c)||(console.error(r.red("This is not a DashNex project.")),process.exit(1)),n("dashnex.json found, checking for package.json"),await s.pathExists(t)||(console.error(r.red("package.json is missing.")),process.exit(1)),n("package.json found, checking for dev script");try{p=await s.readJson(t)}catch(m){a(m),console.error(r.red("Failed to read package.json.")),process.exit(1)}p.scripts&&p.scripts.dev||(console.error(r.red('The "dev" script is missing from package.json. Please add a "dev" script to package.json.')),process.exit(1)),n("dev script found, checking for npm availability");const d=await(async o=>new Promise(s=>{const r=e(`${o} --version`,{stdio:"ignore",shell:!0});r.on("error",()=>{s(!1)}),r.on("close",e=>{s(0===e)})}))("npm");let l;n(`npm available: ${d}`),d||(console.error(r.red("npm is not available. Please install npm to continue.")),process.exit(1)),n("npm available, executing: npm run dev");try{l=await(async o=>new Promise((s,r)=>{const n=e(o,{stdio:"inherit",cwd:process.cwd(),shell:!0});n.on("error",e=>{a(e),r(e)}),n.on("close",e=>{s(null===e?0:e)})}))("npm run dev")}catch(m){return a(m),m instanceof Error?console.error(r.red(`Failed to run npm run dev: ${m.message}`)):console.error(r.red("Failed to run npm run dev")),void process.exit(1)}process.exit(l)}}export{i as DevCommand};
@@ -1,68 +1 @@
1
- import VersionCommand from "./version.js";
2
- import { LoginCommand } from "./login.js";
3
- import { LogoutCommand } from "./logout.js";
4
- import { CreateCommand } from "./create.js";
5
- import { PullCommand } from "./pull.js";
6
- import { PushCommand } from "./push.js";
7
- import { DeleteCommand } from "./delete.js";
8
- import { WhoamiCommand } from "./whoami.js";
9
- const commands = [
10
- {
11
- name: "version",
12
- description: "Display the version of the CLI",
13
- handler: new VersionCommand(),
14
- options: []
15
- },
16
- {
17
- name: "login",
18
- description: "Log in to your DashNex account",
19
- handler: new LoginCommand(),
20
- options: []
21
- },
22
- {
23
- name: "logout",
24
- description: "Log out and remove local credentials",
25
- handler: new LogoutCommand(),
26
- options: []
27
- },
28
- {
29
- name: "create",
30
- description: "Create a new DashNex application",
31
- handler: new CreateCommand(),
32
- options: [
33
- {
34
- flags: "-t, --template <template>",
35
- description: "Template (name@branch-or-tag)",
36
- defaultValue: "webapp-base@live"
37
- }
38
- ]
39
- },
40
- {
41
- name: "pull",
42
- description: "Pull existing application to current folder",
43
- handler: new PullCommand(),
44
- options: []
45
- },
46
- {
47
- name: "push",
48
- description: "Push local application to DashNex",
49
- handler: new PushCommand(),
50
- options: []
51
- },
52
- {
53
- name: "delete",
54
- description: "Delete application from DashNex",
55
- handler: new DeleteCommand(),
56
- options: []
57
- },
58
- {
59
- name: "whoami",
60
- description: "Show current logged-in business and user",
61
- handler: new WhoamiCommand(),
62
- options: []
63
- }
64
- ];
65
- export {
66
- commands as default
67
- };
68
- //# sourceMappingURL=index.js.map
1
+ import e from"./version.js";import{LoginCommand as o}from"./login.js";import{LogoutCommand as n}from"./logout.js";import{CreateCommand as i}from"./create.js";import{PullCommand as t}from"./pull.js";import{PushCommand as a}from"./push.js";import{DeleteCommand as r}from"./delete.js";import{WhoamiCommand as p}from"./whoami.js";import{DeployCommand as s}from"./deploy.js";import{InstallCommand as l}from"./install.js";import{DevCommand as m}from"./dev.js";const d=[{name:"version",description:"Display the version of the CLI",handler:new e,options:[]},{name:"login",description:"Log in to your DashNex account",handler:new o,options:[]},{name:"logout",description:"Log out and remove local credentials",handler:new n,options:[]},{name:"create",description:"Create a new DashNex application",handler:new i,options:[{flags:"-t, --template <template>",description:"Template (name@branch-or-tag)",defaultValue:"webapp-base@live"}]},{name:"pull",description:"Pull existing application to specified folder",handler:new t,options:[]},{name:"push",description:"Push local application to DashNex",handler:new a,options:[]},{name:"delete",description:"Delete application from DashNex",handler:new r,options:[]},{name:"whoami",description:"Show current logged-in business and user",handler:new p,options:[]},{name:"deploy",description:"Deploy application to DashNex",handler:new s,options:[]},{name:"install",description:"Install dependencies using pnpm or npm",handler:new l,options:[]},{name:"dev",description:"Run the development server",handler:new m,options:[]}];export{d as default};
@@ -0,0 +1 @@
1
+ import{spawn as e}from"child_process";import n from"chalk";import{debug as o,debugError as r}from"../lib/debug.js";const s=async n=>new Promise(o=>{const r=e(`${n} --version`,{stdio:"ignore",shell:!0});r.on("error",()=>{o(!1)}),r.on("close",e=>{o(0===e)})});class l{async execute(){o("Install flow started");let l=null,a=null;o("Checking for pnpm availability");const i=await s("pnpm");if(o(`pnpm available: ${i}`),i)l="pnpm",a="pnpm";else{o("pnpm not available, checking for npm");const e=await s("npm");o(`npm available: ${e}`),e&&(l="npm",a="npm")}l&&a||(console.error(n.red("Neither pnpm nor npm is available. Please install pnpm (recommended) or npm to continue.")),process.exit(1)),o(`Using package manager: ${l}`),o(`Executing: ${a} install`);try{const n=await(async n=>new Promise((o,s)=>{const l=e(`${n} install`,{stdio:"inherit",cwd:process.cwd(),shell:!0});l.on("error",e=>{r(e),s(e)}),l.on("close",e=>{o(null===e?0:e)})}))(a);process.exit(n)}catch(t){r(t),t instanceof Error?console.error(n.red(`Failed to run ${a} install: ${t.message}`)):console.error(n.red(`Failed to run ${a} install`)),process.exit(1)}}}export{l as InstallCommand};