cardbuddy 0.9.0 → 0.10.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 +17 -2
- package/dist/cli.js +3 -0
- package/dist/config.js +7 -0
- package/dist/portGuard.js +293 -0
- package/dist/preview-editor/assets/index-C_UKS0NF.css +1 -0
- package/dist/preview-editor/assets/index-D1iIJ4sl.js +81 -0
- package/dist/preview-editor/index.html +2 -2
- package/dist/server-core/assetProxy.js +3 -22
- package/dist/server-core/buildDataFromSchema.js +36 -4
- package/dist/server-core/cardListCache.js +0 -17
- package/dist/server-core/index.js +3 -5
- package/dist/server-core/logStream.js +1 -6
- package/dist/standalone.js +24 -8
- package/dist/vendored/App.vue +187 -77
- package/dist/vendored/components/ComponentPalette.vue +1 -1
- package/dist/vendored/components/DebugPanel.vue +737 -91
- package/dist/vendored/components/NumberStepper.vue +125 -0
- package/dist/vendored/components/ProgressSlider.vue +9 -1
- package/dist/vendored/components/StructureTree.vue +2 -2
- package/dist/vendored/runtime/clipboard-node.js +0 -5
- package/dist/vendored/styles/app.css +707 -252
- package/dist/vendored/styles/card-gallery.css +3 -3
- package/dist/vendored/styles/card-select.css +13 -6
- package/dist/vendored/styles/dropdown.css +1 -2
- package/dist/vendored/styles/json-tree.css +3 -3
- package/dist/vendored/styles/node-inspector.css +7 -294
- package/dist/vendored/styles/setters.css +48 -49
- package/dist/vendored/styles/structure-tree.css +6 -11
- package/package.json +1 -1
- package/dist/preview-editor/assets/index-CrcrVs4F.css +0 -1
- package/dist/preview-editor/assets/index-DnpHHKWl.js +0 -80
- package/dist/vendored/assets/logo.png +0 -0
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon-16-Cg6Nrosk.png" />
|
|
9
9
|
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon-32-B_1744sp.png" />
|
|
10
10
|
<link rel="apple-touch-icon" sizes="180x180" href="/assets/apple-touch-icon-BQcES9QK.png" />
|
|
11
|
-
<script type="module" crossorigin src="/assets/index-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-D1iIJ4sl.js"></script>
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/index-C_UKS0NF.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<div id="app"></div>
|
|
@@ -87,13 +87,9 @@ async function fetchUpstream(pathname, upstream) {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
|
-
* 资源代理 +
|
|
91
|
-
*
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* 资源代理 + 落盘缓存中间件(与 Express / Vite middleware 容器解耦)。
|
|
95
|
-
* 既可由 Vite 插件 configureServer 挂载,也可由 server/core 的 mountCoreMiddlewares
|
|
96
|
-
* 直接挂载到 cardbuddy(8787),实现「Vite 零后端插件、8787 是唯一后端」。
|
|
90
|
+
* 资源代理 + 落盘缓存中间件(回源地址从传入的 upstream 取;与 Express / Vite middleware 容器解耦)。
|
|
91
|
+
* 由 server/core 的 mountCoreMiddlewares 挂载到 cardbuddy(8787),
|
|
92
|
+
* 实现「Vite 零后端插件、8787 是唯一后端」。
|
|
97
93
|
* @param {{ root: string, upstream: string }} opts
|
|
98
94
|
* @returns {(req: import('http').IncomingMessage, res: import('http').ServerResponse, next: Function) => void}
|
|
99
95
|
*/
|
|
@@ -137,18 +133,3 @@ export function createAssetProxyMiddleware({ root, upstream }) {
|
|
|
137
133
|
return res.end(PLACEHOLDER)
|
|
138
134
|
}
|
|
139
135
|
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Vite 插件适配层(保留以兼容纯 vite dev 场景):configureServer 阶段把
|
|
143
|
-
* createAssetProxyMiddleware 挂到 server.middlewares。前后分离架构下已由 server/core
|
|
144
|
-
* 的 mountCoreMiddlewares 挂载到 cardbuddy(8787),Vite 不再需要此插件。
|
|
145
|
-
* @param {{ root: string, upstream: string }} opts
|
|
146
|
-
*/
|
|
147
|
-
export function createAssetProxyPlugin({ root, upstream }) {
|
|
148
|
-
return {
|
|
149
|
-
name: 'finmall-asset-proxy',
|
|
150
|
-
configureServer(server) {
|
|
151
|
-
server.middlewares.use(createAssetProxyMiddleware({ root, upstream }))
|
|
152
|
-
},
|
|
153
|
-
}
|
|
154
|
-
}
|
|
@@ -8,13 +8,21 @@
|
|
|
8
8
|
* 仅当 defaultValue 为空 / 空对象 / 未定义时,回退到 param.desc 里的 JSON 兜底
|
|
9
9
|
* (desc 以 '{' 开头且解析后含该 key 时生效)。
|
|
10
10
|
*
|
|
11
|
+
* mock 覆盖(dictionary.mocks):
|
|
12
|
+
* 平台变量面板的「配置变量 mock」把设计期覆盖值写在 dictionary.mocks(key → 值),
|
|
13
|
+
* 与「默认值」inputParams[].defaultValue 分仓:defaultValue 是随卡发布的缺省数据,
|
|
14
|
+
* mocks 仅供设计期预览覆盖(编辑器画布),不进入 data.json。故默认(options.includeMocks
|
|
15
|
+
* falsy)只按 defaultValue 派生 —— 服务端写盘 / 同步落盘走这条;编辑器预览态传
|
|
16
|
+
* { includeMocks: true },在 defaultValue 之上按 key 叠加非空 mock 值。
|
|
17
|
+
*
|
|
11
18
|
* 本文件是纯 ESM(无任何 node / 浏览器专有依赖),因此既能被服务端(Node)import,
|
|
12
19
|
* 也能被预览前端(Vite 打包)直接 import,避免逻辑漂移。
|
|
13
20
|
*/
|
|
14
|
-
export function buildDataFromSchema(schema) {
|
|
21
|
+
export function buildDataFromSchema(schema, options = {}) {
|
|
15
22
|
// 稳健性:schema 缺失 / 非对象(如外部改坏 schema.json)时返回空对象,
|
|
16
23
|
// 不抛错,避免 GET /__card 在损坏卡片上返回 500 堆栈。
|
|
17
24
|
if (!schema || typeof schema !== 'object') return {}
|
|
25
|
+
const mocks = options.includeMocks ? readMocks(schema) : null
|
|
18
26
|
const data = {}
|
|
19
27
|
for (const param of schema.dictionary?.inputParams || []) {
|
|
20
28
|
const fallback = parseDescFallback(param)
|
|
@@ -24,15 +32,39 @@ export function buildDataFromSchema(schema) {
|
|
|
24
32
|
typeof defaultValue === 'object' &&
|
|
25
33
|
!Array.isArray(defaultValue) &&
|
|
26
34
|
Object.keys(defaultValue).length === 0
|
|
27
|
-
|
|
35
|
+
let value =
|
|
28
36
|
fallback !== undefined && (defaultValue === undefined || defaultValue === '' || emptyObject)
|
|
29
37
|
? fallback
|
|
30
|
-
: defaultValue
|
|
31
|
-
|
|
38
|
+
: defaultValue
|
|
39
|
+
// mock 覆盖优先于默认值;空 mock(未配置)不覆盖,回退 defaultValue / desc 兜底
|
|
40
|
+
if (mocks && hasMockValue(mocks, param.key)) value = mocks[param.key]
|
|
41
|
+
data[param.key] = clone(value)
|
|
32
42
|
}
|
|
33
43
|
return data
|
|
34
44
|
}
|
|
35
45
|
|
|
46
|
+
/**
|
|
47
|
+
* 读取 dictionary.mocks(key → mock 值)。历史卡 / 同步脚本可能写成数组或缺省,
|
|
48
|
+
* 一律归一为 null(视为「没有 mock 表」),调用方无需再判形。
|
|
49
|
+
*/
|
|
50
|
+
export function readMocks(schema) {
|
|
51
|
+
const mocks = schema && schema.dictionary && schema.dictionary.mocks
|
|
52
|
+
return mocks && typeof mocks === 'object' && !Array.isArray(mocks) ? mocks : null
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 某 key 是否「配置了 mock」:undefined / null / 空串 / 空容器 视为未配置
|
|
57
|
+
* (与变量列表的 m 徽标同一判据,避免空壳 mock 被当成有效覆盖)。
|
|
58
|
+
*/
|
|
59
|
+
export function hasMockValue(mocks, key) {
|
|
60
|
+
if (!mocks || !Object.prototype.hasOwnProperty.call(mocks, key)) return false
|
|
61
|
+
const value = mocks[key]
|
|
62
|
+
if (value === undefined || value === null || value === '') return false
|
|
63
|
+
if (Array.isArray(value)) return value.length > 0
|
|
64
|
+
if (typeof value === 'object') return Object.keys(value).length > 0
|
|
65
|
+
return true
|
|
66
|
+
}
|
|
67
|
+
|
|
36
68
|
function parseDescFallback(param) {
|
|
37
69
|
if (!param.desc || typeof param.desc !== 'string') return undefined
|
|
38
70
|
const text = param.desc.trim()
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
const cardIndex = new Map(); // cardId(String) -> { cardId, code, cardName }
|
|
16
|
-
let lastRefreshedAt = 0;
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
18
|
* 写入/合并卡片列表。
|
|
@@ -27,7 +26,6 @@ export function refreshCardList(cards, { full = false } = {}) {
|
|
|
27
26
|
const id = String(c.cardId);
|
|
28
27
|
cardIndex.set(id, { cardId: id, code: c.code, cardName: c.cardName });
|
|
29
28
|
}
|
|
30
|
-
lastRefreshedAt = Date.now();
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
/** 卡片是否存在于缓存列表(按 cardId / pageId 查)。 */
|
|
@@ -35,16 +33,6 @@ export function hasCardId(cardId) {
|
|
|
35
33
|
return cardIndex.has(String(cardId));
|
|
36
34
|
}
|
|
37
35
|
|
|
38
|
-
/** 取缓存中的卡片元信息,不存在返回 null。 */
|
|
39
|
-
export function getCard(cardId) {
|
|
40
|
-
return cardIndex.get(String(cardId)) || null;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** 缓存是否已非空(至少同步过一次全量列表)。 */
|
|
44
|
-
export function cacheSize() {
|
|
45
|
-
return cardIndex.size;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
36
|
/**
|
|
49
37
|
* 推送前存在性校验:目标卡片是否确实在远端卡片列表中(按 cardId/pageId 查)。
|
|
50
38
|
* - 缓存为空(本次 dev server 尚未全量同步过):放行,返回 allowed=true,避免误拦截首推。
|
|
@@ -61,8 +49,3 @@ export function checkPushAllowed(pageId) {
|
|
|
61
49
|
reason: `卡片 pageId=${pageId} 不在远端卡片列表中,疑似已删除或 pageId 错位,请先「远程同步」刷新列表后再推送`,
|
|
62
50
|
};
|
|
63
51
|
}
|
|
64
|
-
|
|
65
|
-
/** 上次刷新时间戳(ms),未刷新为 0。 */
|
|
66
|
-
export function lastRefreshed() {
|
|
67
|
-
return lastRefreshedAt;
|
|
68
|
-
}
|
|
@@ -3,11 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 设计:
|
|
5
5
|
* - 每个端点都是独立 `(req, res, next)` 中间件工厂(见同目录各文件),与 Express / Vite
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* - mountCoreMiddlewares(app, opts) 把全部中间件挂到任意 Connect 风格容器(Vite 的
|
|
10
|
-
* server.middlewares 或 connect 实例皆可),两处共用、改一处两处同步。
|
|
6
|
+
* 中间件容器解耦,由本地开发服务 packages/cardbuddy 统一装配(dev 与发布态同一份)。
|
|
7
|
+
* - mountCoreMiddlewares(app, opts) 把全部中间件挂到任意 Connect 风格容器(cardbuddy 的
|
|
8
|
+
* connect 实例,或 tools/regress-data.mjs 里的临时容器),改一处全链路同步。
|
|
11
9
|
*
|
|
12
10
|
* 注意:renderStatus / nodeModels 需要活着的 vite 实例做 ssrLoadModule,故 mountCoreMiddlewares
|
|
13
11
|
* 接收 viteServer 参数透传;无 SSR 需求的场景可传 null(这两个端点会返回明确错误)。
|
|
@@ -166,11 +166,6 @@ export function subscribeLog(cb) {
|
|
|
166
166
|
return () => subscribers.delete(cb)
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
/** 当前订阅者数量(诊断用)。 */
|
|
170
|
-
export function logSubscriberCount() {
|
|
171
|
-
return subscribers.size
|
|
172
|
-
}
|
|
173
|
-
|
|
174
169
|
let mirrorInstalled = false
|
|
175
170
|
|
|
176
171
|
/**
|
|
@@ -218,7 +213,7 @@ export function installLogMirror() {
|
|
|
218
213
|
|
|
219
214
|
/**
|
|
220
215
|
* 日志流 HTTP 端点:GET /__logs(历史/补漏)、POST /__logs/ingest(外部进程注入)。
|
|
221
|
-
* 挂在 mountCoreMiddlewares
|
|
216
|
+
* 挂在 mountCoreMiddlewares 里,随 cardbuddy 本地服务一并生效。
|
|
222
217
|
*/
|
|
223
218
|
export function createLogMiddleware() {
|
|
224
219
|
const sendJson = (res, status, payload) => {
|
package/dist/standalone.js
CHANGED
|
@@ -24,6 +24,7 @@ import chalk from 'chalk'
|
|
|
24
24
|
|
|
25
25
|
import { mountCoreMiddlewares, installLogMirror, subscribeLog } from './core.js'
|
|
26
26
|
import { loadConfig } from './config.js'
|
|
27
|
+
import { ensurePortFree } from './portGuard.js'
|
|
27
28
|
|
|
28
29
|
const MIME_TYPES = {
|
|
29
30
|
'.html': 'text/html; charset=utf-8',
|
|
@@ -45,6 +46,13 @@ const MIME_TYPES = {
|
|
|
45
46
|
'.map': 'application/json; charset=utf-8',
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
// 被 dev.mjs 拉起时(DSL_LAUNCHER='dev'),来源标签由启动器用带背景色的 chip 标注,
|
|
50
|
+
// 这里让出前缀避免双重来源标签;直接运行 / dev:prod(stdio:inherit)则自带标签。
|
|
51
|
+
const srcTag =
|
|
52
|
+
process.env.DSL_LAUNCHER === 'dev'
|
|
53
|
+
? ''
|
|
54
|
+
: chalk.magenta('▌ ') + chalk.magenta.bold('cardbuddy') + ' '
|
|
55
|
+
|
|
48
56
|
function decodePathname(url) {
|
|
49
57
|
if (!url) return '/'
|
|
50
58
|
const raw = url.split('?')[0]
|
|
@@ -382,6 +390,21 @@ async function resolveTls(config) {
|
|
|
382
390
|
*/
|
|
383
391
|
export async function startServer(userConfig = {}) {
|
|
384
392
|
const config = { ...loadConfig(), ...userConfig }
|
|
393
|
+
|
|
394
|
+
// 日志镜像尽早安装(幂等,CLI 入口已先行装过一次):让端口接管等启动期日志也能进入
|
|
395
|
+
// 编辑器底部「服务日志」面板的环形缓冲。
|
|
396
|
+
installLogMirror()
|
|
397
|
+
|
|
398
|
+
// 端口前置检查:被「上一个 cardbuddy 实例」占用时主动结束它再接管(见 src/portGuard.js)。
|
|
399
|
+
// 放在最前面,避免白跑一遍 TLS / Vite 初始化后才以 EADDRINUSE 失败。
|
|
400
|
+
await ensurePortFree({
|
|
401
|
+
port: config.port,
|
|
402
|
+
tls: config.https,
|
|
403
|
+
token: config.token,
|
|
404
|
+
mode: config.portTakeover,
|
|
405
|
+
log: (msg) => console.log(srcTag + msg),
|
|
406
|
+
})
|
|
407
|
+
|
|
385
408
|
const app = connect()
|
|
386
409
|
|
|
387
410
|
app.use(corsMiddleware)
|
|
@@ -403,8 +426,7 @@ export async function startServer(userConfig = {}) {
|
|
|
403
426
|
|
|
404
427
|
// 服务日志流:镜像本进程 stdout/stderr(含 chalk ANSI)→ 环形缓冲 → SSE 批量推送。
|
|
405
428
|
// 编辑器底部「服务日志」面板订阅 event: service-log;历史与断线补漏走 GET /__logs。
|
|
406
|
-
//
|
|
407
|
-
installLogMirror()
|
|
429
|
+
// 镜像本体在函数开头安装,这里只负责把新增行转推给 SSE 订阅者。
|
|
408
430
|
subscribeLog((lines) => events.notify({ lines }, 'service-log'))
|
|
409
431
|
|
|
410
432
|
const vite = await createEmbeddedVite(config)
|
|
@@ -437,12 +459,6 @@ export async function startServer(userConfig = {}) {
|
|
|
437
459
|
})
|
|
438
460
|
|
|
439
461
|
const bind = `${scheme}://127.0.0.1:${config.port}`
|
|
440
|
-
// 被 dev.mjs 拉起时(DSL_LAUNCHER='dev'),来源标签由启动器用带背景色的 chip 标注,
|
|
441
|
-
// 这里让出前缀避免双重来源标签;直接运行 / dev:prod(stdio:inherit)则自带标签。
|
|
442
|
-
const srcTag =
|
|
443
|
-
process.env.DSL_LAUNCHER === 'dev'
|
|
444
|
-
? ''
|
|
445
|
-
: chalk.magenta('▌ ') + chalk.magenta.bold('cardbuddy') + ' '
|
|
446
462
|
console.log(
|
|
447
463
|
srcTag +
|
|
448
464
|
chalk.green(`本地开发服务已启动:${bind}`) +
|