openyida 2026.7.18 → 2026.7.21
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 +37 -2
- package/bin/yida.js +113 -18
- package/docs/capabilities.md +202 -0
- package/lib/agent-center/agent-center.js +2 -3
- package/lib/app/app-list.js +3 -4
- package/lib/app/build-page.js +13 -6
- package/lib/app/check-page.js +16 -6
- package/lib/app/compile.js +17 -7
- package/lib/app/create-app.js +14 -2
- package/lib/app/create-form/api-path.js +25 -0
- package/lib/app/create-form/args.js +13 -0
- package/lib/app/create-form/commands.js +4 -0
- package/lib/app/create-form/definition-reader.js +23 -23
- package/lib/app/create-form/field-normalizers.js +26 -7
- package/lib/app/create-form/schema-patch.js +4 -1
- package/lib/app/create-form.js +155 -68
- package/lib/app/create-page.js +47 -10
- package/lib/app/generate-page.js +20 -1
- package/lib/app/get-form-config.js +2 -1
- package/lib/app/get-schema.js +67 -15
- package/lib/app/import-app.js +94 -42
- package/lib/app/list-forms.js +4 -8
- package/lib/app/page-ir.js +140 -0
- package/lib/app/publish.js +289 -556
- package/lib/app/schema-field-resolution.js +370 -0
- package/lib/app/services/app-reader.js +85 -0
- package/lib/app/services/app-service.js +235 -0
- package/lib/app/services/canvas-page-compiler.js +91 -0
- package/lib/app/services/canvas-page-schema-builder.js +149 -0
- package/lib/app/services/field-bindings.js +68 -0
- package/lib/app/services/form-compiler.js +1922 -0
- package/lib/app/services/form-mode-service.js +182 -0
- package/lib/app/services/form-schema-patcher.js +333 -0
- package/lib/app/services/form-schema-reader.js +59 -0
- package/lib/app/services/form-service.js +379 -0
- package/lib/app/services/form-validation.js +562 -0
- package/lib/app/services/native-page-compiler.js +92 -0
- package/lib/app/services/native-page-schema-builder.js +428 -0
- package/lib/app/services/page-resource-service.js +185 -0
- package/lib/app/update-app.js +22 -9
- package/lib/app/update-form-config.js +4 -2
- package/lib/asset/asset-cmd.js +19 -6
- package/lib/auth/oauth-loopback.js +376 -15
- package/lib/auth/token-auth.js +34 -3
- package/lib/auth/token-store.js +22 -4
- package/lib/basic-info/basic-info.js +2 -1
- package/lib/bridge/bridge.js +43 -18
- package/lib/core/agent-capabilities.js +5 -3
- package/lib/core/command-errors.js +38 -0
- package/lib/core/command-manifest.js +59 -1
- package/lib/core/copy.js +12 -0
- package/lib/core/doctor.js +15 -4
- package/lib/core/env-cmd.js +1 -1
- package/lib/core/env.js +7 -6
- package/lib/core/i18n.js +66 -8
- package/lib/core/legacy-schema-guard.js +408 -0
- package/lib/core/locales/en.js +38 -46
- package/lib/core/locales/zh.js +30 -46
- package/lib/core/sample.js +12 -2
- package/lib/core/utils.js +334 -66
- package/lib/core/yida-client.js +108 -5
- package/lib/corp-efficiency/corp-efficiency.js +2 -2
- package/lib/corp-manager/corp-manager.js +3 -3
- package/lib/formula/evaluate.js +11 -68
- package/lib/formula/field-refs.js +83 -0
- package/lib/i18n-management/i18n-management.js +2 -3
- package/lib/process/configure-process.js +44 -1992
- package/lib/process/create-process.js +54 -87
- package/lib/process/preview-process.js +20 -8
- package/lib/process/services/process-compiler.js +2056 -0
- package/lib/process/services/process-reader.js +232 -0
- package/lib/process/services/process-resource-service.js +571 -0
- package/lib/process/services/process-service.js +122 -0
- package/lib/process/services/process-stage-checkpoint.js +246 -0
- package/lib/report/append.js +7 -26
- package/lib/report/http.js +31 -5
- package/lib/report/index.js +10 -2
- package/lib/samples/yida-canvas-custom-page/business-list.canvas.jsx +63 -14
- package/lib/samples/yida-canvas-custom-page/dashboard-overview.canvas.jsx +176 -32
- package/lib/samples/yida-canvas-custom-page/dashboard-starter.canvas.jsx +5 -2
- package/lib/samples/yida-canvas-custom-page/data-management.canvas.jsx +228 -14
- package/lib/samples/yida-canvas-custom-page/portal-shell-home.canvas.jsx +2 -2
- package/lib/samples/yida-canvas-custom-page/split-pane-detail.canvas.jsx +206 -10
- package/lib/samples/yida-custom-page/data-management.oyd.jsx +14 -3
- package/lib/samples/yida-custom-page/design-tokens.js +2 -2
- package/lib/samples/yida-custom-page/detail-profile.oyd.jsx +1 -1
- package/lib/samples/yida-custom-page/portal-shell-home.oyd.jsx +7 -2
- package/lib/samples/yida-custom-page/split-pane-detail.oyd.jsx +2 -1
- package/lib/schema/adapters/app-adapter.js +210 -0
- package/lib/schema/adapters/form-adapter.js +1362 -0
- package/lib/schema/adapters/keys.js +19 -0
- package/lib/schema/adapters/page-adapter.js +566 -0
- package/lib/schema/adapters/process-adapter.js +519 -0
- package/lib/schema/applier.js +1878 -0
- package/lib/schema/apply-store.js +1083 -0
- package/lib/schema/command.js +645 -0
- package/lib/schema/dependency-graph.js +83 -0
- package/lib/schema/errors.js +481 -0
- package/lib/schema/hash.js +9 -0
- package/lib/schema/manifest-limits.js +177 -0
- package/lib/schema/manifest-loader.js +309 -0
- package/lib/schema/manifest-schema-v1.json +193 -0
- package/lib/schema/normalize-manifest.js +281 -0
- package/lib/schema/page-canvas-foundation.js +447 -0
- package/lib/schema/page-data-source-builder.js +561 -0
- package/lib/schema/page-foundation.js +556 -0
- package/lib/schema/page-source-loader.js +314 -0
- package/lib/schema/planner.js +691 -0
- package/lib/schema/remote-dispatch-boundary.js +39 -0
- package/lib/schema/remote-missing.js +21 -0
- package/lib/schema/remote-reader.js +189 -0
- package/lib/schema/resource-registry.js +157 -0
- package/lib/schema/server-revision.js +71 -0
- package/lib/schema/sort.js +28 -0
- package/lib/schema/state-store.js +589 -0
- package/package.json +10 -8
- package/scripts/check-release-risks.js +254 -0
- package/scripts/generate-command-docs.js +6 -1
- package/scripts/i18n-baseline.json +11 -11
- package/scripts/postinstall.js +8 -12
- package/scripts/validate-ci.sh +15 -11
- package/scripts/validate-i18n.js +30 -9
- package/scripts/validate-package-size.js +5 -2
- package/scripts/validate-skills.js +4 -0
- package/scripts/validate-structure.js +15 -0
- package/yida-skills/SKILL.md +117 -30
- package/yida-skills/references/schema-as-code-phase1.md +99 -0
- package/yida-skills/references/setup-and-env.md +59 -59
- package/yida-skills/references/task-retrospective.md +6 -6
- package/yida-skills/skills/yida-app/SKILL.md +78 -17
- package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +18 -7
- package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +3 -3
- package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +15 -0
- package/yida-skills/skills/yida-create-app/SKILL.md +21 -3
- package/yida-skills/skills/yida-create-form-page/SKILL.md +19 -1
- package/yida-skills/skills/yida-create-page/SKILL.md +16 -3
- package/yida-skills/skills/yida-create-process/SKILL.md +100 -4
- package/yida-skills/skills/yida-custom-page/SKILL.md +19 -4
- package/yida-skills/skills/yida-dashboard/SKILL.md +1 -1
- package/yida-skills/skills/yida-dashboard/references/pitfalls.md +1 -1
- package/yida-skills/skills/yida-get-schema/SKILL.md +49 -5
- package/yida-skills/skills/yida-i18n/SKILL.md +1 -1
- package/yida-skills/skills/yida-integration/SKILL.md +7 -1
- package/yida-skills/skills/yida-login/SKILL.md +50 -99
- package/yida-skills/skills/yida-page-config/SKILL.md +7 -1
- package/yida-skills/skills/yida-page-uiux/references/app/blueprint.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/app/navigation-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/app/role-journey.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/app-blueprint.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/chart-contracts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/component-contracts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/layout-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/theme-recipes.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/object-narrative.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/section-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/timeline-and-related.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/assets-workflow.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/industry-playbooks.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/research-levels.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/section-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/drawer-detail.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/empty-loading-error.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/filter-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/table-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/scenes/screen.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/entry-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/portal-layouts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/task-feed.md +0 -1
- package/yida-skills/skills/yida-page-uiux/workflow/output-decision-block.md +1 -1
- package/yida-skills/skills/yida-process-rule/SKILL.md +35 -1
- package/yida-skills/skills/yida-publish-page/SKILL.md +46 -4
- package/yida-skills/skills/yida-report/SKILL.md +9 -235
- package/yida-skills/skills/yida-report/references/schema-builder-details.md +239 -0
- package/yida-skills/skills/yida-skill-evaluator/SKILL.md +170 -0
- package/yida-skills/skills-index.json +238 -54
- package/lib/core/locales/ar.js +0 -834
- package/lib/core/locales/de.js +0 -834
- package/lib/core/locales/es.js +0 -834
- package/lib/core/locales/fr.js +0 -834
- package/lib/core/locales/hi.js +0 -834
- package/lib/core/locales/ja.js +0 -1227
- package/lib/core/locales/ko.js +0 -836
- package/lib/core/locales/pt.js +0 -834
- package/lib/core/locales/vi.js +0 -834
- package/lib/core/locales/zh-HK.js +0 -1263
- package/project/pages/src/demo-birthday-game.oyd.jsx +0 -832
- package/project/pages/src/demo-chip-insight.oyd.jsx +0 -983
- package/project/pages/src/demo-compat-smoke.oyd.jsx +0 -58
- package/project/pages/src/demo-crm-batch-entry.oyd.jsx +0 -805
- package/project/pages/src/demo-crm-dashboard.oyd.jsx +0 -677
- package/project/pages/src/demo-future-vision-2026.oyd.jsx +0 -1102
- package/project/pages/src/demo-ppt.oyd.jsx +0 -1192
- package/project/pages/src/demo-salary-calculator.oyd.jsx +0 -904
- package/project/pages/src/openyida-knowledge-doc.oyd.jsx +0 -1714
- package/yida-skills/skills/large-file-write/SKILL.md +0 -93
- package/yida-skills/skills/large-file-write/references/write-patterns.md +0 -147
- package/yida-skills/skills/large-file-write/scripts/write.js +0 -157
- package/yida-skills/skills/sls-log-workbench/SKILL.md +0 -134
- package/yida-skills/skills/sls-log-workbench/references/workbench-reference.md +0 -130
- package/yida-skills/skills/sls-log-workbench/sls-query.js +0 -295
package/lib/app/publish.js
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
* 流程:
|
|
12
12
|
* 1. 读取源文件,通过内置 babel-transform 编译 + UglifyJS 压缩
|
|
13
13
|
* 2. 用代码动态构建 Schema,将 source/compiled 填入 actions.module
|
|
14
|
-
* 3.
|
|
15
|
-
* 4. 通过 HTTP POST 调用 saveFormSchema
|
|
14
|
+
* 3. 读取 token session,在写前确认登录态
|
|
15
|
+
* 4. 通过 HTTP POST 调用 saveFormSchema,token 失效时尝试 token refresh
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
const fs = require('fs');
|
|
@@ -22,22 +22,38 @@ const http = require('http');
|
|
|
22
22
|
const querystring = require('querystring');
|
|
23
23
|
const {
|
|
24
24
|
findProjectRoot,
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
isLoginExpired,
|
|
26
|
+
isCsrfTokenExpired,
|
|
27
27
|
httpPost,
|
|
28
28
|
httpGet,
|
|
29
29
|
requestWithAutoLogin,
|
|
30
30
|
} = require('../core/utils');
|
|
31
|
+
const { createAuthRef, isTokenAuthRef } = require('../core/yida-client');
|
|
32
|
+
const { requireSchemaServerRevision } = require('../schema/server-revision');
|
|
31
33
|
const { t } = require('../core/i18n');
|
|
32
34
|
const { banner, step, label, success, fail, warn, info, error, result, usage, hint } = require('../core/chalk');
|
|
33
35
|
const { compileSource } = require('./page-compiler');
|
|
34
36
|
const { compileCanvas } = require('./canvas-compile');
|
|
35
|
-
const { stripSubtableFieldPrefix } = require('../formula/evaluate');
|
|
36
37
|
const { runLintCheck } = require('./page-linter');
|
|
37
38
|
const { buildPageFile, shouldBuildPageSource } = require('./page-compat');
|
|
38
39
|
const { warnLargePageSource } = require('./page-size-guard');
|
|
39
40
|
const { fetchFormPageList } = require('./form-navigation');
|
|
40
41
|
const { parseOpenOption, withBrowserHandoff } = require('../core/browser-handoff');
|
|
42
|
+
const {
|
|
43
|
+
assertLegacyDirectWriteAllowed,
|
|
44
|
+
extractLegacyGuardArgs,
|
|
45
|
+
} = require('../core/legacy-schema-guard');
|
|
46
|
+
const {
|
|
47
|
+
buildDefaultPageDataSource,
|
|
48
|
+
buildNativePageSchemaContent,
|
|
49
|
+
countCustomPageDataSources,
|
|
50
|
+
extractPageDataSource,
|
|
51
|
+
extractSchemaContent,
|
|
52
|
+
mergePageDataSource,
|
|
53
|
+
} = require('./services/native-page-schema-builder');
|
|
54
|
+
const {
|
|
55
|
+
buildCanvasPageSchemaContent,
|
|
56
|
+
} = require('./services/canvas-page-schema-builder');
|
|
41
57
|
|
|
42
58
|
// ── 配置读取 ──────────────────────────────────────────
|
|
43
59
|
const CONFIG = fs.existsSync(path.resolve(findProjectRoot(), 'config.json')) ? JSON.parse(fs.readFileSync(path.resolve(findProjectRoot(), 'config.json'), 'utf-8')) : {};
|
|
@@ -76,13 +92,20 @@ function normalizePublishArgs(positionals) {
|
|
|
76
92
|
|
|
77
93
|
function parseArgs(argv = process.argv.slice(2)) {
|
|
78
94
|
const openOption = parseOpenOption(argv);
|
|
79
|
-
const
|
|
95
|
+
const guardSplit = extractLegacyGuardArgs(openOption.args);
|
|
96
|
+
const args = guardSplit.args;
|
|
80
97
|
const skipLint = args.includes('--skip-lint');
|
|
81
98
|
const healthCheck = args.includes('--health-check') || args.includes('--check');
|
|
82
99
|
const compat = args.includes('--compat') || args.includes('--modern');
|
|
83
100
|
const force = args.includes('--force');
|
|
84
101
|
const canvas = args.includes('--canvas');
|
|
85
|
-
const
|
|
102
|
+
const help = args.includes('--help') || args.includes('-h');
|
|
103
|
+
const filteredArgs = args.filter(arg => arg !== '--skip-lint' && arg !== '--health-check' && arg !== '--check' && arg !== '--compat' && arg !== '--modern' && arg !== '--force' && arg !== '--canvas' && arg !== '--help' && arg !== '-h');
|
|
104
|
+
|
|
105
|
+
if (help) {
|
|
106
|
+
usage(t('publish.usage'), t('publish.example'));
|
|
107
|
+
return { help: true };
|
|
108
|
+
}
|
|
86
109
|
|
|
87
110
|
if (filteredArgs.length < 3) {
|
|
88
111
|
usage(t('publish.usage'), t('publish.example'));
|
|
@@ -99,230 +122,23 @@ function parseArgs(argv = process.argv.slice(2)) {
|
|
|
99
122
|
force,
|
|
100
123
|
canvas,
|
|
101
124
|
browserOpenMode: openOption.mode,
|
|
125
|
+
legacyGuardOptions: guardSplit.guardOptions,
|
|
102
126
|
};
|
|
103
127
|
}
|
|
104
128
|
|
|
105
|
-
// ──
|
|
106
|
-
|
|
107
|
-
function resolveBaseUrl(authData) {
|
|
108
|
-
return (authData.base_url || DEFAULT_BASE_URL).replace(/\/+$/, '');
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// ── ID 生成工具 ──────────────────────────────────────
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* 创建一个独立的 nodeId 生成器,每次调用 buildSchemaContent 时应创建新实例,
|
|
115
|
-
* 避免模块级全局计数器在多次调用时累加导致 ID 不可预期。
|
|
116
|
-
*/
|
|
117
|
-
function createNodeIdGenerator() {
|
|
118
|
-
let counter = 1;
|
|
119
|
-
return function nextNodeId() {
|
|
120
|
-
return 'node_oc' + Date.now().toString(36) + (counter++).toString(36);
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function generateSuffix() {
|
|
125
|
-
return Date.now().toString(36) + Math.random().toString(36).substring(2, 8);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// ── 2. 构建 Schema ──────────────────────────────────
|
|
129
|
-
|
|
130
|
-
function getGlobalDataSourceFitConfig() {
|
|
131
|
-
const fitCompiled = "'use strict';\n\nvar __preParser__ = function fit(response) {\n var content = response.content !== undefined ? response.content : response;\n var error = {\n message: response.errorMsg || response.errors && response.errors[0] && response.errors[0].msg || response.content || '远程数据源请求出错,success is false'\n };\n var success = true;\n if (response.success !== undefined) {\n success = response.success;\n } else if (response.hasError !== undefined) {\n success = !response.hasError;\n }\n return {\n content: content,\n success: success,\n error: error\n };\n};";
|
|
132
|
-
const fitSource = "function fit(response) {\r\n const content = (response.content !== undefined) ? response.content : response;\r\n const error = {\r\n message: response.errorMsg ||\r\n (response.errors && response.errors[0] && response.errors[0].msg) ||\r\n response.content || '远程数据源请求出错,success is false',\r\n };\r\n let success = true;\r\n if (response.success !== undefined) {\r\n success = response.success;\r\n } else if (response.hasError !== undefined) {\r\n success = !response.hasError;\r\n }\r\n return {\r\n content,\r\n success,\r\n error,\r\n };\r\n}";
|
|
133
|
-
|
|
134
|
-
return {
|
|
135
|
-
fit: {
|
|
136
|
-
compiled: fitCompiled,
|
|
137
|
-
source: fitSource,
|
|
138
|
-
type: 'js',
|
|
139
|
-
error: {},
|
|
140
|
-
},
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function buildDefaultPageDataSource(formUuid) {
|
|
145
|
-
const urlParamsDataSource = {
|
|
146
|
-
id: 'VCB660714833IBHEOXK376TA7XJH2AXUWR8MMW',
|
|
147
|
-
name: 'urlParams',
|
|
148
|
-
description: '当前页面地址的参数:如 aliwork.com/APP_XXX/workbench?id=1&name=宜搭,可通过 this.state.urlParams.name 获取到宜搭',
|
|
149
|
-
formUuid: formUuid,
|
|
150
|
-
protocal: 'URI',
|
|
151
|
-
isReadonly: true,
|
|
152
|
-
};
|
|
153
|
-
const timestampDataSource = {
|
|
154
|
-
id: '',
|
|
155
|
-
name: 'timestamp',
|
|
156
|
-
description: '',
|
|
157
|
-
formUuid: formUuid,
|
|
158
|
-
protocal: 'VALUE',
|
|
159
|
-
initialData: '',
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
return {
|
|
163
|
-
offline: [],
|
|
164
|
-
globalConfig: getGlobalDataSourceFitConfig(),
|
|
165
|
-
online: [urlParamsDataSource, timestampDataSource],
|
|
166
|
-
list: [urlParamsDataSource, timestampDataSource],
|
|
167
|
-
sync: true,
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function cloneJson(value) {
|
|
172
|
-
if (value === undefined || value === null) {
|
|
173
|
-
return value;
|
|
174
|
-
}
|
|
175
|
-
return JSON.parse(JSON.stringify(value));
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function getDataSourceIdentity(item) {
|
|
179
|
-
if (!item || typeof item !== 'object') {
|
|
180
|
-
return '';
|
|
181
|
-
}
|
|
182
|
-
if (isBuiltInPageDataSource(item)) {
|
|
183
|
-
return 'builtin:' + item.name;
|
|
184
|
-
}
|
|
185
|
-
if (item.id) {
|
|
186
|
-
return 'id:' + item.id;
|
|
187
|
-
}
|
|
188
|
-
if (item.name && item.protocal) {
|
|
189
|
-
return 'name:' + item.name + '|protocal:' + item.protocal;
|
|
190
|
-
}
|
|
191
|
-
if (item.name) {
|
|
192
|
-
return 'name:' + item.name;
|
|
193
|
-
}
|
|
194
|
-
return JSON.stringify(item);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function mergeDataSourceArray(existingItems, generatedItems) {
|
|
198
|
-
const merged = Array.isArray(existingItems) ? cloneJson(existingItems) : [];
|
|
199
|
-
const seen = new Set(merged.map(getDataSourceIdentity).filter(Boolean));
|
|
200
|
-
|
|
201
|
-
(Array.isArray(generatedItems) ? generatedItems : []).forEach((item) => {
|
|
202
|
-
const identity = getDataSourceIdentity(item);
|
|
203
|
-
if (!identity || !seen.has(identity)) {
|
|
204
|
-
merged.push(cloneJson(item));
|
|
205
|
-
if (identity) {
|
|
206
|
-
seen.add(identity);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
return merged;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
function mergePageDataSource(existingDataSource, generatedDataSource) {
|
|
215
|
-
if (!existingDataSource || typeof existingDataSource !== 'object') {
|
|
216
|
-
return cloneJson(generatedDataSource);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const existing = cloneJson(existingDataSource);
|
|
220
|
-
const generated = cloneJson(generatedDataSource || {});
|
|
221
|
-
const merged = Object.assign({}, generated, existing);
|
|
222
|
-
|
|
223
|
-
merged.offline = mergeDataSourceArray(existing.offline, generated.offline);
|
|
224
|
-
merged.online = mergeDataSourceArray(existing.online, generated.online);
|
|
225
|
-
merged.list = mergeDataSourceArray(existing.list, generated.list);
|
|
226
|
-
merged.globalConfig = Object.assign(
|
|
227
|
-
{},
|
|
228
|
-
generated.globalConfig || {},
|
|
229
|
-
existing.globalConfig || {}
|
|
230
|
-
);
|
|
231
|
-
merged.sync = existing.sync !== undefined ? existing.sync : generated.sync;
|
|
232
|
-
|
|
233
|
-
return merged;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function extractSchemaContent(schemaResult) {
|
|
237
|
-
if (!schemaResult) {
|
|
238
|
-
return null;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
let content = schemaResult.content !== undefined ? schemaResult.content : schemaResult;
|
|
242
|
-
if (typeof content === 'string') {
|
|
243
|
-
try {
|
|
244
|
-
content = JSON.parse(content);
|
|
245
|
-
} catch {
|
|
246
|
-
return null;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (content && typeof content === 'object' && content.pages) {
|
|
251
|
-
return content;
|
|
252
|
-
}
|
|
253
|
-
if (schemaResult.pages) {
|
|
254
|
-
return schemaResult;
|
|
255
|
-
}
|
|
256
|
-
return null;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
function extractPageDataSource(schema) {
|
|
260
|
-
if (!schema || !Array.isArray(schema.pages)) {
|
|
261
|
-
return null;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
function findPageDataSource(node) {
|
|
265
|
-
if (!node || typeof node !== 'object') {
|
|
266
|
-
return null;
|
|
267
|
-
}
|
|
268
|
-
if (node.componentName === 'Page' && node.dataSource) {
|
|
269
|
-
return node.dataSource;
|
|
270
|
-
}
|
|
271
|
-
const children = Array.isArray(node.children) ? node.children : [];
|
|
272
|
-
for (const child of children) {
|
|
273
|
-
const dataSource = findPageDataSource(child);
|
|
274
|
-
if (dataSource) {
|
|
275
|
-
return dataSource;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
return null;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
for (const page of schema.pages) {
|
|
282
|
-
const tree = page && Array.isArray(page.componentsTree) ? page.componentsTree : [];
|
|
283
|
-
for (const component of tree) {
|
|
284
|
-
const dataSource = findPageDataSource(component);
|
|
285
|
-
if (dataSource) {
|
|
286
|
-
return dataSource;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
return null;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
function isBuiltInPageDataSource(item) {
|
|
294
|
-
return !!(item && (item.name === 'urlParams' || item.name === 'timestamp'));
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
function countCustomPageDataSources(dataSource) {
|
|
298
|
-
if (!dataSource || typeof dataSource !== 'object') {
|
|
299
|
-
return 0;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const identities = new Set();
|
|
303
|
-
['offline', 'online', 'list'].forEach((key) => {
|
|
304
|
-
(Array.isArray(dataSource[key]) ? dataSource[key] : []).forEach((item) => {
|
|
305
|
-
if (!isBuiltInPageDataSource(item)) {
|
|
306
|
-
const identity = getDataSourceIdentity(item);
|
|
307
|
-
if (identity) {
|
|
308
|
-
identities.add(identity);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
return identities.size;
|
|
314
|
-
}
|
|
129
|
+
// ── 2. 读取并构建 Schema ────────────────────────────
|
|
315
130
|
|
|
316
131
|
async function fetchExistingSchemaContent(appType, formUuid, authRef) {
|
|
317
132
|
const result = await requestWithAutoLogin((auth) => {
|
|
318
133
|
return httpGet(
|
|
319
134
|
auth.baseUrl,
|
|
320
135
|
`/alibaba/web/${appType}/${PREFIX}/query/formdesign/getFormSchema.json`,
|
|
321
|
-
{ formUuid, schemaVersion: SCHEMA_VERSION }
|
|
136
|
+
{ formUuid, schemaVersion: SCHEMA_VERSION },
|
|
137
|
+
auth.cookies
|
|
322
138
|
);
|
|
323
139
|
}, authRef);
|
|
324
140
|
|
|
325
|
-
if (!result || result.success === false || result.__needLogin) {
|
|
141
|
+
if (!result || result.success === false || result.__needLogin || result.__csrfExpired) {
|
|
326
142
|
const errorMsg = result ? result.errorMsg || t('common.unknown_error') : t('common.request_failed');
|
|
327
143
|
throw new Error(errorMsg);
|
|
328
144
|
}
|
|
@@ -332,13 +148,16 @@ async function fetchExistingSchemaContent(appType, formUuid, authRef) {
|
|
|
332
148
|
throw new Error(t('create_form.schema_parse_failed'));
|
|
333
149
|
}
|
|
334
150
|
|
|
335
|
-
return
|
|
151
|
+
return {
|
|
152
|
+
schema,
|
|
153
|
+
serverRevision: requireSchemaServerRevision(result),
|
|
154
|
+
};
|
|
336
155
|
}
|
|
337
156
|
|
|
338
157
|
async function readExistingPageDataSource(appType, formUuid, authRef) {
|
|
339
158
|
info(t('publish.data_source_fetching'));
|
|
340
|
-
const
|
|
341
|
-
const dataSource = extractPageDataSource(
|
|
159
|
+
const existing = await fetchExistingSchemaContent(appType, formUuid, authRef);
|
|
160
|
+
const dataSource = extractPageDataSource(existing.schema);
|
|
342
161
|
const customCount = countCustomPageDataSources(dataSource);
|
|
343
162
|
|
|
344
163
|
if (customCount > 0) {
|
|
@@ -347,338 +166,249 @@ async function readExistingPageDataSource(appType, formUuid, authRef) {
|
|
|
347
166
|
info(t('publish.data_source_none'));
|
|
348
167
|
}
|
|
349
168
|
|
|
350
|
-
return dataSource;
|
|
169
|
+
return { dataSource, serverRevision: existing.serverRevision };
|
|
351
170
|
}
|
|
352
171
|
|
|
353
172
|
function buildSchemaContent(sourceCode, compiledCode, formUuid, options = {}) {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
const fixedRefs = sourceFix.count + compiledFix.count;
|
|
361
|
-
if (fixedRefs > 0) {
|
|
362
|
-
info(t('publish.formula_prefix_fixed', fixedRefs));
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
const nextNodeId = createNodeIdGenerator();
|
|
366
|
-
|
|
367
|
-
// 构造函数代码(固定模板)
|
|
368
|
-
const constructorCode = "function constructor() {\nvar module = { exports: {} };\nvar _this = this;\nthis.__initMethods__(module.exports, module);\nObject.keys(module.exports).forEach(function(item) {\n if(typeof module.exports[item] === 'function'){\n _this[item] = module.exports[item];\n }\n});\n\n}";
|
|
369
|
-
const pageDataSource = mergePageDataSource(
|
|
370
|
-
options.existingDataSource,
|
|
371
|
-
buildDefaultPageDataSource(formUuid)
|
|
372
|
-
);
|
|
373
|
-
|
|
374
|
-
const schema = {
|
|
375
|
-
schemaType: 'superform',
|
|
376
|
-
schemaVersion: '5.0',
|
|
377
|
-
pages: [
|
|
378
|
-
{
|
|
379
|
-
utils: [
|
|
380
|
-
{
|
|
381
|
-
name: 'legaoBuiltin',
|
|
382
|
-
type: 'npm',
|
|
383
|
-
content: {
|
|
384
|
-
package: '@ali/vu-legao-builtin',
|
|
385
|
-
version: '3.0.0',
|
|
386
|
-
exportName: 'legaoBuiltin',
|
|
387
|
-
},
|
|
388
|
-
},
|
|
389
|
-
{
|
|
390
|
-
name: 'yidaPlugin',
|
|
391
|
-
type: 'npm',
|
|
392
|
-
content: {
|
|
393
|
-
package: '@ali/vu-yida-plugin',
|
|
394
|
-
version: '1.1.0',
|
|
395
|
-
exportName: 'yidaPlugin',
|
|
396
|
-
},
|
|
397
|
-
},
|
|
398
|
-
],
|
|
399
|
-
componentsMap: [
|
|
400
|
-
{ package: '@ali/vc-deep-yida', version: '1.5.169', componentName: 'RootHeader' },
|
|
401
|
-
{ package: '@ali/vc-deep-yida', version: '1.5.169', componentName: 'Jsx' },
|
|
402
|
-
{ package: '@ali/vc-deep-yida', version: '1.5.169', componentName: 'RootContent' },
|
|
403
|
-
{ package: '@ali/vc-deep-yida', version: '1.5.169', componentName: 'RootFooter' },
|
|
404
|
-
{ package: '@ali/vc-deep-yida', version: '1.5.169', componentName: 'Page' },
|
|
405
|
-
],
|
|
406
|
-
componentsTree: [
|
|
407
|
-
{
|
|
408
|
-
componentName: 'Page',
|
|
409
|
-
id: nextNodeId(),
|
|
410
|
-
props: {
|
|
411
|
-
contentBgColor: 'white',
|
|
412
|
-
pageStyle: { backgroundColor: '#f2f3f5' },
|
|
413
|
-
contentMargin: '0',
|
|
414
|
-
contentPadding: '0',
|
|
415
|
-
showTitle: false,
|
|
416
|
-
contentPaddingMobile: '0',
|
|
417
|
-
templateVersion: '1.0.0',
|
|
418
|
-
contentMarginMobile: '0',
|
|
419
|
-
className: 'page_' + generateSuffix(),
|
|
420
|
-
contentBgColorMobile: 'white',
|
|
421
|
-
},
|
|
422
|
-
condition: true,
|
|
423
|
-
css: 'body{background-color:#f2f3f5}.vc-page-yida-page{--yida-form-content-padding:0;--yida-form-content-margin:0;--yida-layout-padding:0}.vc-deep-container-entry.vc-rootcontent{padding:0!important;margin-top:0!important;margin-right:0!important;margin-bottom:0!important;margin-left:0!important}',
|
|
424
|
-
methods: {
|
|
425
|
-
__initMethods__: {
|
|
426
|
-
type: 'js',
|
|
427
|
-
source: 'function (exports, module) { /*set actions code here*/ }',
|
|
428
|
-
compiled: 'function (exports, module) { /*set actions code here*/ }',
|
|
429
|
-
},
|
|
430
|
-
},
|
|
431
|
-
dataSource: pageDataSource,
|
|
432
|
-
lifeCycles: {
|
|
433
|
-
constructor: {
|
|
434
|
-
type: 'js',
|
|
435
|
-
compiled: constructorCode,
|
|
436
|
-
source: constructorCode,
|
|
437
|
-
},
|
|
438
|
-
componentWillUnmount: {
|
|
439
|
-
name: 'didUnmount',
|
|
440
|
-
id: 'didUnmount',
|
|
441
|
-
type: 'actionRef',
|
|
442
|
-
params: {},
|
|
443
|
-
},
|
|
444
|
-
componentDidMount: {
|
|
445
|
-
name: 'didMount',
|
|
446
|
-
id: 'didMount',
|
|
447
|
-
params: {},
|
|
448
|
-
type: 'actionRef',
|
|
449
|
-
},
|
|
450
|
-
},
|
|
451
|
-
hidden: false,
|
|
452
|
-
title: '',
|
|
453
|
-
isLocked: false,
|
|
454
|
-
conditionGroup: '',
|
|
455
|
-
children: [
|
|
456
|
-
{
|
|
457
|
-
componentName: 'RootHeader',
|
|
458
|
-
id: nextNodeId(),
|
|
459
|
-
props: {},
|
|
460
|
-
condition: true,
|
|
461
|
-
hidden: false,
|
|
462
|
-
title: '',
|
|
463
|
-
isLocked: false,
|
|
464
|
-
conditionGroup: '',
|
|
465
|
-
},
|
|
466
|
-
{
|
|
467
|
-
componentName: 'RootContent',
|
|
468
|
-
id: nextNodeId(),
|
|
469
|
-
props: {},
|
|
470
|
-
condition: true,
|
|
471
|
-
hidden: false,
|
|
472
|
-
title: '',
|
|
473
|
-
isLocked: false,
|
|
474
|
-
conditionGroup: '',
|
|
475
|
-
children: [
|
|
476
|
-
{
|
|
477
|
-
componentName: 'Jsx',
|
|
478
|
-
id: nextNodeId(),
|
|
479
|
-
props: {
|
|
480
|
-
render: {
|
|
481
|
-
type: 'js',
|
|
482
|
-
compiled: 'function main(){\n \n "use strict";\n\nvar __compiledFunc__ = function render() {\n return this.renderJsx();\n};\n return __compiledFunc__.apply(this, arguments);\n }',
|
|
483
|
-
source: 'function render() {\n return this.renderJsx();\n}',
|
|
484
|
-
error: {},
|
|
485
|
-
},
|
|
486
|
-
__style__: {},
|
|
487
|
-
fieldId: 'jsx_' + generateSuffix(),
|
|
488
|
-
},
|
|
489
|
-
condition: true,
|
|
490
|
-
hidden: false,
|
|
491
|
-
title: '',
|
|
492
|
-
isLocked: false,
|
|
493
|
-
conditionGroup: '',
|
|
494
|
-
},
|
|
495
|
-
],
|
|
496
|
-
},
|
|
497
|
-
{
|
|
498
|
-
componentName: 'RootFooter',
|
|
499
|
-
id: nextNodeId(),
|
|
500
|
-
props: {},
|
|
501
|
-
condition: true,
|
|
502
|
-
hidden: false,
|
|
503
|
-
title: '',
|
|
504
|
-
isLocked: false,
|
|
505
|
-
conditionGroup: '',
|
|
506
|
-
},
|
|
507
|
-
],
|
|
508
|
-
},
|
|
509
|
-
],
|
|
510
|
-
id: formUuid,
|
|
511
|
-
connectComponent: [],
|
|
512
|
-
},
|
|
513
|
-
],
|
|
514
|
-
// ★ 核心:source 和 compiled 由编译结果动态填入
|
|
515
|
-
actions: {
|
|
516
|
-
module: {
|
|
517
|
-
compiled: compiledCode,
|
|
518
|
-
source: sourceCode,
|
|
519
|
-
},
|
|
520
|
-
type: 'FUNCTION',
|
|
521
|
-
list: [
|
|
522
|
-
{ id: 'getCustomState', title: 'getCustomState' },
|
|
523
|
-
{ id: 'setCustomState', title: 'setCustomState' },
|
|
524
|
-
{ id: 'forceUpdate', title: 'forceUpdate' },
|
|
525
|
-
{ id: 'didMount', title: 'didMount' },
|
|
526
|
-
{ id: 'didUnmount', title: 'didUnmount' },
|
|
527
|
-
{ id: 'renderJsx', title: 'renderJsx' },
|
|
528
|
-
],
|
|
529
|
-
},
|
|
530
|
-
config: {
|
|
531
|
-
connectComponent: [],
|
|
173
|
+
const logInfo = options.silent === true ? () => {} : info;
|
|
174
|
+
return buildNativePageSchemaContent(sourceCode, compiledCode, formUuid, {
|
|
175
|
+
...options,
|
|
176
|
+
onBuildingSchema: () => logInfo(t('publish.building_schema')),
|
|
177
|
+
onFormulaPrefixFixed: fixedRefs => {
|
|
178
|
+
logInfo(t('publish.formula_prefix_fixed', fixedRefs));
|
|
532
179
|
},
|
|
533
|
-
};
|
|
534
|
-
|
|
535
|
-
return JSON.stringify(schema);
|
|
180
|
+
});
|
|
536
181
|
}
|
|
537
182
|
|
|
538
183
|
// ── 2b. 构建 Code Canvas Schema ─────────────────────
|
|
539
|
-
//
|
|
184
|
+
// 与 native 的差异仅在 content JSON:Page.children 直接挂一个 YidaCodeCanvas
|
|
540
185
|
// 节点,无 RootHeader/RootContent/Jsx/RootFooter;actions.module 为默认 didMount
|
|
541
186
|
// 样板;Page.dataSource 精简(canvas 无原生数据桥)。
|
|
542
|
-
// wire 层(path/query/body/headers
|
|
543
|
-
|
|
544
|
-
// canvas 页无用户页面方法,actions.module 只需注册一个空 didMount。
|
|
545
|
-
const CANVAS_ACTIONS_SOURCE = 'export function didMount() {}';
|
|
546
|
-
const CANVAS_ACTIONS_COMPILED = '"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.didMount=didMount;function didMount(){}';
|
|
187
|
+
// wire 层(path/query/body/headers)复用单次 save transport。
|
|
547
188
|
|
|
548
189
|
function buildCanvasSchemaContent(sourceCode, runtimeCode, importedModules, formUuid) {
|
|
549
190
|
info(t('publish.building_schema'));
|
|
191
|
+
return buildCanvasPageSchemaContent(sourceCode, runtimeCode, importedModules, formUuid);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
// ── 4. 发送 saveFormSchema 请求 ──────────────────────
|
|
196
|
+
|
|
197
|
+
function sendSaveRequestOnce(csrfToken, cookies, schemaContent, baseUrl, appType, formUuid, serverRevision) {
|
|
198
|
+
if (
|
|
199
|
+
typeof csrfToken !== 'string' ||
|
|
200
|
+
csrfToken.length === 0 ||
|
|
201
|
+
!Array.isArray(cookies) ||
|
|
202
|
+
typeof baseUrl !== 'string' ||
|
|
203
|
+
baseUrl.length === 0
|
|
204
|
+
) {
|
|
205
|
+
const authError = new Error('Publish Schema write authentication is not ready.');
|
|
206
|
+
authError.code = 'PUBLISH_SCHEMA_WRITE_PRECHECK_FAILED';
|
|
207
|
+
return Promise.reject(authError);
|
|
208
|
+
}
|
|
209
|
+
const gmtModified = requireSchemaServerRevision({ gmtModified: serverRevision });
|
|
210
|
+
return new Promise((resolve, reject) => {
|
|
211
|
+
const saveSchemaPath = `/alibaba/web/${appType}/${PREFIX}/query/formdesign/saveFormSchema.json?_stamp=${Date.now()}`;
|
|
212
|
+
|
|
213
|
+
const postData = querystring.stringify({
|
|
214
|
+
_csrf_token: csrfToken,
|
|
215
|
+
prefix: PREFIX,
|
|
216
|
+
content: schemaContent,
|
|
217
|
+
formUuid: formUuid,
|
|
218
|
+
gmtModified,
|
|
219
|
+
schemaVersion: SCHEMA_VERSION,
|
|
220
|
+
domainCode: DOMAIN_CODE,
|
|
221
|
+
importSchema: true,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
const cookieHeader = cookies
|
|
225
|
+
.map((cookie) => `${cookie.name}=${cookie.value}`)
|
|
226
|
+
.join('; ');
|
|
227
|
+
|
|
228
|
+
const parsedUrl = new URL(baseUrl);
|
|
229
|
+
const isHttps = parsedUrl.protocol === 'https:';
|
|
230
|
+
const requestModule = isHttps ? https : http;
|
|
550
231
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
type: 'npm',
|
|
563
|
-
content: { package: '@ali/vu-legao-builtin', version: '3.0.0', exportName: 'legaoBuiltin' },
|
|
564
|
-
},
|
|
565
|
-
{
|
|
566
|
-
name: 'yidaPlugin',
|
|
567
|
-
type: 'npm',
|
|
568
|
-
content: { package: '@ali/vu-yida-plugin', version: '1.1.0', exportName: 'yidaPlugin' },
|
|
569
|
-
},
|
|
570
|
-
],
|
|
571
|
-
componentsMap: [
|
|
572
|
-
{ package: '@ali/vc-deep-yida', version: '1.5.169', componentName: 'YidaCodeCanvas' },
|
|
573
|
-
{ package: '@ali/vc-deep-yida', version: '1.5.169', componentName: 'RootHeader' },
|
|
574
|
-
{ package: '@ali/vc-deep-yida', version: '1.5.169', componentName: 'RootContent' },
|
|
575
|
-
{ package: '@ali/vc-deep-yida', version: '1.5.169', componentName: 'RootFooter' },
|
|
576
|
-
{ package: '@ali/vc-deep-yida', version: '1.5.169', componentName: 'Page' },
|
|
577
|
-
],
|
|
578
|
-
componentsTree: [
|
|
579
|
-
{
|
|
580
|
-
componentName: 'Page',
|
|
581
|
-
id: nextNodeId(),
|
|
582
|
-
props: {
|
|
583
|
-
contentBgColor: 'white',
|
|
584
|
-
pageStyle: { backgroundColor: '#f2f3f5' },
|
|
585
|
-
contentMargin: '0',
|
|
586
|
-
contentPadding: '0',
|
|
587
|
-
showTitle: false,
|
|
588
|
-
contentPaddingMobile: '0',
|
|
589
|
-
templateVersion: '1.0.0',
|
|
590
|
-
contentMarginMobile: '0',
|
|
591
|
-
className: 'page_' + generateSuffix(),
|
|
592
|
-
contentBgColorMobile: 'white',
|
|
593
|
-
},
|
|
594
|
-
condition: true,
|
|
595
|
-
css: 'body{background-color:#f2f3f5}.vc-page-yida-page{--yida-form-content-padding:0;--yida-form-content-margin:0;--yida-layout-padding:0}.vc-deep-container-entry.vc-rootcontent{padding:0!important;margin-top:0!important;margin-right:0!important;margin-bottom:0!important;margin-left:0!important}',
|
|
596
|
-
methods: {
|
|
597
|
-
__initMethods__: {
|
|
598
|
-
type: 'js',
|
|
599
|
-
source: 'function (exports, module) { /*set actions code here*/ }',
|
|
600
|
-
compiled: 'function (exports, module) { /*set actions code here*/ }',
|
|
601
|
-
},
|
|
602
|
-
},
|
|
603
|
-
dataSource: {
|
|
604
|
-
offline: [],
|
|
605
|
-
globalConfig: getGlobalDataSourceFitConfig(),
|
|
606
|
-
online: [],
|
|
607
|
-
list: [],
|
|
608
|
-
sync: true,
|
|
609
|
-
},
|
|
610
|
-
lifeCycles: {
|
|
611
|
-
constructor: { type: 'js', compiled: constructorCode, source: constructorCode },
|
|
612
|
-
componentWillUnmount: '',
|
|
613
|
-
componentDidMount: { name: 'didMount', id: 'didMount', params: {}, type: 'actionRef' },
|
|
614
|
-
},
|
|
615
|
-
hidden: false,
|
|
616
|
-
title: '',
|
|
617
|
-
isLocked: false,
|
|
618
|
-
conditionGroup: '',
|
|
619
|
-
children: [
|
|
620
|
-
{
|
|
621
|
-
componentName: 'YidaCodeCanvas',
|
|
622
|
-
id: nextNodeId(),
|
|
623
|
-
props: {
|
|
624
|
-
code: sourceCode,
|
|
625
|
-
runtimeCode: runtimeCode,
|
|
626
|
-
pageType: 'application',
|
|
627
|
-
isWebCCompiled: true,
|
|
628
|
-
componentProps: {},
|
|
629
|
-
importedModules: importedModules || '',
|
|
630
|
-
},
|
|
631
|
-
condition: true,
|
|
632
|
-
hidden: false,
|
|
633
|
-
title: '',
|
|
634
|
-
isLocked: false,
|
|
635
|
-
conditionGroup: '',
|
|
636
|
-
},
|
|
637
|
-
],
|
|
638
|
-
},
|
|
639
|
-
],
|
|
640
|
-
id: formUuid,
|
|
641
|
-
connectComponent: [],
|
|
232
|
+
const requestOptions = {
|
|
233
|
+
hostname: parsedUrl.hostname,
|
|
234
|
+
port: parsedUrl.port || (isHttps ? 443 : 80),
|
|
235
|
+
path: saveSchemaPath,
|
|
236
|
+
method: 'POST',
|
|
237
|
+
headers: {
|
|
238
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
239
|
+
'Content-Length': Buffer.byteLength(postData),
|
|
240
|
+
Origin: baseUrl,
|
|
241
|
+
Referer: `${baseUrl}/`,
|
|
242
|
+
Cookie: cookieHeader,
|
|
642
243
|
},
|
|
643
|
-
|
|
644
|
-
actions: {
|
|
645
|
-
module: { compiled: CANVAS_ACTIONS_COMPILED, source: CANVAS_ACTIONS_SOURCE },
|
|
646
|
-
type: 'FUNCTION',
|
|
647
|
-
list: [{ id: 'didMount', title: 'didMount' }],
|
|
648
|
-
},
|
|
649
|
-
config: { connectComponent: [] },
|
|
650
|
-
};
|
|
244
|
+
};
|
|
651
245
|
|
|
652
|
-
|
|
653
|
-
|
|
246
|
+
const request = requestModule.request(requestOptions, (response) => {
|
|
247
|
+
let responseData = '';
|
|
248
|
+
response.on('data', (chunk) => { responseData += chunk; });
|
|
249
|
+
response.on('end', () => {
|
|
250
|
+
info(t('common.http_status', response.statusCode));
|
|
251
|
+
let parsed;
|
|
252
|
+
try {
|
|
253
|
+
parsed = JSON.parse(responseData);
|
|
254
|
+
} catch (parseError) {
|
|
255
|
+
warn(t('common.response_body', responseData.substring(0, 500)));
|
|
256
|
+
resolve({ success: false, errorMsg: 'HTTP ' + response.statusCode + ': ' + t('common.response_not_json') });
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
// 检测登录过期(errorCode: "307")
|
|
260
|
+
if (isLoginExpired(parsed)) {
|
|
261
|
+
warn(t('common.login_expired', parsed.errorMsg));
|
|
262
|
+
resolve({ __needLogin: true });
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
// 检测 csrf_token 过期(errorCode: "TIANSHU_000030")
|
|
266
|
+
if (isCsrfTokenExpired(parsed)) {
|
|
267
|
+
warn(t('common.csrf_expired', parsed.errorMsg));
|
|
268
|
+
resolve({ __csrfExpired: true });
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
resolve(parsed);
|
|
272
|
+
});
|
|
273
|
+
});
|
|
654
274
|
|
|
275
|
+
request.on('error', (requestError) => { reject(requestError); });
|
|
655
276
|
|
|
656
|
-
|
|
277
|
+
request.write(postData);
|
|
278
|
+
request.end();
|
|
279
|
+
});
|
|
280
|
+
}
|
|
657
281
|
|
|
658
|
-
function
|
|
282
|
+
function sendSaveRequestWithAuth(authRef, schemaContent, appType, formUuid, serverRevision) {
|
|
283
|
+
if (!authRef || typeof authRef.baseUrl !== 'string' || authRef.baseUrl.length === 0) {
|
|
284
|
+
const authError = new Error('Publish Schema write authentication is not ready.');
|
|
285
|
+
authError.code = 'PUBLISH_SCHEMA_WRITE_PRECHECK_FAILED';
|
|
286
|
+
return Promise.reject(authError);
|
|
287
|
+
}
|
|
288
|
+
if (!isTokenAuthRef(authRef)) {
|
|
289
|
+
return sendSaveRequestOnce(
|
|
290
|
+
authRef.csrfToken,
|
|
291
|
+
authRef.cookies,
|
|
292
|
+
schemaContent,
|
|
293
|
+
authRef.baseUrl,
|
|
294
|
+
appType,
|
|
295
|
+
formUuid,
|
|
296
|
+
serverRevision
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
const gmtModified = requireSchemaServerRevision({ gmtModified: serverRevision });
|
|
659
300
|
const saveSchemaPath = `/alibaba/web/${appType}/${PREFIX}/query/formdesign/saveFormSchema.json?_stamp=${Date.now()}`;
|
|
660
301
|
const postData = querystring.stringify({
|
|
302
|
+
_csrf_token: authRef.csrfToken,
|
|
661
303
|
prefix: PREFIX,
|
|
662
304
|
content: schemaContent,
|
|
663
|
-
formUuid
|
|
305
|
+
formUuid,
|
|
306
|
+
gmtModified,
|
|
664
307
|
schemaVersion: SCHEMA_VERSION,
|
|
665
308
|
domainCode: DOMAIN_CODE,
|
|
666
309
|
importSchema: true,
|
|
667
310
|
});
|
|
668
|
-
return httpPost(baseUrl, saveSchemaPath, postData);
|
|
311
|
+
return httpPost(authRef.baseUrl, saveSchemaPath, postData, authRef.cookies, { silentStatus: true });
|
|
669
312
|
}
|
|
670
313
|
|
|
671
314
|
// ── 5. 发送 updateFormConfig 请求 ────────────────────
|
|
672
315
|
|
|
673
|
-
function sendUpdateConfigRequest(baseUrl, appType, formUuid, version, value) {
|
|
316
|
+
function sendUpdateConfigRequest(csrfToken, cookies, baseUrl, appType, formUuid, version, value) {
|
|
674
317
|
const updateConfigPath = `/dingtalk/web/${appType}/query/formdesign/updateFormConfig.json`;
|
|
675
318
|
const postData = querystring.stringify({
|
|
319
|
+
_csrf_token: csrfToken,
|
|
676
320
|
formUuid: formUuid,
|
|
677
321
|
version: version,
|
|
678
322
|
configType: 'MINI_RESOURCE',
|
|
679
323
|
value: value,
|
|
680
324
|
});
|
|
681
|
-
|
|
325
|
+
if (!Array.isArray(cookies) || cookies.length === 0) {
|
|
326
|
+
return httpPost(baseUrl, updateConfigPath, postData);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return new Promise((resolve, reject) => {
|
|
330
|
+
const cookieHeader = cookies
|
|
331
|
+
.map((cookie) => `${cookie.name}=${cookie.value}`)
|
|
332
|
+
.join('; ');
|
|
333
|
+
|
|
334
|
+
const parsedUrl = new URL(baseUrl);
|
|
335
|
+
const isHttps = parsedUrl.protocol === 'https:';
|
|
336
|
+
const requestModule = isHttps ? https : http;
|
|
337
|
+
|
|
338
|
+
const requestOptions = {
|
|
339
|
+
hostname: parsedUrl.hostname,
|
|
340
|
+
port: parsedUrl.port || (isHttps ? 443 : 80),
|
|
341
|
+
path: updateConfigPath,
|
|
342
|
+
method: 'POST',
|
|
343
|
+
headers: {
|
|
344
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
345
|
+
'Content-Length': Buffer.byteLength(postData),
|
|
346
|
+
Origin: baseUrl,
|
|
347
|
+
Referer: `${baseUrl}/`,
|
|
348
|
+
Cookie: cookieHeader,
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
const request = requestModule.request(requestOptions, (response) => {
|
|
353
|
+
let responseData = '';
|
|
354
|
+
response.on('data', (chunk) => { responseData += chunk; });
|
|
355
|
+
response.on('end', () => {
|
|
356
|
+
info(t('common.http_status', response.statusCode));
|
|
357
|
+
let parsed;
|
|
358
|
+
try {
|
|
359
|
+
parsed = JSON.parse(responseData);
|
|
360
|
+
} catch (parseError) {
|
|
361
|
+
warn(t('common.response_body', responseData.substring(0, 500)));
|
|
362
|
+
resolve({ success: false, errorMsg: 'HTTP ' + response.statusCode + ': ' + t('common.response_not_json') });
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
// 检测登录过期(errorCode: "307")
|
|
366
|
+
if (isLoginExpired(parsed)) {
|
|
367
|
+
warn(t('common.login_expired', parsed.errorMsg));
|
|
368
|
+
resolve({ __needLogin: true });
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
// 检测 csrf_token 过期(errorCode: "TIANSHU_000030")
|
|
372
|
+
if (isCsrfTokenExpired(parsed)) {
|
|
373
|
+
warn(t('common.csrf_expired', parsed.errorMsg));
|
|
374
|
+
resolve({ __csrfExpired: true });
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
resolve(parsed);
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
request.on('error', (requestError) => { reject(requestError); });
|
|
382
|
+
|
|
383
|
+
request.write(postData);
|
|
384
|
+
request.end();
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
async function sendUpdateConfigRequestWithAuth(authRef, appType, formUuid, version, value) {
|
|
389
|
+
return requestWithAutoLogin(async (currentAuthRef) => {
|
|
390
|
+
const requestAuthRef = currentAuthRef || {};
|
|
391
|
+
const response = await sendUpdateConfigRequest(
|
|
392
|
+
requestAuthRef.csrfToken,
|
|
393
|
+
requestAuthRef.cookies,
|
|
394
|
+
requestAuthRef.baseUrl || DEFAULT_BASE_URL,
|
|
395
|
+
appType,
|
|
396
|
+
formUuid,
|
|
397
|
+
version,
|
|
398
|
+
value
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
if (response && response.__csrfExpired && isTokenAuthRef(requestAuthRef)) {
|
|
402
|
+
return {
|
|
403
|
+
...response,
|
|
404
|
+
__needLogin: true,
|
|
405
|
+
errorCode: response.errorCode || 'TOKEN_AUTH_REQUIRED',
|
|
406
|
+
errorMsg: response.errorMsg || 'token_auth_required: token auth was rejected while updating page config. Run openyida auth refresh or openyida login.',
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return response;
|
|
411
|
+
}, authRef);
|
|
682
412
|
}
|
|
683
413
|
|
|
684
414
|
function walkFiles(dir, results, limit) {
|
|
@@ -819,13 +549,14 @@ async function ensurePublishTargetOrExit(appType, formUuid, authRef, options = {
|
|
|
819
549
|
return null;
|
|
820
550
|
}
|
|
821
551
|
|
|
822
|
-
|
|
823
|
-
const { getAccessToken } = require('../auth/token-auth');
|
|
824
|
-
const accessToken = await getAccessToken();
|
|
552
|
+
function sendHealthCheckRequest(pageUrl, cookies) {
|
|
825
553
|
return new Promise((resolve) => {
|
|
826
554
|
const parsedUrl = new URL(pageUrl);
|
|
827
555
|
const isHttps = parsedUrl.protocol === 'https:';
|
|
828
556
|
const requestModule = isHttps ? https : http;
|
|
557
|
+
const cookieHeader = cookies
|
|
558
|
+
.map((cookie) => `${cookie.name}=${cookie.value}`)
|
|
559
|
+
.join('; ');
|
|
829
560
|
const requestOptions = {
|
|
830
561
|
hostname: parsedUrl.hostname,
|
|
831
562
|
port: parsedUrl.port || (isHttps ? 443 : 80),
|
|
@@ -833,7 +564,7 @@ async function sendHealthCheckRequest(pageUrl) {
|
|
|
833
564
|
method: 'GET',
|
|
834
565
|
headers: {
|
|
835
566
|
Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
836
|
-
|
|
567
|
+
Cookie: cookieHeader,
|
|
837
568
|
},
|
|
838
569
|
timeout: 30000,
|
|
839
570
|
};
|
|
@@ -871,14 +602,25 @@ async function sendHealthCheckRequest(pageUrl) {
|
|
|
871
602
|
// ── 主流程 ────────────────────────────────────────────
|
|
872
603
|
|
|
873
604
|
async function main(argv) {
|
|
874
|
-
const
|
|
605
|
+
const options = parseArgs(argv);
|
|
606
|
+
if (options.help) {
|
|
607
|
+
return options;
|
|
608
|
+
}
|
|
609
|
+
const { appType, formUuid, sourceFile, skipLint, healthCheck, compat, force, canvas: canvasFlag, browserOpenMode, legacyGuardOptions } = options;
|
|
610
|
+
assertLegacyDirectWriteAllowed({
|
|
611
|
+
command: 'publish',
|
|
612
|
+
resourceType: 'page',
|
|
613
|
+
action: 'update',
|
|
614
|
+
appType,
|
|
615
|
+
formUuid,
|
|
616
|
+
}, { guardOptions: legacyGuardOptions });
|
|
875
617
|
|
|
876
618
|
let sourcePath = path.resolve(sourceFile);
|
|
877
619
|
if (!fs.existsSync(sourcePath)) {
|
|
878
620
|
error(t('publish.source_not_found', sourcePath));
|
|
879
621
|
}
|
|
880
622
|
|
|
881
|
-
//
|
|
623
|
+
// 路由:默认 native;.canvas.jsx / .canvas.tsx 源文件自动走 Code Canvas 链路,
|
|
882
624
|
// --canvas 作为显式覆盖(用于扩展名不规范但确为 canvas 源码的场景)。
|
|
883
625
|
const isCanvas = canvasFlag || /\.canvas\.(jsx|tsx)$/i.test(sourcePath);
|
|
884
626
|
|
|
@@ -890,7 +632,7 @@ async function main(argv) {
|
|
|
890
632
|
let canvasResult = null;
|
|
891
633
|
|
|
892
634
|
if (isCanvas) {
|
|
893
|
-
// Code Canvas
|
|
635
|
+
// Code Canvas 链路:跳过 native 编译/lint,改用本地 Babel 编译
|
|
894
636
|
// (JSX/TS → runtimeCode + importedModules),无需登录态,可在开浏览器前失败快。
|
|
895
637
|
step(1, t('publish.step_canvas_compile'));
|
|
896
638
|
info(t('publish.canvas_compiling'));
|
|
@@ -939,35 +681,35 @@ async function main(argv) {
|
|
|
939
681
|
const compiledPath = path.join(findProjectRoot(), 'pages', 'dist', `${parsedSource.name}.js`);
|
|
940
682
|
|
|
941
683
|
step(2, t('common.step_login', 2));
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
authData = triggerLogin();
|
|
946
|
-
}
|
|
947
|
-
let baseUrl = resolveBaseUrl(authData);
|
|
948
|
-
const authRef = {
|
|
949
|
-
baseUrl,
|
|
950
|
-
authData,
|
|
951
|
-
authMode: authData.auth_mode || '',
|
|
952
|
-
authSource: authData.auth_source || '',
|
|
953
|
-
corpId: authData.corp_id || '',
|
|
954
|
-
userId: authData.user_id || '',
|
|
955
|
-
};
|
|
684
|
+
const authRef = createAuthRef();
|
|
685
|
+
let cookies = authRef.cookies;
|
|
686
|
+
let baseUrl = authRef.baseUrl;
|
|
956
687
|
await ensurePublishTargetOrExit(appType, formUuid, authRef, { force });
|
|
688
|
+
cookies = authRef.cookies;
|
|
957
689
|
baseUrl = authRef.baseUrl;
|
|
958
690
|
|
|
959
691
|
let schemaContent;
|
|
692
|
+
let serverRevision;
|
|
960
693
|
if (isCanvas) {
|
|
694
|
+
try {
|
|
695
|
+
serverRevision = (await fetchExistingSchemaContent(appType, formUuid, authRef)).serverRevision;
|
|
696
|
+
} catch (schemaReadError) {
|
|
697
|
+
fail(t('publish.data_source_fetch_failed', schemaReadError.message));
|
|
698
|
+
process.exit(1);
|
|
699
|
+
}
|
|
961
700
|
// canvasResult 已在登录前本地编译完成,这里只需据其装配 Schema content。
|
|
962
701
|
schemaContent = buildCanvasSchemaContent(sourceCode, canvasResult.runtimeCode, canvasResult.importedModules, formUuid);
|
|
963
702
|
} else {
|
|
964
703
|
let existingDataSource = null;
|
|
965
704
|
try {
|
|
966
|
-
|
|
705
|
+
const existing = await readExistingPageDataSource(appType, formUuid, authRef);
|
|
706
|
+
existingDataSource = existing.dataSource;
|
|
707
|
+
serverRevision = existing.serverRevision;
|
|
967
708
|
} catch (dataSourceError) {
|
|
968
709
|
fail(t('publish.data_source_fetch_failed', dataSourceError.message));
|
|
969
710
|
process.exit(1);
|
|
970
711
|
}
|
|
712
|
+
cookies = authRef.cookies;
|
|
971
713
|
baseUrl = authRef.baseUrl;
|
|
972
714
|
schemaContent = buildSchemaContent(sourceCode, compiledCode, formUuid, { existingDataSource });
|
|
973
715
|
}
|
|
@@ -980,18 +722,12 @@ async function main(argv) {
|
|
|
980
722
|
label('Source:', sourcePath);
|
|
981
723
|
label('Compiled:', compiledPath);
|
|
982
724
|
step(3, t('publish.step_publish'));
|
|
983
|
-
const response = await
|
|
984
|
-
schemaContent,
|
|
985
|
-
ref.baseUrl,
|
|
986
|
-
appType,
|
|
987
|
-
formUuid
|
|
988
|
-
), authRef);
|
|
989
|
-
baseUrl = authRef.baseUrl;
|
|
725
|
+
const response = await sendSaveRequestWithAuth(authRef, schemaContent, appType, formUuid, serverRevision);
|
|
990
726
|
|
|
991
727
|
if (!response || !response.success) {
|
|
992
728
|
const errorMsg = response ? response.errorMsg || t('common.unknown_error') : t('common.request_failed');
|
|
993
729
|
fail(t('publish.publish_failed', errorMsg));
|
|
994
|
-
if (response && !response.__needLogin) {
|
|
730
|
+
if (response && !response.__needLogin && !response.__csrfExpired) {
|
|
995
731
|
hint(t('common.response_detail', JSON.stringify(response, null, 2)));
|
|
996
732
|
}
|
|
997
733
|
process.exit(1);
|
|
@@ -1006,20 +742,15 @@ async function main(argv) {
|
|
|
1006
742
|
|
|
1007
743
|
step(4, t('publish.step_config'));
|
|
1008
744
|
info(t('publish.sending_config'));
|
|
1009
|
-
const configResponse = await
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
savedFormUuid,
|
|
1013
|
-
version,
|
|
1014
|
-
8
|
|
1015
|
-
), authRef);
|
|
1016
|
-
baseUrl = authRef.baseUrl;
|
|
745
|
+
const configResponse = await sendUpdateConfigRequestWithAuth(authRef, appType, savedFormUuid, version, 8);
|
|
746
|
+
cookies = authRef.cookies;
|
|
747
|
+
baseUrl = authRef.baseUrl || baseUrl;
|
|
1017
748
|
|
|
1018
749
|
const pageUrl = `${baseUrl}/${appType}/workbench/${savedFormUuid}`;
|
|
1019
750
|
let healthCheckResult = null;
|
|
1020
751
|
if (healthCheck) {
|
|
1021
752
|
step(5, t('publish.step_health_check'));
|
|
1022
|
-
healthCheckResult = await sendHealthCheckRequest(pageUrl);
|
|
753
|
+
healthCheckResult = await sendHealthCheckRequest(pageUrl, cookies);
|
|
1023
754
|
if (healthCheckResult.ok) {
|
|
1024
755
|
success(t('publish.health_check_ok', healthCheckResult.statusCode));
|
|
1025
756
|
} else {
|
|
@@ -1081,4 +812,6 @@ if (require.main === module) {
|
|
|
1081
812
|
module.exports.countCustomPageDataSources = countCustomPageDataSources;
|
|
1082
813
|
module.exports.buildSchemaContent = buildSchemaContent;
|
|
1083
814
|
module.exports.buildCanvasSchemaContent = buildCanvasSchemaContent;
|
|
815
|
+
module.exports.sendSaveRequestOnce = sendSaveRequestOnce;
|
|
816
|
+
module.exports.sendUpdateConfigRequestWithAuth = sendUpdateConfigRequestWithAuth;
|
|
1084
817
|
}
|