@lark-apaas/miaoda-cli 0.1.23 → 0.1.24-alpha.1425dbf
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/api/app/api.js +20 -0
- package/dist/api/app/index.js +2 -1
- package/dist/cli/commands/app/index.js +60 -7
- package/dist/cli/commands/deploy/modern.js +1 -1
- package/dist/cli/handlers/app/export.js +185 -0
- package/dist/cli/handlers/app/index.js +5 -1
- package/dist/cli/handlers/app/sync.js +26 -8
- package/dist/cli/handlers/deploy/patch.js +1 -1
- package/dist/config/migrate-configs/vite-react-to-nestjs-react-fullstack.js +4 -0
- package/dist/services/app/init/template.js +1 -1
- package/dist/services/deploy/modern/patch/index.js +1 -1
- package/dist/services/deploy/modern/pipelines/design-local.js +0 -4
- package/dist/services/deploy/modern/pipelines/local.js +0 -4
- package/package.json +1 -1
package/dist/api/app/api.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getAppInfo = getAppInfo;
|
|
4
4
|
exports.updateAppMeta = updateAppMeta;
|
|
5
|
+
exports.getCodeArchive = getCodeArchive;
|
|
5
6
|
const http_1 = require("../../utils/http");
|
|
6
7
|
const devops_error_1 = require("../../utils/devops-error");
|
|
7
8
|
const DEFAULT_ERR_CODE = 'INTERNAL_DEVOPS_ERROR';
|
|
@@ -23,3 +24,22 @@ async function updateAppMeta(req) {
|
|
|
23
24
|
// 路径已带 appID,body 里也保留以匹配 BAM IDL 的 sensitive:"no" 透传约定
|
|
24
25
|
return (0, http_1.postInnerApi)(url, req, envelopeOpts('Failed to update app'));
|
|
25
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* GET /api/v1/studio/innerapi/apps/:appID/code-archive?sourceAppID=xxx — 导出源应用源码归档。
|
|
29
|
+
* 走 studio_server inner 通道(force 身份,服务侧 force→lark 换取后按 DOWNLOAD 鉴权,
|
|
30
|
+
* 鉴权对象是 sourceAppID),与 comment 域同一 inner 信封;创意应用升级链路(app export)消费。
|
|
31
|
+
*
|
|
32
|
+
* path :appID 必须是当前沙箱应用:网关 apaas_force_admin_plugin 强校验 URL appID 与沙箱
|
|
33
|
+
* AK 绑定应用一致(不一致 400 "appID in url is illegal"),跨应用导出目标因此走 query。
|
|
34
|
+
*/
|
|
35
|
+
async function getCodeArchive(params) {
|
|
36
|
+
const { appID, sourceAppID, checkpointID } = params;
|
|
37
|
+
let url = `/api/v1/studio/innerapi/apps/${encodeURIComponent(appID)}/code-archive` +
|
|
38
|
+
`?sourceAppID=${encodeURIComponent(sourceAppID)}`;
|
|
39
|
+
if (checkpointID !== undefined && checkpointID > 0) {
|
|
40
|
+
url += `&checkPointID=${String(checkpointID)}`;
|
|
41
|
+
}
|
|
42
|
+
return (0, http_1.getInnerApi)(url, {
|
|
43
|
+
errPrefix: 'Failed to export code archive',
|
|
44
|
+
});
|
|
45
|
+
}
|
package/dist/api/app/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ArchType = exports.Source = exports.BizType = exports.AppType = exports.AppMode = exports.AppStatus = exports.appMetaSchema = exports.updateAppMeta = exports.getAppInfo = void 0;
|
|
3
|
+
exports.ArchType = exports.Source = exports.BizType = exports.AppType = exports.AppMode = exports.AppStatus = exports.appMetaSchema = exports.getCodeArchive = exports.updateAppMeta = exports.getAppInfo = void 0;
|
|
4
4
|
var api_1 = require("./api");
|
|
5
5
|
Object.defineProperty(exports, "getAppInfo", { enumerable: true, get: function () { return api_1.getAppInfo; } });
|
|
6
6
|
Object.defineProperty(exports, "updateAppMeta", { enumerable: true, get: function () { return api_1.updateAppMeta; } });
|
|
7
|
+
Object.defineProperty(exports, "getCodeArchive", { enumerable: true, get: function () { return api_1.getCodeArchive; } });
|
|
7
8
|
var schemas_1 = require("./schemas");
|
|
8
9
|
Object.defineProperty(exports, "appMetaSchema", { enumerable: true, get: function () { return schemas_1.appMetaSchema; } });
|
|
9
10
|
var types_1 = require("./types");
|
|
@@ -21,6 +21,7 @@ function registerAppCommands(program, opts = {}) {
|
|
|
21
21
|
`);
|
|
22
22
|
registerAppGet(appCmd);
|
|
23
23
|
registerAppUpdate(appCmd);
|
|
24
|
+
registerAppExport(appCmd);
|
|
24
25
|
if (opts.includeInit) {
|
|
25
26
|
registerAppInit(appCmd);
|
|
26
27
|
registerAppSync(appCmd);
|
|
@@ -96,6 +97,9 @@ function registerAppSync(parent) {
|
|
|
96
97
|
action-plugin postinstall 在 npm install 时缺平台 env 的卡点(需要时再
|
|
97
98
|
FORCE_AUTHN_INNERAPI_DOMAIN=... npm install 手动跑一次)。
|
|
98
99
|
|
|
100
|
+
stack 未纳入 sync 范围(无 SyncConfig 且无 upgrade/templates/<stack>/,如 design-html
|
|
101
|
+
buildless 静态 HTML)→ 跳过同步(no-op, skipped=true),退出码 0,不阻断 dev/启动链路。
|
|
102
|
+
|
|
99
103
|
JSON 输出
|
|
100
104
|
{"data": {"stack": "...",
|
|
101
105
|
"appliedRules": [{"type": "...", "action": "...", "path": "...", "detail": "..."}],
|
|
@@ -103,6 +107,7 @@ JSON 输出
|
|
|
103
107
|
"mergedJsonFiles": [{"path": "...", "keys": [...]}],
|
|
104
108
|
"patchedScripts": [...],
|
|
105
109
|
"upgradedPackages": [{"name": "...", "from": "...", "to": "...", "section": "..."}]}}
|
|
110
|
+
跳过时:{"data": {"stack": "...", "skipped": true, "reason": "stack_not_in_sync_scope", ...空数组}}
|
|
106
111
|
|
|
107
112
|
示例
|
|
108
113
|
$ miaoda app sync
|
|
@@ -115,6 +120,54 @@ JSON 输出
|
|
|
115
120
|
});
|
|
116
121
|
}));
|
|
117
122
|
}
|
|
123
|
+
function registerAppExport(parent) {
|
|
124
|
+
const cmd = parent
|
|
125
|
+
.command('export <app-id>')
|
|
126
|
+
.description('导出指定应用的源码到本工程(创意应用升级:拉取创意稿作只读参考物)')
|
|
127
|
+
.option('--out <dir>', '输出目录(相对当前目录)', 'source_package/creative')
|
|
128
|
+
.option('--checkpoint <n>', '按检查点版本导出;缺省为最新提交(HEAD)')
|
|
129
|
+
.addHelpText('after', `
|
|
130
|
+
说明
|
|
131
|
+
从服务端导出 <app-id> 对应应用(源应用,可以不是当前应用)的源码归档并解压到 --out
|
|
132
|
+
目录,导出完成后写 --out/.upgrade-manifest.json(含 sourceAppId / 导出时间 / 文件数),
|
|
133
|
+
供升级链路幂等判定与 skill 发现使用。调用者须为源应用协作者(服务端 DOWNLOAD 鉴权)。
|
|
134
|
+
请求以当前应用(MIAODA_APP_ID)为路径主体、源应用走 sourceAppID 参数。
|
|
135
|
+
|
|
136
|
+
幂等
|
|
137
|
+
--out 已存在 manifest 且 sourceAppId 一致时跳过导出(skipped=true),重复调用安全。
|
|
138
|
+
|
|
139
|
+
JSON 输出
|
|
140
|
+
{"data": {"appId": "...", "out": "source_package/creative", "fileCount": <n>,
|
|
141
|
+
"archiveName": "...", "skipped": false}}
|
|
142
|
+
跳过时:{"data": {"appId": "...", "out": "...", "skipped": true, "reason": "already_exported"}}
|
|
143
|
+
|
|
144
|
+
失败
|
|
145
|
+
源应用无可导出内容(从未提交过代码)→ EXPORT_EMPTY_ARCHIVE,请先在源应用完成一轮创作。
|
|
146
|
+
无权限(非源应用协作者)→ 服务端鉴权错误透传。
|
|
147
|
+
|
|
148
|
+
示例
|
|
149
|
+
$ miaoda app export app_demo_source
|
|
150
|
+
$ miaoda app export app_demo_source --out source_package/creative
|
|
151
|
+
$ miaoda app export app_demo_source --checkpoint 3
|
|
152
|
+
`);
|
|
153
|
+
cmd.action((0, shared_1.withHelp)(cmd, async (appId, rawOpts) => {
|
|
154
|
+
const checkpointRaw = rawOpts.checkpoint;
|
|
155
|
+
let checkpoint;
|
|
156
|
+
if (checkpointRaw !== undefined) {
|
|
157
|
+
checkpoint = Number(checkpointRaw);
|
|
158
|
+
if (!Number.isInteger(checkpoint) || checkpoint <= 0) {
|
|
159
|
+
(0, shared_1.failArgs)(`--checkpoint 须为正整数:${checkpointRaw}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
await (0, index_1.handleAppExport)({
|
|
163
|
+
appId,
|
|
164
|
+
// path :appID 必须是当前沙箱应用(网关 AK 校验),从 MIAODA_APP_ID/app_id 解析
|
|
165
|
+
currentAppId: (0, shared_1.resolveAppId)({}),
|
|
166
|
+
out: rawOpts.out,
|
|
167
|
+
checkpoint,
|
|
168
|
+
});
|
|
169
|
+
}));
|
|
170
|
+
}
|
|
118
171
|
function registerAppGet(parent) {
|
|
119
172
|
const cmd = parent
|
|
120
173
|
.command('get')
|
|
@@ -183,8 +236,8 @@ function registerAppInit(parent) {
|
|
|
183
236
|
env 未设置时回退到 meta.json.app_id。
|
|
184
237
|
|
|
185
238
|
技术栈解析(--template / --app-type)
|
|
186
|
-
--template 传了 → 直接用(vite-react / html / nestjs-react-fullstack)
|
|
187
|
-
否则 --app-type 传了 → 查表:html→html, modern_html→html, jspage→vite-react, full_stack→nestjs-react-fullstack
|
|
239
|
+
--template 传了 → 直接用(vite-react / html / design-html / nestjs-react-fullstack)
|
|
240
|
+
否则 --app-type 传了 → 查表:html→design-html, modern_html→html, jspage→vite-react, full_stack→nestjs-react-fullstack
|
|
188
241
|
两者都没传 → 报错 ARGS_INVALID
|
|
189
242
|
|
|
190
243
|
源码导入(--source-path)
|
|
@@ -193,11 +246,11 @@ function registerAppInit(parent) {
|
|
|
193
246
|
source-path 不存在 → 报错;非 modern_html 传了 source-path → 警告并忽略,继续正常 init。
|
|
194
247
|
app_type 不写入 .spark/meta.json。
|
|
195
248
|
|
|
196
|
-
|
|
197
|
-
init
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
249
|
+
平台同步(不在 init 内做)
|
|
250
|
+
init 不跑 'miaoda app sync' 的任何子动作(SyncRule 应用 / 平台脚本覆盖 / patches /
|
|
251
|
+
升 @lark-apaas/* 到 latest)。渲染出的 scripts/ 等是 template 包发版时的版本,
|
|
252
|
+
package.json 与 template 完全一致。首次同步交给 'miaoda app sync':本地 dev.sh 入口
|
|
253
|
+
起服务前会先跑一次,沙箱 pod 启动阶段平台侧也会做,init 不重复。
|
|
201
254
|
|
|
202
255
|
依赖安装
|
|
203
256
|
默认:npm install --no-audit --no-fund
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.UPGRADE_MANIFEST_FILENAME = exports.DEFAULT_EXPORT_OUT = void 0;
|
|
40
|
+
exports.handleAppExport = handleAppExport;
|
|
41
|
+
const node_child_process_1 = require("node:child_process");
|
|
42
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
43
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
44
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
45
|
+
const api = __importStar(require("../../../api/index"));
|
|
46
|
+
const error_1 = require("../../../utils/error");
|
|
47
|
+
const output_1 = require("../../../utils/output");
|
|
48
|
+
const logger_1 = require("../../../utils/logger");
|
|
49
|
+
/** 导出目录默认值:创意升级链路的参考物约定位置。 */
|
|
50
|
+
exports.DEFAULT_EXPORT_OUT = 'source_package/creative';
|
|
51
|
+
/** 升级 manifest 文件名:前置钩子幂等标记 / skill workspace-contains 锚点 / skill 第 0 步信息源。 */
|
|
52
|
+
exports.UPGRADE_MANIFEST_FILENAME = '.upgrade-manifest.json';
|
|
53
|
+
/** 解码后归档大小上限(对齐服务端 UploadHtmlArtifact 的 50MB 口径)。 */
|
|
54
|
+
const MAX_ARCHIVE_BYTES = 50 * 1024 * 1024;
|
|
55
|
+
/** 校验相对输出路径:禁绝对路径、禁含 ".." 段(与 deploy patch 的 normalizeRel 同口径)。 */
|
|
56
|
+
function normalizeOutDir(rel) {
|
|
57
|
+
if (node_path_1.default.isAbsolute(rel) || rel.startsWith('/')) {
|
|
58
|
+
throw new error_1.AppError('ARGS_INVALID', `输出目录不能是绝对路径:${rel}`);
|
|
59
|
+
}
|
|
60
|
+
const posix = rel.split(node_path_1.default.sep).join('/').replace(/^\.\//, '');
|
|
61
|
+
if (posix.split('/').includes('..')) {
|
|
62
|
+
throw new error_1.AppError('ARGS_INVALID', `输出目录不能包含 "..":${rel}`);
|
|
63
|
+
}
|
|
64
|
+
return posix;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 按魔数识别归档格式并解压到 destDir。
|
|
68
|
+
* 服务端 GetCodeArchive 的归档名以 .zip 结尾,但底层 git archive 格式由 devops_platform
|
|
69
|
+
* 决定,历史文档亦有 tar.gz 记载 —— 两种都兼容,识别不了才报错。
|
|
70
|
+
*/
|
|
71
|
+
function extractArchive(archivePath, destDir, head) {
|
|
72
|
+
const isZip = head.length >= 4 && head[0] === 0x50 && head[1] === 0x4b;
|
|
73
|
+
const isGzip = head.length >= 2 && head[0] === 0x1f && head[1] === 0x8b;
|
|
74
|
+
if (isZip) {
|
|
75
|
+
(0, node_child_process_1.execFileSync)('unzip', ['-q', '-o', archivePath, '-d', destDir], { stdio: 'pipe' });
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (isGzip) {
|
|
79
|
+
(0, node_child_process_1.execFileSync)('tar', ['-xzf', archivePath, '-C', destDir], { stdio: 'pipe' });
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
throw new error_1.AppError('EXPORT_ARCHIVE_INVALID', '无法识别归档格式(非 zip / tar.gz)', {
|
|
83
|
+
next_actions: ['稍后重试 miaoda app export;持续失败请携带 log_id 反馈平台'],
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function countFiles(dir) {
|
|
87
|
+
let count = 0;
|
|
88
|
+
const walk = (cur) => {
|
|
89
|
+
for (const entry of node_fs_1.default.readdirSync(cur, { withFileTypes: true })) {
|
|
90
|
+
if (entry.isDirectory())
|
|
91
|
+
walk(node_path_1.default.join(cur, entry.name));
|
|
92
|
+
else
|
|
93
|
+
count += 1;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
walk(dir);
|
|
97
|
+
return count;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* miaoda app export <app-id> [--out <dir>] [--checkpoint <n>]
|
|
101
|
+
*
|
|
102
|
+
* 创意应用升级链路:把源应用(创意稿)的源码从服务端导出到本工程,作为只读参考物。
|
|
103
|
+
* 链路:studio_server InnerGetCodeArchive(inner 通道,force 身份鉴权:调用者须为源应用
|
|
104
|
+
* 协作者)→ git archive → 本地解压 → 末尾写 .upgrade-manifest.json(幂等标记 +
|
|
105
|
+
* skill workspace-contains 锚点 + skill 第 0 步信息源)。
|
|
106
|
+
*
|
|
107
|
+
* URL 形状:path :appID 是当前沙箱应用(网关强校验其与沙箱 AK 一致),源应用走 query
|
|
108
|
+
* sourceAppID —— 跨应用(升级常态:新应用沙箱里导出源创意应用)必须如此。
|
|
109
|
+
*
|
|
110
|
+
* 幂等:--out 已存在 manifest 且 sourceAppId 一致时跳过导出直接返回(重试/多轮不重复拉取)。
|
|
111
|
+
*/
|
|
112
|
+
async function handleAppExport(opts) {
|
|
113
|
+
const appId = (opts.appId || '').trim();
|
|
114
|
+
if (!appId) {
|
|
115
|
+
throw new error_1.AppError('ARGS_INVALID', 'app-id 不能为空');
|
|
116
|
+
}
|
|
117
|
+
// 当前沙箱应用:网关 AK 校验要求 path :appID 与沙箱绑定应用一致
|
|
118
|
+
const currentAppId = (opts.currentAppId || '').trim();
|
|
119
|
+
if (!currentAppId) {
|
|
120
|
+
throw new error_1.AppError('APP_ID_MISSING', '未指定当前应用', {
|
|
121
|
+
next_actions: ['设置 export MIAODA_APP_ID=<id>'],
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
const outRel = normalizeOutDir(opts.out ?? exports.DEFAULT_EXPORT_OUT);
|
|
125
|
+
const outDir = node_path_1.default.resolve(process.cwd(), outRel);
|
|
126
|
+
const manifestPath = node_path_1.default.join(outDir, exports.UPGRADE_MANIFEST_FILENAME);
|
|
127
|
+
// 幂等:同源应用已导出过则直接复用(前置钩子重试 / 多轮对话不重复拉取)
|
|
128
|
+
if (node_fs_1.default.existsSync(manifestPath)) {
|
|
129
|
+
try {
|
|
130
|
+
const prev = JSON.parse(node_fs_1.default.readFileSync(manifestPath, 'utf-8'));
|
|
131
|
+
if (prev.sourceAppId === appId) {
|
|
132
|
+
(0, logger_1.log)('export', `Already exported (manifest matched), skip: ${outRel}`);
|
|
133
|
+
(0, output_1.emit)({ data: { appId, out: outRel, skipped: true, reason: 'already_exported' } });
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// manifest 损坏视为未导出,走覆盖导出
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
(0, logger_1.log)('export', `Fetching code archive of ${appId}...`);
|
|
142
|
+
const resp = await api.app.getCodeArchive({
|
|
143
|
+
appID: currentAppId,
|
|
144
|
+
sourceAppID: appId,
|
|
145
|
+
checkpointID: opts.checkpoint,
|
|
146
|
+
});
|
|
147
|
+
const fileBase64 = resp.file ?? '';
|
|
148
|
+
if (!fileBase64) {
|
|
149
|
+
throw new error_1.AppError('EXPORT_EMPTY_ARCHIVE', '源应用没有可导出的内容(可能从未提交过代码)', {
|
|
150
|
+
next_actions: ['请先在源应用完成一轮创作(至少一次成功提交)后重试 miaoda app export'],
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
const archive = Buffer.from(fileBase64, 'base64');
|
|
154
|
+
if (archive.length === 0) {
|
|
155
|
+
throw new error_1.AppError('EXPORT_EMPTY_ARCHIVE', '归档内容为空,请稍后重试');
|
|
156
|
+
}
|
|
157
|
+
if (archive.length > MAX_ARCHIVE_BYTES) {
|
|
158
|
+
throw new error_1.AppError('EXPORT_ARCHIVE_TOO_LARGE', `归档超过大小上限(${String(archive.length)} > ${String(MAX_ARCHIVE_BYTES)} bytes)`);
|
|
159
|
+
}
|
|
160
|
+
// 归档先落临时文件再解压;解压成功前不动已存在的 outDir 内容之外的文件
|
|
161
|
+
const tmpDir = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), 'miaoda-export-'));
|
|
162
|
+
const archivePath = node_path_1.default.join(tmpDir, resp.name ?? `${appId}.zip`);
|
|
163
|
+
try {
|
|
164
|
+
node_fs_1.default.writeFileSync(archivePath, archive);
|
|
165
|
+
node_fs_1.default.mkdirSync(outDir, { recursive: true });
|
|
166
|
+
(0, logger_1.log)('export', `Extracting to ${outRel}...`);
|
|
167
|
+
extractArchive(archivePath, outDir, archive.subarray(0, 4));
|
|
168
|
+
}
|
|
169
|
+
finally {
|
|
170
|
+
node_fs_1.default.rmSync(tmpDir, { recursive: true, force: true });
|
|
171
|
+
}
|
|
172
|
+
const fileCount = countFiles(outDir);
|
|
173
|
+
const manifest = {
|
|
174
|
+
sourceAppId: appId,
|
|
175
|
+
archiveName: resp.name ?? '',
|
|
176
|
+
checkpointId: opts.checkpoint ?? 0,
|
|
177
|
+
exportedAt: new Date().toISOString(),
|
|
178
|
+
fileCount,
|
|
179
|
+
};
|
|
180
|
+
node_fs_1.default.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
|
|
181
|
+
(0, logger_1.log)('export', 'Exported successfully');
|
|
182
|
+
(0, output_1.emit)({
|
|
183
|
+
data: { appId, out: outRel, fileCount, archiveName: manifest.archiveName, skipped: false },
|
|
184
|
+
});
|
|
185
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SUPPORTED_STACKS = exports.handleAppMigrate = exports.handleAppUpgrade = exports.handleAppSync = exports.handleAppInit = exports.handleAppUpdate = exports.handleAppGet = void 0;
|
|
3
|
+
exports.SUPPORTED_STACKS = exports.handleAppMigrate = exports.UPGRADE_MANIFEST_FILENAME = exports.DEFAULT_EXPORT_OUT = exports.handleAppExport = exports.handleAppUpgrade = exports.handleAppSync = exports.handleAppInit = exports.handleAppUpdate = exports.handleAppGet = void 0;
|
|
4
4
|
var get_1 = require("./get");
|
|
5
5
|
Object.defineProperty(exports, "handleAppGet", { enumerable: true, get: function () { return get_1.handleAppGet; } });
|
|
6
6
|
var update_1 = require("./update");
|
|
@@ -10,6 +10,10 @@ Object.defineProperty(exports, "handleAppInit", { enumerable: true, get: functio
|
|
|
10
10
|
var sync_1 = require("./sync");
|
|
11
11
|
Object.defineProperty(exports, "handleAppSync", { enumerable: true, get: function () { return sync_1.handleAppSync; } });
|
|
12
12
|
Object.defineProperty(exports, "handleAppUpgrade", { enumerable: true, get: function () { return sync_1.handleAppUpgrade; } });
|
|
13
|
+
var export_1 = require("./export");
|
|
14
|
+
Object.defineProperty(exports, "handleAppExport", { enumerable: true, get: function () { return export_1.handleAppExport; } });
|
|
15
|
+
Object.defineProperty(exports, "DEFAULT_EXPORT_OUT", { enumerable: true, get: function () { return export_1.DEFAULT_EXPORT_OUT; } });
|
|
16
|
+
Object.defineProperty(exports, "UPGRADE_MANIFEST_FILENAME", { enumerable: true, get: function () { return export_1.UPGRADE_MANIFEST_FILENAME; } });
|
|
13
17
|
var migrate_1 = require("./migrate");
|
|
14
18
|
Object.defineProperty(exports, "handleAppMigrate", { enumerable: true, get: function () { return migrate_1.handleAppMigrate; } });
|
|
15
19
|
// commands 层渲染 help 时需要这份枚举;从 handler barrel 转发,避免 commands → services 越界
|
|
@@ -54,7 +54,8 @@ const MANAGED_PLATFORM_PACKAGES = {
|
|
|
54
54
|
* 执行流:
|
|
55
55
|
* 1. SyncRule[] 全量 apply —— 来自 src/config/sync-configs/<stack>.ts。每个 stack
|
|
56
56
|
* 自带模板资源在 upgrade/templates/<stack>/templates/。表里没有该 stack 时回退到
|
|
57
|
-
* 旧 platform-sync 兜底(兼容尚未迁移的 stack
|
|
57
|
+
* 旧 platform-sync 兜底(兼容尚未迁移的 stack);两者都识别不了(无 SyncConfig 且无
|
|
58
|
+
* upgrade/templates/<stack>/)→ 跳过同步(no-op, skipped=true),不报错。
|
|
58
59
|
* 2. 平台 deps 指 latest —— user app 已装的 @lark-apaas/* 按 MANAGED_PLATFORM_PACKAGES
|
|
59
60
|
* 白名单改写为 "latest"(紧急止血时表里可填具体版本)。
|
|
60
61
|
* 3. activateGitHooks —— 设置 core.hooksPath(template 自带 .githooks/pre-commit)。
|
|
@@ -71,14 +72,31 @@ async function handleAppSync(opts) {
|
|
|
71
72
|
if (meta.stack === undefined || meta.stack === '') {
|
|
72
73
|
throw new error_1.AppError('SYNC_META_INCOMPLETE', '.spark/meta.json missing stack — run `miaoda app init` first');
|
|
73
74
|
}
|
|
74
|
-
// 1. apply SyncRule[],stack 没注册时回退到旧 platform-sync
|
|
75
|
+
// 1. apply SyncRule[],stack 没注册时回退到旧 platform-sync 兜底
|
|
75
76
|
const syncResults = runStackSync(meta.stack, targetDir, 'sync');
|
|
77
|
+
// stack 未纳入 sync 范围(既无 SyncConfig 也无 upgrade/templates/<stack>/):跳过同步(no-op),
|
|
78
|
+
// 不报错。sync 会在 dev.sh 本地入口 / 沙箱 pod 启动阶段被调用,对不需要 cli 侧 sync 的 stack
|
|
79
|
+
// (如 design-html buildless 静态 HTML)不该阻断启动链路。
|
|
76
80
|
if (!syncResults.stackFound) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
(0, logger_1.log)('sync', `stack '${meta.stack}' 未纳入 sync 范围,跳过同步 (no-op)`);
|
|
82
|
+
if (!(0, output_1.isJsonMode)()) {
|
|
83
|
+
process.stdout.write(`⚠ stack '${meta.stack}' 未纳入 sync 范围,已跳过同步\n`);
|
|
84
|
+
}
|
|
85
|
+
(0, output_1.emit)({
|
|
86
|
+
data: {
|
|
87
|
+
stack: meta.stack,
|
|
88
|
+
skipped: true,
|
|
89
|
+
reason: 'stack_not_in_sync_scope',
|
|
90
|
+
appliedRules: [],
|
|
91
|
+
syncedFiles: [],
|
|
92
|
+
mergedJsonFiles: [],
|
|
93
|
+
patchedScripts: [],
|
|
94
|
+
upgradedPackages: [],
|
|
95
|
+
gitHooks: 'skipped',
|
|
96
|
+
installError: undefined,
|
|
97
|
+
},
|
|
81
98
|
});
|
|
99
|
+
return;
|
|
82
100
|
}
|
|
83
101
|
// 2. activate git hooks(template 自带 .githooks/pre-commit,core.hooksPath 一次性设置)
|
|
84
102
|
const hookActivation = (0, githooks_1.activateGitHooks)(targetDir);
|
|
@@ -138,8 +156,8 @@ exports.handleAppUpgrade = handleAppSync;
|
|
|
138
156
|
* stack 在 STACK_REGISTRY 注册时走新 SyncRule 机制,否则回落到旧 platform-sync。
|
|
139
157
|
*
|
|
140
158
|
* stack 完全不识别(既不在 STACK_REGISTRY 也无 upgrade/templates/<stack>/ 目录)时返回
|
|
141
|
-
* `stackFound: false` 而非抛错 —— 让调用方按场景决定:sync handler
|
|
142
|
-
*
|
|
159
|
+
* `stackFound: false` 而非抛错 —— 让调用方按场景决定:sync handler 跳过同步(no-op),init handler
|
|
160
|
+
* 也允许(fresh init 时 stack 还在加注册的过渡期)。
|
|
143
161
|
*/
|
|
144
162
|
function runStackSync(stack, targetDir, logPrefix) {
|
|
145
163
|
const config = (0, sync_configs_1.getSyncConfig)(stack);
|
|
@@ -263,6 +263,10 @@ exports.MIGRATE_CONFIG = {
|
|
|
263
263
|
'dotenv',
|
|
264
264
|
// client-toolkit:替代 lite,业务代码 codemod 后走它
|
|
265
265
|
'@lark-apaas/client-toolkit',
|
|
266
|
+
// drizzle-orm —— `gen:db-schema` 生成的 server/database/schema.ts 从
|
|
267
|
+
// 'drizzle-orm/pg-core' / 'drizzle-orm' 导入 pgTable / sql 等 runtime API,
|
|
268
|
+
// 缺依赖时 nest build / dev 起来直接 ERR_MODULE_NOT_FOUND。
|
|
269
|
+
'drizzle-orm',
|
|
266
270
|
],
|
|
267
271
|
devDependencies: [
|
|
268
272
|
// nest start / nest build 必需
|
|
@@ -32,7 +32,7 @@ exports.SUPPORTED_STACKS = Object.keys(exports.TEMPLATE_PACKAGE_BY_STACK);
|
|
|
32
32
|
* 与 src/api/app/types.ts 的 AppType 枚举无关,是独立的业务类型概念。
|
|
33
33
|
*/
|
|
34
34
|
exports.STACK_BY_APP_TYPE = {
|
|
35
|
-
html: 'html',
|
|
35
|
+
html: 'design-html',
|
|
36
36
|
modern_html: 'html',
|
|
37
37
|
jspage: 'vite-react',
|
|
38
38
|
full_stack: 'nestjs-react-fullstack',
|
|
@@ -34,7 +34,7 @@ async function patchDesignDeploy(opts) {
|
|
|
34
34
|
appID: opts.appId,
|
|
35
35
|
templateKey,
|
|
36
36
|
actions,
|
|
37
|
-
|
|
37
|
+
sessionID: opts.sessionID,
|
|
38
38
|
});
|
|
39
39
|
(0, logger_1.log)('deploy', `Patched: upsert=${String(res.upsertCount)} delete=${String(res.deleteCount)}`);
|
|
40
40
|
return {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.designLocalPublishPipeline = designLocalPublishPipeline;
|
|
4
|
-
const spark_meta_1 = require("../../../../utils/spark-meta");
|
|
5
4
|
const error_1 = require("../../../../utils/error");
|
|
6
5
|
const logger_1 = require("../../../../utils/logger");
|
|
7
6
|
const index_1 = require("../atoms/index");
|
|
@@ -38,9 +37,6 @@ async function designLocalPublishPipeline(opts) {
|
|
|
38
37
|
await (0, index_1.finalizeLocalRelease)(ctx.appId, release.releaseID, index_1.LocalReleaseStatus.Failed);
|
|
39
38
|
throw err;
|
|
40
39
|
}
|
|
41
|
-
if (release.onlineUrl !== undefined && release.onlineUrl !== '') {
|
|
42
|
-
(0, spark_meta_1.writeSparkMeta)(ctx.projectDir, { appUrl: release.onlineUrl });
|
|
43
|
-
}
|
|
44
40
|
(0, logger_1.log)('deploy', 'Deployed successfully');
|
|
45
41
|
return {
|
|
46
42
|
appId: ctx.appId,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.localBuildLocalPublishPipeline = localBuildLocalPublishPipeline;
|
|
4
|
-
const spark_meta_1 = require("../../../../utils/spark-meta");
|
|
5
4
|
const error_1 = require("../../../../utils/error");
|
|
6
5
|
const logger_1 = require("../../../../utils/logger");
|
|
7
6
|
const index_1 = require("../atoms/index");
|
|
@@ -64,9 +63,6 @@ async function localBuildLocalPublishPipeline(opts) {
|
|
|
64
63
|
await (0, index_1.finalizeLocalRelease)(ctx.appId, release.releaseID, index_1.LocalReleaseStatus.Failed);
|
|
65
64
|
throw err;
|
|
66
65
|
}
|
|
67
|
-
if (release.onlineUrl !== undefined && release.onlineUrl !== '') {
|
|
68
|
-
(0, spark_meta_1.writeSparkMeta)(ctx.projectDir, { appUrl: release.onlineUrl });
|
|
69
|
-
}
|
|
70
66
|
(0, logger_1.log)('deploy', 'Deployed successfully');
|
|
71
67
|
return {
|
|
72
68
|
appId: ctx.appId,
|