openyida 2026.5.15 → 2026.5.17
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 +4 -2
- package/bin/yida.js +8 -1
- package/lib/app/publish.js +89 -2
- package/lib/core/command-manifest.js +2 -2
- package/lib/core/env-cmd.js +11 -4
- package/lib/core/env-manager.js +102 -3
- package/lib/core/locales/ar.js +9 -0
- package/lib/core/locales/de.js +9 -0
- package/lib/core/locales/en.js +9 -0
- package/lib/core/locales/es.js +9 -0
- package/lib/core/locales/fr.js +9 -0
- package/lib/core/locales/hi.js +9 -0
- package/lib/core/locales/ja.js +9 -0
- package/lib/core/locales/ko.js +9 -0
- package/lib/core/locales/pt.js +9 -0
- package/lib/core/locales/vi.js +9 -0
- package/lib/core/locales/zh-HK.js +9 -0
- package/lib/core/locales/zh.js +9 -0
- package/package.json +1 -1
- package/yida-skills/skills/yida-publish-page/SKILL.md +14 -2
package/README.md
CHANGED
|
@@ -258,12 +258,14 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
|
|
|
258
258
|
| `openyida env setup` | Choose a customer-friendly login environment preset: public, overseas, Alibaba intranet, or private deployment |
|
|
259
259
|
| `openyida env <list\|show\|switch\|add\|remove>` | Manage public/private Yida environment profiles |
|
|
260
260
|
| `openyida commands [--json]` | Emit the machine-readable command manifest |
|
|
261
|
-
| `openyida login [--qr\|--agent-qr\|--codex\|--browser] [--env <name>\|--overseas] [--corp-id <corpId>]` | Log in to Yida |
|
|
261
|
+
| `openyida login [--qr\|--agent-qr\|--codex\|--browser] [--env <name>\|--overseas\|--yidaapps] [--corp-id <corpId>]` | Log in to Yida |
|
|
262
262
|
| `openyida logout` | Log out or switch account |
|
|
263
263
|
| `openyida auth <status\|login\|refresh\|logout>` | Manage login status |
|
|
264
264
|
| `openyida org list` | List accessible organizations |
|
|
265
265
|
| `openyida org switch --corp-id <corpId>` | Switch organization without logging in again |
|
|
266
266
|
|
|
267
|
+
Environment selectors such as `--env intl`, `--overseas`, and `--yidaapps` can be used on login-required commands to choose the target Yida environment for that run.
|
|
268
|
+
|
|
267
269
|
### Applications
|
|
268
270
|
|
|
269
271
|
| Command | Description |
|
|
@@ -289,7 +291,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
|
|
|
289
291
|
| `openyida build-page <sourceFile> [--output file\|--write]` | Build/fix Yida-compatible page source from OpenYida authoring JSX |
|
|
290
292
|
| `openyida check-page <sourceFile> [--compat] [--json]` | Check page compatibility; `.oyd.jsx` is compatibility-built before linting |
|
|
291
293
|
| `openyida compile <sourceFile> [--compat]` | Compile a custom page locally; `.oyd.jsx` sources are compatibility-built first |
|
|
292
|
-
| `openyida publish <sourceFile> <appType> <formUuid> [--compat] [--health-check] [--open\|--no-open]` | Compile and publish a custom page |
|
|
294
|
+
| `openyida publish <sourceFile> <appType> <formUuid> [--compat] [--health-check] [--force] [--open\|--no-open]` | Compile and publish a custom display page; by default the target must be `formType=display` |
|
|
293
295
|
| `openyida update-form-config <appType> <formUuid> <isRenderNav> <title>` | Update page/form display configuration |
|
|
294
296
|
|
|
295
297
|
### Data, Permissions, and Sharing
|
package/bin/yida.js
CHANGED
|
@@ -291,6 +291,7 @@ function applyLoginEnvironmentFlags(cliArgs) {
|
|
|
291
291
|
'--overseas': 'intl',
|
|
292
292
|
'--international': 'intl',
|
|
293
293
|
'--global': 'intl',
|
|
294
|
+
'--yidaapps': 'intl',
|
|
294
295
|
'--alibaba': 'alibaba',
|
|
295
296
|
'--internal': 'alibaba',
|
|
296
297
|
'--intranet': 'alibaba',
|
|
@@ -317,6 +318,11 @@ function applyLoginEnvironmentFlags(cliArgs) {
|
|
|
317
318
|
return filteredArgs;
|
|
318
319
|
}
|
|
319
320
|
|
|
321
|
+
function applyGlobalEnvironmentFlags() {
|
|
322
|
+
const filteredArgs = applyLoginEnvironmentFlags(args);
|
|
323
|
+
args.splice(0, args.length, ...filteredArgs);
|
|
324
|
+
}
|
|
325
|
+
|
|
320
326
|
// 解析全局 --quiet 开关:从 args 中剔除并设置 YIDA_QUIET=1,让 chalk.js
|
|
321
327
|
// 的所有装饰输出(banner/step/info/...)变 no-op,AI 即可直接 `... --quiet | jq`。
|
|
322
328
|
function applyQuietFlag() {
|
|
@@ -329,6 +335,7 @@ function applyQuietFlag() {
|
|
|
329
335
|
|
|
330
336
|
async function main() {
|
|
331
337
|
applyQuietFlag();
|
|
338
|
+
applyGlobalEnvironmentFlags();
|
|
332
339
|
|
|
333
340
|
if (!command || command === '--help' || command === '-h') {
|
|
334
341
|
handleFirstRunGuide();
|
|
@@ -611,7 +618,7 @@ async function main() {
|
|
|
611
618
|
case 'publish': {
|
|
612
619
|
// 参数顺序:<源文件路径> <appType> <formUuid>
|
|
613
620
|
// publish.js 内部读取顺序:argv[2]=appType, argv[3]=formUuid, argv[4]=sourceFile
|
|
614
|
-
const passThroughFlags = new Set(['--skip-lint', '--health-check', '--check', '--open', '--no-open', '--compat', '--modern']);
|
|
621
|
+
const passThroughFlags = new Set(['--skip-lint', '--health-check', '--check', '--open', '--no-open', '--compat', '--modern', '--force']);
|
|
615
622
|
const forwardedFlags = args.filter(arg => passThroughFlags.has(arg));
|
|
616
623
|
const filteredArgs = args.filter(arg => !passThroughFlags.has(arg));
|
|
617
624
|
if (filteredArgs.length < 3) {
|
package/lib/app/publish.js
CHANGED
|
@@ -26,6 +26,7 @@ const { banner, step, label, success, fail, warn, info, error, result, usage, hi
|
|
|
26
26
|
const { compileSource } = require('./page-compiler');
|
|
27
27
|
const { runLintCheck } = require('./page-linter');
|
|
28
28
|
const { buildPageFile, isAuthoringPath } = require('./page-compat');
|
|
29
|
+
const { fetchFormPageList } = require('./form-navigation');
|
|
29
30
|
const { parseOpenOption, withBrowserHandoff } = require('../core/browser-handoff');
|
|
30
31
|
|
|
31
32
|
// ── 配置读取 ──────────────────────────────────────────
|
|
@@ -43,7 +44,8 @@ function parseArgs() {
|
|
|
43
44
|
const skipLint = args.includes('--skip-lint');
|
|
44
45
|
const healthCheck = args.includes('--health-check') || args.includes('--check');
|
|
45
46
|
const compat = args.includes('--compat') || args.includes('--modern');
|
|
46
|
-
const
|
|
47
|
+
const force = args.includes('--force');
|
|
48
|
+
const filteredArgs = args.filter(arg => arg !== '--skip-lint' && arg !== '--health-check' && arg !== '--check' && arg !== '--compat' && arg !== '--modern' && arg !== '--force');
|
|
47
49
|
|
|
48
50
|
if (filteredArgs.length < 3) {
|
|
49
51
|
usage(t('publish.usage'), t('publish.example'));
|
|
@@ -56,6 +58,7 @@ function parseArgs() {
|
|
|
56
58
|
skipLint,
|
|
57
59
|
healthCheck,
|
|
58
60
|
compat,
|
|
61
|
+
force,
|
|
59
62
|
browserOpenMode: openOption.mode,
|
|
60
63
|
};
|
|
61
64
|
}
|
|
@@ -522,6 +525,76 @@ function warnDuplicateSourceMismatches(sourcePath) {
|
|
|
522
525
|
return mismatches;
|
|
523
526
|
}
|
|
524
527
|
|
|
528
|
+
function normalizeFormType(formType) {
|
|
529
|
+
return String(formType || '').trim().toLowerCase();
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function findPublishTarget(forms, formUuid) {
|
|
533
|
+
return (Array.isArray(forms) ? forms : []).find((form) => form && form.formUuid === formUuid) || null;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function isCustomPageTarget(form) {
|
|
537
|
+
return normalizeFormType(form && form.formType) === 'display';
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
async function verifyPublishTarget(appType, formUuid, authRef, options = {}) {
|
|
541
|
+
if (options.force) {
|
|
542
|
+
return { ok: true, skipped: true };
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
try {
|
|
546
|
+
const forms = await fetchFormPageList(appType, authRef);
|
|
547
|
+
const target = findPublishTarget(forms, formUuid);
|
|
548
|
+
|
|
549
|
+
if (!target) {
|
|
550
|
+
return { ok: false, reason: 'not_found' };
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
if (!isCustomPageTarget(target)) {
|
|
554
|
+
return { ok: false, reason: 'wrong_type', target };
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
return { ok: true, target };
|
|
558
|
+
} catch (targetError) {
|
|
559
|
+
return { ok: false, reason: 'fetch_failed', error: targetError };
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
async function ensurePublishTargetOrExit(appType, formUuid, authRef, options = {}) {
|
|
564
|
+
if (options.force) {
|
|
565
|
+
warn(t('publish.target_check_forced'));
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
info(t('publish.target_checking'));
|
|
570
|
+
const check = await verifyPublishTarget(appType, formUuid, authRef, options);
|
|
571
|
+
|
|
572
|
+
if (check.ok) {
|
|
573
|
+
const targetName = check.target.formName || formUuid;
|
|
574
|
+
const targetType = check.target.formType || 'display';
|
|
575
|
+
success(t('publish.target_check_ok', targetName, targetType));
|
|
576
|
+
return check.target;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
if (check.reason === 'wrong_type') {
|
|
580
|
+
const target = check.target || {};
|
|
581
|
+
const targetName = target.formName || formUuid;
|
|
582
|
+
const targetType = target.formType || '-';
|
|
583
|
+
fail(t('publish.target_type_invalid', formUuid, targetType));
|
|
584
|
+
hint(t('publish.target_type_hint', targetName, targetType));
|
|
585
|
+
} else if (check.reason === 'not_found') {
|
|
586
|
+
fail(t('publish.target_not_found', formUuid));
|
|
587
|
+
} else {
|
|
588
|
+
const message = check.error && check.error.message ? check.error.message : t('common.unknown_error');
|
|
589
|
+
fail(t('publish.target_check_failed', message));
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
hint(t('publish.target_list_hint', appType));
|
|
593
|
+
hint(t('publish.target_force_hint'));
|
|
594
|
+
process.exit(1);
|
|
595
|
+
return null;
|
|
596
|
+
}
|
|
597
|
+
|
|
525
598
|
function sendHealthCheckRequest(pageUrl, cookies) {
|
|
526
599
|
return new Promise((resolve) => {
|
|
527
600
|
const parsedUrl = new URL(pageUrl);
|
|
@@ -575,7 +648,7 @@ function sendHealthCheckRequest(pageUrl, cookies) {
|
|
|
575
648
|
// ── 主流程 ────────────────────────────────────────────
|
|
576
649
|
|
|
577
650
|
async function main() {
|
|
578
|
-
const { appType, formUuid, sourceFile, skipLint, healthCheck, compat, browserOpenMode } = parseArgs();
|
|
651
|
+
const { appType, formUuid, sourceFile, skipLint, healthCheck, compat, force, browserOpenMode } = parseArgs();
|
|
579
652
|
|
|
580
653
|
let sourcePath = path.resolve(sourceFile);
|
|
581
654
|
if (!fs.existsSync(sourcePath)) {
|
|
@@ -625,6 +698,16 @@ async function main() {
|
|
|
625
698
|
}
|
|
626
699
|
let { csrf_token: csrfToken, cookies } = cookieData;
|
|
627
700
|
let baseUrl = resolveBaseUrl(cookieData);
|
|
701
|
+
const authRef = {
|
|
702
|
+
csrfToken,
|
|
703
|
+
cookies,
|
|
704
|
+
baseUrl,
|
|
705
|
+
cookieData,
|
|
706
|
+
};
|
|
707
|
+
await ensurePublishTargetOrExit(appType, formUuid, authRef, { force });
|
|
708
|
+
csrfToken = authRef.csrfToken;
|
|
709
|
+
cookies = authRef.cookies;
|
|
710
|
+
baseUrl = authRef.baseUrl;
|
|
628
711
|
|
|
629
712
|
banner(t('publish.title'));
|
|
630
713
|
label('Base URL:', baseUrl);
|
|
@@ -744,4 +827,8 @@ if (require.main === module) {
|
|
|
744
827
|
module.exports = main;
|
|
745
828
|
module.exports.findDuplicateSourceMismatches = findDuplicateSourceMismatches;
|
|
746
829
|
module.exports.sendHealthCheckRequest = sendHealthCheckRequest;
|
|
830
|
+
module.exports.normalizeFormType = normalizeFormType;
|
|
831
|
+
module.exports.findPublishTarget = findPublishTarget;
|
|
832
|
+
module.exports.isCustomPageTarget = isCustomPageTarget;
|
|
833
|
+
module.exports.verifyPublishTarget = verifyPublishTarget;
|
|
747
834
|
}
|
|
@@ -20,7 +20,7 @@ const COMMAND_GROUPS = [
|
|
|
20
20
|
id: 'auth',
|
|
21
21
|
titleKey: 'help.group_auth',
|
|
22
22
|
commands: [
|
|
23
|
-
command('login', ['login'], 'login [--qr|--agent-qr|--codex|--browser] [--env <name>|--overseas] [--corp-id <corpId>]', 'help.cmd_login', {
|
|
23
|
+
command('login', ['login'], 'login [--qr|--agent-qr|--codex|--browser] [--env <name>|--overseas|--yidaapps] [--corp-id <corpId>]', 'help.cmd_login', {
|
|
24
24
|
requiresLogin: false,
|
|
25
25
|
output: 'json',
|
|
26
26
|
}),
|
|
@@ -63,7 +63,7 @@ const COMMAND_GROUPS = [
|
|
|
63
63
|
command('build-page', ['build-page'], 'build-page <sourceFile> [--output file|--write]', 'help.cmd_build_page', { requiresLogin: false }),
|
|
64
64
|
command('check-page', ['check-page'], 'check-page <src> [--compat]', 'help.cmd_check_page', { output: 'text|json' }),
|
|
65
65
|
command('compile', ['compile'], 'compile <src>', 'help.cmd_compile', { requiresLogin: false }),
|
|
66
|
-
command('publish', ['publish'], 'publish <src> <appType> <formUuid> [--health-check] [--open|--no-open]', 'help.cmd_publish'),
|
|
66
|
+
command('publish', ['publish'], 'publish <src> <appType> <formUuid> [--health-check] [--force] [--open|--no-open]', 'help.cmd_publish'),
|
|
67
67
|
command('update-form-config', ['update-form-config'], 'update-form-config <appType> ...', 'help.cmd_update_form_config'),
|
|
68
68
|
],
|
|
69
69
|
},
|
package/lib/core/env-cmd.js
CHANGED
|
@@ -23,6 +23,7 @@ const {
|
|
|
23
23
|
DEFAULT_INTERNATIONAL_ENV,
|
|
24
24
|
DEFAULT_ALIBABA_INTERNAL_ENV,
|
|
25
25
|
resolveEnvNameAlias,
|
|
26
|
+
inferLoginUrlForBaseUrl,
|
|
26
27
|
} = require('./env-manager');
|
|
27
28
|
|
|
28
29
|
// ── 颜色常量 ──────────────────────────────────────────
|
|
@@ -101,6 +102,9 @@ function detectSetupRecommendation() {
|
|
|
101
102
|
if ((process.env.OPENYIDA_LOGIN_URL || '').includes('login.dingtalk.io')) {
|
|
102
103
|
return 'intl';
|
|
103
104
|
}
|
|
105
|
+
if ((process.env.OPENYIDA_ENDPOINT || '').includes('yidaapps.com')) {
|
|
106
|
+
return 'intl';
|
|
107
|
+
}
|
|
104
108
|
if ((process.env.OPENYIDA_ENDPOINT || '').includes('alibaba-inc.com')) {
|
|
105
109
|
return 'alibaba';
|
|
106
110
|
}
|
|
@@ -332,9 +336,12 @@ async function cmdAdd(envName) {
|
|
|
332
336
|
process.exit(1);
|
|
333
337
|
}
|
|
334
338
|
|
|
335
|
-
// 自动推导登录 URL
|
|
336
|
-
const inferredLoginUrl = baseUrl
|
|
337
|
-
const
|
|
339
|
+
// 自动推导登录 URL:yidaapps.com 必须走 login.dingtalk.io OAuth。
|
|
340
|
+
const inferredLoginUrl = inferLoginUrlForBaseUrl(baseUrl);
|
|
341
|
+
const workPlatformLoginUrl = baseUrl.replace(/\/+$/, '') + '/workPlatform';
|
|
342
|
+
const defaultLoginUrl = existingConfig?.loginUrl && existingConfig.loginUrl !== workPlatformLoginUrl
|
|
343
|
+
? existingConfig.loginUrl
|
|
344
|
+
: inferredLoginUrl;
|
|
338
345
|
const loginUrl = await askQuestion(`${BOLD}登录页面地址${RESET}:`, defaultLoginUrl);
|
|
339
346
|
|
|
340
347
|
const defaultDescription = existingConfig?.description || '';
|
|
@@ -390,7 +397,7 @@ async function cmdSetup() {
|
|
|
390
397
|
},
|
|
391
398
|
{
|
|
392
399
|
key: 'intl',
|
|
393
|
-
title: '海外 DingTalk / Dingtalk Wukong',
|
|
400
|
+
title: '海外 YiDA Apps / DingTalk / Dingtalk Wukong',
|
|
394
401
|
baseUrl: DEFAULT_INTERNATIONAL_ENV.baseUrl,
|
|
395
402
|
loginUrl: DEFAULT_INTERNATIONAL_ENV.loginUrl,
|
|
396
403
|
},
|
package/lib/core/env-manager.js
CHANGED
|
@@ -31,6 +31,7 @@ const { findProjectRoot } = require('./utils');
|
|
|
31
31
|
|
|
32
32
|
const DEFAULT_BASE_URL = 'https://www.aliwork.com';
|
|
33
33
|
const DEFAULT_LOGIN_URL = 'https://www.aliwork.com/workPlatform';
|
|
34
|
+
const INTERNATIONAL_BASE_URL = 'https://www.yidaapps.com';
|
|
34
35
|
const DINGTALK_OAUTH_CLIENT_ID = 'suite9xvlxxerybljwheo';
|
|
35
36
|
const DINGTALK_LOGIN_ORIGIN = 'https://login.dingtalk.com';
|
|
36
37
|
const DINGTALK_INTL_LOGIN_ORIGIN = 'https://login.dingtalk.io';
|
|
@@ -69,6 +70,11 @@ function buildDingtalkOAuthLoginUrl(options = {}) {
|
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
const INTERNATIONAL_LOGIN_URL = buildDingtalkOAuthLoginUrl({
|
|
73
|
+
loginOrigin: DINGTALK_INTL_LOGIN_ORIGIN,
|
|
74
|
+
baseUrl: INTERNATIONAL_BASE_URL,
|
|
75
|
+
lang: 'en_US',
|
|
76
|
+
});
|
|
77
|
+
const LEGACY_INTERNATIONAL_LOGIN_URL = buildDingtalkOAuthLoginUrl({
|
|
72
78
|
loginOrigin: DINGTALK_INTL_LOGIN_ORIGIN,
|
|
73
79
|
baseUrl: DEFAULT_BASE_URL,
|
|
74
80
|
lang: 'en_US',
|
|
@@ -92,9 +98,9 @@ const DEFAULT_ALIBABA_INTERNAL_ENV = {
|
|
|
92
98
|
|
|
93
99
|
/** 海外版 DingTalk / Wukong 环境配置 */
|
|
94
100
|
const DEFAULT_INTERNATIONAL_ENV = {
|
|
95
|
-
baseUrl:
|
|
101
|
+
baseUrl: INTERNATIONAL_BASE_URL,
|
|
96
102
|
loginUrl: INTERNATIONAL_LOGIN_URL,
|
|
97
|
-
description: '海外版 DingTalk / Wukong(login.dingtalk.io)',
|
|
103
|
+
description: '海外版 YiDA Apps / DingTalk / Wukong(login.dingtalk.io)',
|
|
98
104
|
cookieFile: 'cookies-intl.json',
|
|
99
105
|
};
|
|
100
106
|
|
|
@@ -122,11 +128,13 @@ const ENV_ALIASES = {
|
|
|
122
128
|
|
|
123
129
|
const SHARED_COOKIE_DOMAINS = new Set([
|
|
124
130
|
'aliwork.com',
|
|
131
|
+
'yidaapps.com',
|
|
125
132
|
'alibaba-inc.com',
|
|
126
133
|
]);
|
|
127
134
|
|
|
128
135
|
const KNOWN_YIDA_HOSTS = new Set([
|
|
129
136
|
'www.aliwork.com',
|
|
137
|
+
'www.yidaapps.com',
|
|
130
138
|
'yida-group.alibaba-inc.com',
|
|
131
139
|
]);
|
|
132
140
|
|
|
@@ -156,9 +164,21 @@ function ensureBuiltinEnvironments(config) {
|
|
|
156
164
|
config.environments[envName] = { ...envConfig };
|
|
157
165
|
}
|
|
158
166
|
}
|
|
167
|
+
if (isLegacyInternationalEnv(config.environments.intl)) {
|
|
168
|
+
config.environments.intl = { ...DEFAULT_INTERNATIONAL_ENV };
|
|
169
|
+
}
|
|
159
170
|
return config;
|
|
160
171
|
}
|
|
161
172
|
|
|
173
|
+
function isLegacyInternationalEnv(envConfig) {
|
|
174
|
+
return !!(
|
|
175
|
+
envConfig &&
|
|
176
|
+
normalizeBaseUrl(envConfig.baseUrl, null) === DEFAULT_BASE_URL &&
|
|
177
|
+
(!envConfig.loginUrl || envConfig.loginUrl === LEGACY_INTERNATIONAL_LOGIN_URL) &&
|
|
178
|
+
(!envConfig.cookieFile || envConfig.cookieFile === 'cookies-intl.json')
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
162
182
|
function normalizeBaseUrl(value, fallback = null) {
|
|
163
183
|
if (!value) { return fallback; }
|
|
164
184
|
const trimmed = String(value).trim();
|
|
@@ -199,12 +219,47 @@ function isYidaServiceHost(hostname) {
|
|
|
199
219
|
if (!host) { return false; }
|
|
200
220
|
if (KNOWN_YIDA_HOSTS.has(host)) { return true; }
|
|
201
221
|
if (host.endsWith('.aliwork.com') && host !== 'aliwork.com') { return true; }
|
|
222
|
+
if (host.endsWith('.yidaapps.com') && host !== 'yidaapps.com') { return true; }
|
|
202
223
|
if (host.endsWith('.alibaba-inc.com') && host !== 'alibaba-inc.com') {
|
|
203
224
|
return host.startsWith('yida-') || host.includes('.yida-') || host.includes('.yida.');
|
|
204
225
|
}
|
|
205
226
|
return false;
|
|
206
227
|
}
|
|
207
228
|
|
|
229
|
+
function isYidaAppsHost(hostname) {
|
|
230
|
+
const host = normalizeHostname(hostname);
|
|
231
|
+
return host === 'yidaapps.com' || host.endsWith('.yidaapps.com');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function isDefaultWorkPlatformLoginUrl(loginUrl, baseUrl) {
|
|
235
|
+
const loginOrigin = normalizeBaseUrl(loginUrl, null);
|
|
236
|
+
const baseOrigin = normalizeBaseUrl(baseUrl, null);
|
|
237
|
+
if (!loginOrigin || !baseOrigin || loginOrigin !== baseOrigin) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
try {
|
|
242
|
+
const parsedUrl = new URL(/^[a-z][a-z0-9+.-]*:\/\//i.test(loginUrl) ? loginUrl : `https://${loginUrl}`);
|
|
243
|
+
return parsedUrl.pathname.replace(/\/+$/, '') === '/workPlatform' &&
|
|
244
|
+
!parsedUrl.search &&
|
|
245
|
+
!parsedUrl.hash;
|
|
246
|
+
} catch {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function inferLoginUrlForBaseUrl(baseUrl, fallbackLoginUrl) {
|
|
252
|
+
const normalizedBaseUrl = normalizeBaseUrl(baseUrl, DEFAULT_BASE_URL);
|
|
253
|
+
if (isYidaAppsHost(normalizedBaseUrl)) {
|
|
254
|
+
return buildDingtalkOAuthLoginUrl({
|
|
255
|
+
loginOrigin: DINGTALK_INTL_LOGIN_ORIGIN,
|
|
256
|
+
baseUrl: normalizedBaseUrl,
|
|
257
|
+
lang: 'en_US',
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
return fallbackLoginUrl || `${normalizedBaseUrl}/workPlatform`;
|
|
261
|
+
}
|
|
262
|
+
|
|
208
263
|
function cookieDomainToBaseUrl(domain, fallbackUrl) {
|
|
209
264
|
const host = normalizeHostname(domain);
|
|
210
265
|
if (!host || isSharedCookieDomain(host)) {
|
|
@@ -241,7 +296,15 @@ function deriveBaseUrlFromCookies(cookies = [], fallbackUrl = DEFAULT_BASE_URL)
|
|
|
241
296
|
}
|
|
242
297
|
|
|
243
298
|
function deriveBaseUrlFromUrl(fallbackBaseUrl, candidateUrl) {
|
|
244
|
-
|
|
299
|
+
let fallbackOrigin = normalizeBaseUrl(fallbackBaseUrl, DEFAULT_BASE_URL);
|
|
300
|
+
const fallbackHost = normalizeHostname(fallbackOrigin);
|
|
301
|
+
if (!isYidaServiceHost(fallbackHost)) {
|
|
302
|
+
const callbackOrigin = deriveBaseUrlFromDingtalkOAuthUrl(fallbackBaseUrl, null);
|
|
303
|
+
if (callbackOrigin) {
|
|
304
|
+
fallbackOrigin = callbackOrigin;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
245
308
|
const candidateOrigin = normalizeBaseUrl(candidateUrl, null);
|
|
246
309
|
if (!candidateOrigin) { return fallbackOrigin; }
|
|
247
310
|
|
|
@@ -249,6 +312,29 @@ function deriveBaseUrlFromUrl(fallbackBaseUrl, candidateUrl) {
|
|
|
249
312
|
return isYidaServiceHost(candidateHost) ? candidateOrigin : fallbackOrigin;
|
|
250
313
|
}
|
|
251
314
|
|
|
315
|
+
function deriveBaseUrlFromDingtalkOAuthUrl(oauthUrl, fallbackUrl) {
|
|
316
|
+
if (!oauthUrl) { return fallbackUrl || null; }
|
|
317
|
+
|
|
318
|
+
try {
|
|
319
|
+
const parsedUrl = new URL(oauthUrl);
|
|
320
|
+
const host = normalizeHostname(parsedUrl.hostname);
|
|
321
|
+
const isDingtalkLoginHost = host.endsWith('dingtalk.com') || host.endsWith('dingtalk.io');
|
|
322
|
+
if (!isDingtalkLoginHost || !parsedUrl.pathname.startsWith('/oauth2/')) {
|
|
323
|
+
return fallbackUrl || null;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const redirectUri = parsedUrl.searchParams.get('redirect_uri');
|
|
327
|
+
const redirectOrigin = normalizeBaseUrl(redirectUri, null);
|
|
328
|
+
if (redirectOrigin && isYidaServiceHost(normalizeHostname(redirectOrigin))) {
|
|
329
|
+
return redirectOrigin;
|
|
330
|
+
}
|
|
331
|
+
} catch {
|
|
332
|
+
// ignore malformed URLs
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return fallbackUrl || null;
|
|
336
|
+
}
|
|
337
|
+
|
|
252
338
|
// ── 配置文件读写 ──────────────────────────────────────
|
|
253
339
|
|
|
254
340
|
/**
|
|
@@ -398,13 +484,23 @@ function resolveLoginUrl(projectRoot) {
|
|
|
398
484
|
return process.env.OPENYIDA_LOGIN_URL;
|
|
399
485
|
}
|
|
400
486
|
|
|
487
|
+
if (process.env.OPENYIDA_ENDPOINT) {
|
|
488
|
+
return inferLoginUrlForBaseUrl(process.env.OPENYIDA_ENDPOINT);
|
|
489
|
+
}
|
|
490
|
+
|
|
401
491
|
const { config: envConfig } = getCurrentEnvConfig(projectRoot);
|
|
492
|
+
const baseUrl = normalizeBaseUrl(envConfig.baseUrl, DEFAULT_BASE_URL);
|
|
493
|
+
if (!envConfig.loginUrl || isDefaultWorkPlatformLoginUrl(envConfig.loginUrl, baseUrl)) {
|
|
494
|
+
return inferLoginUrlForBaseUrl(baseUrl, envConfig.loginUrl || DEFAULT_LOGIN_URL);
|
|
495
|
+
}
|
|
496
|
+
|
|
402
497
|
return envConfig.loginUrl || DEFAULT_LOGIN_URL;
|
|
403
498
|
}
|
|
404
499
|
|
|
405
500
|
module.exports = {
|
|
406
501
|
DEFAULT_BASE_URL,
|
|
407
502
|
DEFAULT_LOGIN_URL,
|
|
503
|
+
INTERNATIONAL_BASE_URL,
|
|
408
504
|
DINGTALK_OAUTH_CLIENT_ID,
|
|
409
505
|
DINGTALK_LOGIN_ORIGIN,
|
|
410
506
|
DINGTALK_INTL_LOGIN_ORIGIN,
|
|
@@ -426,6 +522,9 @@ module.exports = {
|
|
|
426
522
|
normalizeBaseUrl,
|
|
427
523
|
normalizeHostname,
|
|
428
524
|
isYidaServiceHost,
|
|
525
|
+
isYidaAppsHost,
|
|
526
|
+
inferLoginUrlForBaseUrl,
|
|
527
|
+
deriveBaseUrlFromDingtalkOAuthUrl,
|
|
429
528
|
deriveBaseUrlFromCookies,
|
|
430
529
|
deriveBaseUrlFromUrl,
|
|
431
530
|
};
|
package/lib/core/locales/ar.js
CHANGED
|
@@ -461,6 +461,15 @@ module.exports = {
|
|
|
461
461
|
lint_passed: ' ✅ فحص الكود ناجح\n',
|
|
462
462
|
lint_skipped: '\n⏭️ تم تخطي فحص الكود المسبق (--skip-lint)\n',
|
|
463
463
|
duplicate_source_mismatch: ' ⚠️ Found another copy with the same file name but different content. Publishing: {0}; other copy: {1}',
|
|
464
|
+
target_checking: ' Checking publish target type...',
|
|
465
|
+
target_check_forced: ' ⚠️ Skipped publish target type check (--force)',
|
|
466
|
+
target_check_ok: ' ✅ Publish target confirmed: {0} ({1})',
|
|
467
|
+
target_check_failed: 'Could not verify publish target: {0}',
|
|
468
|
+
target_not_found: 'Publish target was not found in app navigation: {0}',
|
|
469
|
+
target_type_invalid: 'Publish target is not a custom display page: {0} current type is {1}',
|
|
470
|
+
target_type_hint: 'The current target "{0}" does not look like a custom page (type: {1}). Do not publish JSX to data forms or process forms.',
|
|
471
|
+
target_list_hint: 'Run openyida list-forms {0} --keyword <page name>, then choose a custom page formUuid with formType=display.',
|
|
472
|
+
target_force_hint: 'Append --force only when you intentionally bypass this guard; it overwrites the target Schema and should be used only for a known custom page.',
|
|
464
473
|
step_compile: '\n📦 Step 1: تجميع المصدر وبناء المخطط\n',
|
|
465
474
|
reading_source: '[1/4] جارٍ قراءة مصدر {0}...',
|
|
466
475
|
compiling: '[2/4] جارٍ تجميع {0} بـ Babel...',
|
package/lib/core/locales/de.js
CHANGED
|
@@ -461,6 +461,15 @@ module.exports = {
|
|
|
461
461
|
lint_passed: ' ✅ Code-Prüfung bestanden\n',
|
|
462
462
|
lint_skipped: '\n⏭️ Code-Vorprüfung übersprungen (--skip-lint)\n',
|
|
463
463
|
duplicate_source_mismatch: ' ⚠️ Found another copy with the same file name but different content. Publishing: {0}; other copy: {1}',
|
|
464
|
+
target_checking: ' Checking publish target type...',
|
|
465
|
+
target_check_forced: ' ⚠️ Skipped publish target type check (--force)',
|
|
466
|
+
target_check_ok: ' ✅ Publish target confirmed: {0} ({1})',
|
|
467
|
+
target_check_failed: 'Could not verify publish target: {0}',
|
|
468
|
+
target_not_found: 'Publish target was not found in app navigation: {0}',
|
|
469
|
+
target_type_invalid: 'Publish target is not a custom display page: {0} current type is {1}',
|
|
470
|
+
target_type_hint: 'The current target "{0}" does not look like a custom page (type: {1}). Do not publish JSX to data forms or process forms.',
|
|
471
|
+
target_list_hint: 'Run openyida list-forms {0} --keyword <page name>, then choose a custom page formUuid with formType=display.',
|
|
472
|
+
target_force_hint: 'Append --force only when you intentionally bypass this guard; it overwrites the target Schema and should be used only for a known custom page.',
|
|
464
473
|
step_compile: '\n📦 Step 1: Quellcode kompilieren und Schema erstellen\n',
|
|
465
474
|
reading_source: '[1/4] {0}-Quellcode wird gelesen...',
|
|
466
475
|
compiling: '[2/4] Babel kompiliert {0}...',
|
package/lib/core/locales/en.js
CHANGED
|
@@ -959,6 +959,15 @@ Examples:
|
|
|
959
959
|
lint_passed: ' ✅ Code check passed\n',
|
|
960
960
|
lint_skipped: '\n⏭️ Skipped code pre-check (--skip-lint)\n',
|
|
961
961
|
duplicate_source_mismatch: ' ⚠️ Found another copy with the same file name but different content. Publishing: {0}; other copy: {1}',
|
|
962
|
+
target_checking: ' Checking publish target type...',
|
|
963
|
+
target_check_forced: ' ⚠️ Skipped publish target type check (--force)',
|
|
964
|
+
target_check_ok: ' ✅ Publish target confirmed: {0} ({1})',
|
|
965
|
+
target_check_failed: 'Could not verify publish target: {0}',
|
|
966
|
+
target_not_found: 'Publish target was not found in app navigation: {0}',
|
|
967
|
+
target_type_invalid: 'Publish target is not a custom display page: {0} current type is {1}',
|
|
968
|
+
target_type_hint: 'The current target "{0}" does not look like a custom page (type: {1}). Do not publish JSX to data forms or process forms.',
|
|
969
|
+
target_list_hint: 'Run openyida list-forms {0} --keyword <page name>, then choose a custom page formUuid with formType=display.',
|
|
970
|
+
target_force_hint: 'Append --force only when you intentionally bypass this guard; it overwrites the target Schema and should be used only for a known custom page.',
|
|
962
971
|
step_compile: '\n📦 Step 1: Compile source & build Schema\n',
|
|
963
972
|
reading_source: '[1/4] Reading {0} source...',
|
|
964
973
|
compiling: '[2/4] Babel compiling {0}...',
|
package/lib/core/locales/es.js
CHANGED
|
@@ -461,6 +461,15 @@ module.exports = {
|
|
|
461
461
|
lint_passed: ' ✅ Verificación de código aprobada\n',
|
|
462
462
|
lint_skipped: '\n⏭️ Pre-verificación de código omitida (--skip-lint)\n',
|
|
463
463
|
duplicate_source_mismatch: ' ⚠️ Found another copy with the same file name but different content. Publishing: {0}; other copy: {1}',
|
|
464
|
+
target_checking: ' Checking publish target type...',
|
|
465
|
+
target_check_forced: ' ⚠️ Skipped publish target type check (--force)',
|
|
466
|
+
target_check_ok: ' ✅ Publish target confirmed: {0} ({1})',
|
|
467
|
+
target_check_failed: 'Could not verify publish target: {0}',
|
|
468
|
+
target_not_found: 'Publish target was not found in app navigation: {0}',
|
|
469
|
+
target_type_invalid: 'Publish target is not a custom display page: {0} current type is {1}',
|
|
470
|
+
target_type_hint: 'The current target "{0}" does not look like a custom page (type: {1}). Do not publish JSX to data forms or process forms.',
|
|
471
|
+
target_list_hint: 'Run openyida list-forms {0} --keyword <page name>, then choose a custom page formUuid with formType=display.',
|
|
472
|
+
target_force_hint: 'Append --force only when you intentionally bypass this guard; it overwrites the target Schema and should be used only for a known custom page.',
|
|
464
473
|
step_compile: '\n📦 Step 1: Compilar fuente y construir esquema\n',
|
|
465
474
|
reading_source: '[1/4] Leyendo fuente {0}...',
|
|
466
475
|
compiling: '[2/4] Compilando {0} con Babel...',
|
package/lib/core/locales/fr.js
CHANGED
|
@@ -461,6 +461,15 @@ module.exports = {
|
|
|
461
461
|
lint_passed: ' ✅ Vérification du code réussie\n',
|
|
462
462
|
lint_skipped: '\n⏭️ Pré-vérification du code ignorée (--skip-lint)\n',
|
|
463
463
|
duplicate_source_mismatch: ' ⚠️ Found another copy with the same file name but different content. Publishing: {0}; other copy: {1}',
|
|
464
|
+
target_checking: ' Checking publish target type...',
|
|
465
|
+
target_check_forced: ' ⚠️ Skipped publish target type check (--force)',
|
|
466
|
+
target_check_ok: ' ✅ Publish target confirmed: {0} ({1})',
|
|
467
|
+
target_check_failed: 'Could not verify publish target: {0}',
|
|
468
|
+
target_not_found: 'Publish target was not found in app navigation: {0}',
|
|
469
|
+
target_type_invalid: 'Publish target is not a custom display page: {0} current type is {1}',
|
|
470
|
+
target_type_hint: 'The current target "{0}" does not look like a custom page (type: {1}). Do not publish JSX to data forms or process forms.',
|
|
471
|
+
target_list_hint: 'Run openyida list-forms {0} --keyword <page name>, then choose a custom page formUuid with formType=display.',
|
|
472
|
+
target_force_hint: 'Append --force only when you intentionally bypass this guard; it overwrites the target Schema and should be used only for a known custom page.',
|
|
464
473
|
step_compile: '\n📦 Step 1 : Compilation et construction du schéma\n',
|
|
465
474
|
reading_source: '[1/4] Lecture de la source {0}...',
|
|
466
475
|
compiling: '[2/4] Compilation Babel de {0}...',
|
package/lib/core/locales/hi.js
CHANGED
|
@@ -461,6 +461,15 @@ module.exports = {
|
|
|
461
461
|
lint_passed: ' ✅ कोड जांच पास\n',
|
|
462
462
|
lint_skipped: '\n⏭️ कोड पूर्व-जांच छोड़ी गई (--skip-lint)\n',
|
|
463
463
|
duplicate_source_mismatch: ' ⚠️ Found another copy with the same file name but different content. Publishing: {0}; other copy: {1}',
|
|
464
|
+
target_checking: ' Checking publish target type...',
|
|
465
|
+
target_check_forced: ' ⚠️ Skipped publish target type check (--force)',
|
|
466
|
+
target_check_ok: ' ✅ Publish target confirmed: {0} ({1})',
|
|
467
|
+
target_check_failed: 'Could not verify publish target: {0}',
|
|
468
|
+
target_not_found: 'Publish target was not found in app navigation: {0}',
|
|
469
|
+
target_type_invalid: 'Publish target is not a custom display page: {0} current type is {1}',
|
|
470
|
+
target_type_hint: 'The current target "{0}" does not look like a custom page (type: {1}). Do not publish JSX to data forms or process forms.',
|
|
471
|
+
target_list_hint: 'Run openyida list-forms {0} --keyword <page name>, then choose a custom page formUuid with formType=display.',
|
|
472
|
+
target_force_hint: 'Append --force only when you intentionally bypass this guard; it overwrites the target Schema and should be used only for a known custom page.',
|
|
464
473
|
step_compile: '\n📦 Step 1: स्रोत संकलित करें और स्कीमा बनाएं\n',
|
|
465
474
|
reading_source: '[1/4] {0} स्रोत पढ़ा जा रहा है...',
|
|
466
475
|
compiling: '[2/4] Babel से {0} संकलित हो रहा है...',
|
package/lib/core/locales/ja.js
CHANGED
|
@@ -881,6 +881,15 @@ openyida - Yida CLI ツール
|
|
|
881
881
|
lint_passed: ' ✅ コードチェック合格\n',
|
|
882
882
|
lint_skipped: '\n⏭️ コードプレチェックをスキップしました(--skip-lint)\n',
|
|
883
883
|
duplicate_source_mismatch: ' ⚠️ Found another copy with the same file name but different content. Publishing: {0}; other copy: {1}',
|
|
884
|
+
target_checking: ' Checking publish target type...',
|
|
885
|
+
target_check_forced: ' ⚠️ Skipped publish target type check (--force)',
|
|
886
|
+
target_check_ok: ' ✅ Publish target confirmed: {0} ({1})',
|
|
887
|
+
target_check_failed: 'Could not verify publish target: {0}',
|
|
888
|
+
target_not_found: 'Publish target was not found in app navigation: {0}',
|
|
889
|
+
target_type_invalid: 'Publish target is not a custom display page: {0} current type is {1}',
|
|
890
|
+
target_type_hint: 'The current target "{0}" does not look like a custom page (type: {1}). Do not publish JSX to data forms or process forms.',
|
|
891
|
+
target_list_hint: 'Run openyida list-forms {0} --keyword <page name>, then choose a custom page formUuid with formType=display.',
|
|
892
|
+
target_force_hint: 'Append --force only when you intentionally bypass this guard; it overwrites the target Schema and should be used only for a known custom page.',
|
|
884
893
|
step_compile: '\n📦 Step 1: ソースをコンパイルして Schema を構築\n',
|
|
885
894
|
reading_source: '[1/4] {0} のソースを読み込み中...',
|
|
886
895
|
compiling: '[2/4] Babel で {0} をコンパイル中...',
|
package/lib/core/locales/ko.js
CHANGED
|
@@ -463,6 +463,15 @@ module.exports = {
|
|
|
463
463
|
lint_passed: ' ✅ 코드 검사 통과\n',
|
|
464
464
|
lint_skipped: '\n⏭️ 코드 사전 검사 건너뜀 (--skip-lint)\n',
|
|
465
465
|
duplicate_source_mismatch: ' ⚠️ Found another copy with the same file name but different content. Publishing: {0}; other copy: {1}',
|
|
466
|
+
target_checking: ' Checking publish target type...',
|
|
467
|
+
target_check_forced: ' ⚠️ Skipped publish target type check (--force)',
|
|
468
|
+
target_check_ok: ' ✅ Publish target confirmed: {0} ({1})',
|
|
469
|
+
target_check_failed: 'Could not verify publish target: {0}',
|
|
470
|
+
target_not_found: 'Publish target was not found in app navigation: {0}',
|
|
471
|
+
target_type_invalid: 'Publish target is not a custom display page: {0} current type is {1}',
|
|
472
|
+
target_type_hint: 'The current target "{0}" does not look like a custom page (type: {1}). Do not publish JSX to data forms or process forms.',
|
|
473
|
+
target_list_hint: 'Run openyida list-forms {0} --keyword <page name>, then choose a custom page formUuid with formType=display.',
|
|
474
|
+
target_force_hint: 'Append --force only when you intentionally bypass this guard; it overwrites the target Schema and should be used only for a known custom page.',
|
|
466
475
|
step_compile: '\n📦 Step 1: 소스 컴파일 및 스키마 빌드\n',
|
|
467
476
|
reading_source: '[1/4] {0} 소스 읽는 중...',
|
|
468
477
|
compiling: '[2/4] Babel로 {0} 컴파일 중...',
|
package/lib/core/locales/pt.js
CHANGED
|
@@ -461,6 +461,15 @@ module.exports = {
|
|
|
461
461
|
lint_passed: ' ✅ Verificação de código aprovada\n',
|
|
462
462
|
lint_skipped: '\n⏭️ Pré-verificação de código ignorada (--skip-lint)\n',
|
|
463
463
|
duplicate_source_mismatch: ' ⚠️ Found another copy with the same file name but different content. Publishing: {0}; other copy: {1}',
|
|
464
|
+
target_checking: ' Checking publish target type...',
|
|
465
|
+
target_check_forced: ' ⚠️ Skipped publish target type check (--force)',
|
|
466
|
+
target_check_ok: ' ✅ Publish target confirmed: {0} ({1})',
|
|
467
|
+
target_check_failed: 'Could not verify publish target: {0}',
|
|
468
|
+
target_not_found: 'Publish target was not found in app navigation: {0}',
|
|
469
|
+
target_type_invalid: 'Publish target is not a custom display page: {0} current type is {1}',
|
|
470
|
+
target_type_hint: 'The current target "{0}" does not look like a custom page (type: {1}). Do not publish JSX to data forms or process forms.',
|
|
471
|
+
target_list_hint: 'Run openyida list-forms {0} --keyword <page name>, then choose a custom page formUuid with formType=display.',
|
|
472
|
+
target_force_hint: 'Append --force only when you intentionally bypass this guard; it overwrites the target Schema and should be used only for a known custom page.',
|
|
464
473
|
step_compile: '\n📦 Step 1: Compilar fonte e construir esquema\n',
|
|
465
474
|
reading_source: '[1/4] Lendo fonte {0}...',
|
|
466
475
|
compiling: '[2/4] Compilando {0} com Babel...',
|
package/lib/core/locales/vi.js
CHANGED
|
@@ -461,6 +461,15 @@ module.exports = {
|
|
|
461
461
|
lint_passed: ' ✅ Kiểm tra mã thành công\n',
|
|
462
462
|
lint_skipped: '\n⏭️ Đã bỏ qua kiểm tra mã trước (--skip-lint)\n',
|
|
463
463
|
duplicate_source_mismatch: ' ⚠️ Found another copy with the same file name but different content. Publishing: {0}; other copy: {1}',
|
|
464
|
+
target_checking: ' Checking publish target type...',
|
|
465
|
+
target_check_forced: ' ⚠️ Skipped publish target type check (--force)',
|
|
466
|
+
target_check_ok: ' ✅ Publish target confirmed: {0} ({1})',
|
|
467
|
+
target_check_failed: 'Could not verify publish target: {0}',
|
|
468
|
+
target_not_found: 'Publish target was not found in app navigation: {0}',
|
|
469
|
+
target_type_invalid: 'Publish target is not a custom display page: {0} current type is {1}',
|
|
470
|
+
target_type_hint: 'The current target "{0}" does not look like a custom page (type: {1}). Do not publish JSX to data forms or process forms.',
|
|
471
|
+
target_list_hint: 'Run openyida list-forms {0} --keyword <page name>, then choose a custom page formUuid with formType=display.',
|
|
472
|
+
target_force_hint: 'Append --force only when you intentionally bypass this guard; it overwrites the target Schema and should be used only for a known custom page.',
|
|
464
473
|
step_compile: '\n📦 Step 1: Biên dịch nguồn và xây dựng schema\n',
|
|
465
474
|
reading_source: '[1/4] Đang đọc nguồn {0}...',
|
|
466
475
|
compiling: '[2/4] Đang biên dịch {0} với Babel...',
|
|
@@ -792,6 +792,15 @@ openyida - 宜搭命令列工具
|
|
|
792
792
|
lint_passed: ' ✅ 程式碼檢查通過\n',
|
|
793
793
|
lint_skipped: '\n⏭️ 跳過程式碼預檢(--skip-lint)\n',
|
|
794
794
|
duplicate_source_mismatch: ' ⚠️ 偵測到同名雙副本但內容不一致。目前發布:{0};另一份:{1}',
|
|
795
|
+
target_checking: ' 正在校驗發布目標類型...',
|
|
796
|
+
target_check_forced: ' ⚠️ 已跳過發布目標類型校驗(--force)',
|
|
797
|
+
target_check_ok: ' ✅ 發布目標已確認:{0} ({1})',
|
|
798
|
+
target_check_failed: '無法校驗發布目標:{0}',
|
|
799
|
+
target_not_found: '未在應用程式導航中找到發布目標:{0}',
|
|
800
|
+
target_type_invalid: '發布目標不是自訂展示頁面:{0} 目前類型為 {1}',
|
|
801
|
+
target_type_hint: '目前目標「{0}」看起來不是自訂頁面(類型:{1})。請不要把 JSX 發布到資料表或流程表單。',
|
|
802
|
+
target_list_hint: '可先執行 openyida list-forms {0} --keyword <頁面名>,選擇 formType=display 的自訂頁面 formUuid。',
|
|
803
|
+
target_force_hint: '確認要繞過保護時可追加 --force;這會覆蓋目標 Schema,請只在明確知道目標是自訂頁面時使用。',
|
|
795
804
|
step_compile: '\n📦 Step 1:編譯原始碼 & 建構 Schema\n',
|
|
796
805
|
reading_source: '[1/4] 讀取 {0} 原始碼...',
|
|
797
806
|
compiling: '[2/4] Babel 編譯 {0}...',
|
package/lib/core/locales/zh.js
CHANGED
|
@@ -961,6 +961,15 @@ openyida - 宜搭命令行工具
|
|
|
961
961
|
lint_passed: ' ✅ 代码检查通过\n',
|
|
962
962
|
lint_skipped: '\n⏭️ 跳过代码预检(--skip-lint)\n',
|
|
963
963
|
duplicate_source_mismatch: ' ⚠️ 检测到同名双副本但内容不一致。当前发布: {0};另一份: {1}',
|
|
964
|
+
target_checking: ' 正在校验发布目标类型...',
|
|
965
|
+
target_check_forced: ' ⚠️ 已跳过发布目标类型校验(--force)',
|
|
966
|
+
target_check_ok: ' ✅ 发布目标已确认:{0} ({1})',
|
|
967
|
+
target_check_failed: '无法校验发布目标:{0}',
|
|
968
|
+
target_not_found: '未在应用导航中找到发布目标:{0}',
|
|
969
|
+
target_type_invalid: '发布目标不是自定义展示页面:{0} 当前类型为 {1}',
|
|
970
|
+
target_type_hint: '当前目标「{0}」看起来不是自定义页面(类型:{1})。请不要把 JSX 发布到数据表或流程表单。',
|
|
971
|
+
target_list_hint: '可先运行 openyida list-forms {0} --keyword <页面名>,选择 formType=display 的自定义页面 formUuid。',
|
|
972
|
+
target_force_hint: '确认要绕过保护时可追加 --force;这会覆盖目标 Schema,请只在明确知道目标是自定义页面时使用。',
|
|
964
973
|
step_compile: '\n📦 Step 1: 编译源码 & 构建 Schema\n',
|
|
965
974
|
reading_source: '[1/4] 读取 {0} 源码...',
|
|
966
975
|
compiling: '[2/4] Babel 编译 {0}...',
|
package/package.json
CHANGED
|
@@ -44,16 +44,27 @@ description: 将 JSX 源码编译发布到宜搭自定义页面。Babel 转 ES5
|
|
|
44
44
|
## 命令
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
-
openyida publish <源文件路径> <appType> <formUuid> [--compat] [--health-check]
|
|
47
|
+
openyida publish <源文件路径> <appType> <formUuid> [--compat] [--health-check] [--force]
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
| 参数 | 必填 | 说明 |
|
|
51
51
|
|------|------|------|
|
|
52
52
|
| `源文件路径` | 是 | JSX 源码路径,推荐 `project/pages/src/my-page.oyd.jsx` |
|
|
53
53
|
| `appType` | 是 | 应用 ID |
|
|
54
|
-
| `formUuid` | 是 | 自定义页面 ID |
|
|
54
|
+
| `formUuid` | 是 | 自定义页面 ID,必须是 `openyida list-forms <appType>` 返回的 `formType=display` 目标,不要使用数据底表或流程表单 ID |
|
|
55
55
|
| `--compat` / `--modern` | 否 | 对普通 `.jsx` 也强制启用 OpenYida 兼容构建;`.oyd.jsx` 默认自动启用 |
|
|
56
56
|
| `--health-check` | 否 | 发布成功后请求页面 URL,回显 HTTP 健康检查结果,避免只看到 200 接口返回但首屏坏掉 |
|
|
57
|
+
| `--force` | 否 | 显式绕过发布目标类型保护;只有确认目标是自定义页面但导航接口暂时无法识别时才使用 |
|
|
58
|
+
|
|
59
|
+
## 发布目标确认
|
|
60
|
+
|
|
61
|
+
发布前先确认目标页面,避免把 JSX 覆盖到数据底表:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
openyida list-forms <appType> --keyword <页面名>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
只选择 `formType=display` 的 `formUuid` 作为发布目标。源码里用于 `this.utils.yida` 读写数据的普通表单常量(如 `FORM_SKILL`、`FORM_DATA`、`FORM_TABLE`)通常是数据底表,不能作为 `openyida publish` 的第三个参数。
|
|
57
68
|
|
|
58
69
|
## OpenYida 兼容编译
|
|
59
70
|
|
|
@@ -99,6 +110,7 @@ body { background-color: #f2f3f5; }
|
|
|
99
110
|
| OpenYida 兼容构建失败 | 查看 `check-page --json` 的 `build.errors`,通常是不支持的 Hook、非空 useEffect deps、未支持 import |
|
|
100
111
|
| Babel 编译失败 | 检查 JSX 语法;如果是现代 React authoring,确认文件是 `.oyd.jsx` 或发布时加 `--compat` |
|
|
101
112
|
| UglifyJS 压缩失败 | 检查是否有 ES6+ 语法未被 Babel 转译,确认 export function 格式正确 |
|
|
113
|
+
| 发布目标不是自定义展示页面 | 运行 `openyida list-forms <appType> --keyword <页面名>`,改用 `formType=display` 的页面 ID;不要对数据底表追加 `--force` |
|
|
102
114
|
| saveFormSchema 接口失败(401) | 执行 `openyida login` 重新登录后重试 |
|
|
103
115
|
| corpId 不匹配 | 询问用户是否切换组织或创建新应用,不得强行发布 |
|
|
104
116
|
| 发布后页面空白 | 检查 `renderJsx` 函数是否正确导出,检查浏览器控制台报错 |
|