cardbuddy 0.22.0 → 0.24.0
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 +11 -11
- package/dist/cli.js +2 -2
- package/dist/config.js +3 -3
- package/dist/init.js +13 -13
- package/dist/mcp.js +1 -1
- package/dist/preview-editor/assets/{index-CPpLZZyi.js → index-BumNBo-n.js} +81 -80
- package/dist/preview-editor/assets/{index-CU8zVA2P.css → index-MWKPP9nd.css} +1 -1
- package/dist/preview-editor/index.html +2 -2
- package/dist/skills-upgrade.js +1 -1
- package/dist/standalone.js +2 -2
- package/dist/vendored/card-editor/runtime/adapter.js +10 -11
- package/dist/vendored/mcp/client.mjs +50 -13
- package/dist/vendored/mcp/tools.mjs +13 -7
- package/dist/vendored/server/core/ai-chat.js +540 -183
- package/dist/vendored/server/core/assetProxy.js +1 -1
- package/dist/vendored/server/core/browser.js +1 -1
- package/dist/vendored/server/core/cardCompile.js +202 -0
- package/dist/vendored/server/core/cardDigest.js +324 -0
- package/dist/vendored/server/core/cardExport.js +5 -5
- package/dist/vendored/server/core/cardFiles.js +1 -1
- package/dist/vendored/server/core/cardHistoryRemote.js +1 -1
- package/dist/vendored/server/core/cardImportMeta.js +1 -1
- package/dist/vendored/server/core/cardListCache.js +92 -10
- package/dist/vendored/server/core/cardPublish.js +11 -6
- package/dist/vendored/server/core/cardPublishVersions.js +8 -8
- package/dist/vendored/server/core/cardSave.js +14 -10
- package/dist/vendored/server/core/cardSidecar.js +3 -3
- package/dist/vendored/server/core/cardSync.js +35 -23
- package/dist/vendored/server/core/cardVersion.js +1 -1
- package/dist/vendored/server/core/flameCompile/client.js +466 -0
- package/dist/vendored/server/core/flameCompile/clientElements.js +372 -0
- package/dist/vendored/server/core/flameCompile/common.js +253 -0
- package/dist/vendored/server/core/flameCompile/h5.js +326 -0
- package/dist/vendored/server/core/flameCompile/index.js +126 -0
- package/dist/vendored/server/core/flameCompile/model.js +162 -0
- package/dist/vendored/server/core/index.js +12 -6
- package/dist/vendored/server/core/logger.js +1 -1
- package/dist/vendored/server/core/remoteCard.js +5 -5
- package/dist/vendored/server/core/skillPaths.js +1 -1
- package/dist/vendored/server/core/sliceUpload.js +4 -4
- package/dist/vendored/skills/README.md +13 -13
- package/dist/vendored/skills/card-doctor/SKILL.md +2 -2
- package/dist/vendored/skills/dsl-card-ai/SKILL.md +4 -4
- package/dist/vendored/skills/dsl-card-generator/SKILL.md +2 -2
- package/dist/vendored/skills/dsl-card-generator/references/amount_formatting.md +1 -1
- package/dist/vendored/skills/dsl-card-generator/references/build_protocol.md +54 -0
- package/dist/vendored/skills/dsl-card-generator/references/component_rules.md +2 -2
- package/dist/vendored/skills/dsl-card-generator/references/converge_protocol.md +36 -0
- package/dist/vendored/skills/dsl-card-generator/references/event_patterns.md +1 -1
- package/dist/vendored/skills/dsl-card-generator/references/generation_pitfalls.md +1 -1
- package/dist/vendored/skills/dsl-card-generator/references/image_to_card.md +1 -1
- package/dist/vendored/skills/dsl-card-generator/references/quickref.md +1 -1
- package/dist/vendored/skills/dsl-card-generator/references/recipes.md +4 -4
- package/dist/vendored/skills/dsl-card-generator/references/rules.md +1 -1
- package/dist/vendored/skills/dsl-card-generator/references/slices_convention.md +6 -6
- package/dist/vendored/skills/dsl-card-generator/scripts/inventory_schemas.py +1 -1
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/scaffold.mjs +1 -1
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/slice_dedupe.mjs +2 -2
- package/dist/vendored/skills/dsl-card-generator/vendor/preview/assets/standalone-CeVX_y-M.js +137 -0
- package/dist/vendored/skills/dsl-card-generator/vendor/preview/assets/standalone-DiEiY59H.css +1 -0
- package/dist/vendored/skills/dsl-card-generator/vendor/preview/standalone.html +2 -2
- package/dist/vendored/skills/{finmall-card-sync → platform-card-sync}/SKILL.md +26 -26
- package/dist/vendored/skills/{finmall-card-sync → platform-card-sync}/scripts/api_batch_sync.mjs +184 -162
- package/dist/vendored/skills/{finmall-card-sync → platform-card-sync}/scripts/slice_upload.mjs +48 -29
- package/dist/vendored/skills/{finmall-session-navigator → platform-session-navigator}/SKILL.md +13 -13
- package/dist/vendored/skills/{finmall-session-navigator → platform-session-navigator}/scripts/package-lock.json +2 -2
- package/dist/vendored/skills/{finmall-session-navigator → platform-session-navigator}/scripts/package.json +2 -2
- package/dist/vendored/skills/{finmall-session-navigator/scripts/finmall_login.mjs → platform-session-navigator/scripts/platform_login.mjs} +41 -31
- package/dist/vendored/skills/{finmall-session-navigator → platform-session-navigator}/scripts/session-manager.mjs +17 -17
- package/dist/vendored/skills/shared/README.md +21 -21
- package/dist/vendored/skills/shared/auth-model.md +8 -10
- package/dist/vendored/skills/shared/{finmall-config.mjs → platform-config.mjs} +10 -10
- package/dist/vendored/tools/{finmall-env.mjs → platform-env.mjs} +13 -13
- package/package.json +1 -1
- package/dist/vendored/skills/dsl-card-generator/vendor/preview/assets/standalone-BCLshIzC.css +0 -1
- package/dist/vendored/skills/dsl-card-generator/vendor/preview/assets/standalone-pP5kTKiI.js +0 -88
package/dist/vendored/skills/{finmall-card-sync → platform-card-sync}/scripts/api_batch_sync.mjs
RENAMED
|
@@ -2,14 +2,35 @@ import { mkdir, stat, writeFile, readFile, readdir } from 'node:fs/promises';
|
|
|
2
2
|
import { createHash } from 'node:crypto';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
5
|
-
import {
|
|
5
|
+
import { platformConfig } from '../../shared/platform-config.mjs';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 对端站点 host(从配置派生,不写死域名)。
|
|
9
|
+
* 用于在多个标签页里认出「已登录的那个」——控制台里常同时开着本地 dev 页与对端页。
|
|
10
|
+
* 配置缺失时返回空串,调用方按「找不到就新建页」处理。
|
|
11
|
+
*/
|
|
12
|
+
const PLATFORM_HOST = (() => {
|
|
13
|
+
try {
|
|
14
|
+
return new URL(platformConfig.baseUrl).host;
|
|
15
|
+
} catch {
|
|
16
|
+
return '';
|
|
17
|
+
}
|
|
18
|
+
})();
|
|
19
|
+
/** 该标签页是否属于对端站点 */
|
|
20
|
+
function isPlatformPage(page) {
|
|
21
|
+
try {
|
|
22
|
+
return Boolean(PLATFORM_HOST) && page.url().includes(PLATFORM_HOST);
|
|
23
|
+
} catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
6
27
|
|
|
7
28
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
8
29
|
const skillDir = path.resolve(scriptDir, '..');
|
|
9
30
|
// skill now lives under <repo-root>/skills/<name>: repo root is two levels up from skillDir
|
|
10
31
|
const workspace = path.resolve(skillDir, '..', '..');
|
|
11
|
-
// 与
|
|
12
|
-
// playwright。原硬编码路径指向 .workbuddy/skills/
|
|
32
|
+
// 与 platform_login.mjs 保持一致的解析方式:用裸标识符让 Node 从项目根 node_modules 解析
|
|
33
|
+
// playwright。原硬编码路径指向 .workbuddy/skills/platform-session-navigator/scripts/node_modules
|
|
13
34
|
// (该 node_modules 是已失效的断链符号链接),导致「Cannot find module」报错。
|
|
14
35
|
const { chromium } = await import('playwright');
|
|
15
36
|
|
|
@@ -31,18 +52,18 @@ try {
|
|
|
31
52
|
}
|
|
32
53
|
|
|
33
54
|
// 后台会话管理:点击预览「同步远程数据」时自动拉起/复用无界面 Chrome 并登录,
|
|
34
|
-
// 无需手动运行
|
|
35
|
-
import {
|
|
55
|
+
// 无需手动运行 platform-session-navigator。
|
|
56
|
+
import { ensurePlatformSession } from "../../platform-session-navigator/scripts/session-manager.mjs";
|
|
36
57
|
import {
|
|
37
58
|
performLogin,
|
|
38
59
|
clearTimeoutPrompts,
|
|
39
60
|
waitForAuthenticatedPage,
|
|
40
61
|
loadCredentials,
|
|
41
|
-
} from "../../
|
|
62
|
+
} from "../../platform-session-navigator/scripts/platform_login.mjs";
|
|
42
63
|
|
|
43
64
|
// 代理处理:本机设了 HTTP_PROXY,但 Chrome 远程调试端口在 127.0.0.1,需把
|
|
44
65
|
// localhost 排除在代理外,否则 connectOverCDP 会经代理拿到 502 / ECONNREFUSED。
|
|
45
|
-
// 仅影响 Node 侧 CDP
|
|
66
|
+
// 仅影响 Node 侧 CDP 连接;浏览器内访问对端站点仍走代理。
|
|
46
67
|
for (const key of ["NO_PROXY", "no_proxy"]) {
|
|
47
68
|
const cur = process.env[key];
|
|
48
69
|
const extra = "127.0.0.1,localhost";
|
|
@@ -77,9 +98,9 @@ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
|
77
98
|
// 404,而是直接挂起不响应;page.evaluate 本身没有默认超时,裸 fetch 会把整次同步永久拖死。
|
|
78
99
|
// 内部用 AbortController 掐断请求,外部再包一层 Promise.race 兜住 evaluate 自身不返回的情况。
|
|
79
100
|
const COVER_FETCH_TIMEOUT_MS = Number(process.env.CARDBUDDY_COVER_TIMEOUT_MS || 15000);
|
|
80
|
-
//
|
|
101
|
+
// 远端交易请求超时。IDC10001/IDC10012 偶发挂起(后端不响应),同样没有任何默认超时,
|
|
81
102
|
// 一张卡挂住就会拖垮整批同步——所以和预览图一样,内层 abort + 外层 race 双重设防。
|
|
82
|
-
const
|
|
103
|
+
const PLATFORM_POST_TIMEOUT_MS = Number(process.env.CARDBUDDY_POST_TIMEOUT_MS || 30000);
|
|
83
104
|
// 卡片预览图上传(IDC10014.do)超时。与切图上传同款设防:内层 AbortController +
|
|
84
105
|
// 外层 Promise.race 兜住 page.evaluate 自身不返回(evaluate 无默认超时)。
|
|
85
106
|
const PREVIEW_UPLOAD_TIMEOUT_MS = Number(process.env.CARDBUDDY_PREVIEW_UPLOAD_TIMEOUT_MS || 30000);
|
|
@@ -94,37 +115,37 @@ function withTimeout(promise, ms, label) {
|
|
|
94
115
|
]).finally(() => clearTimeout(timer));
|
|
95
116
|
}
|
|
96
117
|
|
|
97
|
-
// 服务端判定会话/权限失效并应「重新进入」的特征集合。命中后由
|
|
118
|
+
// 服务端判定会话/权限失效并应「重新进入」的特征集合。命中后由 platformPostWithHeal
|
|
98
119
|
// 自动清 session 重登再试一次——覆盖会话超时(BLEC0006)、token 失效、
|
|
99
120
|
// 「您当前角色菜单权限发生变化,请重新进入」这类权限态异常,以及前端页面会话键丢失
|
|
100
121
|
// (localStorage._sessionId 为空,如后台 Chrome 被清理/重启后):本地凭证仍在即可自愈。
|
|
101
122
|
const SESSION_INVALID_RE = /BLEC0006|会话超时|会话过期|登录超时|未登录|登录失效|登录已失效|请重新登录|invalid token|token|角色菜单权限发生变化|权限发生变化|重新进入|请重新进入|缺少会话凭据/i;
|
|
102
123
|
|
|
103
124
|
/**
|
|
104
|
-
*
|
|
125
|
+
* 带自愈的远端接口调用:正常请求,若命中会话/权限失效特征则清 session 重登后重试一次。
|
|
105
126
|
* 列表(IDC10001)与 schema(IDC10012)共用,确保任意一步出现权限态异常都能自动恢复。
|
|
106
127
|
*/
|
|
107
|
-
async function
|
|
128
|
+
async function platformPostWithHeal(page, urlPath, requestBody, transCode = urlPath) {
|
|
108
129
|
try {
|
|
109
|
-
return await
|
|
130
|
+
return await platformPost(page, urlPath, requestBody, transCode);
|
|
110
131
|
} catch (error) {
|
|
111
132
|
if (SESSION_INVALID_RE.test(error.message)) {
|
|
112
133
|
log.warn('会话/权限失效,自动重新登录后重试', { url: urlPath, reason: error.message.slice(0, 40) });
|
|
113
134
|
await relogin(page);
|
|
114
|
-
return await
|
|
135
|
+
return await platformPost(page, urlPath, requestBody, transCode);
|
|
115
136
|
}
|
|
116
137
|
throw error;
|
|
117
138
|
}
|
|
118
139
|
}
|
|
119
140
|
|
|
120
141
|
/**
|
|
121
|
-
*
|
|
142
|
+
* 从已认证的远端浏览器会话同步卡片到 src/cards。
|
|
122
143
|
* 既可由 CLI 直接运行(api_batch_sync.mjs),也可被 Vite 中间件 import 后供预览「同步远程数据」按钮调用。
|
|
123
144
|
*
|
|
124
|
-
* 会话由
|
|
145
|
+
* 会话由 ensurePlatformSession 自动保证:若后台无界面 Chrome(专用端口)未启动或会话缺失,
|
|
125
146
|
* 会自动拉起并登录;完成后只 disconnect 不关闭进程,便于复用。
|
|
126
147
|
* 若服务端会话/权限失效(IDC10012 返回 BLEC0006 或「角色菜单权限发生变化」等),
|
|
127
|
-
*
|
|
148
|
+
* platformPostWithHeal 会自动清 session 重登再重试。
|
|
128
149
|
*
|
|
129
150
|
* @param {object} opts
|
|
130
151
|
* @param {string} [opts.cardCode] 仅同步该英文卡 id(用列表接口 searchValue 定位)
|
|
@@ -135,7 +156,7 @@ async function finmallPostWithHeal(page, urlPath, requestBody, transCode = urlPa
|
|
|
135
156
|
* @param {number} [opts.maxCards] 最多同步张数(不传=全部)
|
|
136
157
|
* @param {string} [opts.appId]
|
|
137
158
|
* @param {string} [opts.workspaceId]
|
|
138
|
-
* @param {string} [opts.cdpUrl] 已废弃:会话现在由
|
|
159
|
+
* @param {string} [opts.cdpUrl] 已废弃:会话现在由 ensurePlatformSession 在专用后台端口自动管理
|
|
139
160
|
* @param {string} [opts.outRoot] 输出根目录(默认 workspace/src/cards)
|
|
140
161
|
* @param {(p: {done:number,total:number|null,currentId:string,currentTitle:string}) => void} [opts.onProgress]
|
|
141
162
|
* 每张卡处理完毕后的进度回调(失败也回调),供前端进度条消费
|
|
@@ -157,8 +178,8 @@ export async function syncCards(opts = {}) {
|
|
|
157
178
|
const startIndex = Number(opts.startIndex || 0);
|
|
158
179
|
const pageSize = Number(opts.pageSize || 24);
|
|
159
180
|
const maxCards = opts.maxCards != null ? Number(opts.maxCards) : Infinity;
|
|
160
|
-
const appId = opts.appId ||
|
|
161
|
-
const workspaceId = opts.workspaceId ||
|
|
181
|
+
const appId = opts.appId || platformConfig.appId;
|
|
182
|
+
const workspaceId = opts.workspaceId || platformConfig.workspaceId;
|
|
162
183
|
// 单卡筛选:传 cardCode 时仅同步该卡
|
|
163
184
|
const cardCodeFilter = opts.cardCode || '';
|
|
164
185
|
// 集合筛选:cardCodes 非空时仅同步集合内卡片(与单卡筛选互斥,单卡优先)。
|
|
@@ -175,8 +196,8 @@ export async function syncCards(opts = {}) {
|
|
|
175
196
|
// 预期总张数:单卡=1;集合=集合大小;全量=0(未知,边拉边算)
|
|
176
197
|
const expectedTotal = cardCodeFilter ? 1 : cardCodeSet ? cardCodeSet.size : 0;
|
|
177
198
|
|
|
178
|
-
//
|
|
179
|
-
const session = await
|
|
199
|
+
// 自动确保后台远端会话:未启动/缺失则拉起无界面 Chrome 并登录,无需手动触发。
|
|
200
|
+
const session = await ensurePlatformSession();
|
|
180
201
|
const browser = session.browser;
|
|
181
202
|
const summary = { success: true, synced: [], failed: [], duplicates: [] };
|
|
182
203
|
// 重复 schema 检测:记录每张卡 schema 的 MD5,若不同 code 命中相同 schema 说明抓取仍串卡。
|
|
@@ -184,8 +205,8 @@ export async function syncCards(opts = {}) {
|
|
|
184
205
|
|
|
185
206
|
try {
|
|
186
207
|
const context = browser.contexts()[0];
|
|
187
|
-
const page = context?.pages().find((p) => p
|
|
188
|
-
if (!page) throw new Error('未能在后台 Chrome
|
|
208
|
+
const page = context?.pages().find((p) => isPlatformPage(p)) || context?.pages()[0];
|
|
209
|
+
if (!page) throw new Error('未能在后台 Chrome 中找到远端页面,请检查凭据或重新触发同步。');
|
|
189
210
|
await page.bringToFront();
|
|
190
211
|
|
|
191
212
|
const firstList = await fetchCardList(page, { pageNo: startPage, pageSize, appId, workspaceId, searchValue: cardCodeFilter });
|
|
@@ -256,7 +277,8 @@ export async function syncCards(opts = {}) {
|
|
|
256
277
|
// 全部分页,allCards 即完整列表,整体刷新同样准确。缓存未就绪则跳过(不影响同步)。
|
|
257
278
|
try {
|
|
258
279
|
const cache = await getCardListCache();
|
|
259
|
-
|
|
280
|
+
// 盖 appId / workspaceId 戳:环境切换后旧 app 的缓存会被闸门识别为失效而非误判
|
|
281
|
+
if (cache) cache.refreshCardList(allCards, { full: !cardCodeFilter, appId, workspaceId });
|
|
260
282
|
} catch (e) {
|
|
261
283
|
log.warn('刷新卡片列表缓存失败(不影响同步)', { error: e && e.message });
|
|
262
284
|
}
|
|
@@ -269,7 +291,7 @@ export async function syncCards(opts = {}) {
|
|
|
269
291
|
|
|
270
292
|
/**
|
|
271
293
|
* 拉取远端完整卡片列表(IDC10001 分页全量),供编辑器「查看全部」网格浏览。
|
|
272
|
-
* 只读、不落盘;与 syncCards
|
|
294
|
+
* 只读、不落盘;与 syncCards 共用同一后台远端会话(ensurePlatformSession 自动保活)。
|
|
273
295
|
*
|
|
274
296
|
* @param {object} [opts]
|
|
275
297
|
* @param {number} [opts.pageSize=50] 列表分页大小
|
|
@@ -277,22 +299,22 @@ export async function syncCards(opts = {}) {
|
|
|
277
299
|
* @param {string} [opts.appId]
|
|
278
300
|
* @param {string} [opts.workspaceId]
|
|
279
301
|
* @returns {Promise<Array<{id:string,title:string,cardId:string|number,coverUrl:string,picUrl:string,cardClassId:string}>>}
|
|
280
|
-
* id=英文卡 code(本地目录名同源);coverUrl
|
|
302
|
+
* id=英文卡 code(本地目录名同源);coverUrl 为远端图片库绝对地址(可能为空串);
|
|
281
303
|
* picUrl 为原始 `@filestore/...` 站内地址、cardClassId 为卡片类型 id,二者供「编辑基本信息」原样回传。
|
|
282
304
|
*/
|
|
283
305
|
export async function listRemoteCards(opts = {}) {
|
|
284
|
-
const appId = opts.appId ||
|
|
285
|
-
const workspaceId = opts.workspaceId ||
|
|
306
|
+
const appId = opts.appId || platformConfig.appId;
|
|
307
|
+
const workspaceId = opts.workspaceId || platformConfig.workspaceId;
|
|
286
308
|
const pageSize = Number(opts.pageSize || 50);
|
|
287
309
|
const maxPages = Number(opts.maxPages || 400);
|
|
288
310
|
|
|
289
|
-
//
|
|
290
|
-
const session = await
|
|
311
|
+
// 自动确保后台远端会话:未启动/缺失则拉起无界面 Chrome 并登录,无需手动触发。
|
|
312
|
+
const session = await ensurePlatformSession();
|
|
291
313
|
const browser = session.browser;
|
|
292
314
|
try {
|
|
293
315
|
const context = browser.contexts()[0];
|
|
294
|
-
const page = context?.pages().find((p) => p
|
|
295
|
-
if (!page) throw new Error('未能在后台 Chrome
|
|
316
|
+
const page = context?.pages().find((p) => isPlatformPage(p)) || context?.pages()[0];
|
|
317
|
+
if (!page) throw new Error('未能在后台 Chrome 中找到远端页面,请检查凭据或重新触发。');
|
|
296
318
|
await page.bringToFront();
|
|
297
319
|
|
|
298
320
|
const out = [];
|
|
@@ -333,11 +355,11 @@ export async function listRemoteCards(opts = {}) {
|
|
|
333
355
|
}
|
|
334
356
|
}
|
|
335
357
|
|
|
336
|
-
/**
|
|
337
|
-
function
|
|
358
|
+
/** 从后台会话中取出远端页面(列表 / 字典 / 新建 / 编辑共用同一页面上下文) */
|
|
359
|
+
function platformPage(browser) {
|
|
338
360
|
const context = browser.contexts()[0];
|
|
339
|
-
const page = context?.pages().find((p) => p
|
|
340
|
-
if (!page) throw new Error('未能在后台 Chrome
|
|
361
|
+
const page = context?.pages().find((p) => isPlatformPage(p)) || context?.pages()[0];
|
|
362
|
+
if (!page) throw new Error('未能在后台 Chrome 中找到远端页面,请检查凭据或重新触发。');
|
|
341
363
|
return page;
|
|
342
364
|
}
|
|
343
365
|
|
|
@@ -353,14 +375,14 @@ function finmallPage(browser) {
|
|
|
353
375
|
* @returns {Promise<Array<{id:string,name:string,count:number}>>}
|
|
354
376
|
*/
|
|
355
377
|
export async function listRemoteCardTypes(opts = {}) {
|
|
356
|
-
const appId = opts.appId ||
|
|
357
|
-
const workspaceId = opts.workspaceId ||
|
|
358
|
-
const session = await
|
|
378
|
+
const appId = opts.appId || platformConfig.appId;
|
|
379
|
+
const workspaceId = opts.workspaceId || platformConfig.workspaceId;
|
|
380
|
+
const session = await ensurePlatformSession();
|
|
359
381
|
const browser = session.browser;
|
|
360
382
|
try {
|
|
361
|
-
const page =
|
|
383
|
+
const page = platformPage(browser);
|
|
362
384
|
await page.bringToFront();
|
|
363
|
-
const body = await
|
|
385
|
+
const body = await platformPostWithHeal(
|
|
364
386
|
page,
|
|
365
387
|
`/ubomp-web/IDC10009.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`,
|
|
366
388
|
{
|
|
@@ -395,20 +417,20 @@ export async function listRemoteCardTypes(opts = {}) {
|
|
|
395
417
|
* @returns {Promise<{cardId:string, code:string}>}
|
|
396
418
|
*/
|
|
397
419
|
export async function createRemoteCard(input = {}) {
|
|
398
|
-
const appId = input.appId ||
|
|
399
|
-
const workspaceId = input.workspaceId ||
|
|
420
|
+
const appId = input.appId || platformConfig.appId;
|
|
421
|
+
const workspaceId = input.workspaceId || platformConfig.workspaceId;
|
|
400
422
|
const code = String(input.code || '').trim();
|
|
401
423
|
const cardName = String(input.cardName || '').trim();
|
|
402
424
|
if (!/^[A-Za-z0-9_-]+$/.test(code)) throw new Error(`卡片编码非法(仅允许字母/数字/_/-):${code || '(空)'}`);
|
|
403
425
|
if (!cardName) throw new Error('卡片名称不能为空');
|
|
404
426
|
if (input.cardClassId == null || String(input.cardClassId) === '') throw new Error('请选择卡片类型');
|
|
405
427
|
|
|
406
|
-
const session = await
|
|
428
|
+
const session = await ensurePlatformSession();
|
|
407
429
|
const browser = session.browser;
|
|
408
430
|
try {
|
|
409
|
-
const page =
|
|
431
|
+
const page = platformPage(browser);
|
|
410
432
|
await page.bringToFront();
|
|
411
|
-
const body = await
|
|
433
|
+
const body = await platformPostWithHeal(
|
|
412
434
|
page,
|
|
413
435
|
`/ubomp-web/IDC10002.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`,
|
|
414
436
|
{
|
|
@@ -439,8 +461,8 @@ export async function createRemoteCard(input = {}) {
|
|
|
439
461
|
* @returns {Promise<{cardId:string, code:string}>}
|
|
440
462
|
*/
|
|
441
463
|
export async function updateRemoteCard(input = {}) {
|
|
442
|
-
const appId = input.appId ||
|
|
443
|
-
const workspaceId = input.workspaceId ||
|
|
464
|
+
const appId = input.appId || platformConfig.appId;
|
|
465
|
+
const workspaceId = input.workspaceId || platformConfig.workspaceId;
|
|
444
466
|
const cardId = String(input.cardId || '');
|
|
445
467
|
const code = String(input.code || '').trim();
|
|
446
468
|
const cardName = String(input.cardName || '').trim();
|
|
@@ -449,14 +471,14 @@ export async function updateRemoteCard(input = {}) {
|
|
|
449
471
|
if (!cardName) throw new Error('卡片名称不能为空');
|
|
450
472
|
if (input.cardClassId == null || String(input.cardClassId) === '') throw new Error('请选择卡片类型');
|
|
451
473
|
|
|
452
|
-
const session = await
|
|
474
|
+
const session = await ensurePlatformSession();
|
|
453
475
|
const browser = session.browser;
|
|
454
476
|
try {
|
|
455
|
-
const page =
|
|
477
|
+
const page = platformPage(browser);
|
|
456
478
|
await page.bringToFront();
|
|
457
479
|
// 线上实测:IDC10008 的 URL 不带 sassAppId 查询串(只有 transCode 里带),
|
|
458
480
|
// 带了也能用;此处按实测的干净路径发送,减少与官方实现的差异面。
|
|
459
|
-
const body = await
|
|
481
|
+
const body = await platformPostWithHeal(
|
|
460
482
|
page,
|
|
461
483
|
'/ubomp-web/IDC10008.do',
|
|
462
484
|
{
|
|
@@ -485,25 +507,25 @@ export async function updateRemoteCard(input = {}) {
|
|
|
485
507
|
* { channel:'', cardId }
|
|
486
508
|
* 即只认数字主键 cardId(列表行数据的 `id`),**不传英文 code**。
|
|
487
509
|
*
|
|
488
|
-
*
|
|
510
|
+
* 不可逆:删除后该卡在远端侧的元数据与已发布版本一并消失,无法通过重新新建
|
|
489
511
|
* 恢复同一 cardId。调用方必须在执行前做二次确认。本地 src/cards/<code> 目录不受影响。
|
|
490
512
|
*
|
|
491
513
|
* @param {{cardId:string|number, channel?:string, appId?:string, workspaceId?:string}} input
|
|
492
514
|
* @returns {Promise<{cardId:string}>}
|
|
493
515
|
*/
|
|
494
516
|
export async function deleteRemoteCard(input = {}) {
|
|
495
|
-
const appId = input.appId ||
|
|
496
|
-
const workspaceId = input.workspaceId ||
|
|
517
|
+
const appId = input.appId || platformConfig.appId;
|
|
518
|
+
const workspaceId = input.workspaceId || platformConfig.workspaceId;
|
|
497
519
|
const cardId = String(input.cardId || '').trim();
|
|
498
520
|
if (!cardId) throw new Error('缺少 cardId,无法删除远端卡片');
|
|
499
521
|
|
|
500
|
-
const session = await
|
|
522
|
+
const session = await ensurePlatformSession();
|
|
501
523
|
const browser = session.browser;
|
|
502
524
|
try {
|
|
503
|
-
const page =
|
|
525
|
+
const page = platformPage(browser);
|
|
504
526
|
await page.bringToFront();
|
|
505
527
|
// 与 IDC10002(新建)同一写法:URL 带 sassAppId / sassWorkspaceId,transCode 取默认(同 URL)
|
|
506
|
-
await
|
|
528
|
+
await platformPostWithHeal(
|
|
507
529
|
page,
|
|
508
530
|
`/ubomp-web/IDC10003.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`,
|
|
509
531
|
{
|
|
@@ -518,8 +540,8 @@ export async function deleteRemoteCard(input = {}) {
|
|
|
518
540
|
}
|
|
519
541
|
|
|
520
542
|
/**
|
|
521
|
-
* 把一张卡片的最新 schema
|
|
522
|
-
* 与 syncCards 共用同一套已登录浏览器会话与带自愈的
|
|
543
|
+
* 把一张卡片的最新 schema 写回远端(线上编辑器「保存」接口 IDC10010.do)。
|
|
544
|
+
* 与 syncCards 共用同一套已登录浏览器会话与带自愈的 platformPost,
|
|
523
545
|
* 确保任意一步会话/权限失效都能自动重登重试。
|
|
524
546
|
*
|
|
525
547
|
* 入参 schema 即本地 src/cards/<id>/schema.json 的完整内容(含 pageId / dictionary / view …)。
|
|
@@ -528,7 +550,7 @@ export async function deleteRemoteCard(input = {}) {
|
|
|
528
550
|
* - body.schemaValue = 整张 schema 的 JSON 字符串(非对象)
|
|
529
551
|
* - body.skeletonScreen = 骨架屏 SVG(仅用于编辑器列表缩略图,可传空串)
|
|
530
552
|
*
|
|
531
|
-
* 保存成功后默认立刻读回(IDC10012.do
|
|
553
|
+
* 保存成功后默认立刻读回(IDC10012.do)做落库校验——远端网关有
|
|
532
554
|
* 「errorCode=0 但 body 空/未落库」的静默空返回先例,不校验无法判断真实生效。
|
|
533
555
|
*
|
|
534
556
|
* @param {object} schema 完整卡片 schema(含 pageId)
|
|
@@ -540,14 +562,14 @@ export async function saveCardToRemote(schema, { skeletonScreen = '', verify = t
|
|
|
540
562
|
if (!schema || !schema.pageId) {
|
|
541
563
|
throw new Error('schema 缺少 pageId,无法确定要保存的卡片(IDC10010.do 需要数字型 cardId)。')
|
|
542
564
|
}
|
|
543
|
-
const appId =
|
|
544
|
-
const workspaceId =
|
|
545
|
-
const session = await
|
|
565
|
+
const appId = platformConfig.appId
|
|
566
|
+
const workspaceId = platformConfig.workspaceId
|
|
567
|
+
const session = await ensurePlatformSession()
|
|
546
568
|
const browser = session.browser
|
|
547
569
|
try {
|
|
548
570
|
const context = browser.contexts()[0]
|
|
549
|
-
const page = context?.pages().find((p) => p
|
|
550
|
-
if (!page) throw new Error('未能在后台 Chrome
|
|
571
|
+
const page = context?.pages().find((p) => isPlatformPage(p)) || context?.pages()[0]
|
|
572
|
+
if (!page) throw new Error('未能在后台 Chrome 中找到远端页面,请检查凭据或重新触发同步。')
|
|
551
573
|
await page.bringToFront()
|
|
552
574
|
|
|
553
575
|
// 保护远端列表缩略图:本地未提供骨架屏时,先读回远端已有的 skeletonScreen 复用,
|
|
@@ -555,7 +577,7 @@ export async function saveCardToRemote(schema, { skeletonScreen = '', verify = t
|
|
|
555
577
|
let sk = skeletonScreen && String(skeletonScreen).trim() ? skeletonScreen : ''
|
|
556
578
|
if (!sk) {
|
|
557
579
|
try {
|
|
558
|
-
const pre = await
|
|
580
|
+
const pre = await platformPostWithHeal(page, '/ubomp-web/IDC10012.do', {
|
|
559
581
|
cardId: String(schema.pageId),
|
|
560
582
|
sassAppId: appId,
|
|
561
583
|
sassWorkspaceId: workspaceId,
|
|
@@ -565,7 +587,7 @@ export async function saveCardToRemote(schema, { skeletonScreen = '', verify = t
|
|
|
565
587
|
}
|
|
566
588
|
if (!sk) sk = '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="400"></svg>'
|
|
567
589
|
|
|
568
|
-
//
|
|
590
|
+
// platformPost 会把 requestBody 放进 payload.body,并自己生成 payload.header;
|
|
569
591
|
// 因此这里只传「内层 body」(与读接口 fetchCardSchema 保持一致),切勿再包一层 {header, body}。
|
|
570
592
|
// 关键:IDC10010.do 需要 sassAppId/sassWorkspaceId(与读接口一致),缺失会返回 PEO000003。
|
|
571
593
|
const innerBody = {
|
|
@@ -577,13 +599,13 @@ export async function saveCardToRemote(schema, { skeletonScreen = '', verify = t
|
|
|
577
599
|
}
|
|
578
600
|
const urlPath = `/ubomp-web/IDC10010.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`
|
|
579
601
|
log.info('保存卡片', { pageId: schema.pageId, name: schema.name || '' })
|
|
580
|
-
const response = await
|
|
602
|
+
const response = await platformPostWithHeal(page, urlPath, innerBody, 'IDC10010.do')
|
|
581
603
|
|
|
582
604
|
// 落库校验:保存后立刻读回,确认内容真的写进去了(而非静默空返回)。
|
|
583
605
|
const verified = { ok: false, cardIdMatched: false, fingerprintMatched: false, diff: null, readBackError: null }
|
|
584
606
|
if (verify) {
|
|
585
607
|
try {
|
|
586
|
-
const readBody = await
|
|
608
|
+
const readBody = await platformPostWithHeal(page, '/ubomp-web/IDC10012.do', {
|
|
587
609
|
cardId: String(schema.pageId),
|
|
588
610
|
sassAppId: appId,
|
|
589
611
|
sassWorkspaceId: workspaceId,
|
|
@@ -621,7 +643,7 @@ export async function saveCardToRemote(schema, { skeletonScreen = '', verify = t
|
|
|
621
643
|
* - 没有 `fileName` 纯文本字段;
|
|
622
644
|
* - 鉴权头只有 `token`。
|
|
623
645
|
*
|
|
624
|
-
* token 仅在页面上下文内读取并直接用于请求,不回传 Node 侧、不打印、不落盘(与
|
|
646
|
+
* token 仅在页面上下文内读取并直接用于请求,不回传 Node 侧、不打印、不落盘(与 platformPost 同纪律)。
|
|
625
647
|
*
|
|
626
648
|
* @returns {Promise<string>} 原始响应文本(交由 parsePreviewUploadResponse 解析)
|
|
627
649
|
*/
|
|
@@ -651,7 +673,7 @@ async function postPreviewUpload(page, { cardId, fileName, base64, appId, worksp
|
|
|
651
673
|
};
|
|
652
674
|
const sessionToken = readSessionToken();
|
|
653
675
|
if (!sessionToken) {
|
|
654
|
-
throw new Error('页面缺少会话凭据(localStorage._sessionId 为空),请先运行
|
|
676
|
+
throw new Error('页面缺少会话凭据(localStorage._sessionId 为空),请先运行 platform-session-navigator 登录。');
|
|
655
677
|
}
|
|
656
678
|
const binary = atob(base64);
|
|
657
679
|
const bytes = new Uint8Array(binary.length);
|
|
@@ -683,7 +705,7 @@ async function postPreviewUpload(page, { cardId, fileName, base64, appId, worksp
|
|
|
683
705
|
/**
|
|
684
706
|
* 解析 IDC10014.do 响应(导出仅为单测可直接断言;正常路径走 uploadCardPreview)。
|
|
685
707
|
*
|
|
686
|
-
*
|
|
708
|
+
* 该接口的响应体形态没有可比对的既有文档,故按远端交易接口的通用信封
|
|
687
709
|
* (`{header:{errorCode,errorMsg}, body:{...}}`)做**宽松**判定:
|
|
688
710
|
* - 空响应体 → 视为成功(HTTP 2xx 已由调用方保证,接口可能不返回业务体);
|
|
689
711
|
* - 非 JSON 非空 → 直接报错(多半是网关 HTML 错误页,不能当成功);
|
|
@@ -712,7 +734,7 @@ export function parsePreviewUploadResponse(text, cardId) {
|
|
|
712
734
|
const bad = codes.find((c) => String(c) !== '0');
|
|
713
735
|
if (bad != null) {
|
|
714
736
|
throw new Error(
|
|
715
|
-
|
|
737
|
+
`远端预览图上传失败 [errorCode=${bad}] ${header.errorMsg || body.errorMsg || ''} | ${raw.slice(0, 300)}`,
|
|
716
738
|
);
|
|
717
739
|
}
|
|
718
740
|
// 地址字段多键兜底:接口未回地址属正常(上传即生效),所以这里只做尽力提取。
|
|
@@ -728,10 +750,10 @@ export function parsePreviewUploadResponse(text, cardId) {
|
|
|
728
750
|
|
|
729
751
|
/**
|
|
730
752
|
* 上传卡片预览图到远端(IDC10014.do)。供「推送」成功后由 server/core/cardSave.js 调用:
|
|
731
|
-
* 本地无头渲染出透明底 PNG →
|
|
753
|
+
* 本地无头渲染出透明底 PNG → 交给已登录的远端后台会话上传,卡片列表缩略图随之更新。
|
|
732
754
|
*
|
|
733
755
|
* 与 saveCardToRemote 的会话纪律一致:saveCardToRemote 末尾会 disconnect,故本函数自行
|
|
734
|
-
*
|
|
756
|
+
* ensurePlatformSession 重新取一次连接(Chrome 已常驻时这一步是廉价的 attach)。
|
|
735
757
|
* 会话/权限失效命中 SESSION_INVALID_RE 时自动清 session 重登并重试一次。
|
|
736
758
|
*
|
|
737
759
|
* @param {{ cardId: string|number, pngBase64: string, appId?: string, workspaceId?: string }} opts
|
|
@@ -744,16 +766,16 @@ export async function uploadCardPreview({ cardId, pngBase64, appId, workspaceId
|
|
|
744
766
|
}
|
|
745
767
|
const base64 = String(pngBase64 == null ? '' : pngBase64);
|
|
746
768
|
if (!base64) throw new Error('上传卡片预览图缺少 PNG 内容(pngBase64 为空)。');
|
|
747
|
-
const appIdv = appId ||
|
|
748
|
-
const workspaceIdv = workspaceId ||
|
|
769
|
+
const appIdv = appId || platformConfig.appId;
|
|
770
|
+
const workspaceIdv = workspaceId || platformConfig.workspaceId;
|
|
749
771
|
const fileName = `${id}.png`;
|
|
750
772
|
|
|
751
|
-
const session = await
|
|
773
|
+
const session = await ensurePlatformSession();
|
|
752
774
|
const browser = session.browser;
|
|
753
775
|
try {
|
|
754
776
|
const context = browser.contexts()[0];
|
|
755
|
-
const page = context?.pages().find((p) => p
|
|
756
|
-
if (!page) throw new Error('未能在后台 Chrome
|
|
777
|
+
const page = context?.pages().find((p) => isPlatformPage(p)) || context?.pages()[0];
|
|
778
|
+
if (!page) throw new Error('未能在后台 Chrome 中找到远端页面,请检查凭据或重新触发同步。');
|
|
757
779
|
await page.bringToFront();
|
|
758
780
|
|
|
759
781
|
const payload = { cardId: id, fileName, base64, appId: appIdv, workspaceId: workspaceIdv };
|
|
@@ -788,7 +810,7 @@ export async function uploadCardPreview({ cardId, pngBase64, appId, workspaceId
|
|
|
788
810
|
* 前端据返回的 cardCode 生成 scheme 二维码:
|
|
789
811
|
* app://previewCard?cardId=<id>&cardCode=<code>&cardVersion=00000000&socket=<wss>
|
|
790
812
|
*
|
|
791
|
-
* 会话由
|
|
813
|
+
* 会话由 ensurePlatformSession 自动保证;与「保存到远端」共用同一套已登录后台 Chrome。
|
|
792
814
|
* 注意:saveCardToRemote 内部会自行 ensure+disconnect,故本函数先调用它(自带会话),
|
|
793
815
|
* 之后再重新 ensure 一次拿干净会话处理后续三个接口,避免复用已被 disconnect 的 page。
|
|
794
816
|
*
|
|
@@ -800,8 +822,8 @@ export async function previewCardRemote(schema, { skeletonScreen = '', publish =
|
|
|
800
822
|
if (!schema || !schema.pageId) {
|
|
801
823
|
throw new Error('schema 缺少 pageId,无法确定要预览的卡片(IDC10020.do 需要 cardId)。')
|
|
802
824
|
}
|
|
803
|
-
const appId =
|
|
804
|
-
const workspaceId =
|
|
825
|
+
const appId = platformConfig.appId
|
|
826
|
+
const workspaceId = platformConfig.workspaceId
|
|
805
827
|
const cardId = String(schema.pageId)
|
|
806
828
|
const result = { cardCode: '', version: '00000000', steps: {} }
|
|
807
829
|
|
|
@@ -816,17 +838,17 @@ export async function previewCardRemote(schema, { skeletonScreen = '', publish =
|
|
|
816
838
|
}
|
|
817
839
|
|
|
818
840
|
// 后续三个接口使用一次干净的会话
|
|
819
|
-
const session = await
|
|
841
|
+
const session = await ensurePlatformSession()
|
|
820
842
|
const browser = session.browser
|
|
821
843
|
try {
|
|
822
844
|
const context = browser.contexts()[0]
|
|
823
|
-
const page = context?.pages().find((p) => p
|
|
824
|
-
if (!page) throw new Error('未能在后台 Chrome
|
|
845
|
+
const page = context?.pages().find((p) => isPlatformPage(p)) || context?.pages()[0]
|
|
846
|
+
if (!page) throw new Error('未能在后台 Chrome 中找到远端页面,请先运行 platform-session-navigator 登录。')
|
|
825
847
|
await page.bringToFront()
|
|
826
848
|
|
|
827
849
|
// 2) 取卡片 code(对齐 ubomp queryCardDetail → IDC10015.do 的 code 字段)
|
|
828
850
|
try {
|
|
829
|
-
const detail = await
|
|
851
|
+
const detail = await platformPostWithHeal(
|
|
830
852
|
page,
|
|
831
853
|
`/ubomp-web/IDC10015.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`,
|
|
832
854
|
{ cardId, sassAppId: appId, sassWorkspaceId: workspaceId },
|
|
@@ -840,7 +862,7 @@ export async function previewCardRemote(schema, { skeletonScreen = '', publish =
|
|
|
840
862
|
// 3) 发布预览测试版(对齐 ubomp submitForm → IDC10020.do)
|
|
841
863
|
if (publish) {
|
|
842
864
|
try {
|
|
843
|
-
await
|
|
865
|
+
await platformPostWithHeal(
|
|
844
866
|
page,
|
|
845
867
|
`/ubomp-web/IDC10020.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`,
|
|
846
868
|
{
|
|
@@ -862,7 +884,7 @@ export async function previewCardRemote(schema, { skeletonScreen = '', publish =
|
|
|
862
884
|
// 4) 消息通知(对齐 ubomp doNotify → IDC10021.do)
|
|
863
885
|
if (notify) {
|
|
864
886
|
try {
|
|
865
|
-
await
|
|
887
|
+
await platformPostWithHeal(
|
|
866
888
|
page,
|
|
867
889
|
`/ubomp-web/IDC10021.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`,
|
|
868
890
|
{ agentId: cardId, sassAppId: appId, sassWorkspaceId: workspaceId },
|
|
@@ -882,7 +904,7 @@ export async function previewCardRemote(schema, { skeletonScreen = '', publish =
|
|
|
882
904
|
}
|
|
883
905
|
|
|
884
906
|
/**
|
|
885
|
-
*
|
|
907
|
+
* 远端版本号格式:8 位「年份 + 4 位序号」,如 20260025。
|
|
886
908
|
* 该格式的最小值约 20200001,故任何 < 10000000 的纯数字都不符合格式
|
|
887
909
|
* (含旧实现首发时误写出的 1 / 2 / 3…)。
|
|
888
910
|
*/
|
|
@@ -916,7 +938,7 @@ export function nextPublishVersion(maxVersion) {
|
|
|
916
938
|
* 2) IDC10016.do 以 nextPublishVersion(maxVersion) 作为新版本号发布(发布的是远端「当前已保存」的卡片内容——
|
|
917
939
|
* 故发布前应先用「推送当前卡」把本地内容保存到远端,否则会发布陈旧内容)。
|
|
918
940
|
* 版本号格式为 8 位「年份 + 4 位序号」:远端从未发布时取 `${当前年份}0001`(不是裸 1)。
|
|
919
|
-
* 会话由
|
|
941
|
+
* 会话由 ensurePlatformSession 自动保证;与 saveCardToRemote / syncCards / previewCardRemote
|
|
920
942
|
* 共用同一套已登录后台 Chrome,命中会话/权限失效(BLEC0006 等)时自动清 session 重登重试一次。
|
|
921
943
|
*
|
|
922
944
|
* @param {object} schema 当前卡片 schema(需含 pageId)
|
|
@@ -926,19 +948,19 @@ export async function publishCard(schema) {
|
|
|
926
948
|
if (!schema || !schema.pageId) {
|
|
927
949
|
throw new Error('schema 缺少 pageId,无法确定要发布的卡片(IDC10016.do 需要 cardId)。')
|
|
928
950
|
}
|
|
929
|
-
const appId =
|
|
930
|
-
const workspaceId =
|
|
951
|
+
const appId = platformConfig.appId
|
|
952
|
+
const workspaceId = platformConfig.workspaceId
|
|
931
953
|
const cardId = String(schema.pageId)
|
|
932
|
-
const session = await
|
|
954
|
+
const session = await ensurePlatformSession()
|
|
933
955
|
const browser = session.browser
|
|
934
956
|
try {
|
|
935
957
|
const context = browser.contexts()[0]
|
|
936
|
-
const page = context?.pages().find((p) => p
|
|
937
|
-
if (!page) throw new Error('未能在后台 Chrome
|
|
958
|
+
const page = context?.pages().find((p) => isPlatformPage(p)) || context?.pages()[0]
|
|
959
|
+
if (!page) throw new Error('未能在后台 Chrome 中找到远端页面,请先运行 platform-session-navigator 登录。')
|
|
938
960
|
await page.bringToFront()
|
|
939
961
|
|
|
940
962
|
// 1) 取当前最大版本号
|
|
941
|
-
const maxResp = await
|
|
963
|
+
const maxResp = await platformPostWithHeal(
|
|
942
964
|
page,
|
|
943
965
|
`/ubomp-web/IDC10004.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`,
|
|
944
966
|
{ cardId, pageNo: 1, pageSize: 1, sassAppId: appId, sassWorkspaceId: workspaceId },
|
|
@@ -949,7 +971,7 @@ export async function publishCard(schema) {
|
|
|
949
971
|
log.info('发布前取最大版本', { cardId, maxVersion, nextVersion })
|
|
950
972
|
|
|
951
973
|
// 2) 以 maxVersion+1 发布(发布类型/平台等参数对齐 ubomp 发布弹窗的默认值)
|
|
952
|
-
const response = await
|
|
974
|
+
const response = await platformPostWithHeal(
|
|
953
975
|
page,
|
|
954
976
|
`/ubomp-web/IDC10016.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`,
|
|
955
977
|
{
|
|
@@ -978,7 +1000,7 @@ export async function publishCard(schema) {
|
|
|
978
1000
|
/**
|
|
979
1001
|
* 取远端「当前卡片最新版本号」:IDC10004 返回 maxVersion(该卡线上已发布的最高版本)。
|
|
980
1002
|
* 供 UI「卡片来源」tab 展示「远端最新版本」,让用户一眼看到线上当前版本。
|
|
981
|
-
* 只读、不发布;与 publishCard
|
|
1003
|
+
* 只读、不发布;与 publishCard 共用同一后台远端会话(ensurePlatformSession + platformPostWithHeal)。
|
|
982
1004
|
* @param {string|number} cardId
|
|
983
1005
|
* @returns {Promise<{ maxVersion: string }>}
|
|
984
1006
|
*/
|
|
@@ -986,17 +1008,17 @@ export async function fetchCardLatestVersion(cardId) {
|
|
|
986
1008
|
if (cardId == null) {
|
|
987
1009
|
throw new Error('缺少 cardId,无法查询远端版本(IDC10004.do 需要 cardId)。')
|
|
988
1010
|
}
|
|
989
|
-
const appId =
|
|
990
|
-
const workspaceId =
|
|
1011
|
+
const appId = platformConfig.appId
|
|
1012
|
+
const workspaceId = platformConfig.workspaceId
|
|
991
1013
|
const id = String(cardId)
|
|
992
|
-
const session = await
|
|
1014
|
+
const session = await ensurePlatformSession()
|
|
993
1015
|
const browser = session.browser
|
|
994
1016
|
try {
|
|
995
1017
|
const context = browser.contexts()[0]
|
|
996
|
-
const page = context?.pages().find((p) => p
|
|
997
|
-
if (!page) throw new Error('未能在后台 Chrome
|
|
1018
|
+
const page = context?.pages().find((p) => isPlatformPage(p)) || context?.pages()[0]
|
|
1019
|
+
if (!page) throw new Error('未能在后台 Chrome 中找到远端页面,请先运行 platform-session-navigator 登录。')
|
|
998
1020
|
await page.bringToFront()
|
|
999
|
-
const maxResp = await
|
|
1021
|
+
const maxResp = await platformPostWithHeal(
|
|
1000
1022
|
page,
|
|
1001
1023
|
`/ubomp-web/IDC10004.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`,
|
|
1002
1024
|
{ cardId: id, pageNo: 1, pageSize: 1, sassAppId: appId, sassWorkspaceId: workspaceId },
|
|
@@ -1044,8 +1066,8 @@ function normalizeVersionTask(raw) {
|
|
|
1044
1066
|
* 取远端「发布版本记录」分页列表:IDC10004.do 的 versionList(新→旧,最多一页 pageSize 条)。
|
|
1045
1067
|
* 供调试面板「导入信息」tab 的「发布版本记录」弹框渲染
|
|
1046
1068
|
* (版本号 / 平台 / 状态 / 发布时间 / 操作:停止发布)。
|
|
1047
|
-
* 只读;与 fetchCardLatestVersion / fetchCardHistory
|
|
1048
|
-
* (
|
|
1069
|
+
* 只读;与 fetchCardLatestVersion / fetchCardHistory 共用同一后台远端会话
|
|
1070
|
+
* (ensurePlatformSession + platformPostWithHeal,命中会话失效自动清 session 重登重试一次)。
|
|
1049
1071
|
*
|
|
1050
1072
|
* 响应体(逆向 innermanage 前端 inner_flamePublish 页面):
|
|
1051
1073
|
* body.versionList[] = { versionId, version, platformStatus(JSON 字符串,如 '["iOS","Android"]'),
|
|
@@ -1075,17 +1097,17 @@ export async function fetchCardPublishVersions(
|
|
|
1075
1097
|
if (cardId == null) {
|
|
1076
1098
|
throw new Error('缺少 cardId,无法查询发布版本记录(IDC10004.do 需要 cardId)。');
|
|
1077
1099
|
}
|
|
1078
|
-
const appId =
|
|
1079
|
-
const workspaceId =
|
|
1100
|
+
const appId = platformConfig.appId;
|
|
1101
|
+
const workspaceId = platformConfig.workspaceId;
|
|
1080
1102
|
const id = String(cardId);
|
|
1081
|
-
const session = await
|
|
1103
|
+
const session = await ensurePlatformSession();
|
|
1082
1104
|
const browser = session.browser;
|
|
1083
1105
|
try {
|
|
1084
1106
|
const context = browser.contexts()[0];
|
|
1085
|
-
const page = context?.pages().find((p) => p
|
|
1086
|
-
if (!page) throw new Error('未能在后台 Chrome
|
|
1107
|
+
const page = context?.pages().find((p) => isPlatformPage(p)) || context?.pages()[0];
|
|
1108
|
+
if (!page) throw new Error('未能在后台 Chrome 中找到远端页面,请先运行 platform-session-navigator 登录。');
|
|
1087
1109
|
await page.bringToFront();
|
|
1088
|
-
const resp = await
|
|
1110
|
+
const resp = await platformPostWithHeal(
|
|
1089
1111
|
page,
|
|
1090
1112
|
`/ubomp-web/IDC10004.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`,
|
|
1091
1113
|
{
|
|
@@ -1136,7 +1158,7 @@ export async function fetchCardPublishVersions(
|
|
|
1136
1158
|
await Promise.all(
|
|
1137
1159
|
pending.slice(i, i + TASK_CONCURRENCY).map(async (row) => {
|
|
1138
1160
|
try {
|
|
1139
|
-
const taskResp = await
|
|
1161
|
+
const taskResp = await platformPostWithHeal(
|
|
1140
1162
|
page,
|
|
1141
1163
|
`/ubomp-web/IDC20002.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`,
|
|
1142
1164
|
{ packageInfoId: row.versionId },
|
|
@@ -1190,17 +1212,17 @@ export async function fetchCardVersionTasks(packageInfoId) {
|
|
|
1190
1212
|
if (packageInfoId == null || packageInfoId === '') {
|
|
1191
1213
|
throw new Error('缺少 packageInfoId(版本记录 versionId),无法查询发布任务(IDC20002.do)。');
|
|
1192
1214
|
}
|
|
1193
|
-
const appId =
|
|
1194
|
-
const workspaceId =
|
|
1215
|
+
const appId = platformConfig.appId;
|
|
1216
|
+
const workspaceId = platformConfig.workspaceId;
|
|
1195
1217
|
const id = String(packageInfoId);
|
|
1196
|
-
const session = await
|
|
1218
|
+
const session = await ensurePlatformSession();
|
|
1197
1219
|
const browser = session.browser;
|
|
1198
1220
|
try {
|
|
1199
1221
|
const context = browser.contexts()[0];
|
|
1200
|
-
const page = context?.pages().find((p) => p
|
|
1201
|
-
if (!page) throw new Error('未能在后台 Chrome
|
|
1222
|
+
const page = context?.pages().find((p) => isPlatformPage(p)) || context?.pages()[0];
|
|
1223
|
+
if (!page) throw new Error('未能在后台 Chrome 中找到远端页面,请先运行 platform-session-navigator 登录。');
|
|
1202
1224
|
await page.bringToFront();
|
|
1203
|
-
const resp = await
|
|
1225
|
+
const resp = await platformPostWithHeal(
|
|
1204
1226
|
page,
|
|
1205
1227
|
`/ubomp-web/IDC20002.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`,
|
|
1206
1228
|
{ packageInfoId: id },
|
|
@@ -1234,16 +1256,16 @@ export async function updateCardTaskStatus({ taskId, taskStatus = '0' } = {}) {
|
|
|
1234
1256
|
if (taskId == null || taskId === '') {
|
|
1235
1257
|
throw new Error('缺少 taskId,无法变更发布任务状态(IDC20003.do 需要 taskId)。');
|
|
1236
1258
|
}
|
|
1237
|
-
const appId =
|
|
1238
|
-
const workspaceId =
|
|
1239
|
-
const session = await
|
|
1259
|
+
const appId = platformConfig.appId;
|
|
1260
|
+
const workspaceId = platformConfig.workspaceId;
|
|
1261
|
+
const session = await ensurePlatformSession();
|
|
1240
1262
|
const browser = session.browser;
|
|
1241
1263
|
try {
|
|
1242
1264
|
const context = browser.contexts()[0];
|
|
1243
|
-
const page = context?.pages().find((p) => p
|
|
1244
|
-
if (!page) throw new Error('未能在后台 Chrome
|
|
1265
|
+
const page = context?.pages().find((p) => isPlatformPage(p)) || context?.pages()[0];
|
|
1266
|
+
if (!page) throw new Error('未能在后台 Chrome 中找到远端页面,请先运行 platform-session-navigator 登录。');
|
|
1245
1267
|
await page.bringToFront();
|
|
1246
|
-
const body = await
|
|
1268
|
+
const body = await platformPostWithHeal(
|
|
1247
1269
|
page,
|
|
1248
1270
|
`/ubomp-web/IDC20003.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`,
|
|
1249
1271
|
{
|
|
@@ -1287,16 +1309,16 @@ export async function createCardPublishTask({ cardId, versionId, version = "", m
|
|
|
1287
1309
|
if (cardId == null || cardId === "" || versionId == null || versionId === "") {
|
|
1288
1310
|
throw new Error("缺少 cardId / versionId,无法创建发布任务(IDC20004.do 需要两者)。");
|
|
1289
1311
|
}
|
|
1290
|
-
const appId =
|
|
1291
|
-
const workspaceId =
|
|
1292
|
-
const session = await
|
|
1312
|
+
const appId = platformConfig.appId;
|
|
1313
|
+
const workspaceId = platformConfig.workspaceId;
|
|
1314
|
+
const session = await ensurePlatformSession();
|
|
1293
1315
|
const browser = session.browser;
|
|
1294
1316
|
try {
|
|
1295
1317
|
const context = browser.contexts()[0];
|
|
1296
1318
|
const page = context?.pages().find((p) => p.url().includes("finmall.com")) || context?.pages()[0];
|
|
1297
|
-
if (!page) throw new Error("未能在后台 Chrome
|
|
1319
|
+
if (!page) throw new Error("未能在后台 Chrome 中找到远端页面,请先运行 platform-session-navigator 登录。");
|
|
1298
1320
|
await page.bringToFront();
|
|
1299
|
-
const body = await
|
|
1321
|
+
const body = await platformPostWithHeal(
|
|
1300
1322
|
page,
|
|
1301
1323
|
`/ubomp-web/IDC20004.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`,
|
|
1302
1324
|
{
|
|
@@ -1325,7 +1347,7 @@ export async function createCardPublishTask({ cardId, versionId, version = "", m
|
|
|
1325
1347
|
/**
|
|
1326
1348
|
* 取远端「卡片历史版本时间线」:IDC10013 按 cardId 分页返回 schemaValueList(新→旧)。
|
|
1327
1349
|
* 供编辑器「卡片历史记录」tab 渲染 git 式时间线。只读;与 fetchCardLatestVersion 共用
|
|
1328
|
-
*
|
|
1350
|
+
* 同一后台远端会话(ensurePlatformSession + platformPostWithHeal)。
|
|
1329
1351
|
*
|
|
1330
1352
|
* schema 全量(每条数 KB~上百 KB)不跨端透传:服务端就地解析为轻量摘要 + 相邻版本 diff
|
|
1331
1353
|
* 标签,响应体积与 schema 大小解耦,UI 拿到的就是可直接渲染的字段。
|
|
@@ -1339,7 +1361,7 @@ export async function createCardPublishTask({ cardId, versionId, version = "", m
|
|
|
1339
1361
|
// fetchCardHistory(时间线列表)本来就会解析页内全部 schema 算 diff,顺手按
|
|
1340
1362
|
// (cardId, versionId) 缓存;fetchCardVersionSchema 命中缓存时零网络请求,
|
|
1341
1363
|
// 把点击到加载的等待从 ~7s 降到毫秒级。未命中仍走原分页翻找兜底。
|
|
1342
|
-
const SCHEMA_CACHE_TTL_MS = Number(process.env.
|
|
1364
|
+
const SCHEMA_CACHE_TTL_MS = Number(process.env.PLATFORM_SCHEMA_CACHE_TTL_MS || 300000)
|
|
1343
1365
|
const SCHEMA_CACHE_MAX = 500
|
|
1344
1366
|
const _versionSchemaCache = new Map() // `${cardId}::${versionId}` → { schema, createTime, at }
|
|
1345
1367
|
|
|
@@ -1371,17 +1393,17 @@ export async function fetchCardHistory(cardId, { pageNo = 1, pageSize = 30 } = {
|
|
|
1371
1393
|
if (cardId == null) {
|
|
1372
1394
|
throw new Error('缺少 cardId,无法查询远端历史(IDC10013.do 需要 cardId)。')
|
|
1373
1395
|
}
|
|
1374
|
-
const appId =
|
|
1375
|
-
const workspaceId =
|
|
1396
|
+
const appId = platformConfig.appId
|
|
1397
|
+
const workspaceId = platformConfig.workspaceId
|
|
1376
1398
|
const id = String(cardId)
|
|
1377
|
-
const session = await
|
|
1399
|
+
const session = await ensurePlatformSession()
|
|
1378
1400
|
const browser = session.browser
|
|
1379
1401
|
try {
|
|
1380
1402
|
const context = browser.contexts()[0]
|
|
1381
|
-
const page = context?.pages().find((p) => p
|
|
1382
|
-
if (!page) throw new Error('未能在后台 Chrome
|
|
1403
|
+
const page = context?.pages().find((p) => isPlatformPage(p)) || context?.pages()[0]
|
|
1404
|
+
if (!page) throw new Error('未能在后台 Chrome 中找到远端页面,请先运行 platform-session-navigator 登录。')
|
|
1383
1405
|
await page.bringToFront()
|
|
1384
|
-
const resp = await
|
|
1406
|
+
const resp = await platformPostWithHeal(
|
|
1385
1407
|
page,
|
|
1386
1408
|
`/ubomp-web/IDC10013.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`,
|
|
1387
1409
|
{ cardId: id, pageNo, pageSize, sassAppId: appId, sassWorkspaceId: workspaceId },
|
|
@@ -1442,20 +1464,20 @@ export async function fetchCardVersionSchema(cardId, versionId) {
|
|
|
1442
1464
|
log.info('命中版本 schema 缓存(零网络)', { cardId: id, versionId: want })
|
|
1443
1465
|
return { schema: cached.schema, record: { id: want, createTime: cached.createTime || '' } }
|
|
1444
1466
|
}
|
|
1445
|
-
const appId =
|
|
1446
|
-
const workspaceId =
|
|
1447
|
-
const session = await
|
|
1467
|
+
const appId = platformConfig.appId
|
|
1468
|
+
const workspaceId = platformConfig.workspaceId
|
|
1469
|
+
const session = await ensurePlatformSession()
|
|
1448
1470
|
const browser = session.browser
|
|
1449
1471
|
try {
|
|
1450
1472
|
const context = browser.contexts()[0]
|
|
1451
|
-
const page = context?.pages().find((p) => p
|
|
1452
|
-
if (!page) throw new Error('未能在后台 Chrome
|
|
1473
|
+
const page = context?.pages().find((p) => isPlatformPage(p)) || context?.pages()[0]
|
|
1474
|
+
if (!page) throw new Error('未能在后台 Chrome 中找到远端页面,请先运行 platform-session-navigator 登录。')
|
|
1453
1475
|
await page.bringToFront()
|
|
1454
1476
|
const url = `/ubomp-web/IDC10013.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`
|
|
1455
1477
|
let pageNo = 1
|
|
1456
1478
|
let totalPages = 1
|
|
1457
1479
|
do {
|
|
1458
|
-
const resp = await
|
|
1480
|
+
const resp = await platformPostWithHeal(
|
|
1459
1481
|
page,
|
|
1460
1482
|
url,
|
|
1461
1483
|
{ cardId: id, pageNo, pageSize: 100, sassAppId: appId, sassWorkspaceId: workspaceId },
|
|
@@ -1626,7 +1648,7 @@ function parseArgs(argv) {
|
|
|
1626
1648
|
}
|
|
1627
1649
|
|
|
1628
1650
|
async function fetchCardList(page, { pageNo, pageSize, appId, workspaceId, searchValue = '' }) {
|
|
1629
|
-
const body = await
|
|
1651
|
+
const body = await platformPostWithHeal(page, `/ubomp-web/IDC10001.do?sassAppId=${appId}&sassWorkspaceId=${workspaceId}`, {
|
|
1630
1652
|
channel: '',
|
|
1631
1653
|
applyScene: '1',
|
|
1632
1654
|
pageNo,
|
|
@@ -1640,7 +1662,7 @@ async function fetchCardList(page, { pageNo, pageSize, appId, workspaceId, searc
|
|
|
1640
1662
|
}
|
|
1641
1663
|
|
|
1642
1664
|
/**
|
|
1643
|
-
* 拉取远端 schema。返回 `null`
|
|
1665
|
+
* 拉取远端 schema。返回 `null` 表示「空白卡」——该卡片在远端侧从未保存过
|
|
1644
1666
|
* schema(新建后未编辑),IDC10012.do 会返回 errorCode=0 但 body 无 schemaValue。
|
|
1645
1667
|
* 这是合法状态而非主键错误,调用方须走「空白卡落盘」分支,不要当成同步失败。
|
|
1646
1668
|
*/
|
|
@@ -1651,7 +1673,7 @@ async function fetchCardSchema(page, card, { appId, workspaceId }) {
|
|
|
1651
1673
|
// dialog 变体的 cardId 本就不同(如 activityLevel=10000840 / activityLevelDialog=10000841),
|
|
1652
1674
|
// 因此按 cardId 抓取不会串卡;此前的串卡来自已废弃的编辑器 DOM 抓取路径。
|
|
1653
1675
|
if (!card.cardId) throw new Error(`列表未返回 cardId,无法抓取 ${card.id} 的 schema。`);
|
|
1654
|
-
const body = await
|
|
1676
|
+
const body = await platformPostWithHeal(page, '/ubomp-web/IDC10012.do', {
|
|
1655
1677
|
cardId: card.cardId,
|
|
1656
1678
|
sassAppId: appId,
|
|
1657
1679
|
sassWorkspaceId: workspaceId,
|
|
@@ -1673,9 +1695,9 @@ async function fetchCardSchema(page, card, { appId, workspaceId }) {
|
|
|
1673
1695
|
}
|
|
1674
1696
|
|
|
1675
1697
|
/**
|
|
1676
|
-
* 取 schema(已在
|
|
1698
|
+
* 取 schema(已在 platformPostWithHeal 内带会话/权限失效自愈)。
|
|
1677
1699
|
* IDC10012.do 只接受数字型 `cardId` 作为主键,命中 SESSION_INVALID_RE 特征时
|
|
1678
|
-
*
|
|
1700
|
+
* platformPostWithHeal 会自动清 session 重登再试一次,覆盖会话超时与权限态异常。
|
|
1679
1701
|
*/
|
|
1680
1702
|
|
|
1681
1703
|
/** 清空过期会话并以保存的凭据重新登录(复用导航器的登录逻辑,全程在页面上下文内完成)。 */
|
|
@@ -1689,7 +1711,7 @@ async function relogin(page) {
|
|
|
1689
1711
|
/* ignore */
|
|
1690
1712
|
}
|
|
1691
1713
|
}),
|
|
1692
|
-
|
|
1714
|
+
PLATFORM_POST_TIMEOUT_MS,
|
|
1693
1715
|
'page.evaluate(localStorage.clear)',
|
|
1694
1716
|
).catch(() => {});
|
|
1695
1717
|
await page.reload({ waitUntil: "domcontentloaded", timeout: 15000 }).catch(() => {});
|
|
@@ -1708,12 +1730,12 @@ async function relogin(page) {
|
|
|
1708
1730
|
await waitForAuthenticatedPage(page, 20000);
|
|
1709
1731
|
}
|
|
1710
1732
|
|
|
1711
|
-
async function
|
|
1733
|
+
async function platformPost(page, urlPath, requestBody, transCode = urlPath) {
|
|
1712
1734
|
return withTimeout(
|
|
1713
1735
|
page.evaluate(async ({ urlPath, requestBody, transCode, timeoutMs }) => {
|
|
1714
1736
|
const controller = new AbortController();
|
|
1715
1737
|
setTimeout(() => controller.abort(), timeoutMs);
|
|
1716
|
-
//
|
|
1738
|
+
// 远端不用 Cookie 鉴权(document.cookie 恒为空),会话凭据存在 localStorage
|
|
1717
1739
|
// 的 `_sessionId` 中,由前端以 `token` 请求头透传。缺这个头时 IDC10001.do(不鉴权)
|
|
1718
1740
|
// 仍能返回,但 IDC10012.do 会返回 BLEC0006「会话超时」——这正是此前抓取失败的根因。
|
|
1719
1741
|
// 该值仅在页面上下文内读取并直接用于请求,不回传 Node 侧、不打印、不落盘。
|
|
@@ -1733,7 +1755,7 @@ async function finmallPost(page, urlPath, requestBody, transCode = urlPath) {
|
|
|
1733
1755
|
};
|
|
1734
1756
|
const sessionToken = readSessionToken();
|
|
1735
1757
|
if (!sessionToken) {
|
|
1736
|
-
throw new Error('页面缺少会话凭据(localStorage._sessionId 为空),请先运行
|
|
1758
|
+
throw new Error('页面缺少会话凭据(localStorage._sessionId 为空),请先运行 platform-session-navigator 登录。');
|
|
1737
1759
|
}
|
|
1738
1760
|
const url = new URL(urlPath, location.origin).href;
|
|
1739
1761
|
const payload = {
|
|
@@ -1772,12 +1794,12 @@ async function finmallPost(page, urlPath, requestBody, transCode = urlPath) {
|
|
|
1772
1794
|
if (errorCode && errorCode !== '0') {
|
|
1773
1795
|
// 把 errorCode 与响应体片段一并抛出,便于排查(如 cardId 不存在 / 无权限 / 入参结构不符)。
|
|
1774
1796
|
const detail = JSON.stringify(parsed).slice(0, 600);
|
|
1775
|
-
throw new Error(
|
|
1797
|
+
throw new Error(`远端交易失败 [errorCode=${errorCode}] ${parsed.header?.errorMsg || parsed.body?.errorMsg || ''} | ${detail}`);
|
|
1776
1798
|
}
|
|
1777
1799
|
return parsed.body;
|
|
1778
|
-
}, { urlPath, requestBody, transCode, timeoutMs:
|
|
1779
|
-
|
|
1780
|
-
|
|
1800
|
+
}, { urlPath, requestBody, transCode, timeoutMs: PLATFORM_POST_TIMEOUT_MS }),
|
|
1801
|
+
PLATFORM_POST_TIMEOUT_MS + 2000,
|
|
1802
|
+
`远端请求 ${transCode}`
|
|
1781
1803
|
);
|
|
1782
1804
|
}
|
|
1783
1805
|
|
|
@@ -1794,7 +1816,7 @@ function normalizeCard(raw) {
|
|
|
1794
1816
|
}
|
|
1795
1817
|
|
|
1796
1818
|
function filestoreToUrl(value) {
|
|
1797
|
-
return
|
|
1819
|
+
return platformConfig.filestoreUrl(value);
|
|
1798
1820
|
}
|
|
1799
1821
|
|
|
1800
1822
|
async function syncCard(page, card, { outRoot, appId, workspaceId, summary, schemaHashes, importMeta }) {
|
|
@@ -1813,7 +1835,7 @@ async function syncCard(page, card, { outRoot, appId, workspaceId, summary, sche
|
|
|
1813
1835
|
}
|
|
1814
1836
|
const coverPath = await saveCover(page, card, cardDir);
|
|
1815
1837
|
// 注意:schema 内部的 pageId 一律以「远端拉取」的为准,原样落盘,不做覆盖。
|
|
1816
|
-
// 远端返回的 pageId
|
|
1838
|
+
// 远端返回的 pageId 是远端编辑器维护的权威页面/模板 ID,落盘后随 schema 一并保留,
|
|
1817
1839
|
// 供保存(IDC10010)/预览(IDC10015/10020/10021)链路按此主键打到线上。
|
|
1818
1840
|
// 重复 schema 检测:若不同 code 抓到了字节完全相同的 schema,说明仍串卡,
|
|
1819
1841
|
// 记录到 duplicates 并把整体结果标为失败,便于重抓时立即发现而非事后排查。
|
|
@@ -2008,7 +2030,7 @@ async function writeImportSidecar(cardDir, { appId, workspaceId, card, files, im
|
|
|
2008
2030
|
const mod = importMeta || (await import(pathToFileURL(path.resolve(workspace, 'server', 'core', 'cardImportMeta.js')).href));
|
|
2009
2031
|
const raw = card.raw || {};
|
|
2010
2032
|
const meta = mod.buildImportMeta({
|
|
2011
|
-
baseUrl:
|
|
2033
|
+
baseUrl: platformConfig.baseUrl,
|
|
2012
2034
|
appId,
|
|
2013
2035
|
workspaceId,
|
|
2014
2036
|
cardId: card.cardId,
|