@nexical/cli 0.11.3 → 0.11.5
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/chunk-2FKDEDDE.js +39 -0
- package/dist/chunk-2FKDEDDE.js.map +1 -0
- package/dist/chunk-2JW5BYZW.js +24 -0
- package/dist/chunk-2JW5BYZW.js.map +1 -0
- package/dist/chunk-EKCOW7FM.js +118 -0
- package/dist/chunk-EKCOW7FM.js.map +1 -0
- package/dist/index.js +13 -11
- package/dist/index.js.map +1 -1
- package/dist/src/commands/deploy.d.ts +3 -12
- package/dist/src/commands/deploy.js +106 -108
- package/dist/src/commands/deploy.js.map +1 -1
- package/dist/src/commands/init.js +3 -3
- package/dist/src/commands/module/add.js +3 -3
- package/dist/src/deploy/config-manager.d.ts +11 -0
- package/dist/src/deploy/config-manager.js +9 -0
- package/dist/src/deploy/config-manager.js.map +1 -0
- package/dist/src/deploy/providers/cloudflare.d.ts +12 -0
- package/dist/src/deploy/providers/cloudflare.js +113 -0
- package/dist/src/deploy/providers/cloudflare.js.map +1 -0
- package/dist/src/deploy/providers/github.d.ts +10 -0
- package/dist/src/deploy/providers/github.js +121 -0
- package/dist/src/deploy/providers/github.js.map +1 -0
- package/dist/src/deploy/providers/railway.d.ts +12 -0
- package/dist/src/deploy/providers/railway.js +89 -0
- package/dist/src/deploy/providers/railway.js.map +1 -0
- package/dist/src/deploy/registry.d.ts +15 -0
- package/dist/src/deploy/registry.js +9 -0
- package/dist/src/deploy/registry.js.map +1 -0
- package/dist/src/deploy/types.d.ts +47 -0
- package/dist/src/deploy/types.js +8 -0
- package/dist/src/deploy/types.js.map +1 -0
- package/dist/src/deploy/utils.d.ts +6 -0
- package/dist/src/deploy/utils.js +11 -0
- package/dist/src/deploy/utils.js.map +1 -0
- package/package.json +13 -11
- package/src/commands/deploy.ts +128 -144
- package/src/deploy/config-manager.ts +41 -0
- package/src/deploy/providers/cloudflare.ts +143 -0
- package/src/deploy/providers/github.ts +135 -0
- package/src/deploy/providers/railway.ts +103 -0
- package/src/deploy/registry.ts +136 -0
- package/src/deploy/types.ts +63 -0
- package/src/deploy/utils.ts +13 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createRequire } from "module"; const require = createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
init_esm_shims
|
|
4
|
+
} from "./chunk-OYFWMYPG.js";
|
|
5
|
+
|
|
6
|
+
// src/deploy/config-manager.ts
|
|
7
|
+
init_esm_shims();
|
|
8
|
+
import fs from "fs/promises";
|
|
9
|
+
import path from "path";
|
|
10
|
+
import YAML from "yaml";
|
|
11
|
+
var ConfigManager = class {
|
|
12
|
+
configPath;
|
|
13
|
+
constructor(cwd) {
|
|
14
|
+
this.configPath = path.join(cwd, "nexical.yaml");
|
|
15
|
+
}
|
|
16
|
+
async load() {
|
|
17
|
+
try {
|
|
18
|
+
const content = await fs.readFile(this.configPath, "utf-8");
|
|
19
|
+
return YAML.parse(content);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async save(config) {
|
|
28
|
+
const content = YAML.stringify(config);
|
|
29
|
+
await fs.writeFile(this.configPath, content, "utf-8");
|
|
30
|
+
}
|
|
31
|
+
exists() {
|
|
32
|
+
return fs.access(this.configPath).then(() => true).catch(() => false);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
ConfigManager
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=chunk-2FKDEDDE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/deploy/config-manager.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport YAML from 'yaml';\nimport { NexicalConfig } from './types';\n\nexport class ConfigManager {\n private configPath: string;\n\n constructor(cwd: string) {\n this.configPath = path.join(cwd, 'nexical.yaml');\n }\n\n async load(): Promise<NexicalConfig> {\n try {\n const content = await fs.readFile(this.configPath, 'utf-8');\n return YAML.parse(content) as NexicalConfig;\n } catch (error: unknown) {\n if (\n error &&\n typeof error === 'object' &&\n 'code' in error &&\n (error as { code: unknown }).code === 'ENOENT'\n ) {\n return {};\n }\n throw error;\n }\n }\n\n async save(config: NexicalConfig): Promise<void> {\n const content = YAML.stringify(config);\n await fs.writeFile(this.configPath, content, 'utf-8');\n }\n\n exists(): Promise<boolean> {\n return fs\n .access(this.configPath)\n .then(() => true)\n .catch(() => false);\n }\n}\n"],"mappings":";;;;;;AAAA;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,UAAU;AAGV,IAAM,gBAAN,MAAoB;AAAA,EACjB;AAAA,EAER,YAAY,KAAa;AACvB,SAAK,aAAa,KAAK,KAAK,KAAK,cAAc;AAAA,EACjD;AAAA,EAEA,MAAM,OAA+B;AACnC,QAAI;AACF,YAAM,UAAU,MAAM,GAAG,SAAS,KAAK,YAAY,OAAO;AAC1D,aAAO,KAAK,MAAM,OAAO;AAAA,IAC3B,SAAS,OAAgB;AACvB,UACE,SACA,OAAO,UAAU,YACjB,UAAU,SACT,MAA4B,SAAS,UACtC;AACA,eAAO,CAAC;AAAA,MACV;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,QAAsC;AAC/C,UAAM,UAAU,KAAK,UAAU,MAAM;AACrC,UAAM,GAAG,UAAU,KAAK,YAAY,SAAS,OAAO;AAAA,EACtD;AAAA,EAEA,SAA2B;AACzB,WAAO,GACJ,OAAO,KAAK,UAAU,EACtB,KAAK,MAAM,IAAI,EACf,MAAM,MAAM,KAAK;AAAA,EACtB;AACF;","names":[]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createRequire } from "module"; const require = createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
init_esm_shims
|
|
4
|
+
} from "./chunk-OYFWMYPG.js";
|
|
5
|
+
|
|
6
|
+
// src/deploy/utils.ts
|
|
7
|
+
init_esm_shims();
|
|
8
|
+
import { exec } from "child_process";
|
|
9
|
+
import { promisify } from "util";
|
|
10
|
+
var execAsync = promisify(exec);
|
|
11
|
+
async function checkCommand(command) {
|
|
12
|
+
try {
|
|
13
|
+
await execAsync(command);
|
|
14
|
+
return true;
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
execAsync,
|
|
22
|
+
checkCommand
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=chunk-2JW5BYZW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/deploy/utils.ts"],"sourcesContent":["import { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nexport const execAsync = promisify(exec);\n\nexport async function checkCommand(command: string): Promise<boolean> {\n try {\n await execAsync(command);\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":";;;;;;AAAA;AAAA,SAAS,YAAY;AACrB,SAAS,iBAAiB;AAEnB,IAAM,YAAY,UAAU,IAAI;AAEvC,eAAsB,aAAa,SAAmC;AACpE,MAAI;AACF,UAAM,UAAU,OAAO;AACvB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { createRequire } from "module"; const require = createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
init_esm_shims
|
|
4
|
+
} from "./chunk-OYFWMYPG.js";
|
|
5
|
+
|
|
6
|
+
// src/deploy/registry.ts
|
|
7
|
+
init_esm_shims();
|
|
8
|
+
import path from "path";
|
|
9
|
+
import fs from "fs/promises";
|
|
10
|
+
import { logger } from "@nexical/cli-core";
|
|
11
|
+
var ProviderRegistry = class {
|
|
12
|
+
deploymentProviders = /* @__PURE__ */ new Map();
|
|
13
|
+
repositoryProviders = /* @__PURE__ */ new Map();
|
|
14
|
+
registerDeploymentProvider(provider) {
|
|
15
|
+
this.deploymentProviders.set(provider.name, provider);
|
|
16
|
+
}
|
|
17
|
+
registerRepositoryProvider(provider) {
|
|
18
|
+
this.repositoryProviders.set(provider.name, provider);
|
|
19
|
+
}
|
|
20
|
+
getDeploymentProvider(name) {
|
|
21
|
+
return this.deploymentProviders.get(name);
|
|
22
|
+
}
|
|
23
|
+
getRepositoryProvider(name) {
|
|
24
|
+
return this.repositoryProviders.get(name);
|
|
25
|
+
}
|
|
26
|
+
registerProviderFromModule(module, source) {
|
|
27
|
+
const moduleAny = module;
|
|
28
|
+
let provider = moduleAny.default;
|
|
29
|
+
if (!provider && Object.keys(moduleAny).length > 0) {
|
|
30
|
+
for (const key of Object.keys(moduleAny)) {
|
|
31
|
+
if (typeof moduleAny[key] === "function") {
|
|
32
|
+
provider = moduleAny[key];
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (typeof provider === "function") {
|
|
38
|
+
try {
|
|
39
|
+
provider = new provider();
|
|
40
|
+
} catch {
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (provider) {
|
|
44
|
+
if (typeof provider.provision === "function" && typeof provider.getCIConfig === "function") {
|
|
45
|
+
logger.info(`[Registry] Loaded ${source} deployment provider: ${provider.name}`);
|
|
46
|
+
this.registerDeploymentProvider(provider);
|
|
47
|
+
} else if (typeof provider.configureSecrets === "function" && typeof provider.generateWorkflow === "function") {
|
|
48
|
+
logger.info(`[Registry] Loaded ${source} repository provider: ${provider.name}`);
|
|
49
|
+
this.registerRepositoryProvider(provider);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async loadCoreProviders() {
|
|
54
|
+
const dirname = path.dirname(new URL(import.meta.url).pathname);
|
|
55
|
+
const candidates = [
|
|
56
|
+
path.join(dirname, "providers"),
|
|
57
|
+
path.join(dirname, "src/deploy/providers")
|
|
58
|
+
];
|
|
59
|
+
let providersDir = "";
|
|
60
|
+
for (const candidate of candidates) {
|
|
61
|
+
try {
|
|
62
|
+
await fs.access(candidate);
|
|
63
|
+
providersDir = candidate;
|
|
64
|
+
break;
|
|
65
|
+
} catch {
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (!providersDir) {
|
|
69
|
+
logger.warn(
|
|
70
|
+
`[Registry] Could not locate core providers directory. Checked: ${candidates.join(", ")}`
|
|
71
|
+
);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const files = await fs.readdir(providersDir);
|
|
76
|
+
for (const file of files) {
|
|
77
|
+
if (file.endsWith(".js") || file.endsWith(".ts") && !file.endsWith(".d.ts")) {
|
|
78
|
+
try {
|
|
79
|
+
const providerPath = path.join(providersDir, file);
|
|
80
|
+
const module = await import(providerPath);
|
|
81
|
+
this.registerProviderFromModule(module, "core");
|
|
82
|
+
} catch (e) {
|
|
83
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
84
|
+
logger.warn(`Failed to load core provider from ${file}: ${message}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
} catch (e) {
|
|
89
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
90
|
+
logger.warn(`Failed to scan core providers at ${providersDir}: ${message}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async loadLocalProviders(cwd) {
|
|
94
|
+
const deployDir = path.join(cwd, "deploy");
|
|
95
|
+
try {
|
|
96
|
+
const files = await fs.readdir(deployDir);
|
|
97
|
+
for (const file of files) {
|
|
98
|
+
if (file.endsWith(".ts") || file.endsWith(".js")) {
|
|
99
|
+
try {
|
|
100
|
+
const providerPath = path.join(deployDir, file);
|
|
101
|
+
const jiti = (await import("jiti")).createJiti(import.meta.url);
|
|
102
|
+
const module = await jiti.import(providerPath);
|
|
103
|
+
this.registerProviderFromModule(module, "local");
|
|
104
|
+
} catch (e) {
|
|
105
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
106
|
+
logger.warn(`Failed to load local provider from ${file}: ${message}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} catch {
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export {
|
|
116
|
+
ProviderRegistry
|
|
117
|
+
};
|
|
118
|
+
//# sourceMappingURL=chunk-EKCOW7FM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/deploy/registry.ts"],"sourcesContent":["import path from 'node:path';\nimport fs from 'node:fs/promises';\nimport { logger } from '@nexical/cli-core';\nimport { DeploymentProvider, RepositoryProvider } from './types';\n\nexport class ProviderRegistry {\n private deploymentProviders: Map<string, DeploymentProvider> = new Map();\n private repositoryProviders: Map<string, RepositoryProvider> = new Map();\n\n registerDeploymentProvider(provider: DeploymentProvider) {\n this.deploymentProviders.set(provider.name, provider);\n }\n\n registerRepositoryProvider(provider: RepositoryProvider) {\n this.repositoryProviders.set(provider.name, provider);\n }\n\n getDeploymentProvider(name: string): DeploymentProvider | undefined {\n return this.deploymentProviders.get(name);\n }\n\n getRepositoryProvider(name: string): RepositoryProvider | undefined {\n return this.repositoryProviders.get(name);\n }\n\n private registerProviderFromModule(module: unknown, source: string) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const moduleAny = module as any;\n let provider = moduleAny.default;\n\n // Handle named exports if default is missing (fallback)\n if (!provider && Object.keys(moduleAny).length > 0) {\n // Try to find a class export that looks like a provider\n for (const key of Object.keys(moduleAny)) {\n if (typeof moduleAny[key] === 'function') {\n provider = moduleAny[key];\n break;\n }\n }\n }\n\n // If it's a class, instantiate it\n if (typeof provider === 'function') {\n try {\n provider = new provider();\n } catch {\n // Not a constructor or failed\n }\n }\n\n if (provider) {\n if (typeof provider.provision === 'function' && typeof provider.getCIConfig === 'function') {\n logger.info(`[Registry] Loaded ${source} deployment provider: ${provider.name}`);\n this.registerDeploymentProvider(provider as DeploymentProvider);\n } else if (\n typeof provider.configureSecrets === 'function' &&\n typeof provider.generateWorkflow === 'function'\n ) {\n logger.info(`[Registry] Loaded ${source} repository provider: ${provider.name}`);\n this.registerRepositoryProvider(provider as RepositoryProvider);\n }\n }\n }\n\n async loadCoreProviders() {\n const dirname = path.dirname(new URL(import.meta.url).pathname);\n\n // Try multiple paths to find the providers directory\n // 1. 'providers' - Standard source structure / flattened dist\n // 2. 'src/deploy/providers' - tsup output (chunk in root, files in src/...)\n const candidates = [\n path.join(dirname, 'providers'),\n path.join(dirname, 'src/deploy/providers'),\n ];\n\n let providersDir = '';\n for (const candidate of candidates) {\n try {\n await fs.access(candidate);\n providersDir = candidate;\n break;\n } catch {\n // Ignore missing dir\n }\n }\n\n if (!providersDir) {\n logger.warn(\n `[Registry] Could not locate core providers directory. Checked: ${candidates.join(', ')}`,\n );\n return;\n }\n\n try {\n const files = await fs.readdir(providersDir);\n for (const file of files) {\n if (file.endsWith('.js') || (file.endsWith('.ts') && !file.endsWith('.d.ts'))) {\n try {\n const providerPath = path.join(providersDir, file);\n const module = await import(providerPath);\n this.registerProviderFromModule(module, 'core');\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n logger.warn(`Failed to load core provider from ${file}: ${message}`);\n }\n }\n }\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n logger.warn(`Failed to scan core providers at ${providersDir}: ${message}`);\n }\n }\n\n async loadLocalProviders(cwd: string) {\n const deployDir = path.join(cwd, 'deploy');\n try {\n const files = await fs.readdir(deployDir);\n for (const file of files) {\n if (file.endsWith('.ts') || file.endsWith('.js')) {\n try {\n const providerPath = path.join(deployDir, file);\n // Use jiti to load TS/JS files dynamically\n const jiti = (await import('jiti')).createJiti(import.meta.url);\n const module = (await jiti.import(providerPath)) as unknown;\n this.registerProviderFromModule(module, 'local');\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n logger.warn(`Failed to load local provider from ${file}: ${message}`);\n }\n }\n }\n } catch {\n // Ignore if deploy dir doesn't exist\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import { fileURLToPath } from "url";
|
|
|
15
15
|
// package.json
|
|
16
16
|
var package_default = {
|
|
17
17
|
name: "@nexical/cli",
|
|
18
|
-
version: "0.11.
|
|
18
|
+
version: "0.11.5",
|
|
19
19
|
type: "module",
|
|
20
20
|
bin: {
|
|
21
21
|
nexical: "./dist/index.js"
|
|
@@ -44,31 +44,33 @@ var package_default = {
|
|
|
44
44
|
},
|
|
45
45
|
dependencies: {
|
|
46
46
|
"@nexical/cli-core": "^0.1.12",
|
|
47
|
-
|
|
48
|
-
"fast-glob": "^3.3.3"
|
|
47
|
+
dotenv: "^17.3.1",
|
|
48
|
+
"fast-glob": "^3.3.3",
|
|
49
|
+
jiti: "^2.6.1",
|
|
50
|
+
yaml: "^2.3.4"
|
|
49
51
|
},
|
|
50
52
|
devDependencies: {
|
|
53
|
+
"@eslint/js": "^9.39.2",
|
|
51
54
|
"@types/fs-extra": "^11.0.4",
|
|
52
55
|
"@types/node": "^20.10.0",
|
|
53
56
|
"@vitest/coverage-v8": "^4.0.15",
|
|
54
|
-
execa: "^9.6.1",
|
|
55
|
-
"fs-extra": "^11.3.2",
|
|
56
|
-
tsup: "^8.0.1",
|
|
57
|
-
tsx: "^4.21.0",
|
|
58
|
-
typescript: "^5.3.3",
|
|
59
|
-
vitest: "^4.0.15",
|
|
60
|
-
"@eslint/js": "^9.39.2",
|
|
61
57
|
eslint: "^9.39.2",
|
|
62
58
|
"eslint-config-prettier": "^10.1.8",
|
|
63
59
|
"eslint-plugin-astro": "^1.5.0",
|
|
64
60
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
65
61
|
"eslint-plugin-react": "^7.37.5",
|
|
66
62
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
63
|
+
execa: "^9.6.1",
|
|
64
|
+
"fs-extra": "^11.3.2",
|
|
67
65
|
globals: "^17.2.0",
|
|
68
66
|
husky: "^9.1.7",
|
|
69
67
|
"lint-staged": "^16.2.7",
|
|
70
68
|
prettier: "^3.8.1",
|
|
71
|
-
|
|
69
|
+
tsup: "^8.0.1",
|
|
70
|
+
tsx: "^4.21.0",
|
|
71
|
+
typescript: "^5.3.3",
|
|
72
|
+
"typescript-eslint": "^8.54.0",
|
|
73
|
+
vitest: "^4.0.15"
|
|
72
74
|
}
|
|
73
75
|
};
|
|
74
76
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../index.ts","../package.json"],"sourcesContent":["#!/usr/bin/env node\nimport { CLI, findProjectRoot } from '@nexical/cli-core';\nimport { fileURLToPath } from 'node:url';\nimport { discoverCommandDirectories } from './src/utils/discovery.js';\nimport pkg from './package.json';\nimport path from 'node:path';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nconst commandName = 'nexical';\nconst projectRoot = (await findProjectRoot(commandName, process.cwd())) || process.cwd();\nconst coreCommandsDir = path.resolve(__dirname, './src/commands');\nconst additionalCommands = discoverCommandDirectories(projectRoot);\n\n// Filter out duplicate core commands and source versions\nconst filteredAdditional = additionalCommands.filter((dir) => {\n const resolvedDir = path.resolve(dir);\n const resolvedCore = path.resolve(coreCommandsDir);\n\n if (resolvedDir === resolvedCore) return false;\n\n // Check if this is another instance of the core CLI commands (by checking path suffix)\n const coreSuffix = path.join('@nexical', 'cli', 'dist', 'src', 'commands');\n const coreSuffixSrc = path.join('packages', 'cli', 'dist', 'src', 'commands');\n const coreSuffixRawSrc = path.join('packages', 'cli', 'src', 'commands');\n\n if (\n resolvedDir.endsWith(coreSuffix) ||\n resolvedDir.endsWith(coreSuffixSrc) ||\n resolvedDir.endsWith(coreSuffixRawSrc)\n ) {\n return false;\n }\n\n // Handle mismatch between dist/src and src/\n if (resolvedCore.includes(path.join(path.sep, 'dist', 'src', 'commands'))) {\n const srcVersion = resolvedCore.replace(\n path.join(path.sep, 'dist', 'src', 'commands'),\n path.join(path.sep, 'src', 'commands'),\n );\n if (resolvedDir === srcVersion) return false;\n }\n\n return true;\n});\n\nconst app = new CLI({\n version: pkg.version,\n commandName: commandName,\n searchDirectories: [...new Set([coreCommandsDir, ...filteredAdditional])],\n});\napp.start();\n","{\n \"name\": \"@nexical/cli\",\n \"version\": \"0.11.
|
|
1
|
+
{"version":3,"sources":["../index.ts","../package.json"],"sourcesContent":["#!/usr/bin/env node\nimport { CLI, findProjectRoot } from '@nexical/cli-core';\nimport { fileURLToPath } from 'node:url';\nimport { discoverCommandDirectories } from './src/utils/discovery.js';\nimport pkg from './package.json';\nimport path from 'node:path';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nconst commandName = 'nexical';\nconst projectRoot = (await findProjectRoot(commandName, process.cwd())) || process.cwd();\nconst coreCommandsDir = path.resolve(__dirname, './src/commands');\nconst additionalCommands = discoverCommandDirectories(projectRoot);\n\n// Filter out duplicate core commands and source versions\nconst filteredAdditional = additionalCommands.filter((dir) => {\n const resolvedDir = path.resolve(dir);\n const resolvedCore = path.resolve(coreCommandsDir);\n\n if (resolvedDir === resolvedCore) return false;\n\n // Check if this is another instance of the core CLI commands (by checking path suffix)\n const coreSuffix = path.join('@nexical', 'cli', 'dist', 'src', 'commands');\n const coreSuffixSrc = path.join('packages', 'cli', 'dist', 'src', 'commands');\n const coreSuffixRawSrc = path.join('packages', 'cli', 'src', 'commands');\n\n if (\n resolvedDir.endsWith(coreSuffix) ||\n resolvedDir.endsWith(coreSuffixSrc) ||\n resolvedDir.endsWith(coreSuffixRawSrc)\n ) {\n return false;\n }\n\n // Handle mismatch between dist/src and src/\n if (resolvedCore.includes(path.join(path.sep, 'dist', 'src', 'commands'))) {\n const srcVersion = resolvedCore.replace(\n path.join(path.sep, 'dist', 'src', 'commands'),\n path.join(path.sep, 'src', 'commands'),\n );\n if (resolvedDir === srcVersion) return false;\n }\n\n return true;\n});\n\nconst app = new CLI({\n version: pkg.version,\n commandName: commandName,\n searchDirectories: [...new Set([coreCommandsDir, ...filteredAdditional])],\n});\napp.start();\n","{\n \"name\": \"@nexical/cli\",\n \"version\": \"0.11.5\",\n \"type\": \"module\",\n \"bin\": {\n \"nexical\": \"./dist/index.js\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"start\": \"node dist/index.js\",\n \"test\": \"npm run test:unit && npm run test:integration && npm run test:e2e\",\n \"test:unit\": \"vitest run --config vitest.config.ts --coverage\",\n \"test:integration\": \"vitest run --config vitest.integration.config.ts\",\n \"test:e2e\": \"npm run build && vitest run --config vitest.e2e.config.ts\",\n \"test:watch\": \"vitest\",\n \"format\": \"prettier --write .\",\n \"lint\": \"eslint .\",\n \"lint:fix\": \"eslint . --fix\",\n \"prepare\": \"husky\"\n },\n \"lint-staged\": {\n \"**/*\": [\n \"prettier --write --ignore-unknown\"\n ],\n \"**/*.{js,jsx,ts,tsx,astro}\": [\n \"eslint --fix\"\n ]\n },\n \"dependencies\": {\n \"@nexical/cli-core\": \"^0.1.12\",\n \"dotenv\": \"^17.3.1\",\n \"fast-glob\": \"^3.3.3\",\n \"jiti\": \"^2.6.1\",\n \"yaml\": \"^2.3.4\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.2\",\n \"@types/fs-extra\": \"^11.0.4\",\n \"@types/node\": \"^20.10.0\",\n \"@vitest/coverage-v8\": \"^4.0.15\",\n \"eslint\": \"^9.39.2\",\n \"eslint-config-prettier\": \"^10.1.8\",\n \"eslint-plugin-astro\": \"^1.5.0\",\n \"eslint-plugin-jsx-a11y\": \"^6.10.2\",\n \"eslint-plugin-react\": \"^7.37.5\",\n \"eslint-plugin-react-hooks\": \"^7.0.1\",\n \"execa\": \"^9.6.1\",\n \"fs-extra\": \"^11.3.2\",\n \"globals\": \"^17.2.0\",\n \"husky\": \"^9.1.7\",\n \"lint-staged\": \"^16.2.7\",\n \"prettier\": \"^3.8.1\",\n \"tsup\": \"^8.0.1\",\n \"tsx\": \"^4.21.0\",\n \"typescript\": \"^5.3.3\",\n \"typescript-eslint\": \"^8.54.0\",\n \"vitest\": \"^4.0.15\"\n }\n}\n"],"mappings":";;;;;;;;;;AAAA;AACA,SAAS,KAAK,uBAAuB;AACrC,SAAS,qBAAqB;;;ACF9B;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,MAAQ;AAAA,EACR,KAAO;AAAA,IACL,SAAW;AAAA,EACb;AAAA,EACA,SAAW;AAAA,IACT,OAAS;AAAA,IACT,KAAO;AAAA,IACP,OAAS;AAAA,IACT,MAAQ;AAAA,IACR,aAAa;AAAA,IACb,oBAAoB;AAAA,IACpB,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,QAAU;AAAA,IACV,MAAQ;AAAA,IACR,YAAY;AAAA,IACZ,SAAW;AAAA,EACb;AAAA,EACA,eAAe;AAAA,IACb,QAAQ;AAAA,MACN;AAAA,IACF;AAAA,IACA,8BAA8B;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAAA,EACA,cAAgB;AAAA,IACd,qBAAqB;AAAA,IACrB,QAAU;AAAA,IACV,aAAa;AAAA,IACb,MAAQ;AAAA,IACR,MAAQ;AAAA,EACV;AAAA,EACA,iBAAmB;AAAA,IACjB,cAAc;AAAA,IACd,mBAAmB;AAAA,IACnB,eAAe;AAAA,IACf,uBAAuB;AAAA,IACvB,QAAU;AAAA,IACV,0BAA0B;AAAA,IAC1B,uBAAuB;AAAA,IACvB,0BAA0B;AAAA,IAC1B,uBAAuB;AAAA,IACvB,6BAA6B;AAAA,IAC7B,OAAS;AAAA,IACT,YAAY;AAAA,IACZ,SAAW;AAAA,IACX,OAAS;AAAA,IACT,eAAe;AAAA,IACf,UAAY;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,IACP,YAAc;AAAA,IACd,qBAAqB;AAAA,IACrB,QAAU;AAAA,EACZ;AACF;;;ADtDA,OAAO,UAAU;AAEjB,IAAM,YAAY,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAE7D,IAAM,cAAc;AACpB,IAAM,cAAe,MAAM,gBAAgB,aAAa,QAAQ,IAAI,CAAC,KAAM,QAAQ,IAAI;AACvF,IAAM,kBAAkB,KAAK,QAAQ,WAAW,gBAAgB;AAChE,IAAM,qBAAqB,2BAA2B,WAAW;AAGjE,IAAM,qBAAqB,mBAAmB,OAAO,CAAC,QAAQ;AAC5D,QAAM,cAAc,KAAK,QAAQ,GAAG;AACpC,QAAM,eAAe,KAAK,QAAQ,eAAe;AAEjD,MAAI,gBAAgB,aAAc,QAAO;AAGzC,QAAM,aAAa,KAAK,KAAK,YAAY,OAAO,QAAQ,OAAO,UAAU;AACzE,QAAM,gBAAgB,KAAK,KAAK,YAAY,OAAO,QAAQ,OAAO,UAAU;AAC5E,QAAM,mBAAmB,KAAK,KAAK,YAAY,OAAO,OAAO,UAAU;AAEvE,MACE,YAAY,SAAS,UAAU,KAC/B,YAAY,SAAS,aAAa,KAClC,YAAY,SAAS,gBAAgB,GACrC;AACA,WAAO;AAAA,EACT;AAGA,MAAI,aAAa,SAAS,KAAK,KAAK,KAAK,KAAK,QAAQ,OAAO,UAAU,CAAC,GAAG;AACzE,UAAM,aAAa,aAAa;AAAA,MAC9B,KAAK,KAAK,KAAK,KAAK,QAAQ,OAAO,UAAU;AAAA,MAC7C,KAAK,KAAK,KAAK,KAAK,OAAO,UAAU;AAAA,IACvC;AACA,QAAI,gBAAgB,WAAY,QAAO;AAAA,EACzC;AAEA,SAAO;AACT,CAAC;AAED,IAAM,MAAM,IAAI,IAAI;AAAA,EAClB,SAAS,gBAAI;AAAA,EACb;AAAA,EACA,mBAAmB,CAAC,GAAG,oBAAI,IAAI,CAAC,iBAAiB,GAAG,kBAAkB,CAAC,CAAC;AAC1E,CAAC;AACD,IAAI,MAAM;","names":[]}
|
|
@@ -1,28 +1,19 @@
|
|
|
1
1
|
import { BaseCommand } from '@nexical/cli-core';
|
|
2
2
|
|
|
3
|
-
interface DeployOptions {
|
|
4
|
-
dryRun: boolean;
|
|
5
|
-
railwayToken?: string;
|
|
6
|
-
cloudflareToken?: string;
|
|
7
|
-
cloudflareAccount?: string;
|
|
8
|
-
}
|
|
9
3
|
declare class DeployCommand extends BaseCommand {
|
|
10
4
|
static description: string;
|
|
11
5
|
static args: {
|
|
12
6
|
options: ({
|
|
13
7
|
name: string;
|
|
14
8
|
description: string;
|
|
15
|
-
default
|
|
9
|
+
default?: undefined;
|
|
16
10
|
} | {
|
|
17
11
|
name: string;
|
|
18
12
|
description: string;
|
|
19
|
-
default
|
|
13
|
+
default: boolean;
|
|
20
14
|
})[];
|
|
21
15
|
};
|
|
22
|
-
run(options:
|
|
23
|
-
private setupRailway;
|
|
24
|
-
private setupCloudflare;
|
|
25
|
-
private setupGitHubSecrets;
|
|
16
|
+
run(options: Record<string, unknown>): Promise<void>;
|
|
26
17
|
}
|
|
27
18
|
|
|
28
19
|
export { DeployCommand as default };
|
|
@@ -1,145 +1,143 @@
|
|
|
1
1
|
import { createRequire } from "module"; const require = createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
ConfigManager
|
|
4
|
+
} from "../../chunk-2FKDEDDE.js";
|
|
5
|
+
import {
|
|
6
|
+
ProviderRegistry
|
|
7
|
+
} from "../../chunk-EKCOW7FM.js";
|
|
2
8
|
import {
|
|
3
9
|
init_esm_shims
|
|
4
10
|
} from "../../chunk-OYFWMYPG.js";
|
|
5
11
|
|
|
6
12
|
// src/commands/deploy.ts
|
|
7
13
|
init_esm_shims();
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
var execAsync = promisify(exec);
|
|
14
|
+
import path from "path";
|
|
15
|
+
import dotenv from "dotenv";
|
|
16
|
+
import { BaseCommand } from "@nexical/cli-core";
|
|
12
17
|
var DeployCommand = class extends BaseCommand {
|
|
13
|
-
static description =
|
|
18
|
+
static description = `Deploy the application based on nexical.yaml configuration.
|
|
19
|
+
|
|
20
|
+
This command orchestrates the deployment of your frontend and backend applications
|
|
21
|
+
by interacting with the providers specified in your configuration file.
|
|
22
|
+
|
|
23
|
+
CONFIGURATION:
|
|
24
|
+
- Requires a 'nexical.yaml' file in the project root.
|
|
25
|
+
- If the file or specific sections are missing, the CLI will prompt you to run an interactive setup
|
|
26
|
+
and save the configuration for future uses.
|
|
27
|
+
- Supports loading environment variables from a .env file in the project root.
|
|
28
|
+
|
|
29
|
+
PROVIDERS:
|
|
30
|
+
- Backend: Railway, etc.
|
|
31
|
+
- Frontend: Cloudflare Pages, etc.
|
|
32
|
+
- Repository: GitHub, GitLab, etc.
|
|
33
|
+
|
|
34
|
+
PROCESS:
|
|
35
|
+
1. Loads environment variables from '.env'.
|
|
36
|
+
2. Loads configuration from 'nexical.yaml'.
|
|
37
|
+
3. Provisions resources via the selected providers.
|
|
38
|
+
4. Configures the repository (secrets/variables) for CI/CD.
|
|
39
|
+
5. Generates CI/CD workflow files.`;
|
|
14
40
|
static args = {
|
|
15
41
|
options: [
|
|
16
42
|
{
|
|
17
|
-
name: "--
|
|
18
|
-
description: "
|
|
19
|
-
default: false
|
|
43
|
+
name: "--backend <provider>",
|
|
44
|
+
description: "Override backend provider"
|
|
20
45
|
},
|
|
21
46
|
{
|
|
22
|
-
name: "--
|
|
23
|
-
description: "
|
|
47
|
+
name: "--frontend <provider>",
|
|
48
|
+
description: "Override frontend provider"
|
|
24
49
|
},
|
|
25
50
|
{
|
|
26
|
-
name: "--
|
|
27
|
-
description: "
|
|
51
|
+
name: "--repo <provider>",
|
|
52
|
+
description: "Override repositroy provider"
|
|
28
53
|
},
|
|
29
54
|
{
|
|
30
|
-
name: "--
|
|
31
|
-
description: "
|
|
55
|
+
name: "--dry-run",
|
|
56
|
+
description: "Simulate the deployment process",
|
|
57
|
+
default: false
|
|
32
58
|
}
|
|
33
59
|
]
|
|
34
60
|
};
|
|
35
61
|
async run(options) {
|
|
36
|
-
this.info("Starting Nexical Deployment
|
|
37
|
-
|
|
38
|
-
|
|
62
|
+
this.info("Starting Nexical Deployment...");
|
|
63
|
+
dotenv.config({ path: path.join(process.cwd(), ".env") });
|
|
64
|
+
const configManager = new ConfigManager(process.cwd());
|
|
65
|
+
const config = await configManager.load();
|
|
66
|
+
const registry = new ProviderRegistry();
|
|
67
|
+
await registry.loadCoreProviders();
|
|
68
|
+
await registry.loadLocalProviders(process.cwd());
|
|
69
|
+
const backendProviderName = options.backend || config.deploy?.backend?.provider;
|
|
70
|
+
if (!backendProviderName) {
|
|
71
|
+
this.error(
|
|
72
|
+
"Backend provider not specified. Use --backend flag or configure 'deploy.backend.provider' in nexical.yaml."
|
|
73
|
+
);
|
|
39
74
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
} catch (error) {
|
|
46
|
-
if (error instanceof Error) {
|
|
47
|
-
this.error(`Deployment failed: ${error.message}`);
|
|
48
|
-
} else {
|
|
49
|
-
this.error(`Deployment failed: ${String(error)}`);
|
|
50
|
-
}
|
|
51
|
-
process.exit(1);
|
|
75
|
+
const frontendProviderName = options.frontend || config.deploy?.frontend?.provider;
|
|
76
|
+
if (!frontendProviderName) {
|
|
77
|
+
this.error(
|
|
78
|
+
"Frontend provider not specified. Use --frontend flag or configure 'deploy.frontend.provider' in nexical.yaml."
|
|
79
|
+
);
|
|
52
80
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
this.info("[Dry Run] Would run: railway add --database postgres");
|
|
59
|
-
return;
|
|
81
|
+
const repoProviderName = options.repo || config.deploy?.repository?.provider;
|
|
82
|
+
if (!repoProviderName) {
|
|
83
|
+
this.error(
|
|
84
|
+
"Repository provider not specified. Use --repo flag or configure 'deploy.repository.provider' in nexical.yaml."
|
|
85
|
+
);
|
|
60
86
|
}
|
|
87
|
+
const backendProvider = registry.getDeploymentProvider(backendProviderName);
|
|
88
|
+
const frontendProvider = registry.getDeploymentProvider(frontendProviderName);
|
|
89
|
+
const repoProvider = registry.getRepositoryProvider(repoProviderName);
|
|
90
|
+
if (!backendProvider) throw new Error(`Backend provider '${backendProviderName}' not found.`);
|
|
91
|
+
if (!frontendProvider)
|
|
92
|
+
throw new Error(`Frontend provider '${frontendProviderName}' not found.`);
|
|
93
|
+
if (!repoProvider) throw new Error(`Repository provider '${repoProviderName}' not found.`);
|
|
94
|
+
const context = {
|
|
95
|
+
cwd: process.cwd(),
|
|
96
|
+
config,
|
|
97
|
+
options
|
|
98
|
+
};
|
|
99
|
+
this.info(`Provisioning Backend with ${backendProvider.name}...`);
|
|
100
|
+
await backendProvider.provision(context);
|
|
101
|
+
this.info(`Provisioning Frontend with ${frontendProvider.name}...`);
|
|
102
|
+
await frontendProvider.provision(context);
|
|
103
|
+
this.info(`Configuring Repository with ${repoProvider.name}...`);
|
|
104
|
+
const secrets = {};
|
|
105
|
+
this.info(`Resolving secrets from ${backendProvider.name}...`);
|
|
61
106
|
try {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
process.env.RAILWAY_TOKEN = options.railwayToken;
|
|
65
|
-
}
|
|
66
|
-
try {
|
|
67
|
-
await runCommand("railway status");
|
|
68
|
-
} catch {
|
|
69
|
-
this.info("No Railway project detected. Initializing...");
|
|
70
|
-
await runCommand("railway init");
|
|
71
|
-
}
|
|
72
|
-
this.info("Adding PostgreSQL service if missing...");
|
|
73
|
-
const { stdout: status } = await execAsync("railway status");
|
|
74
|
-
if (!status.includes("postgres")) {
|
|
75
|
-
await runCommand("railway add --database postgres");
|
|
76
|
-
}
|
|
107
|
+
const backendSecrets = await backendProvider.getSecrets(context);
|
|
108
|
+
Object.assign(secrets, backendSecrets);
|
|
77
109
|
} catch (e) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
);
|
|
81
|
-
throw e;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
async setupCloudflare(options) {
|
|
85
|
-
this.info("Configuring Cloudflare Pages...");
|
|
86
|
-
if (options.dryRun) {
|
|
87
|
-
this.info("[Dry Run] Would run: wrangler pages project create nexical-frontend");
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
if (!options.cloudflareToken || !options.cloudflareAccount) {
|
|
91
|
-
this.warn("Cloudflare credentials missing. Skipping automated Cloudflare setup.");
|
|
92
|
-
this.info("You can manually set up Cloudflare Pages and add the secrets to GitHub.");
|
|
93
|
-
return;
|
|
110
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
111
|
+
this.error(`Failed to resolve secrets for ${backendProvider.name}: ${message}`);
|
|
94
112
|
}
|
|
113
|
+
this.info(`Resolving secrets from ${frontendProvider.name}...`);
|
|
95
114
|
try {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
await execAsync(`wrangler pages project create ${projectName} --production-branch main`, {
|
|
100
|
-
env: {
|
|
101
|
-
...process.env,
|
|
102
|
-
CLOUDFLARE_API_TOKEN: options.cloudflareToken,
|
|
103
|
-
CLOUDFLARE_ACCOUNT_ID: options.cloudflareAccount
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
} catch {
|
|
107
|
-
this.info("Cloudflare project might already exist.");
|
|
108
|
-
}
|
|
115
|
+
const frontendSecrets = await frontendProvider.getSecrets(context);
|
|
116
|
+
Object.assign(secrets, frontendSecrets);
|
|
109
117
|
} catch (e) {
|
|
110
|
-
|
|
111
|
-
|
|
118
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
119
|
+
this.error(`Failed to resolve secrets for ${frontendProvider.name}: ${message}`);
|
|
112
120
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
await repoProvider.configureSecrets(context, secrets);
|
|
122
|
+
const variables = {};
|
|
123
|
+
try {
|
|
124
|
+
const backendVars = await backendProvider.getVariables(context);
|
|
125
|
+
Object.assign(variables, backendVars);
|
|
126
|
+
} catch (e) {
|
|
127
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
128
|
+
this.error(`Failed to resolve variables for ${backendProvider.name}: ${message}`);
|
|
121
129
|
}
|
|
122
130
|
try {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
await runCommand(`gh secret set RAILWAY_TOKEN --body "${options.railwayToken}"`);
|
|
126
|
-
}
|
|
127
|
-
if (options.cloudflareToken) {
|
|
128
|
-
this.info("Setting CLOUDFLARE_API_TOKEN in GitHub...");
|
|
129
|
-
await runCommand(`gh secret set CLOUDFLARE_API_TOKEN --body "${options.cloudflareToken}"`);
|
|
130
|
-
}
|
|
131
|
-
if (options.cloudflareAccount) {
|
|
132
|
-
this.info("Setting CLOUDFLARE_ACCOUNT_ID in GitHub...");
|
|
133
|
-
await runCommand(
|
|
134
|
-
`gh secret set CLOUDFLARE_ACCOUNT_ID --body "${options.cloudflareAccount}"`
|
|
135
|
-
);
|
|
136
|
-
}
|
|
131
|
+
const frontendVars = await frontendProvider.getVariables(context);
|
|
132
|
+
Object.assign(variables, frontendVars);
|
|
137
133
|
} catch (e) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
);
|
|
141
|
-
throw e;
|
|
134
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
135
|
+
this.error(`Failed to resolve variables for ${frontendProvider.name}: ${message}`);
|
|
142
136
|
}
|
|
137
|
+
await repoProvider.configureVariables(context, variables);
|
|
138
|
+
this.info("Generating CI/CD Workflows...");
|
|
139
|
+
await repoProvider.generateWorkflow(context, [backendProvider, frontendProvider]);
|
|
140
|
+
this.success("Deployment configuration complete!");
|
|
143
141
|
}
|
|
144
142
|
};
|
|
145
143
|
export {
|