gingee-cli 1.0.1 → 1.0.2
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/commands/addApp.js +99 -41
- package/commands/apiClient.js +1 -3
- package/commands/installStoreApp.js +1 -1
- package/package.json +2 -2
- package/templates/spa-generic/app.json +12 -0
package/commands/addApp.js
CHANGED
|
@@ -24,7 +24,10 @@ async function addApp(appName) {
|
|
|
24
24
|
type: 'list',
|
|
25
25
|
name: 'type',
|
|
26
26
|
message: 'What type of app is this?',
|
|
27
|
-
choices: [
|
|
27
|
+
choices: [
|
|
28
|
+
{ name: 'MPA (Multi-Page App, Traditional Web App)', value: 'MPA' },
|
|
29
|
+
{ name: 'SPA (Single Page App, React/Vue/etc.)', value: 'SPA' }
|
|
30
|
+
],
|
|
28
31
|
default: 'MPA',
|
|
29
32
|
},
|
|
30
33
|
{
|
|
@@ -41,27 +44,27 @@ async function addApp(appName) {
|
|
|
41
44
|
when: (ans) => ans.configureDb,
|
|
42
45
|
},
|
|
43
46
|
{
|
|
44
|
-
type: 'input', name: 'dbName', message: 'Connection Name (e.g., main_db):', default: 'main_db',
|
|
47
|
+
type: 'input', name: 'dbName', message: 'Connection Name (e.g., main_db):', default: 'main_db',
|
|
45
48
|
when: (ans) => ans.configureDb,
|
|
46
49
|
},
|
|
47
50
|
{
|
|
48
|
-
type: 'input', name: 'dbHost', message: 'Database Host:', default: 'localhost',
|
|
51
|
+
type: 'input', name: 'dbHost', message: 'Database Host:', default: 'localhost',
|
|
49
52
|
when: (ans) => ans.configureDb && ans.dbType !== 'sqlite',
|
|
50
53
|
},
|
|
51
54
|
{
|
|
52
|
-
type: 'input', name: 'dbUser', message: 'Database User:',
|
|
55
|
+
type: 'input', name: 'dbUser', message: 'Database User:',
|
|
53
56
|
when: (ans) => ans.configureDb && ans.dbType !== 'sqlite',
|
|
54
57
|
},
|
|
55
58
|
{
|
|
56
|
-
type: 'password', name: 'dbPass', message: 'Database Password:', mask: '*',
|
|
59
|
+
type: 'password', name: 'dbPass', message: 'Database Password:', mask: '*',
|
|
57
60
|
when: (ans) => ans.configureDb && ans.dbType !== 'sqlite',
|
|
58
61
|
},
|
|
59
62
|
{
|
|
60
|
-
type: 'input', name: 'dbDatabase', message: 'Database Name:',
|
|
63
|
+
type: 'input', name: 'dbDatabase', message: 'Database Name:',
|
|
61
64
|
when: (ans) => ans.configureDb && ans.dbType !== 'sqlite',
|
|
62
65
|
},
|
|
63
66
|
{
|
|
64
|
-
type: 'input', name: 'dbFile', message: 'Database File Path (relative to box folder):', default: 'data/app.db',
|
|
67
|
+
type: 'input', name: 'dbFile', message: 'Database File Path (relative to box folder):', default: 'data/app.db',
|
|
65
68
|
when: (ans) => ans.dbType === 'sqlite',
|
|
66
69
|
},
|
|
67
70
|
{
|
|
@@ -72,45 +75,100 @@ async function addApp(appName) {
|
|
|
72
75
|
},
|
|
73
76
|
]);
|
|
74
77
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
78
|
+
if (answers.type === 'SPA') {
|
|
79
|
+
// --- Scaffolding files and folders for SPA ---
|
|
80
|
+
console.log('Scaffolding SPA app structure...');
|
|
81
|
+
const boxPath = path.join(appPath, 'box');
|
|
82
|
+
const apiPath = path.join(boxPath, 'api');
|
|
83
|
+
fs.ensureDirSync(apiPath);
|
|
84
|
+
|
|
85
|
+
// Create sample API endpoint
|
|
86
|
+
const sampleApiContent = `module.exports = async function() {\n await gingee(async ($g) => {\n $g.response.send({ message: 'Hello from your Gingee SPA backend!' });\n });\n};`;
|
|
87
|
+
fs.writeFileSync(path.join(apiPath, 'hello.js'), sampleApiContent);
|
|
88
|
+
|
|
89
|
+
// Create the pre-configured app.json from template
|
|
90
|
+
const templatePath = path.join(__dirname, '..', 'templates', 'spa-generic', 'app.json');
|
|
91
|
+
const appConfig = fs.readJsonSync(templatePath);
|
|
92
|
+
appConfig.name = appName;
|
|
93
|
+
|
|
94
|
+
if (answers.configureDb) {
|
|
95
|
+
appConfig.db = [{
|
|
96
|
+
type: answers.dbType,
|
|
97
|
+
name: answers.dbName,
|
|
98
|
+
host: answers.dbHost,
|
|
99
|
+
user: answers.dbUser,
|
|
100
|
+
password: answers.dbPass,
|
|
101
|
+
database: answers.dbType === 'sqlite' ? answers.dbFile : answers.dbDatabase,
|
|
102
|
+
}];
|
|
103
|
+
}
|
|
104
|
+
if (answers.configureJwt) {
|
|
105
|
+
appConfig.jwt_secret = crypto.randomBytes(32).toString('hex');
|
|
106
|
+
}
|
|
107
|
+
fs.writeJsonSync(path.join(boxPath, 'app.json'), appConfig, { spaces: 2 });
|
|
108
|
+
|
|
109
|
+
} else {
|
|
99
110
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
111
|
+
// --- Scaffold the files and folders for MPA ---
|
|
112
|
+
console.log('Scaffolding MPA app structure...');
|
|
113
|
+
const boxPath = path.join(appPath, 'box');
|
|
114
|
+
fs.ensureDirSync(boxPath);
|
|
115
|
+
fs.ensureDirSync(path.join(appPath, 'css'));
|
|
116
|
+
fs.ensureDirSync(path.join(appPath, 'images'));
|
|
117
|
+
fs.ensureDirSync(path.join(appPath, 'scripts'));
|
|
103
118
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
119
|
+
// --- Create app.json ---
|
|
120
|
+
const appConfig = { name: appName, version: '1.0.0', type: answers.type };
|
|
121
|
+
if (answers.configureDb) {
|
|
122
|
+
appConfig.db = [{
|
|
123
|
+
type: answers.dbType,
|
|
124
|
+
name: answers.dbName,
|
|
125
|
+
host: answers.dbHost,
|
|
126
|
+
user: answers.dbUser,
|
|
127
|
+
password: answers.dbPass,
|
|
128
|
+
database: answers.dbType === 'sqlite' ? answers.dbFile : answers.dbDatabase,
|
|
129
|
+
}];
|
|
130
|
+
}
|
|
131
|
+
if (answers.configureJwt) {
|
|
132
|
+
appConfig.jwt_secret = crypto.randomBytes(32).toString('hex');
|
|
133
|
+
}
|
|
134
|
+
fs.writeJsonSync(path.join(boxPath, 'app.json'), appConfig, { spaces: 2 });
|
|
107
135
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
136
|
+
// --- Create hello.js ---
|
|
137
|
+
const helloScriptContent = `module.exports = async function() {\n await gingee(async ($g) => {\n $g.response.send({ message: 'Hello from the ${appName} server script!' });\n });\n};`;
|
|
138
|
+
fs.writeFileSync(path.join(boxPath, 'hello.js'), helloScriptContent);
|
|
139
|
+
|
|
140
|
+
// --- Create index.html ---
|
|
141
|
+
const indexHtmlContent = `<!DOCTYPE html>\n<html lang="en">\n<head>\n <meta charset="UTF-8">\n <title>${appName}</title>\n</head>\n<body>\n <h1>${appName}</h1>\n <button id="helloButton">Say Hello</button>\n <div id="response" style="margin-top: 1rem; font-family: monospace;"></div>\n <script src="/${appName}/scripts/cl_app.js"></script>\n</body>\n</html>`;
|
|
142
|
+
fs.writeFileSync(path.join(appPath, 'index.html'), indexHtmlContent);
|
|
143
|
+
|
|
144
|
+
// --- Create cl_app.js ---
|
|
145
|
+
const clAppJsContent = `document.getElementById('helloButton').addEventListener('click', async () => {\n const responseElement = document.getElementById('response');\n responseElement.innerText = 'Loading...';\n try {\n const res = await fetch('/${appName}/hello');\n const data = await res.json();\n responseElement.innerText = \`Server says: \${data.message}\`;\n } catch (err) {\n responseElement.innerText = 'Error: Could not connect to server.';\n }\n});`;
|
|
146
|
+
fs.writeFileSync(path.join(appPath, 'scripts', 'cl_app.js'), clAppJsContent);
|
|
147
|
+
}
|
|
111
148
|
|
|
112
149
|
console.log(chalk.bgGreen(`\n✅ Success!`), chalk.blueBright(`App '${appName}' created.`));
|
|
113
|
-
|
|
150
|
+
if (answers.type === 'SPA') {
|
|
151
|
+
console.log(chalk.blueBright(`\nYour Gingee app is ready. Now, set up your frontend framework:`));
|
|
152
|
+
console.log(chalk.blueBright(`\n1. Navigate into your new app's folder:`));
|
|
153
|
+
console.log(chalk.white(` cd web/${appName}`));
|
|
154
|
+
console.log(chalk.blueBright(`\n2. Use your favorite tool to initialize your project HERE.`));
|
|
155
|
+
console.log(chalk.dim(` (For example, to use Vite + React, run:)`));
|
|
156
|
+
console.log(chalk.white(` npm create vite@latest`));
|
|
157
|
+
|
|
158
|
+
console.log(chalk.blueBright(`\n3. IMPORTANT After initializing, you MUST configure your frontend tool`));
|
|
159
|
+
console.log(chalk.blueBright(`to use a base path. For Vite, edit 'vite.config.js' and add:`));
|
|
160
|
+
console.log(chalk.white(` base: '/${appName}/'`));
|
|
161
|
+
|
|
162
|
+
console.log(chalk.blueBright(`\n4. Install the frontend dependencies:`));
|
|
163
|
+
console.log(chalk.white(` npm install`));
|
|
164
|
+
console.log(chalk.blueBright(`\n5. Review 'box/app.json' to ensure the proxy and build paths match your tool.`));
|
|
165
|
+
console.log(chalk.blueBright(`\n6. Return to the project root and start the server:`));
|
|
166
|
+
console.log(chalk.white(` cd ../..`));
|
|
167
|
+
console.log(chalk.white(` npm start`));
|
|
168
|
+
console.log('\n\n');
|
|
169
|
+
} else {
|
|
170
|
+
console.log(` Navigate to /${appName} in your browser to see it in action.`);
|
|
171
|
+
}
|
|
114
172
|
|
|
115
173
|
} catch (err) {
|
|
116
174
|
if (err.errors) { //for AggregateError
|
package/commands/apiClient.js
CHANGED
|
@@ -14,9 +14,7 @@ const credsDir = path.join(configDir, 'sessions');
|
|
|
14
14
|
function getCredsFilePath(serverUrl) {
|
|
15
15
|
// Use a hash to create a unique, fixed-length, safe filename
|
|
16
16
|
const hash = crypto.createHash('sha256').update(serverUrl).digest('hex');
|
|
17
|
-
|
|
18
|
-
fs.mkdirSync(credsDir);
|
|
19
|
-
}
|
|
17
|
+
fs.ensureDirSync(credsDir);
|
|
20
18
|
return path.join(credsDir, `${hash}.json`);
|
|
21
19
|
}
|
|
22
20
|
|
|
@@ -27,7 +27,7 @@ async function installStoreApp(appName, options) {
|
|
|
27
27
|
spinner.start(`Fetching manifest from ${resolvedStoreUrl}...`);
|
|
28
28
|
|
|
29
29
|
const manifestResponse = await axios.get(resolvedStoreUrl);
|
|
30
|
-
const appConfig = manifestResponse.data.apps.find(a => a.
|
|
30
|
+
const appConfig = manifestResponse.data.apps.find(a => a.installName === appName);
|
|
31
31
|
if (!appConfig) {
|
|
32
32
|
throw new Error(`App '${appName}' not found in the store manifest.`);
|
|
33
33
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gingee-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "The Gingee Command Line Interface (CLI), official command line tool for creating and managing Gingee projects.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"commander": "^14.0.0",
|
|
42
42
|
"form-data": "^4.0.4",
|
|
43
43
|
"fs-extra": "^11.3.1",
|
|
44
|
-
"gingee": "^1.0.
|
|
44
|
+
"gingee": "^1.0.1",
|
|
45
45
|
"inquirer": "^12.9.2",
|
|
46
46
|
"ora": "^8.2.0",
|
|
47
47
|
"yauzl": "^3.2.0"
|