@codemoreira/esad 1.4.6-9 → 2.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -96
- package/bin/esad.js +88 -114
- package/package.json +13 -13
- package/src/cli/commands/build.js +20 -25
- package/src/cli/commands/createCdn.js +44 -45
- package/src/cli/commands/createModule.js +5 -2
- package/src/cli/commands/deploy.js +80 -118
- package/src/cli/commands/dev.js +43 -103
- package/src/cli/commands/host.js +15 -18
- package/src/cli/commands/init.js +33 -14
- package/src/cli/utils/config.js +40 -37
- package/src/cli/utils/process.js +66 -21
- package/src/cli/utils/scaffold.js +96 -112
- package/src/cli/utils/transformer.js +44 -0
- package/src/client/index.js +69 -82
- package/src/plugin/index.js +70 -37
- package/src/plugin/config-plugin.js +0 -45
|
@@ -1,118 +1,80 @@
|
|
|
1
|
-
const fs = require('fs-extra');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const AdmZip = require('adm-zip');
|
|
4
|
-
const chalk = require('chalk');
|
|
5
|
-
const { getWorkspaceConfig
|
|
6
|
-
const { resolveModuleMetadata
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
console.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const zipPath = path.join(cwd, `bundle-${moduleId}-${version}.zip`);
|
|
82
|
-
zip.writeZip(zipPath);
|
|
83
|
-
console.log(`🗜️ Zipped output to ${zipPath}`);
|
|
84
|
-
|
|
85
|
-
console.log(`🚀 Uploading to CDN via multipart POST...`);
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
const FormData = require('form-data'); // Standard in Node versions, or use native if available
|
|
89
|
-
const form = new FormData();
|
|
90
|
-
form.append('version', version);
|
|
91
|
-
form.append('bundle', fs.createReadStream(zipPath));
|
|
92
|
-
|
|
93
|
-
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
|
|
94
|
-
|
|
95
|
-
// Simple CDN expects POST /api/admin/assets/:id/versions
|
|
96
|
-
const uploadUrl = deployUrl.includes('/versions') ? deployUrl : `${deployUrl}/versions`;
|
|
97
|
-
|
|
98
|
-
const response = await fetch(uploadUrl, {
|
|
99
|
-
method: 'POST',
|
|
100
|
-
body: form,
|
|
101
|
-
headers: form.getHeaders(),
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
if (response.ok) {
|
|
105
|
-
const result = await response.json();
|
|
106
|
-
console.log(chalk.green(`✅ Successfully uploaded ${moduleId} v${version} to CDN!`));
|
|
107
|
-
console.log(`📄 Active Version is now: ${result.active_version}`);
|
|
108
|
-
} else {
|
|
109
|
-
const errorText = await response.text();
|
|
110
|
-
console.error(chalk.red(`❌ Failed to upload: ${response.status} ${response.statusText}`));
|
|
111
|
-
console.error(errorText);
|
|
112
|
-
}
|
|
113
|
-
} catch (err) {
|
|
114
|
-
console.error(chalk.red(`❌ Error during upload: ${err.message}`));
|
|
115
|
-
} finally {
|
|
116
|
-
fs.unlinkSync(zipPath);
|
|
117
|
-
}
|
|
118
|
-
};
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const AdmZip = require('adm-zip');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const { getWorkspaceConfig } = require('../utils/config');
|
|
6
|
+
const { resolveModuleMetadata } = require('../utils/resolution');
|
|
7
|
+
|
|
8
|
+
module.exports = async (options) => {
|
|
9
|
+
const configObj = getWorkspaceConfig();
|
|
10
|
+
if (!configObj) {
|
|
11
|
+
console.error(chalk.red(`❌ Error: esad.config.js not found in this or parent directories.`));
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const config = await configObj.load();
|
|
16
|
+
const workspaceRoot = configObj.root;
|
|
17
|
+
const projectName = config.default?.projectName || config.projectName;
|
|
18
|
+
|
|
19
|
+
let moduleId = options.id;
|
|
20
|
+
let cwd = process.cwd();
|
|
21
|
+
|
|
22
|
+
// Resolve Context
|
|
23
|
+
if (moduleId) {
|
|
24
|
+
const meta = resolveModuleMetadata(moduleId, configObj);
|
|
25
|
+
if (!meta) {
|
|
26
|
+
console.error(chalk.red(`❌ Error: Module not found: ${moduleId}`));
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
cwd = meta.path;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
33
|
+
if (!fs.existsSync(pkgPath)) {
|
|
34
|
+
console.error(chalk.red(`❌ Error: package.json not found in ${cwd}.`));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const pkg = fs.readJsonSync(pkgPath);
|
|
39
|
+
const resolvedModuleId = moduleId || pkg.name;
|
|
40
|
+
const version = options.version || pkg.version;
|
|
41
|
+
|
|
42
|
+
console.log(`\n🚀 Starting ESAD Deploy for ${chalk.cyan(resolvedModuleId)} (v${version})\n`);
|
|
43
|
+
|
|
44
|
+
const distPath = path.join(cwd, 'build');
|
|
45
|
+
if (!fs.existsSync(distPath)) {
|
|
46
|
+
console.error(chalk.red(`❌ Error: build/ directory not found. Please run 'esad build' first.`));
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ZIP BUNDLE
|
|
51
|
+
const zip = new AdmZip();
|
|
52
|
+
zip.addLocalFolder(distPath);
|
|
53
|
+
const buffer = zip.toBuffer();
|
|
54
|
+
|
|
55
|
+
console.log(`🗜️ Generated bundle zip (${(buffer.length / 1024).toFixed(2)} KB)`);
|
|
56
|
+
|
|
57
|
+
// RUN DEPLOY HOOK
|
|
58
|
+
const deployHook = config.default?.deploy || config.deploy;
|
|
59
|
+
|
|
60
|
+
if (typeof deployHook !== 'function') {
|
|
61
|
+
console.error(chalk.red(`❌ Error: 'deploy' function not found in esad.config.js.`));
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
console.log(`📡 Invoking custom 'deploy' hook...`);
|
|
67
|
+
const result = await deployHook(buffer, {
|
|
68
|
+
version,
|
|
69
|
+
moduleId: resolvedModuleId,
|
|
70
|
+
options
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
console.log(chalk.green(`\n✅ Deployment successful!`));
|
|
74
|
+
if (result) console.log(JSON.stringify(result, null, 2));
|
|
75
|
+
} catch (err) {
|
|
76
|
+
console.error(chalk.red(`\n❌ Deployment failed: ${err.message}`));
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
package/src/cli/commands/dev.js
CHANGED
|
@@ -1,130 +1,70 @@
|
|
|
1
|
-
const {
|
|
2
|
-
const { getWorkspaceConfig
|
|
1
|
+
const { runProcess } = require('../utils/process');
|
|
2
|
+
const { getWorkspaceConfig } = require('../utils/config');
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const chalk = require('chalk');
|
|
6
|
-
const { resolveModuleMetadata, listAvailableModules, resolveProjectDir } = require('../utils/resolution');
|
|
7
|
-
const { runProcess } = require('../utils/process');
|
|
8
6
|
const { prepareNative } = require('../utils/scaffold');
|
|
9
|
-
const
|
|
7
|
+
const { resolveProjectDir } = require('../utils/resolution');
|
|
10
8
|
|
|
11
9
|
module.exports = async (options) => {
|
|
12
|
-
let cwd = process.cwd();
|
|
13
|
-
let pkgPath = path.join(cwd, 'package.json');
|
|
14
|
-
|
|
15
|
-
// Enforce Workspace Root
|
|
16
10
|
const configObj = getWorkspaceConfig();
|
|
17
11
|
if (!configObj) {
|
|
18
|
-
console.error(chalk.red(`❌ Error:
|
|
12
|
+
console.error(chalk.red(`❌ Error: esad.config.js not found. Run this from your project root.`));
|
|
19
13
|
process.exit(1);
|
|
20
14
|
}
|
|
21
15
|
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
// Synchronize Host Config
|
|
26
|
-
syncHostConfig(configObj);
|
|
16
|
+
const config = await configObj.load();
|
|
17
|
+
const workspaceRoot = configObj.root;
|
|
18
|
+
const projectName = config.default?.projectName || config.projectName;
|
|
27
19
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
20
|
+
let cwd = process.cwd();
|
|
21
|
+
let selectedModuleId = options.id;
|
|
22
|
+
|
|
23
|
+
if (selectedModuleId) {
|
|
24
|
+
const targetDir = resolveProjectDir(selectedModuleId, configObj);
|
|
25
|
+
if (!targetDir) {
|
|
26
|
+
console.error(chalk.red(`❌ Error: Module not found: ${selectedModuleId}`));
|
|
33
27
|
process.exit(1);
|
|
34
28
|
}
|
|
35
|
-
cwd =
|
|
36
|
-
moduleId = metadata.id;
|
|
37
|
-
pkgPath = path.join(cwd, 'package.json');
|
|
38
|
-
console.log(chalk.green(`📂 Module detected: ${path.relative(workspaceRoot, cwd)} (ID: ${moduleId})`));
|
|
39
|
-
} else {
|
|
40
|
-
// Target host by default if in root
|
|
41
|
-
const hostDir = path.join(workspaceRoot, `${projectName}-host`);
|
|
42
|
-
if (fs.existsSync(hostDir)) {
|
|
43
|
-
cwd = hostDir;
|
|
44
|
-
moduleId = pkg.name; // Fallback to package name if in host
|
|
45
|
-
pkgPath = path.join(cwd, 'package.json');
|
|
46
|
-
console.log(chalk.green(`📂 Host detected: ${path.relative(workspaceRoot, cwd)}`));
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (!fs.existsSync(pkgPath)) {
|
|
51
|
-
console.error(chalk.red(`❌ Error: package.json not found in ${cwd}.`));
|
|
52
|
-
process.exit(1);
|
|
29
|
+
cwd = targetDir;
|
|
53
30
|
}
|
|
54
31
|
|
|
32
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
55
33
|
const pkg = fs.readJsonSync(pkgPath);
|
|
56
|
-
|
|
57
|
-
const
|
|
34
|
+
const moduleId = selectedModuleId || pkg.name;
|
|
35
|
+
const port = options.port || '8081';
|
|
58
36
|
|
|
59
|
-
|
|
37
|
+
// Determine if it's a Host or Module
|
|
38
|
+
const isHost = pkg.name.endsWith('-host') || pkg.dependencies?.['@callstack/repack'];
|
|
60
39
|
|
|
61
|
-
|
|
62
|
-
const devUrlBase = config?.devModeEndpoint || config?.deployEndpoint?.replace('/versions', '');
|
|
63
|
-
|
|
64
|
-
if (!devUrlBase) {
|
|
65
|
-
console.error(chalk.red(`❌ Error: 'devModeEndpoint' or 'deployEndpoint' not configured in esad.config.json.`));
|
|
66
|
-
process.exit(1);
|
|
67
|
-
}
|
|
40
|
+
await prepareNative(cwd, 'all');
|
|
68
41
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
42
|
+
if (isHost && !selectedModuleId) {
|
|
43
|
+
console.log(`\n🚀 Starting ${chalk.green('Host App')} Dev Server (Re.Pack/Rspack)...\n`);
|
|
44
|
+
await runProcess('npx', ['react-native', 'webpack-start'], { cwd });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
74
47
|
|
|
75
|
-
|
|
76
|
-
console.log(`\n🏗️ Step 1/3: Building bundle...`);
|
|
77
|
-
const bundleOutput = path.join(cwd, 'build', platform, 'index.bundle');
|
|
78
|
-
await fs.ensureDir(path.dirname(bundleOutput));
|
|
48
|
+
const { updateDevMode, removeDevMode } = require('../utils/transformer');
|
|
79
49
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
'--bundle-output', bundleOutput,
|
|
87
|
-
'--assets-dest', path.dirname(bundleOutput),
|
|
88
|
-
'--reset-cache'
|
|
89
|
-
], cwd);
|
|
90
|
-
} catch (err) {
|
|
91
|
-
console.error(chalk.red(`❌ Build failed.`));
|
|
92
|
-
process.exit(1);
|
|
93
|
-
}
|
|
50
|
+
console.log(`\n⚡ Starting ESAD Dev Server for ${chalk.cyan(moduleId)} on port ${port}...\n`);
|
|
51
|
+
|
|
52
|
+
// Automate devMode update in esad.config.js
|
|
53
|
+
const localBundleUrl = `http://localhost:${port}/index.bundle`;
|
|
54
|
+
updateDevMode(configObj.path, moduleId, localBundleUrl);
|
|
55
|
+
console.log(chalk.gray(`📡 Mode: Module Dev. Host configured to load ${moduleId} from ${localBundleUrl}`));
|
|
94
56
|
|
|
95
|
-
|
|
96
|
-
console.log(`\n🗜️ Step 2/3: Zipping assets...`);
|
|
97
|
-
const zip = new AdmZip();
|
|
98
|
-
const buildDir = path.join(cwd, 'build');
|
|
99
|
-
zip.addLocalFolder(buildDir);
|
|
100
|
-
const zipPath = path.join(cwd, `dev-bundle-${moduleId}.zip`);
|
|
101
|
-
zip.writeZip(zipPath);
|
|
57
|
+
const proc = runProcess('npx', ['react-native', 'webpack-start', '--port', port], { cwd });
|
|
102
58
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
59
|
+
const shutdown = async () => {
|
|
60
|
+
console.log(`\n🛑 Stopping ESAD Dev Server and reverting config...`);
|
|
61
|
+
removeDevMode(configObj.path, moduleId);
|
|
62
|
+
if (proc.kill) proc.kill();
|
|
63
|
+
process.exit(0);
|
|
64
|
+
};
|
|
109
65
|
|
|
110
|
-
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
|
|
111
|
-
const response = await fetch(devUploadUrl, {
|
|
112
|
-
method: 'POST',
|
|
113
|
-
body: form,
|
|
114
|
-
headers: form.getHeaders(),
|
|
115
|
-
});
|
|
116
66
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
console.log(`📱 Host app configured with 'devModeFor: ["${options.id || moduleId}"]' will now load this version.\n`);
|
|
120
|
-
} else {
|
|
121
|
-
const errorText = await response.text();
|
|
122
|
-
console.error(chalk.red(`❌ Cloud Sync failed: ${response.status} ${response.statusText}`));
|
|
123
|
-
console.error(errorText);
|
|
124
|
-
}
|
|
125
|
-
} catch (err) {
|
|
126
|
-
console.error(chalk.red(`❌ Error during sync: ${err.message}`));
|
|
127
|
-
} finally {
|
|
128
|
-
if (fs.existsSync(zipPath)) fs.unlinkSync(zipPath);
|
|
129
|
-
}
|
|
67
|
+
process.on('SIGINT', shutdown);
|
|
68
|
+
process.on('SIGTERM', shutdown);
|
|
130
69
|
};
|
|
70
|
+
|
package/src/cli/commands/host.js
CHANGED
|
@@ -7,7 +7,12 @@ const readline = require('readline');
|
|
|
7
7
|
const { getWorkspaceConfig } = require('../utils/config');
|
|
8
8
|
const { prepareNative } = require('../utils/scaffold');
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
const rl = readline.createInterface({
|
|
11
|
+
input: process.stdin,
|
|
12
|
+
output: process.stdout
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const askQuestion = (query) => new Promise((resolve) => rl.question(query, resolve));
|
|
11
16
|
|
|
12
17
|
/**
|
|
13
18
|
* Check if a port is in use
|
|
@@ -23,12 +28,6 @@ const isPortInUse = (port) => new Promise((resolve) => {
|
|
|
23
28
|
});
|
|
24
29
|
|
|
25
30
|
module.exports = async (subcommand) => {
|
|
26
|
-
const rl = readline.createInterface({
|
|
27
|
-
input: process.stdin,
|
|
28
|
-
output: process.stdout
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
if (!subcommand) subcommand = 'dev';
|
|
32
31
|
let cwd = process.cwd();
|
|
33
32
|
let pkgPath = path.join(cwd, 'package.json');
|
|
34
33
|
|
|
@@ -65,7 +64,7 @@ module.exports = async (subcommand) => {
|
|
|
65
64
|
console.log(`[b] Bundler Only`);
|
|
66
65
|
console.log(`[c] Cancel`);
|
|
67
66
|
|
|
68
|
-
const choice = (await askQuestion(`\nSelect platform:
|
|
67
|
+
const choice = (await askQuestion(`\nSelect platform: `)).toLowerCase();
|
|
69
68
|
|
|
70
69
|
if (choice === 'c') {
|
|
71
70
|
console.log(`\n❌ Cancelled.`);
|
|
@@ -87,13 +86,14 @@ module.exports = async (subcommand) => {
|
|
|
87
86
|
if (shouldStartBundler && choice !== 'c') {
|
|
88
87
|
console.log(`\n🛠️ Starting Rspack Bundler in a new window...`);
|
|
89
88
|
if (process.platform === 'win32') {
|
|
90
|
-
|
|
89
|
+
const npxCmd = 'npx.cmd';
|
|
90
|
+
spawn('cmd', ['/c', 'start', '/D', cwd, npxCmd, 'react-native', 'webpack-start'], {
|
|
91
91
|
detached: true,
|
|
92
92
|
stdio: 'ignore',
|
|
93
93
|
shell: true
|
|
94
94
|
}).unref();
|
|
95
95
|
} else {
|
|
96
|
-
spawn('npx', ['react-native', 'start'
|
|
96
|
+
spawn('npx', ['react-native', 'webpack-start'], {
|
|
97
97
|
cwd,
|
|
98
98
|
detached: true,
|
|
99
99
|
stdio: 'inherit',
|
|
@@ -123,10 +123,10 @@ module.exports = async (subcommand) => {
|
|
|
123
123
|
// 6. Launch Native App
|
|
124
124
|
if (choice === 'a') {
|
|
125
125
|
console.log(`🤖 Compiling and launching on Android...`);
|
|
126
|
-
await runProcess('
|
|
126
|
+
await runProcess('react-native', ['run-android', '--no-packager'], cwd);
|
|
127
127
|
} else if (choice === 'i') {
|
|
128
128
|
console.log(`🍎 Compiling and launching on iOS...`);
|
|
129
|
-
await runProcess('
|
|
129
|
+
await runProcess('react-native', ['run-ios', '--no-packager'], cwd);
|
|
130
130
|
} else if (choice === 'b') {
|
|
131
131
|
if (portBusy) {
|
|
132
132
|
console.log(`✨ Bundler is already active. You can launch manual native runs.`);
|
|
@@ -140,16 +140,13 @@ module.exports = async (subcommand) => {
|
|
|
140
140
|
// Other subcommands (android, ios directly)
|
|
141
141
|
try {
|
|
142
142
|
if (subcommand === 'android') {
|
|
143
|
-
|
|
144
|
-
await runProcess('npx', ['expo', 'run:android', '--no-bundler'], cwd);
|
|
143
|
+
await runProcess('react-native', ['run-android', '--no-packager'], cwd);
|
|
145
144
|
} else if (subcommand === 'ios') {
|
|
146
|
-
|
|
147
|
-
await runProcess('npx', ['expo', 'run:ios', '--no-bundler'], cwd);
|
|
145
|
+
await runProcess('react-native', ['run-ios', '--no-packager'], cwd);
|
|
148
146
|
}
|
|
149
147
|
} catch (err) {
|
|
150
148
|
console.error(`❌ Error running host command: ${err.message}`);
|
|
151
|
-
} finally {
|
|
152
|
-
rl.close();
|
|
153
149
|
}
|
|
150
|
+
rl.close();
|
|
154
151
|
}
|
|
155
152
|
};
|
package/src/cli/commands/init.js
CHANGED
|
@@ -10,34 +10,53 @@ module.exports = async (projectName) => {
|
|
|
10
10
|
|
|
11
11
|
fs.ensureDirSync(workspaceDir);
|
|
12
12
|
|
|
13
|
-
const configPath = path.join(workspaceDir, 'esad.config.
|
|
13
|
+
const configPath = path.join(workspaceDir, 'esad.config.js');
|
|
14
14
|
if (!fs.existsSync(configPath)) {
|
|
15
|
-
const configTemplate =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
const configTemplate = `/**
|
|
16
|
+
* ESAD: Super App Configuration
|
|
17
|
+
*/
|
|
18
|
+
export default {
|
|
19
|
+
projectName: '${projectName}',
|
|
20
|
+
|
|
21
|
+
// 1. Development Overrides
|
|
22
|
+
// Managed automatically by 'esad dev'
|
|
23
|
+
devMode: {},
|
|
24
|
+
|
|
25
|
+
// 2. Programmable Deployment
|
|
26
|
+
// Receives the compiled bundle.
|
|
27
|
+
async deploy(bundle, { version, moduleId, options }) {
|
|
28
|
+
console.log('🚀 Starting custom upload for ' + moduleId + '...');
|
|
29
|
+
|
|
30
|
+
// Example: Simple CDN V2 upload
|
|
31
|
+
// const response = await fetch('http://localhost:3000/api/admin/modules/' + moduleId + '/versions', {
|
|
32
|
+
// method: 'POST',
|
|
33
|
+
// body: bundle,
|
|
34
|
+
// headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
|
|
35
|
+
// });
|
|
36
|
+
// return await response.json();
|
|
37
|
+
|
|
38
|
+
return { status: 'mock_success', moduleId, version };
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
`;
|
|
42
|
+
fs.writeFileSync(configPath, configTemplate);
|
|
43
|
+
console.log(`✅ Generated programmable configuration: esad.config.js`);
|
|
23
44
|
}
|
|
24
45
|
|
|
25
46
|
const gitignorePath = path.join(workspaceDir, '.gitignore');
|
|
26
47
|
if (!fs.existsSync(gitignorePath)) {
|
|
27
48
|
const hostName = `${projectName}-host`;
|
|
28
49
|
const gitignoreContent = `# ESAD Workspace Git Configuration\n` +
|
|
29
|
-
`# Ignore everything by default\n` +
|
|
30
50
|
`/*\n\n` +
|
|
31
|
-
`# Exceptions: Track only the Host and Configs\n` +
|
|
32
51
|
`!/${hostName}/\n` +
|
|
33
|
-
`!/esad.config.
|
|
52
|
+
`!/esad.config.js\n` +
|
|
34
53
|
`!/.gitignore\n` +
|
|
35
|
-
`\n
|
|
36
|
-
`node_modules/\n`;
|
|
54
|
+
`\nnode_modules/\n`;
|
|
37
55
|
fs.writeFileSync(gitignorePath, gitignoreContent);
|
|
38
56
|
console.log(`✅ Generated .gitignore`);
|
|
39
57
|
}
|
|
40
58
|
|
|
59
|
+
|
|
41
60
|
const hostName = `${projectName}-host`;
|
|
42
61
|
const hostDir = path.join(workspaceDir, hostName);
|
|
43
62
|
|
package/src/cli/utils/config.js
CHANGED
|
@@ -1,37 +1,40 @@
|
|
|
1
|
-
const fs = require('fs-extra');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
let
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { createJiti } = require('jiti');
|
|
4
|
+
|
|
5
|
+
const getWorkspaceConfig = () => {
|
|
6
|
+
let current = process.cwd();
|
|
7
|
+
let configPath = null;
|
|
8
|
+
|
|
9
|
+
// Search upwards for esad.config.js
|
|
10
|
+
while (current !== path.parse(current).root) {
|
|
11
|
+
const check = path.join(current, 'esad.config.js');
|
|
12
|
+
if (fs.existsSync(check)) {
|
|
13
|
+
configPath = check;
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
current = path.dirname(current);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!configPath) return null;
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const jiti = createJiti(__filename);
|
|
23
|
+
const configModule = jiti.import(configPath);
|
|
24
|
+
// jiti.import returns a promise for async imports if needed, but for esad.config.js
|
|
25
|
+
// we expect a sync structure or we resolve it.
|
|
26
|
+
// However, jiti v2 import is async.
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
path: configPath,
|
|
30
|
+
root: path.dirname(configPath),
|
|
31
|
+
load: () => configModule
|
|
32
|
+
};
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.error(`❌ Failed to load esad.config.js: ${err.message}`);
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
module.exports = { getWorkspaceConfig };
|
|
40
|
+
|