esa-cli 0.0.2-beta.21 → 0.0.2-beta.22
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/commands/commit/index.js +5 -0
- package/dist/commands/common/utils.js +87 -87
- package/dist/commands/deploy/index.js +1 -0
- package/dist/commands/deployments/delete.js +2 -2
- package/dist/commands/dev/ew2/devPack.js +9 -9
- package/dist/commands/dev/ew2/kvService.js +7 -1
- package/dist/commands/dev/ew2/mock/kv.js +1 -1
- package/dist/commands/dev/ew2/server.js +1 -2
- package/dist/commands/dev/index.js +1 -1
- package/dist/commands/dev/mockWorker/devPack.js +3 -3
- package/dist/commands/init/helper.js +7 -9
- package/dist/commands/init/template.jsonc +1 -1
- package/dist/commands/route/add.js +19 -52
- package/dist/commands/route/helper.js +9 -10
- package/dist/commands/routine/list.js +38 -20
- package/dist/commands/utils.js +4 -4
- package/dist/components/filterSelector.js +1 -1
- package/dist/components/routeBuilder.js +68 -0
- package/dist/i18n/locales.json +39 -3
- package/dist/libs/apiService.js +7 -6
- package/dist/libs/logger.js +4 -4
- package/dist/utils/checkIsRoutineCreated.js +1 -1
- package/dist/utils/compress.js +5 -5
- package/dist/utils/download.js +2 -2
- package/dist/utils/fileUtils/index.js +69 -18
- package/package.json +1 -1
|
@@ -69,6 +69,11 @@ export function handleCommit(argv) {
|
|
|
69
69
|
}
|
|
70
70
|
logger.startSubStep('Generating code version');
|
|
71
71
|
const res = yield generateCodeVersion(projectName, description, argv === null || argv === void 0 ? void 0 : argv.entry, argv === null || argv === void 0 ? void 0 : argv.assets, argv === null || argv === void 0 ? void 0 : argv.minify);
|
|
72
|
+
const { isSuccess } = res || {};
|
|
73
|
+
if (!isSuccess) {
|
|
74
|
+
logger.endSubStep('Generate version failed');
|
|
75
|
+
exit(1);
|
|
76
|
+
}
|
|
72
77
|
const codeVersion = (_b = (_a = res === null || res === void 0 ? void 0 : res.res) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.CodeVersion;
|
|
73
78
|
if (!codeVersion) {
|
|
74
79
|
logger.endSubStep('Missing CodeVersion in response');
|
|
@@ -61,6 +61,9 @@ export function commitRoutineWithAssets(requestParams, zipBuffer) {
|
|
|
61
61
|
if (uploadSuccess) {
|
|
62
62
|
break;
|
|
63
63
|
}
|
|
64
|
+
if (i < 2) {
|
|
65
|
+
yield new Promise((resolve) => setTimeout(resolve, 2000));
|
|
66
|
+
}
|
|
64
67
|
}
|
|
65
68
|
return {
|
|
66
69
|
isSuccess: uploadSuccess,
|
|
@@ -120,100 +123,97 @@ export function generateCodeVersion(projectName_1, description_1, entry_1, asset
|
|
|
120
123
|
return __awaiter(this, arguments, void 0, function* (projectName, description, entry, assets, minify = false, projectPath) {
|
|
121
124
|
var _a;
|
|
122
125
|
const { zip, sourceList, dynamicSources } = yield compress(entry, assets, minify, projectPath);
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
node.children.set(part, { children: new Map(), isFile: false });
|
|
135
|
-
}
|
|
136
|
-
const child = node.children.get(part);
|
|
137
|
-
if (i === parts.length - 1)
|
|
138
|
-
child.isFile = true;
|
|
139
|
-
node = child;
|
|
126
|
+
// Pretty print upload directory tree
|
|
127
|
+
const buildTree = (paths, decorateTopLevel) => {
|
|
128
|
+
const root = { children: new Map(), isFile: false };
|
|
129
|
+
const sorted = [...paths].sort((a, b) => a.localeCompare(b));
|
|
130
|
+
for (const p of sorted) {
|
|
131
|
+
const parts = p.split('/').filter(Boolean);
|
|
132
|
+
let node = root;
|
|
133
|
+
for (let i = 0; i < parts.length; i++) {
|
|
134
|
+
const part = parts[i];
|
|
135
|
+
if (!node.children.has(part)) {
|
|
136
|
+
node.children.set(part, { children: new Map(), isFile: false });
|
|
140
137
|
}
|
|
138
|
+
const child = node.children.get(part);
|
|
139
|
+
if (i === parts.length - 1)
|
|
140
|
+
child.isFile = true;
|
|
141
|
+
node = child;
|
|
141
142
|
}
|
|
142
|
-
const lines = [];
|
|
143
|
-
const render = (node, prefix, depth) => {
|
|
144
|
-
const entries = [...node.children.entries()];
|
|
145
|
-
entries.forEach(([_name, _child], idx) => {
|
|
146
|
-
const isLast = idx === entries.length - 1;
|
|
147
|
-
const connector = isLast ? '└ ' : '├ ';
|
|
148
|
-
const nextPrefix = prefix + (isLast ? ' ' : '│ ');
|
|
149
|
-
const displayName = depth === 0 ? decorateTopLevel(_name) : _name;
|
|
150
|
-
lines.push(prefix + connector + displayName);
|
|
151
|
-
render(_child, nextPrefix, depth + 1);
|
|
152
|
-
});
|
|
153
|
-
};
|
|
154
|
-
render(root, '', 0);
|
|
155
|
-
return lines.length ? lines : ['-'];
|
|
156
|
-
};
|
|
157
|
-
const header = chalk.hex('#22c55e')('UPLOAD') + ' Files to be uploaded (source paths)';
|
|
158
|
-
logger.block();
|
|
159
|
-
logger.log(header);
|
|
160
|
-
const dynamicSet = new Set(dynamicSources);
|
|
161
|
-
const LIMIT = 300;
|
|
162
|
-
const staticPaths = sourceList
|
|
163
|
-
.filter((p) => !dynamicSet.has(p))
|
|
164
|
-
.sort((a, b) => a.localeCompare(b));
|
|
165
|
-
const dynamicPaths = sourceList
|
|
166
|
-
.filter((p) => dynamicSet.has(p))
|
|
167
|
-
.sort((a, b) => a.localeCompare(b));
|
|
168
|
-
let omitted = 0;
|
|
169
|
-
let shownStatic = staticPaths;
|
|
170
|
-
if (staticPaths.length > LIMIT) {
|
|
171
|
-
shownStatic = staticPaths.slice(0, LIMIT);
|
|
172
|
-
omitted = staticPaths.length - LIMIT;
|
|
173
143
|
}
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
stat.hasStatic = true;
|
|
186
|
-
topLevelStats.set(top, stat);
|
|
144
|
+
const lines = [];
|
|
145
|
+
const render = (node, prefix, depth) => {
|
|
146
|
+
const entries = [...node.children.entries()];
|
|
147
|
+
entries.forEach(([_name, _child], idx) => {
|
|
148
|
+
const isLast = idx === entries.length - 1;
|
|
149
|
+
const connector = isLast ? '└ ' : '├ ';
|
|
150
|
+
const nextPrefix = prefix + (isLast ? ' ' : '│ ');
|
|
151
|
+
const displayName = depth === 0 ? decorateTopLevel(_name) : _name;
|
|
152
|
+
lines.push(prefix + connector + displayName);
|
|
153
|
+
render(_child, nextPrefix, depth + 1);
|
|
154
|
+
});
|
|
187
155
|
};
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
156
|
+
render(root, '', 0);
|
|
157
|
+
return lines.length ? lines : ['-'];
|
|
158
|
+
};
|
|
159
|
+
const header = chalk.hex('#22c55e')('UPLOAD') + ' Files to be uploaded (source paths)';
|
|
160
|
+
logger.block();
|
|
161
|
+
logger.log(header);
|
|
162
|
+
const dynamicSet = new Set(dynamicSources);
|
|
163
|
+
const LIMIT = 300;
|
|
164
|
+
const staticPaths = sourceList
|
|
165
|
+
.filter((p) => !dynamicSet.has(p))
|
|
166
|
+
.sort((a, b) => a.localeCompare(b));
|
|
167
|
+
const dynamicPaths = sourceList
|
|
168
|
+
.filter((p) => dynamicSet.has(p))
|
|
169
|
+
.sort((a, b) => a.localeCompare(b));
|
|
170
|
+
let omitted = 0;
|
|
171
|
+
let shownStatic = staticPaths;
|
|
172
|
+
if (staticPaths.length > LIMIT) {
|
|
173
|
+
shownStatic = staticPaths.slice(0, LIMIT);
|
|
174
|
+
omitted = staticPaths.length - LIMIT;
|
|
175
|
+
}
|
|
176
|
+
// Compute top-level markers based on whether a top-level bucket contains dynamic/static files
|
|
177
|
+
const topLevelStats = new Map();
|
|
178
|
+
const addStat = (p, isDynamic) => {
|
|
179
|
+
const top = p.split('/')[0] || p;
|
|
180
|
+
const stat = topLevelStats.get(top) || {
|
|
181
|
+
hasDynamic: false,
|
|
182
|
+
hasStatic: false
|
|
204
183
|
};
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
184
|
+
if (isDynamic)
|
|
185
|
+
stat.hasDynamic = true;
|
|
186
|
+
else
|
|
187
|
+
stat.hasStatic = true;
|
|
188
|
+
topLevelStats.set(top, stat);
|
|
189
|
+
};
|
|
190
|
+
dynamicPaths.forEach((p) => addStat(p, true));
|
|
191
|
+
shownStatic.forEach((p) => addStat(p, false));
|
|
192
|
+
const dynamicMarker = chalk.bold.yellowBright(' (dynamic)');
|
|
193
|
+
const staticMarker = chalk.bold.greenBright(' (static)');
|
|
194
|
+
const decorateTopLevel = (name) => {
|
|
195
|
+
const stat = topLevelStats.get(name);
|
|
196
|
+
if (!stat)
|
|
197
|
+
return name;
|
|
198
|
+
if (stat.hasDynamic && stat.hasStatic) {
|
|
199
|
+
return `${name}${dynamicMarker}${staticMarker}`;
|
|
213
200
|
}
|
|
214
|
-
|
|
201
|
+
if (stat.hasDynamic)
|
|
202
|
+
return `${name}${dynamicMarker}`;
|
|
203
|
+
if (stat.hasStatic)
|
|
204
|
+
return `${name}${staticMarker}`;
|
|
205
|
+
return name;
|
|
206
|
+
};
|
|
207
|
+
const combined = [...dynamicPaths, ...shownStatic];
|
|
208
|
+
const treeLines = buildTree(combined, decorateTopLevel);
|
|
209
|
+
for (const line of treeLines) {
|
|
210
|
+
logger.log(line);
|
|
215
211
|
}
|
|
216
|
-
|
|
212
|
+
if (omitted > 0) {
|
|
213
|
+
const note = chalk.gray(`Only show the first ${LIMIT} static files, omitted ${omitted} files`);
|
|
214
|
+
logger.log(note);
|
|
215
|
+
}
|
|
216
|
+
logger.block();
|
|
217
217
|
const projectConfig = getProjectConfig(projectPath);
|
|
218
218
|
const notFoundStrategy = normalizeNotFoundStrategy((_a = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.assets) === null || _a === void 0 ? void 0 : _a.notFoundStrategy);
|
|
219
219
|
logger.startSubStep('Generating code version');
|
|
@@ -52,7 +52,7 @@ export function handleDeleteDeployments(argv) {
|
|
|
52
52
|
const isInteractive = argv.i;
|
|
53
53
|
if (isInteractive) {
|
|
54
54
|
const { allVersions, stagingVersions, productionVersions } = yield getRoutineCodeVersions(projectConfig.name);
|
|
55
|
-
//
|
|
55
|
+
// Show information about versions being deployed
|
|
56
56
|
if (stagingVersions.length > 0 || productionVersions.length > 0) {
|
|
57
57
|
logger.log(chalk.yellow('⚠️ Currently deploying versions:'));
|
|
58
58
|
if (stagingVersions.length > 0) {
|
|
@@ -64,7 +64,7 @@ export function handleDeleteDeployments(argv) {
|
|
|
64
64
|
logger.log('');
|
|
65
65
|
}
|
|
66
66
|
logger.log(t('delete_deployments_table_title').d(' Version ID Description'));
|
|
67
|
-
//
|
|
67
|
+
// Filter out versions being deployed
|
|
68
68
|
const selectList = allVersions
|
|
69
69
|
.filter((item) => {
|
|
70
70
|
var _a, _b;
|
|
@@ -16,7 +16,7 @@ import { getRoot, getDirName } from '../../../utils/fileUtils/base.js';
|
|
|
16
16
|
import { getDevConf } from '../../../utils/fileUtils/index.js';
|
|
17
17
|
import { EW2Path } from '../../../utils/installEw2.js';
|
|
18
18
|
import devBuild from '../build.js';
|
|
19
|
-
//
|
|
19
|
+
// Generate available Ew2 port
|
|
20
20
|
const generateEw2Port = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
21
21
|
let ew2port = 3322;
|
|
22
22
|
let portAvailable = yield checkPort(ew2port);
|
|
@@ -60,7 +60,7 @@ conf_path = "${erConfPath}"
|
|
|
60
60
|
fs.promises.writeFile(erConfPath, erConf)
|
|
61
61
|
]);
|
|
62
62
|
};
|
|
63
|
-
//
|
|
63
|
+
// Generate entry file
|
|
64
64
|
const generateEntry = (id, projectEntry, userRoot, port) => __awaiter(void 0, void 0, void 0, function* () {
|
|
65
65
|
const __dirname = getDirName(import.meta.url);
|
|
66
66
|
const devDir = path.resolve(userRoot, '.dev');
|
|
@@ -85,20 +85,20 @@ const generateEntry = (id, projectEntry, userRoot, port) => __awaiter(void 0, vo
|
|
|
85
85
|
.replace(/'\$userPath'/g, `'${projectEntry.replace(/\\/g, '/')}'`)
|
|
86
86
|
.replace(/\$userPort/g, `${port}`));
|
|
87
87
|
});
|
|
88
|
-
//
|
|
88
|
+
// Preliminary preparation
|
|
89
89
|
const prepare = (configPath, entry, port, localUpstream, userRoot) => __awaiter(void 0, void 0, void 0, function* () {
|
|
90
90
|
const options = {};
|
|
91
91
|
const currentOptions = { entry, port, localUpstream };
|
|
92
|
-
//
|
|
92
|
+
// Support running multiple workers simultaneously
|
|
93
93
|
const id = new Date().getTime().toString();
|
|
94
94
|
// @ts-ignore
|
|
95
95
|
global.id = id;
|
|
96
|
-
//
|
|
96
|
+
// Generate entry file
|
|
97
97
|
yield generateEntry(id, entry, userRoot, port);
|
|
98
|
-
//
|
|
98
|
+
// Generate Ew2 configuration
|
|
99
99
|
const ew2port = yield generateEw2Port();
|
|
100
100
|
yield writeEw2config(id, ew2port, userRoot);
|
|
101
|
-
//
|
|
101
|
+
// Configuration items for each dev session, distinguished by id in one file
|
|
102
102
|
if (fs.existsSync(configPath)) {
|
|
103
103
|
const currentConfig = fs
|
|
104
104
|
.readFileSync(configPath, 'utf-8')
|
|
@@ -106,7 +106,7 @@ const prepare = (configPath, entry, port, localUpstream, userRoot) => __awaiter(
|
|
|
106
106
|
const currentConfigObj = JSON.parse(currentConfig);
|
|
107
107
|
const currentIds = Object.keys(currentConfigObj);
|
|
108
108
|
if (currentIds[0] && /^\d+$/.test(currentIds[0])) {
|
|
109
|
-
//
|
|
109
|
+
// Remove unused entries
|
|
110
110
|
for (let currentId of currentIds) {
|
|
111
111
|
const unused = yield checkPort(currentConfigObj[currentId].port);
|
|
112
112
|
if (unused) {
|
|
@@ -155,7 +155,7 @@ const devPack = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
155
155
|
}
|
|
156
156
|
else {
|
|
157
157
|
logger.notInProject();
|
|
158
|
-
process.exit(
|
|
158
|
+
process.exit(1);
|
|
159
159
|
}
|
|
160
160
|
return prepare(path.resolve(userRoot, '.dev/devConfig.js'), projectEntry, port, localUpstream, userRoot)
|
|
161
161
|
.then(() => {
|
|
@@ -10,9 +10,15 @@ class EdgeKV {
|
|
|
10
10
|
try {
|
|
11
11
|
const kvJson = fs.readFileSync(kvPath, 'utf8');
|
|
12
12
|
const kvJsonObj = JSON.parse(kvJson);
|
|
13
|
+
console.log(kvJsonObj);
|
|
13
14
|
Object.keys(kvJsonObj).forEach((namespace) => {
|
|
14
|
-
|
|
15
|
+
const childMap = new Map();
|
|
16
|
+
Object.keys(kvJsonObj[namespace]).forEach((key) => {
|
|
17
|
+
childMap.set(key, JSON.stringify(kvJsonObj[namespace][key]));
|
|
18
|
+
});
|
|
19
|
+
EdgeKV.store.set(namespace, childMap);
|
|
15
20
|
});
|
|
21
|
+
console.log(EdgeKV.store);
|
|
16
22
|
}
|
|
17
23
|
catch (err) {
|
|
18
24
|
console.log(t('kv_parse_failed').d('kv.json parse failed, use empty local kv store.'));
|
|
@@ -187,7 +187,7 @@ class Ew2Server {
|
|
|
187
187
|
agent: new HttpProxyAgent(`http://127.0.0.1:${ew2Port}`)
|
|
188
188
|
});
|
|
189
189
|
const workerHeaders = Object.fromEntries(workerRes.headers.entries());
|
|
190
|
-
//
|
|
190
|
+
// Solve gzip compatibility issue, prevent net::ERR_CONTENT_DECODING_FAILED
|
|
191
191
|
workerHeaders['content-encoding'] = 'identity';
|
|
192
192
|
if (workerRes.body) {
|
|
193
193
|
res.writeHead(workerRes.status, workerHeaders);
|
|
@@ -236,7 +236,6 @@ class Ew2Server {
|
|
|
236
236
|
const key = url.searchParams.get('key');
|
|
237
237
|
const namespace = url.searchParams.get('namespace');
|
|
238
238
|
const body = yield this.parseKVBody(req);
|
|
239
|
-
console.log(body);
|
|
240
239
|
if (!key || !namespace) {
|
|
241
240
|
return {
|
|
242
241
|
success: false
|
|
@@ -40,12 +40,12 @@ const generateEntry = (id, projectEntry, userRoot) => __awaiter(void 0, void 0,
|
|
|
40
40
|
const prepare = (configPath, entry, port, localUpstream, userRoot) => __awaiter(void 0, void 0, void 0, function* () {
|
|
41
41
|
const options = {};
|
|
42
42
|
const currentOptions = { entry, port, localUpstream };
|
|
43
|
-
//
|
|
43
|
+
// Support running multiple deno instances simultaneously
|
|
44
44
|
const id = new Date().getTime().toString();
|
|
45
45
|
// @ts-ignore
|
|
46
46
|
global.id = id;
|
|
47
47
|
yield generateEntry(id, entry, userRoot);
|
|
48
|
-
//
|
|
48
|
+
// Configuration items for each dev session, distinguished by id in one file
|
|
49
49
|
if (fs.existsSync(configPath)) {
|
|
50
50
|
const currentConfig = fs
|
|
51
51
|
.readFileSync(configPath, 'utf-8')
|
|
@@ -101,7 +101,7 @@ const devPack = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
101
101
|
}
|
|
102
102
|
else {
|
|
103
103
|
logger.notInProject();
|
|
104
|
-
process.exit(
|
|
104
|
+
process.exit(1);
|
|
105
105
|
}
|
|
106
106
|
return prepare(path.resolve(userRoot, '.dev/devConfig.js'), projectEntry, port, localUpstream, userRoot)
|
|
107
107
|
.then(() => {
|
|
@@ -100,7 +100,7 @@ export function checkAndUpdatePackage(packageName) {
|
|
|
100
100
|
const spinner = logger.ora;
|
|
101
101
|
spinner.text = t('checking_template_update').d('Checking esa-template updates...');
|
|
102
102
|
spinner.start();
|
|
103
|
-
//
|
|
103
|
+
// Get currently installed version
|
|
104
104
|
const __dirname = getDirName(import.meta.url);
|
|
105
105
|
const packageJsonPath = path.join(__dirname, '../../../');
|
|
106
106
|
let versionInfo;
|
|
@@ -124,7 +124,7 @@ export function checkAndUpdatePackage(packageName) {
|
|
|
124
124
|
}
|
|
125
125
|
const match = versionInfo.match(new RegExp(`(${packageName})@([0-9.]+)`));
|
|
126
126
|
const currentVersion = match ? match[2] : '';
|
|
127
|
-
//
|
|
127
|
+
// Get latest version
|
|
128
128
|
const latestVersion = execSync(`npm view ${packageName} version`, {
|
|
129
129
|
cwd: packageJsonPath
|
|
130
130
|
})
|
|
@@ -173,11 +173,10 @@ export function checkAndUpdatePackage(packageName) {
|
|
|
173
173
|
});
|
|
174
174
|
}
|
|
175
175
|
export const getFrameworkConfig = (framework) => {
|
|
176
|
-
//
|
|
176
|
+
// Read template.jsonc from init directory
|
|
177
177
|
const templatePath = path.join(getDirName(import.meta.url), 'template.jsonc');
|
|
178
178
|
const jsonc = fs.readFileSync(templatePath, 'utf-8');
|
|
179
179
|
const json = JSON.parse(jsonc);
|
|
180
|
-
console.log(json);
|
|
181
180
|
return json[framework];
|
|
182
181
|
};
|
|
183
182
|
/**
|
|
@@ -185,7 +184,7 @@ export const getFrameworkConfig = (framework) => {
|
|
|
185
184
|
* @returns 框架全部配置
|
|
186
185
|
*/
|
|
187
186
|
export const getAllFrameworkConfig = () => {
|
|
188
|
-
//
|
|
187
|
+
// Read template.jsonc from init directory
|
|
189
188
|
const templatePath = path.join(getDirName(import.meta.url), 'template.jsonc');
|
|
190
189
|
const jsonc = fs.readFileSync(templatePath, 'utf-8');
|
|
191
190
|
const json = JSON.parse(jsonc);
|
|
@@ -232,7 +231,7 @@ export function getInitParamsFromArgv(argv) {
|
|
|
232
231
|
params.deploy = Boolean(a.deploy);
|
|
233
232
|
return params;
|
|
234
233
|
}
|
|
235
|
-
//
|
|
234
|
+
// Configure project name
|
|
236
235
|
export const configProjectName = (initParams) => __awaiter(void 0, void 0, void 0, function* () {
|
|
237
236
|
if (initParams.name) {
|
|
238
237
|
log.step(`Project name configured ${initParams.name}`);
|
|
@@ -593,7 +592,7 @@ export const initGit = (initParams) => __awaiter(void 0, void 0, void 0, functio
|
|
|
593
592
|
export function getGitVersion() {
|
|
594
593
|
return __awaiter(this, void 0, void 0, function* () {
|
|
595
594
|
try {
|
|
596
|
-
|
|
595
|
+
let stdout = yield execCommand(['git', '--version'], {
|
|
597
596
|
useSpinner: false,
|
|
598
597
|
silent: true,
|
|
599
598
|
captureOutput: true
|
|
@@ -609,7 +608,7 @@ export function getGitVersion() {
|
|
|
609
608
|
}
|
|
610
609
|
export function isGitInstalled() {
|
|
611
610
|
return __awaiter(this, void 0, void 0, function* () {
|
|
612
|
-
return (yield getGitVersion()) !== null;
|
|
611
|
+
return (yield getGitVersion()) !== '' && (yield getGitVersion()) !== null;
|
|
613
612
|
});
|
|
614
613
|
}
|
|
615
614
|
/**
|
|
@@ -685,7 +684,6 @@ function ensureGitignore(projectRoot, assetsDirectory) {
|
|
|
685
684
|
? `${existingContent.replace(/\n$/, '')}\n${toAppend.join('\n')}\n`
|
|
686
685
|
: `${toAppend.join('\n')}\n`;
|
|
687
686
|
fs.writeFileSync(gitignorePath, newContent, 'utf-8');
|
|
688
|
-
logger.log('Updated .gitignore');
|
|
689
687
|
}
|
|
690
688
|
catch (_a) {
|
|
691
689
|
// Do not fail init due to .gitignore issues
|
|
@@ -14,6 +14,7 @@ import logger from '../../libs/logger.js';
|
|
|
14
14
|
import { validRoutine } from '../../utils/checkIsRoutineCreated.js';
|
|
15
15
|
import { getProjectConfig } from '../../utils/fileUtils/index.js';
|
|
16
16
|
import { checkDirectory, checkIsLoginSuccess } from '../utils.js';
|
|
17
|
+
import { routeBuilder } from '../../components/routeBuilder.js';
|
|
17
18
|
import { transferRouteToRuleString } from './helper.js';
|
|
18
19
|
const addRoute = {
|
|
19
20
|
command: 'add [route] [site]',
|
|
@@ -78,7 +79,6 @@ export function handlerAddRoute(argv) {
|
|
|
78
79
|
name: i.SiteName,
|
|
79
80
|
value: i.SiteId
|
|
80
81
|
}));
|
|
81
|
-
// 获取路由名称,支持直接通过参数传入
|
|
82
82
|
let routeName = argv.alias;
|
|
83
83
|
if (!routeName) {
|
|
84
84
|
const response = yield inquirer.prompt([
|
|
@@ -99,35 +99,18 @@ export function handlerAddRoute(argv) {
|
|
|
99
99
|
let siteName = argv.site;
|
|
100
100
|
let siteId;
|
|
101
101
|
if (!siteName) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
{
|
|
109
|
-
type: 'list',
|
|
110
|
-
name: 'routeSite',
|
|
111
|
-
message: t('create_route_site').d('Select a site that is active in your account:'),
|
|
112
|
-
choices: siteList
|
|
113
|
-
}
|
|
114
|
-
]);
|
|
115
|
-
siteId = response.routeSite;
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
// 根据站点名称查找对应的站点ID
|
|
119
|
-
const matchedSite = siteList.find((site) => site.name === siteName);
|
|
120
|
-
if (matchedSite) {
|
|
121
|
-
siteId = matchedSite.value;
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
logger.error(t('site_not_found').d(`Site "${siteName}" not found in your account`));
|
|
125
|
-
return;
|
|
102
|
+
const response = yield inquirer.prompt([
|
|
103
|
+
{
|
|
104
|
+
type: 'list',
|
|
105
|
+
name: 'routeSite',
|
|
106
|
+
message: t('create_route_site').d('Select a site that is active in your account:'),
|
|
107
|
+
choices: siteList
|
|
126
108
|
}
|
|
127
|
-
|
|
109
|
+
]);
|
|
110
|
+
siteId = response.routeSite;
|
|
128
111
|
}
|
|
129
112
|
else {
|
|
130
|
-
//
|
|
113
|
+
// Find corresponding site ID by site name
|
|
131
114
|
const matchedSite = siteList.find((site) => site.name === siteName);
|
|
132
115
|
if (matchedSite) {
|
|
133
116
|
siteId = matchedSite.value;
|
|
@@ -137,40 +120,24 @@ export function handlerAddRoute(argv) {
|
|
|
137
120
|
return;
|
|
138
121
|
}
|
|
139
122
|
}
|
|
140
|
-
// 获取路由值,支持直接通过参数传入
|
|
141
123
|
let inputRoute = argv.route;
|
|
142
124
|
if (!inputRoute) {
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (!
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
type: 'input',
|
|
152
|
-
name: 'inputRoute',
|
|
153
|
-
message: t('create_route_route').d('Enter a Route (e.g., example.com/*):'),
|
|
154
|
-
validate: (input) => {
|
|
155
|
-
if (!input) {
|
|
156
|
-
return t('route_input_required').d('Route is required');
|
|
157
|
-
}
|
|
158
|
-
if (!input.includes('*') && !input.includes('/')) {
|
|
159
|
-
return t('route_format_invalid').d('Route format is invalid. Please include wildcard (*) or path (/)');
|
|
160
|
-
}
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
]);
|
|
165
|
-
inputRoute = response.inputRoute;
|
|
125
|
+
// Get selected site name for route building
|
|
126
|
+
const selectedSite = siteList.find((site) => site.value === siteId);
|
|
127
|
+
const displaySiteName = selectedSite ? selectedSite.name : siteName;
|
|
128
|
+
// Use route builder
|
|
129
|
+
const builtRoute = yield routeBuilder(displaySiteName);
|
|
130
|
+
if (!builtRoute) {
|
|
131
|
+
logger.info(t('route_build_cancelled').d('Route building cancelled'));
|
|
132
|
+
return;
|
|
166
133
|
}
|
|
134
|
+
inputRoute = builtRoute;
|
|
167
135
|
}
|
|
168
136
|
const rule = transferRouteToRuleString(inputRoute);
|
|
169
137
|
if (!rule) {
|
|
170
138
|
logger.error(t('route_format_invalid').d('Invalid route format'));
|
|
171
139
|
return;
|
|
172
140
|
}
|
|
173
|
-
// 获取站点名称用于显示
|
|
174
141
|
const selectedSite = siteList.find((site) => site.value === siteId);
|
|
175
142
|
const displaySiteName = selectedSite ? selectedSite.name : siteName;
|
|
176
143
|
const req = {
|
|
@@ -72,8 +72,7 @@ export const transferRouteToRuleString = (routePath) => {
|
|
|
72
72
|
export const transferRuleStringToRoute = (ruleStr) => {
|
|
73
73
|
if (!ruleStr) {
|
|
74
74
|
return '';
|
|
75
|
-
}
|
|
76
|
-
// 去掉外层括号并按 " and " 分割
|
|
75
|
+
} // Remove outer brackets and split by " and "
|
|
77
76
|
const cleanedRule = ruleStr.replace(/^\(|\)$/g, '');
|
|
78
77
|
const parts = cleanedRule.split(' and ');
|
|
79
78
|
if (parts.length !== 2) {
|
|
@@ -81,36 +80,36 @@ export const transferRuleStringToRoute = (ruleStr) => {
|
|
|
81
80
|
}
|
|
82
81
|
let host = '';
|
|
83
82
|
let uriPath = '';
|
|
84
|
-
//
|
|
83
|
+
// Process host part
|
|
85
84
|
const hostPart = parts[0].trim();
|
|
86
85
|
if (hostPart.startsWith(`${RuleMatchOperatorEndsWith}(${RuleMatchTypeHost},`)) {
|
|
87
|
-
// host
|
|
86
|
+
// Logic when host matches eq
|
|
88
87
|
// ends_with(http.host, "value")
|
|
89
88
|
const match = hostPart.match(/ends_with\(http\.host,\s*"([^"]+)"\)/);
|
|
90
89
|
if (match) {
|
|
91
|
-
host = `*${match[1]}`; //
|
|
90
|
+
host = `*${match[1]}`; // Add prefix *
|
|
92
91
|
}
|
|
93
92
|
}
|
|
94
93
|
else if (hostPart.startsWith(`${RuleMatchTypeHost} ${RuleMatchOperatorEq}`)) {
|
|
95
|
-
// host
|
|
94
|
+
// Logic when host matches eq
|
|
96
95
|
// http.host eq "value"
|
|
97
96
|
const match = hostPart.match(/http\.host eq "([^"]+)"/);
|
|
98
97
|
if (match) {
|
|
99
98
|
host = match[1];
|
|
100
99
|
}
|
|
101
100
|
}
|
|
102
|
-
//
|
|
101
|
+
// Process uriPath part
|
|
103
102
|
const uriPathPart = parts[1].trim();
|
|
104
103
|
if (uriPathPart.startsWith(`${RuleMatchOperatorStartsWith}(${RuleMatchTypeUriPath},`)) {
|
|
105
|
-
// uriPath
|
|
104
|
+
// Logic when uriPath matches startsWith
|
|
106
105
|
// starts_with(http.request.uri.path, "value")
|
|
107
106
|
const match = uriPathPart.match(/starts_with\(http\.request\.uri\.path,\s*"([^"]+)"\)/);
|
|
108
107
|
if (match) {
|
|
109
|
-
uriPath = `${match[1]}*`; //
|
|
108
|
+
uriPath = `${match[1]}*`; // Add suffix *
|
|
110
109
|
}
|
|
111
110
|
}
|
|
112
111
|
else if (uriPathPart.startsWith(`${RuleMatchTypeUriPath} ${RuleMatchOperatorEq}`)) {
|
|
113
|
-
// uriPath
|
|
112
|
+
// Logic when uriPath matches eq
|
|
114
113
|
// http.request.uri.path eq "value"
|
|
115
114
|
const match = uriPathPart.match(/http\.request\.uri\.path eq "([^"]+)"/);
|
|
116
115
|
if (match) {
|
|
@@ -18,37 +18,55 @@ const list = {
|
|
|
18
18
|
command: 'list',
|
|
19
19
|
describe: `📋 ${t('list_describe').d('List all your routines')}`,
|
|
20
20
|
builder: (yargs) => {
|
|
21
|
-
return yargs
|
|
21
|
+
return yargs
|
|
22
|
+
.option('keyword', {
|
|
23
|
+
alias: 'k',
|
|
24
|
+
describe: t('deploy_option_keyword').d('Keyword to search for routines'),
|
|
25
|
+
type: 'string'
|
|
26
|
+
})
|
|
27
|
+
.usage(`${t('common_usage').d('Usage')}: \$0 list [--keyword <keyword>]`);
|
|
22
28
|
},
|
|
23
29
|
handler: (argv) => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
30
|
handleList(argv);
|
|
25
31
|
})
|
|
26
32
|
};
|
|
27
33
|
export default list;
|
|
34
|
+
export function getAllRoutines(options) {
|
|
35
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
var _a;
|
|
37
|
+
const server = yield ApiService.getInstance();
|
|
38
|
+
const allRoutines = [];
|
|
39
|
+
let pageNumber = 1;
|
|
40
|
+
const pageSize = (options === null || options === void 0 ? void 0 : options.PageSize) || 50;
|
|
41
|
+
while (true) {
|
|
42
|
+
const res = yield server.listUserRoutines({
|
|
43
|
+
RegionId: options === null || options === void 0 ? void 0 : options.RegionId,
|
|
44
|
+
PageNumber: pageNumber,
|
|
45
|
+
PageSize: pageSize,
|
|
46
|
+
SearchKeyWord: options === null || options === void 0 ? void 0 : options.SearchKeyWord
|
|
47
|
+
});
|
|
48
|
+
if (!((_a = res === null || res === void 0 ? void 0 : res.body) === null || _a === void 0 ? void 0 : _a.Routines)) {
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
allRoutines.push(...res.body.Routines);
|
|
52
|
+
const totalCount = res.body.TotalCount;
|
|
53
|
+
const currentCount = allRoutines.length;
|
|
54
|
+
if (currentCount >= totalCount) {
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
pageNumber++;
|
|
58
|
+
}
|
|
59
|
+
return allRoutines;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
28
62
|
export function handleList(argv) {
|
|
29
63
|
return __awaiter(this, void 0, void 0, function* () {
|
|
30
|
-
var _a, _b;
|
|
31
|
-
const { site } = argv;
|
|
32
64
|
const isSuccess = yield checkIsLoginSuccess();
|
|
33
65
|
if (!isSuccess)
|
|
34
66
|
return;
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
SiteSearchType: 'fuzzy',
|
|
39
|
-
Status: 'active',
|
|
40
|
-
PageNumber: 1,
|
|
41
|
-
PageSize: 50
|
|
42
|
-
};
|
|
43
|
-
const res = yield server.listSites(req);
|
|
44
|
-
const siteList = (_a = res === null || res === void 0 ? void 0 : res.data.Sites) !== null && _a !== void 0 ? _a : [];
|
|
45
|
-
const siteNameList = siteList === null || siteList === void 0 ? void 0 : siteList.map((item) => item.SiteName);
|
|
46
|
-
logger.log(chalk.bold.bgGray(`📃 ${t('list_site_name_title').d('List all of site names')}:`));
|
|
47
|
-
logger.tree(siteNameList);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
const res = yield server.listUserRoutines();
|
|
51
|
-
const routineList = (_b = res === null || res === void 0 ? void 0 : res.body) === null || _b === void 0 ? void 0 : _b.Routines;
|
|
67
|
+
const routineList = yield getAllRoutines({
|
|
68
|
+
SearchKeyWord: argv.keyword
|
|
69
|
+
});
|
|
52
70
|
if (routineList) {
|
|
53
71
|
logger.log(chalk.bold.bgGray(`📃 ${t('list_routine_name_title').d('List all of routine')}:`));
|
|
54
72
|
displayRoutineList(routineList);
|
package/dist/commands/utils.js
CHANGED
|
@@ -71,7 +71,7 @@ export const bindRoutineWithDomain = (name, domain) => __awaiter(void 0, void 0,
|
|
|
71
71
|
export function validName(name) {
|
|
72
72
|
return /^[a-zA-Z0-9-_]+$/.test(name);
|
|
73
73
|
}
|
|
74
|
-
//
|
|
74
|
+
// Validate if domain is valid
|
|
75
75
|
export function validDomain(domain) {
|
|
76
76
|
return /^(?:[a-z0-9-](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/.test(domain);
|
|
77
77
|
}
|
|
@@ -131,12 +131,12 @@ export function validateLoginCredentials(accessKeyId_1, accessKeySecret_1, endpo
|
|
|
131
131
|
});
|
|
132
132
|
}
|
|
133
133
|
export function isValidRouteForDomain(route, domain) {
|
|
134
|
-
//
|
|
135
|
-
//
|
|
134
|
+
// Build a regex that allows subdomains and arbitrary paths
|
|
135
|
+
// For example, match URLs like *.example.com/*
|
|
136
136
|
return route.includes(domain);
|
|
137
137
|
}
|
|
138
138
|
export function escapeRegExp(string) {
|
|
139
|
-
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $&
|
|
139
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& represents the entire matched string
|
|
140
140
|
}
|
|
141
141
|
export const getAllSites = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
142
142
|
var _a;
|
|
@@ -51,7 +51,7 @@ export const FilterSelector = ({ data, onSubmit, hideCount = 20 }) => {
|
|
|
51
51
|
else if (tabPressCount === 1) {
|
|
52
52
|
const filteredDataInner = data.filter((site) => site.label.includes(inputValue));
|
|
53
53
|
setFilteredData(filteredDataInner);
|
|
54
|
-
//
|
|
54
|
+
// Enter selection mode when match results >= 1
|
|
55
55
|
if ((filteredDataInner.length >= 1 &&
|
|
56
56
|
showAll &&
|
|
57
57
|
filteredDataInner.length > hideCount) ||
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { Box, render, Text } from 'ink';
|
|
11
|
+
import TextInput from 'ink-text-input';
|
|
12
|
+
import React, { useState } from 'react';
|
|
13
|
+
import t from '../i18n/index.js';
|
|
14
|
+
export const RouteBuilder = ({ siteName, onSubmit, onCancel }) => {
|
|
15
|
+
const [prefix, setPrefix] = useState('');
|
|
16
|
+
const [suffix, setSuffix] = useState('');
|
|
17
|
+
const [currentInput, setCurrentInput] = useState('prefix');
|
|
18
|
+
const [error, setError] = useState('');
|
|
19
|
+
const handleSubmit = () => {
|
|
20
|
+
if (currentInput === 'prefix') {
|
|
21
|
+
setCurrentInput('suffix');
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
// Build complete route, add dot before prefix and slash before suffix if not empty
|
|
25
|
+
const prefixWithDot = prefix ? `${prefix}.` : '';
|
|
26
|
+
const suffixWithDot = suffix ? `/${suffix}` : '';
|
|
27
|
+
const route = `${prefixWithDot}${siteName}${suffixWithDot}`;
|
|
28
|
+
onSubmit(route);
|
|
29
|
+
};
|
|
30
|
+
const handleCancel = () => {
|
|
31
|
+
onCancel();
|
|
32
|
+
};
|
|
33
|
+
const currentPrompt = currentInput === 'prefix'
|
|
34
|
+
? t('route_builder_prefix_prompt')
|
|
35
|
+
.d(`Enter route prefix for ${siteName} (e.g., abc, def):`)
|
|
36
|
+
.replace('${siteName}', siteName)
|
|
37
|
+
: t('route_builder_suffix_prompt')
|
|
38
|
+
.d(`Enter route suffix for ${siteName} (e.g., *, users/*):`)
|
|
39
|
+
.replace('${siteName}', siteName);
|
|
40
|
+
const prefixWithDot = prefix ? `${prefix}.` : '';
|
|
41
|
+
const suffixWithDot = suffix ? `/${suffix}` : '';
|
|
42
|
+
const preview = `Preview: ${prefixWithDot}${siteName}${suffixWithDot}`;
|
|
43
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
44
|
+
React.createElement(Box, null,
|
|
45
|
+
React.createElement(Text, null, "Building route for site: "),
|
|
46
|
+
React.createElement(Text, { color: "cyan" }, siteName)),
|
|
47
|
+
React.createElement(Box, { marginTop: 1 },
|
|
48
|
+
React.createElement(Text, null, currentPrompt)),
|
|
49
|
+
React.createElement(Box, { marginTop: 1 },
|
|
50
|
+
React.createElement(TextInput, { value: currentInput === 'prefix' ? prefix : suffix, onChange: currentInput === 'prefix' ? setPrefix : setSuffix, onSubmit: handleSubmit })),
|
|
51
|
+
preview && (React.createElement(Box, { marginTop: 1 },
|
|
52
|
+
React.createElement(Text, { color: "green" }, preview))),
|
|
53
|
+
React.createElement(Box, { marginTop: 1 },
|
|
54
|
+
React.createElement(Text, { color: "gray" }, t('route_builder_instructions').d('Press Enter to continue, Ctrl+C to cancel'))),
|
|
55
|
+
error && (React.createElement(Box, { marginTop: 1 },
|
|
56
|
+
React.createElement(Text, { color: "red" }, error)))));
|
|
57
|
+
};
|
|
58
|
+
export const routeBuilder = (siteName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
59
|
+
return new Promise((resolve) => {
|
|
60
|
+
const { unmount } = render(React.createElement(RouteBuilder, { siteName: siteName, onSubmit: (route) => {
|
|
61
|
+
unmount();
|
|
62
|
+
resolve(route);
|
|
63
|
+
}, onCancel: () => {
|
|
64
|
+
unmount();
|
|
65
|
+
resolve(null);
|
|
66
|
+
} }));
|
|
67
|
+
});
|
|
68
|
+
});
|
package/dist/i18n/locales.json
CHANGED
|
@@ -204,8 +204,8 @@
|
|
|
204
204
|
"zh_CN": "读取 CLI 配置错误"
|
|
205
205
|
},
|
|
206
206
|
"dev_error_no_project_config": {
|
|
207
|
-
"en": "Error reading project configuration esa.toml file.",
|
|
208
|
-
"zh_CN": "读取项目配置 esa.toml 文件错误"
|
|
207
|
+
"en": "Error reading project configuration esa.jsonc (recommended) or esa.toml file.",
|
|
208
|
+
"zh_CN": "读取项目配置 esa.jsonc (推荐) 或 esa.toml 文件错误"
|
|
209
209
|
},
|
|
210
210
|
"dev_build_start": {
|
|
211
211
|
"en": "Starting build process",
|
|
@@ -1271,8 +1271,44 @@
|
|
|
1271
1271
|
"en": "Global update failed. You may need elevated permissions (sudo) or use yarn/pnpm:",
|
|
1272
1272
|
"zh_CN": "全局更新失败。你可能需要更高权限(sudo)或使用 yarn/pnpm:"
|
|
1273
1273
|
},
|
|
1274
|
+
"deploy_option_keyword": {
|
|
1275
|
+
"en": "Keyword to search for routines",
|
|
1276
|
+
"zh_CN": ""
|
|
1277
|
+
},
|
|
1278
|
+
"route_input_method": {
|
|
1279
|
+
"en": "How would you like to input the route?",
|
|
1280
|
+
"zh_CN": "您希望如何输入路由?"
|
|
1281
|
+
},
|
|
1282
|
+
"route_input_builder": {
|
|
1283
|
+
"en": "Use route builder (prefix + suffix)",
|
|
1284
|
+
"zh_CN": "使用路由构建器(前缀 + 后缀)"
|
|
1285
|
+
},
|
|
1286
|
+
"route_input_manual": {
|
|
1287
|
+
"en": "Enter route manually",
|
|
1288
|
+
"zh_CN": "手动输入路由"
|
|
1289
|
+
},
|
|
1290
|
+
"route_build_cancelled": {
|
|
1291
|
+
"en": "Route building cancelled",
|
|
1292
|
+
"zh_CN": "路由构建已取消"
|
|
1293
|
+
},
|
|
1294
|
+
"route_builder_prefix_prompt": {
|
|
1295
|
+
"en": "Enter route prefix for ${siteName} (e.g., api, v1):",
|
|
1296
|
+
"zh_CN": "为 ${siteName} 输入路由前缀(例如:api, v1):"
|
|
1297
|
+
},
|
|
1298
|
+
"route_builder_suffix_prompt": {
|
|
1299
|
+
"en": "Enter route suffix for ${siteName} (e.g., *, users/*):",
|
|
1300
|
+
"zh_CN": "为 ${siteName} 输入路由后缀(例如:*, users/*):"
|
|
1301
|
+
},
|
|
1302
|
+
"route_builder_preview": {
|
|
1303
|
+
"en": "Preview: ${siteName}${prefix}${suffix}",
|
|
1304
|
+
"zh_CN": "预览:{route}"
|
|
1305
|
+
},
|
|
1306
|
+
"route_builder_instructions": {
|
|
1307
|
+
"en": "Press Enter to continue, Ctrl+C to cancel",
|
|
1308
|
+
"zh_CN": "按回车键继续,Ctrl+C 取消"
|
|
1309
|
+
},
|
|
1274
1310
|
"kv_parse_failed": {
|
|
1275
1311
|
"en": "kv.json parse failed, use empty local kv store.",
|
|
1276
|
-
"zh_CN": ""
|
|
1312
|
+
"zh_CN": "kv.json 解析失败,使用空本地 kv 存储。"
|
|
1277
1313
|
}
|
|
1278
1314
|
}
|
package/dist/libs/apiService.js
CHANGED
|
@@ -90,7 +90,6 @@ export class ApiService {
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
catch (error) {
|
|
93
|
-
console.log('error', error);
|
|
94
93
|
return {
|
|
95
94
|
success: false,
|
|
96
95
|
message: t('login_failed').d('An error occurred while trying to log in.')
|
|
@@ -101,15 +100,15 @@ export class ApiService {
|
|
|
101
100
|
quickDeployRoutine(edgeRoutine) {
|
|
102
101
|
return __awaiter(this, void 0, void 0, function* () {
|
|
103
102
|
try {
|
|
104
|
-
//
|
|
103
|
+
// Upload code to unstable version
|
|
105
104
|
const stagingRes = yield this.getRoutineStagingCodeUploadInfo(edgeRoutine);
|
|
106
105
|
if (stagingRes) {
|
|
107
|
-
//
|
|
106
|
+
// Production version
|
|
108
107
|
const commitRes = yield this.commitRoutineStagingCode({
|
|
109
108
|
Name: edgeRoutine.name,
|
|
110
109
|
CodeDescription: edgeRoutine.description
|
|
111
110
|
});
|
|
112
|
-
//
|
|
111
|
+
// Deploy to production environment
|
|
113
112
|
if (commitRes) {
|
|
114
113
|
const deployRes = yield this.publishRoutineCodeVersion({
|
|
115
114
|
Name: edgeRoutine.name,
|
|
@@ -219,7 +218,7 @@ export class ApiService {
|
|
|
219
218
|
return null;
|
|
220
219
|
});
|
|
221
220
|
}
|
|
222
|
-
listUserRoutines() {
|
|
221
|
+
listUserRoutines(requestParams) {
|
|
223
222
|
return __awaiter(this, void 0, void 0, function* () {
|
|
224
223
|
try {
|
|
225
224
|
let params = {
|
|
@@ -236,7 +235,9 @@ export class ApiService {
|
|
|
236
235
|
return this;
|
|
237
236
|
}
|
|
238
237
|
};
|
|
239
|
-
let request = new $OpenApi.OpenApiRequest(
|
|
238
|
+
let request = new $OpenApi.OpenApiRequest({
|
|
239
|
+
query: requestParams || {}
|
|
240
|
+
});
|
|
240
241
|
let runtime = {
|
|
241
242
|
toMap: function () {
|
|
242
243
|
return this;
|
package/dist/libs/logger.js
CHANGED
|
@@ -180,7 +180,7 @@ class Logger {
|
|
|
180
180
|
this.block();
|
|
181
181
|
this.log('If there is code to deploy, you can either:');
|
|
182
182
|
this.subLog(`- Specify an entry-point to your Routine via the command line (ex: ${chalk.green('esa deploy src/index.ts')})`);
|
|
183
|
-
this.subLog('- Or
|
|
183
|
+
this.subLog('- Or create an "esa.jsonc" file (recommended):');
|
|
184
184
|
console.log('```jsonc\n' +
|
|
185
185
|
'{\n' +
|
|
186
186
|
' "name": "my-routine",\n' +
|
|
@@ -188,7 +188,7 @@ class Logger {
|
|
|
188
188
|
' "dev": { "port": 18080 }\n' +
|
|
189
189
|
'}\n' +
|
|
190
190
|
'```');
|
|
191
|
-
this.subLog('- Or, if you prefer TOML,
|
|
191
|
+
this.subLog('- Or, if you prefer TOML, create an "esa.toml" file:');
|
|
192
192
|
console.log('```toml\n' +
|
|
193
193
|
'name = "my-routine"\n' +
|
|
194
194
|
'entry = "src/index.ts"\n' +
|
|
@@ -197,7 +197,7 @@ class Logger {
|
|
|
197
197
|
'port = 18080\n' +
|
|
198
198
|
'```\n');
|
|
199
199
|
this.log('If you are deploying a directory of static assets, you can either:');
|
|
200
|
-
this.subLog(`-
|
|
200
|
+
this.subLog(`- Create an "esa.jsonc" file (recommended) and run ${chalk.green('esa deploy -a ./dist')}`);
|
|
201
201
|
console.log('```jsonc\n' +
|
|
202
202
|
'{\n' +
|
|
203
203
|
' "name": "my-routine",\n' +
|
|
@@ -206,7 +206,7 @@ class Logger {
|
|
|
206
206
|
' }\n' +
|
|
207
207
|
'}\n' +
|
|
208
208
|
'```');
|
|
209
|
-
this.subLog(`- Or
|
|
209
|
+
this.subLog(`- Or create an "esa.toml" file and run ${chalk.green('esa deploy -a ./dist')}`);
|
|
210
210
|
console.log('```toml\n' +
|
|
211
211
|
'name = "my-routine"\n' +
|
|
212
212
|
'\n' +
|
|
@@ -26,7 +26,7 @@ export function validRoutine(name) {
|
|
|
26
26
|
const isCreatedRoutine = yield isRoutineExist(name);
|
|
27
27
|
if (!isCreatedRoutine) {
|
|
28
28
|
logger.warn(`${t('routine_not_exist').d('Routine does not exist, please create a new one. Run command:')} ${chalk.greenBright('esa deploy')}`);
|
|
29
|
-
exit(
|
|
29
|
+
exit(1);
|
|
30
30
|
}
|
|
31
31
|
});
|
|
32
32
|
}
|
package/dist/utils/compress.js
CHANGED
|
@@ -43,10 +43,10 @@ const compress = (scriptEntry_1, assetsDir_1, ...args_1) => __awaiter(void 0, [s
|
|
|
43
43
|
let assetsDirectory = assetsDir || ((_a = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.assets) === null || _a === void 0 ? void 0 : _a.directory);
|
|
44
44
|
const routineType = checkEdgeRoutineType(scriptEntry, assetsDir, projectPath);
|
|
45
45
|
if (!projectConfig && !scriptEntry && !assetsDir) {
|
|
46
|
-
logger.error('esa.jsonc or esa.toml is not found and script entry or assets directory is not provided by command line');
|
|
47
|
-
exit(
|
|
46
|
+
logger.error('esa.jsonc (recommended) or esa.toml is not found and script entry or assets directory is not provided by command line');
|
|
47
|
+
exit(1);
|
|
48
48
|
}
|
|
49
|
-
//
|
|
49
|
+
// Parameter priority: use parameters if available, otherwise use values from config file
|
|
50
50
|
const entry = scriptEntry || (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.entry);
|
|
51
51
|
if (routineType === EDGE_ROUTINE_TYPE.NOT_EXIST) {
|
|
52
52
|
const errorMessage = [
|
|
@@ -61,7 +61,7 @@ const compress = (scriptEntry_1, assetsDir_1, ...args_1) => __awaiter(void 0, [s
|
|
|
61
61
|
chalk.cyan('🔍 Possible issue causes:'),
|
|
62
62
|
chalk.white(' 1. Entry file path is incorrect or file does not exist'),
|
|
63
63
|
chalk.white(' 2. Assets directory path is incorrect or directory does not exist'),
|
|
64
|
-
chalk.white(` 3. Project configuration file ${chalk.yellow('esa.jsonc')} or ${chalk.yellow('esa.toml')} format error`),
|
|
64
|
+
chalk.white(` 3. Project configuration file ${chalk.yellow('esa.jsonc')} (recommended) or ${chalk.yellow('esa.toml')} format error`),
|
|
65
65
|
chalk.white(` 4. Relative path format error, please use ${chalk.yellow('./xxx')} format`),
|
|
66
66
|
'',
|
|
67
67
|
chalk.yellow.bold(`📍 Please check if the following ${chalk.red('absolute paths')} are correct:`),
|
|
@@ -83,7 +83,7 @@ const compress = (scriptEntry_1, assetsDir_1, ...args_1) => __awaiter(void 0, [s
|
|
|
83
83
|
''
|
|
84
84
|
].join('\n');
|
|
85
85
|
logger.error(errorMessage);
|
|
86
|
-
exit(
|
|
86
|
+
exit(1);
|
|
87
87
|
}
|
|
88
88
|
if (routineType === EDGE_ROUTINE_TYPE.JS_ONLY ||
|
|
89
89
|
routineType === EDGE_ROUTINE_TYPE.JS_AND_ASSETS) {
|
package/dist/utils/download.js
CHANGED
|
@@ -92,8 +92,8 @@ function isBinDirInPath(binDir) {
|
|
|
92
92
|
*/
|
|
93
93
|
function addBinDirToPath(binDir) {
|
|
94
94
|
return __awaiter(this, void 0, void 0, function* () {
|
|
95
|
-
//
|
|
96
|
-
// setx
|
|
95
|
+
// Use setx to add to PATH
|
|
96
|
+
// setx has a 2047 character limit for PATH
|
|
97
97
|
const command = `setx Path "%Path%;${binDir}"`;
|
|
98
98
|
try {
|
|
99
99
|
yield execAsync(command);
|
|
@@ -17,8 +17,31 @@ import { getDirName, getRoot } from './base.js';
|
|
|
17
17
|
const projectConfigFile = 'esa.toml';
|
|
18
18
|
const __dirname = getDirName(import.meta.url);
|
|
19
19
|
const root = getRoot();
|
|
20
|
-
|
|
20
|
+
// Function to get the actual project config file path (supports both .jsonc and .toml)
|
|
21
|
+
export const getProjectConfigPath = (filePath = root) => {
|
|
22
|
+
const configFormats = ['esa.jsonc', 'esa.toml'];
|
|
23
|
+
for (const format of configFormats) {
|
|
24
|
+
const configPath = path.join(filePath, format);
|
|
25
|
+
if (fs.existsSync(configPath)) {
|
|
26
|
+
return configPath;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Default to .jsonc if no config file exists
|
|
30
|
+
return path.join(filePath, 'esa.jsonc');
|
|
31
|
+
};
|
|
32
|
+
export const projectConfigPath = getProjectConfigPath();
|
|
21
33
|
export const cliConfigPath = path.join(os.homedir(), '.esa/config/default.toml');
|
|
34
|
+
// Function to get the actual config file path (supports both .toml and .jsonc)
|
|
35
|
+
export const getCliConfigPath = () => {
|
|
36
|
+
const configDir = path.join(os.homedir(), '.esa/config');
|
|
37
|
+
const jsoncPath = path.join(configDir, 'default.jsonc');
|
|
38
|
+
const tomlPath = path.join(configDir, 'default.toml');
|
|
39
|
+
// Check if JSONC file exists first, then fallback to TOML
|
|
40
|
+
if (fs.existsSync(jsoncPath)) {
|
|
41
|
+
return jsoncPath;
|
|
42
|
+
}
|
|
43
|
+
return tomlPath;
|
|
44
|
+
};
|
|
22
45
|
export const hiddenConfigDir = path.join(os.homedir(), '.esa/config');
|
|
23
46
|
export const generateHiddenConfigDir = () => {
|
|
24
47
|
if (!fs.existsSync(hiddenConfigDir)) {
|
|
@@ -28,7 +51,7 @@ export const generateHiddenConfigDir = () => {
|
|
|
28
51
|
export const generateToml = (path) => {
|
|
29
52
|
if (!fs.existsSync(path)) {
|
|
30
53
|
fs.writeFileSync(path, '', 'utf-8');
|
|
31
|
-
//
|
|
54
|
+
// Add default endpoint
|
|
32
55
|
const defaultConfig = {
|
|
33
56
|
endpoint: 'esa.cn-hangzhou.aliyuncs.com'
|
|
34
57
|
};
|
|
@@ -37,20 +60,34 @@ export const generateToml = (path) => {
|
|
|
37
60
|
};
|
|
38
61
|
export const generateDefaultConfig = () => {
|
|
39
62
|
generateHiddenConfigDir();
|
|
40
|
-
|
|
63
|
+
const configPath = getCliConfigPath();
|
|
64
|
+
generateToml(configPath);
|
|
41
65
|
};
|
|
42
66
|
export function updateProjectConfigFile(configUpdate_1) {
|
|
43
67
|
return __awaiter(this, arguments, void 0, function* (configUpdate, filePath = root) {
|
|
44
|
-
const configPath =
|
|
68
|
+
const configPath = getProjectConfigPath(filePath);
|
|
45
69
|
try {
|
|
46
70
|
let configFileContent = yield fsPromises.readFile(configPath, 'utf8');
|
|
47
|
-
let config
|
|
48
|
-
|
|
49
|
-
|
|
71
|
+
let config;
|
|
72
|
+
let updatedConfigString;
|
|
73
|
+
// Detect file format based on file extension
|
|
74
|
+
if (configPath.endsWith('.jsonc') || configPath.endsWith('.json')) {
|
|
75
|
+
// Handle JSONC format
|
|
76
|
+
const jsonContent = configFileContent.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
|
|
77
|
+
config = JSON.parse(jsonContent);
|
|
78
|
+
config = Object.assign(Object.assign({}, config), configUpdate);
|
|
79
|
+
updatedConfigString = JSON.stringify(config, null, 2) + '\n';
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// Handle TOML format (default)
|
|
83
|
+
config = toml.parse(configFileContent);
|
|
84
|
+
config = Object.assign(Object.assign({}, config), configUpdate);
|
|
85
|
+
updatedConfigString = toml.stringify(config);
|
|
86
|
+
}
|
|
50
87
|
yield fsPromises.writeFile(configPath, updatedConfigString);
|
|
51
88
|
}
|
|
52
89
|
catch (error) {
|
|
53
|
-
logger.error(`Error updating
|
|
90
|
+
logger.error(`Error updating config file: ${error}`);
|
|
54
91
|
logger.pathEacces(__dirname);
|
|
55
92
|
}
|
|
56
93
|
});
|
|
@@ -58,16 +95,30 @@ export function updateProjectConfigFile(configUpdate_1) {
|
|
|
58
95
|
export function updateCliConfigFile(configUpdate) {
|
|
59
96
|
return __awaiter(this, void 0, void 0, function* () {
|
|
60
97
|
try {
|
|
61
|
-
|
|
62
|
-
let
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
98
|
+
const configPath = getCliConfigPath();
|
|
99
|
+
let configFileContent = yield fsPromises.readFile(configPath, 'utf8');
|
|
100
|
+
let config;
|
|
101
|
+
let updatedConfigString;
|
|
102
|
+
// Detect file format based on file extension
|
|
103
|
+
if (configPath.endsWith('.jsonc') || configPath.endsWith('.json')) {
|
|
104
|
+
// Handle JSONC format
|
|
105
|
+
const jsonContent = configFileContent.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
|
|
106
|
+
config = JSON.parse(jsonContent);
|
|
107
|
+
config = Object.assign(Object.assign({}, config), configUpdate);
|
|
108
|
+
updatedConfigString = JSON.stringify(config, null, 2) + '\n';
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
// Handle TOML format (default)
|
|
112
|
+
config = toml.parse(configFileContent);
|
|
113
|
+
config = Object.assign(Object.assign({}, config), configUpdate);
|
|
114
|
+
updatedConfigString = toml.stringify(config);
|
|
115
|
+
}
|
|
116
|
+
yield fsPromises.writeFile(configPath, updatedConfigString);
|
|
66
117
|
}
|
|
67
118
|
catch (error) {
|
|
68
|
-
logger.error(`Error updating
|
|
119
|
+
logger.error(`Error updating config file: ${error}`);
|
|
69
120
|
logger.pathEacces(__dirname);
|
|
70
|
-
throw new Error('
|
|
121
|
+
throw new Error('Config update error');
|
|
71
122
|
}
|
|
72
123
|
});
|
|
73
124
|
}
|
|
@@ -88,7 +139,6 @@ export function readConfigFile(configPath) {
|
|
|
88
139
|
}
|
|
89
140
|
}
|
|
90
141
|
catch (error) {
|
|
91
|
-
console.log(error);
|
|
92
142
|
logger.error(`Error parsing config file: ${error}`);
|
|
93
143
|
return null;
|
|
94
144
|
}
|
|
@@ -96,7 +146,8 @@ export function readConfigFile(configPath) {
|
|
|
96
146
|
return null;
|
|
97
147
|
}
|
|
98
148
|
export function getCliConfig() {
|
|
99
|
-
const
|
|
149
|
+
const configPath = getCliConfigPath();
|
|
150
|
+
const res = readConfigFile(configPath);
|
|
100
151
|
if (!res) {
|
|
101
152
|
return null;
|
|
102
153
|
}
|
|
@@ -133,7 +184,7 @@ export function getConfigurations() {
|
|
|
133
184
|
}
|
|
134
185
|
}
|
|
135
186
|
export function generateConfigFile(projectName_1, initConfigs_1, targetDir_1) {
|
|
136
|
-
return __awaiter(this, arguments, void 0, function* (projectName, initConfigs, targetDir, configFormat = '
|
|
187
|
+
return __awaiter(this, arguments, void 0, function* (projectName, initConfigs, targetDir, configFormat = 'jsonc', notFoundStrategy) {
|
|
137
188
|
var _a, _b;
|
|
138
189
|
const outputDir = targetDir !== null && targetDir !== void 0 ? targetDir : process.cwd();
|
|
139
190
|
const currentDirName = path.basename(outputDir);
|