openyida 2026.7.13 → 2026.7.14-2

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.
Files changed (95) hide show
  1. package/README.md +15 -22
  2. package/bin/yida.js +72 -220
  3. package/lib/agent-center/api.js +2 -2
  4. package/lib/aggregate-table/aggregate-table.js +2 -2
  5. package/lib/ai/ai.js +7 -12
  6. package/lib/app/canvas-compile.js +2 -2
  7. package/lib/app/create-app.js +5 -19
  8. package/lib/app/create-form.js +54 -76
  9. package/lib/app/create-page.js +4 -19
  10. package/lib/app/er.js +11 -8
  11. package/lib/app/export-app.js +2 -2
  12. package/lib/app/externalize-form.js +12 -10
  13. package/lib/app/get-schema.js +12 -10
  14. package/lib/app/import-app.js +6 -22
  15. package/lib/app/list-forms.js +3 -19
  16. package/lib/app/nav-group.js +6 -19
  17. package/lib/app/publish.js +60 -198
  18. package/lib/app/update-app.js +4 -18
  19. package/lib/app/update-form-config.js +20 -113
  20. package/lib/app-permission/app-permission.js +2 -2
  21. package/lib/auth/oauth-loopback.js +156 -0
  22. package/lib/auth/org.js +169 -322
  23. package/lib/auth/token-auth.js +346 -0
  24. package/lib/auth/token-store.js +174 -0
  25. package/lib/basic-info/basic-info.js +11 -12
  26. package/lib/bridge/bridge.js +29 -27
  27. package/lib/connector/api.js +4 -4
  28. package/lib/core/agent-capabilities.js +92 -8
  29. package/lib/core/batch.js +8 -8
  30. package/lib/core/check-data.js +2 -2
  31. package/lib/core/command-manifest.js +3 -3
  32. package/lib/core/doctor.js +19 -22
  33. package/lib/core/env-cmd.js +1 -3
  34. package/lib/core/env-manager.js +8 -121
  35. package/lib/core/env.js +30 -72
  36. package/lib/core/locales/ar.js +5 -5
  37. package/lib/core/locales/de.js +5 -5
  38. package/lib/core/locales/en.js +26 -26
  39. package/lib/core/locales/es.js +5 -5
  40. package/lib/core/locales/fr.js +5 -5
  41. package/lib/core/locales/hi.js +5 -5
  42. package/lib/core/locales/ja.js +14 -14
  43. package/lib/core/locales/ko.js +5 -5
  44. package/lib/core/locales/pt.js +5 -5
  45. package/lib/core/locales/vi.js +5 -5
  46. package/lib/core/locales/zh-HK.js +15 -15
  47. package/lib/core/locales/zh.js +26 -26
  48. package/lib/core/query-data.js +2 -2
  49. package/lib/core/task-center.js +2 -2
  50. package/lib/core/utils.js +156 -400
  51. package/lib/core/yida-client.js +57 -22
  52. package/lib/corp-efficiency/corp-efficiency.js +3 -3
  53. package/lib/corp-manager/api.js +2 -2
  54. package/lib/db/db-seq-fix.js +20 -25
  55. package/lib/flash-note/flash-to-prd.js +2 -2
  56. package/lib/i18n-management/i18n-management.js +2 -2
  57. package/lib/integration/integration-check.js +10 -7
  58. package/lib/integration/integration-create.js +11 -8
  59. package/lib/integration/integration-list.js +11 -8
  60. package/lib/mcp/server.js +5 -54
  61. package/lib/page-config/get-page-config.js +2 -2
  62. package/lib/page-config/save-share-config.js +2 -2
  63. package/lib/page-config/verify-short-url.js +2 -2
  64. package/lib/permission/get-permission.js +2 -2
  65. package/lib/permission/save-permission.js +2 -2
  66. package/lib/process/ai-form-setting.js +2 -2
  67. package/lib/process/create-process.js +2 -2
  68. package/lib/process/preview-process.js +2 -2
  69. package/lib/report/append.js +3 -3
  70. package/lib/report/index.js +3 -3
  71. package/package.json +1 -1
  72. package/scripts/check-syntax.js +6 -0
  73. package/scripts/e2e-real/full-runner.js +2 -10
  74. package/scripts/e2e-real/runner.js +0 -31
  75. package/scripts/eval/screenshot.js +27 -69
  76. package/scripts/nightly-smoke.js +16 -34
  77. package/scripts/postinstall.js +6 -2
  78. package/yida-skills/SKILL.md +10 -6
  79. package/yida-skills/references/development-rules.md +2 -2
  80. package/yida-skills/references/setup-and-env.md +10 -9
  81. package/yida-skills/skills/sls-log-workbench/SKILL.md +2 -2
  82. package/yida-skills/skills/sls-log-workbench/sls-query.js +27 -54
  83. package/yida-skills/skills/yida-flash-note-to-prd/SKILL.md +1 -1
  84. package/yida-skills/skills/yida-integration/SKILL.md +3 -3
  85. package/yida-skills/skills/yida-login/SKILL.md +56 -74
  86. package/yida-skills/skills/yida-logout/SKILL.md +13 -12
  87. package/yida-skills/skills/yida-process-rule/SKILL.md +1 -1
  88. package/yida-skills/skills/yida-publish-page/SKILL.md +1 -1
  89. package/yida-skills/skills/yida-report/references/report-api-guide.md +4 -20
  90. package/yida-skills/skills-index.json +4 -4
  91. package/lib/auth/auth.js +0 -313
  92. package/lib/auth/cdp-browser-login.js +0 -390
  93. package/lib/auth/codex-login.js +0 -71
  94. package/lib/auth/login.js +0 -550
  95. package/lib/auth/qr-login.js +0 -1575
@@ -0,0 +1,346 @@
1
+ 'use strict';
2
+
3
+ const http = require('http');
4
+ const https = require('https');
5
+
6
+ const {
7
+ DINGTALK_OAUTH_CLIENT_ID,
8
+ DINGTALK_LOGIN_ORIGIN,
9
+ DINGTALK_INTL_LOGIN_ORIGIN,
10
+ getCurrentEnvConfig,
11
+ normalizeBaseUrl,
12
+ } = require('../core/env-manager');
13
+ const { runDingtalkLoopback } = require('./oauth-loopback');
14
+ const {
15
+ clearTokenSession,
16
+ isAccessTokenUsable,
17
+ loadTokenSession,
18
+ maskToken,
19
+ saveTokenSession,
20
+ } = require('./token-store');
21
+
22
+ const DEFAULT_AUTH_PATH_PREFIX = '/openapi/cli/v1/auth';
23
+
24
+ function stripTrailingSlash(value) {
25
+ return String(value || '').replace(/\/+$/, '');
26
+ }
27
+
28
+ function appendPath(baseUrl, path) {
29
+ return `${stripTrailingSlash(baseUrl)}${path.startsWith('/') ? path : `/${path}`}`;
30
+ }
31
+
32
+ function getArgEndpoint(options = {}) {
33
+ return options.endpoint ||
34
+ null;
35
+ }
36
+
37
+ function resolveTokenBaseUrl(options = {}) {
38
+ const explicitEndpoint = getArgEndpoint(options);
39
+ if (explicitEndpoint) {
40
+ const baseUrl = normalizeBaseUrl(explicitEndpoint, null);
41
+ if (!baseUrl) {
42
+ throw new Error('invalid base_url: pass a valid --endpoint value');
43
+ }
44
+ return baseUrl;
45
+ }
46
+
47
+ const { config } = getCurrentEnvConfig(options.projectRoot);
48
+ const baseUrl = normalizeBaseUrl(process.env.OPENYIDA_ENDPOINT || config.baseUrl, null);
49
+ if (!baseUrl) {
50
+ throw new Error('missing base_url: pass --endpoint or set OPENYIDA_ENDPOINT');
51
+ }
52
+ return baseUrl;
53
+ }
54
+
55
+ function resolveDingtalkLoginOrigin(options = {}) {
56
+ if (options.loginOrigin) {
57
+ return options.loginOrigin;
58
+ }
59
+ try {
60
+ const { config } = getCurrentEnvConfig(options.projectRoot);
61
+ const baseUrl = normalizeBaseUrl(config.baseUrl, '');
62
+ if (baseUrl && baseUrl.includes('yidaapps.com')) {
63
+ return DINGTALK_INTL_LOGIN_ORIGIN;
64
+ }
65
+ } catch {
66
+ // Fall back to domestic DingTalk login.
67
+ }
68
+ return DINGTALK_LOGIN_ORIGIN;
69
+ }
70
+
71
+ function requestJson(method, url, body, headers = {}) {
72
+ return new Promise((resolve, reject) => {
73
+ const parsedUrl = new URL(url);
74
+ const data = body === undefined || body === null ? null : Buffer.from(JSON.stringify(body));
75
+ const transport = parsedUrl.protocol === 'https:' ? https : http;
76
+ const request = transport.request({
77
+ method,
78
+ protocol: parsedUrl.protocol,
79
+ hostname: parsedUrl.hostname,
80
+ port: parsedUrl.port,
81
+ path: `${parsedUrl.pathname}${parsedUrl.search}`,
82
+ headers: {
83
+ accept: 'application/json',
84
+ ...headers,
85
+ ...(data ? {
86
+ 'content-type': 'application/json',
87
+ 'content-length': data.length,
88
+ } : {}),
89
+ },
90
+ }, (response) => {
91
+ const chunks = [];
92
+ response.on('data', (chunk) => chunks.push(chunk));
93
+ response.on('end', () => {
94
+ const text = Buffer.concat(chunks).toString('utf8');
95
+ let payload = null;
96
+ if (text) {
97
+ try {
98
+ payload = JSON.parse(text);
99
+ } catch {
100
+ payload = { raw: text };
101
+ }
102
+ }
103
+ if (response.statusCode < 200 || response.statusCode >= 300) {
104
+ const location = response.headers && response.headers.location;
105
+ const message = payload && payload.message
106
+ ? payload.message
107
+ : `http_${response.statusCode}${location ? `: ${location}` : ''}`;
108
+ const error = new Error(message);
109
+ error.statusCode = response.statusCode;
110
+ error.payload = payload;
111
+ error.headers = response.headers;
112
+ error.location = location;
113
+ reject(error);
114
+ return;
115
+ }
116
+ resolve(payload || {});
117
+ });
118
+ });
119
+
120
+ request.on('error', reject);
121
+ if (data) {
122
+ request.write(data);
123
+ }
124
+ request.end();
125
+ });
126
+ }
127
+
128
+ function sanitizeRawTokenResponse(response) {
129
+ if (!response || typeof response !== 'object') {
130
+ return response;
131
+ }
132
+ const clone = Array.isArray(response) ? [...response] : { ...response };
133
+ delete clone.ai_app_user_auth_token;
134
+ delete clone.aiAppUserAuthToken;
135
+ delete clone.tianshu_csrf_token;
136
+ delete clone.tianshuCsrfToken;
137
+ delete clone.csrf_token;
138
+ delete clone.csrfToken;
139
+ delete clone.access_token;
140
+ delete clone.accessToken;
141
+ delete clone.refresh_token;
142
+ delete clone.refreshToken;
143
+ if (clone.data && typeof clone.data === 'object') {
144
+ clone.data = sanitizeRawTokenResponse(clone.data);
145
+ }
146
+ if (clone.content && typeof clone.content === 'object') {
147
+ clone.content = sanitizeRawTokenResponse(clone.content);
148
+ }
149
+ return clone;
150
+ }
151
+
152
+ function getTokenPayload(response) {
153
+ if (!response || typeof response !== 'object') {
154
+ return response || {};
155
+ }
156
+ return response.data || response.content || response;
157
+ }
158
+
159
+ function normalizeTokenResponse(response, baseUrl, clientId) {
160
+ const data = getTokenPayload(response);
161
+ return {
162
+ auth_mode: 'token',
163
+ status: data.status || 'ok',
164
+ can_auto_use: true,
165
+ message: data.message || data.errorMsg || response.errorMsg,
166
+ token_type: data.token_type || data.tokenType || 'Bearer',
167
+ access_token: data.access_token || data.accessToken,
168
+ refresh_token: data.refresh_token || data.refreshToken,
169
+ expires_in: data.expires_in || data.expiresIn,
170
+ expires_at: data.expires_at || data.expiresAt,
171
+ base_url: baseUrl,
172
+ client_id: data.client_id || data.clientId || clientId,
173
+ corp_id: data.corp_id || data.corpId,
174
+ user_id: data.user_id || data.userId,
175
+ user_name: data.user_name || data.userName,
176
+ open_user_id: data.open_user_id || data.openUserId,
177
+ scope: data.scope,
178
+ raw: sanitizeRawTokenResponse(response),
179
+ };
180
+ }
181
+
182
+ function requireOkResponse(response) {
183
+ const data = getTokenPayload(response);
184
+ const status = data.status || data.code || response.status || response.code;
185
+ if (typeof status === 'string' && status.startsWith('need_')) {
186
+ return;
187
+ }
188
+ if (status && status !== 'ok' && status !== 'success' && status !== true && status !== 200) {
189
+ const error = new Error(data.message || data.error || response.message || response.error || String(status));
190
+ error.payload = response;
191
+ throw error;
192
+ }
193
+ if (response && response.success === false) {
194
+ const error = new Error(response.errorMsg || response.message || 'request_failed');
195
+ error.payload = response;
196
+ throw error;
197
+ }
198
+ }
199
+
200
+ async function tokenLogin(options = {}) {
201
+ const baseUrl = resolveTokenBaseUrl(options);
202
+ const authBaseUrl = appendPath(baseUrl, DEFAULT_AUTH_PATH_PREFIX);
203
+ const clientId = options.clientId || process.env.OPENYIDA_DINGTALK_CLIENT_ID || DINGTALK_OAUTH_CLIENT_ID;
204
+ const callback = await runDingtalkLoopback({
205
+ clientId,
206
+ loginOrigin: resolveDingtalkLoginOrigin(options),
207
+ scope: options.scope || process.env.OPENYIDA_DINGTALK_SCOPE || 'openid corpid',
208
+ prompt: options.prompt,
209
+ port: options.port,
210
+ quiet: options.quiet,
211
+ timeoutMs: options.timeoutMs,
212
+ });
213
+
214
+ const response = await requestJson('POST', appendPath(authBaseUrl, '/dingtalk/token'), {
215
+ code: callback.code,
216
+ authCode: callback.authCode,
217
+ redirectUri: callback.redirectUri,
218
+ state: callback.state,
219
+ clientId,
220
+ });
221
+ requireOkResponse(response);
222
+
223
+ const normalized = normalizeTokenResponse(response, baseUrl, clientId);
224
+ if (!normalized.access_token) {
225
+ return {
226
+ ...normalized,
227
+ ok: false,
228
+ status: 'token_not_issued',
229
+ can_auto_use: false,
230
+ message: 'auth service did not return access_token',
231
+ };
232
+ }
233
+ return saveTokenSession(normalized, options);
234
+ }
235
+
236
+ function tokenStatus(options = {}) {
237
+ const session = loadTokenSession(options);
238
+ if (!session || !session.access_token) {
239
+ return {
240
+ ok: false,
241
+ auth_mode: 'token',
242
+ status: 'not_logged_in',
243
+ can_auto_use: false,
244
+ token_file: require('./token-store').getTokenFilePath(options),
245
+ };
246
+ }
247
+ const usable = isAccessTokenUsable(session);
248
+ return {
249
+ ok: usable,
250
+ auth_mode: 'token',
251
+ status: usable ? 'ok' : 'expired',
252
+ can_auto_use: usable,
253
+ token_type: session.token_type,
254
+ access_token: maskToken(session.access_token),
255
+ refresh_token: maskToken(session.refresh_token),
256
+ expires_at: session.expires_at ? new Date(session.expires_at).toISOString() : undefined,
257
+ base_url: session.base_url,
258
+ corp_id: session.corp_id,
259
+ user_id: session.user_id,
260
+ user_name: session.user_name,
261
+ };
262
+ }
263
+
264
+ async function tokenRefresh(options = {}) {
265
+ const session = loadTokenSession(options);
266
+ if (!session || !session.refresh_token) {
267
+ return {
268
+ ok: false,
269
+ auth_mode: 'token',
270
+ status: 'missing_refresh_token',
271
+ can_auto_use: false,
272
+ };
273
+ }
274
+
275
+ const baseUrl = normalizeBaseUrl(options.endpoint || options.baseUrl || session.base_url, null) ||
276
+ resolveTokenBaseUrl(options);
277
+ const authBaseUrl = appendPath(baseUrl, DEFAULT_AUTH_PATH_PREFIX);
278
+ const clientId = options.clientId || session.client_id || DINGTALK_OAUTH_CLIENT_ID;
279
+ const response = await requestJson('POST', appendPath(authBaseUrl, '/refresh'), {
280
+ refreshToken: session.refresh_token,
281
+ clientId,
282
+ });
283
+ requireOkResponse(response);
284
+ const data = getTokenPayload(response);
285
+ const normalized = normalizeTokenResponse({
286
+ ...data,
287
+ corp_id: data.corp_id || data.corpId || session.corp_id,
288
+ user_id: data.user_id || data.userId || session.user_id,
289
+ user_name: data.user_name || data.userName || session.user_name,
290
+ refresh_token: data.refresh_token || data.refreshToken || session.refresh_token,
291
+ }, baseUrl, clientId);
292
+ if (!normalized.access_token) {
293
+ return {
294
+ ...normalized,
295
+ ok: false,
296
+ status: 'token_not_issued',
297
+ can_auto_use: false,
298
+ message: normalized.message || 'auth service did not return access_token',
299
+ };
300
+ }
301
+ return saveTokenSession(normalized, options);
302
+ }
303
+
304
+ async function tokenLogout(options = {}) {
305
+ const session = loadTokenSession(options);
306
+ if (session && session.refresh_token && session.base_url) {
307
+ try {
308
+ await requestJson('POST', appendPath(appendPath(session.base_url, DEFAULT_AUTH_PATH_PREFIX), '/logout'), {
309
+ refreshToken: session.refresh_token,
310
+ }, session.access_token ? {
311
+ authorization: `${session.token_type || 'Bearer'} ${session.access_token}`,
312
+ } : {});
313
+ } catch {
314
+ // Local logout should still clear the credential cache.
315
+ }
316
+ }
317
+ clearTokenSession(options);
318
+ return {
319
+ ok: true,
320
+ auth_mode: 'token',
321
+ status: 'logged_out',
322
+ can_auto_use: false,
323
+ };
324
+ }
325
+
326
+ async function getAccessToken(options = {}) {
327
+ let session = loadTokenSession(options);
328
+ if (isAccessTokenUsable(session, options.skewMs)) {
329
+ return session.access_token;
330
+ }
331
+ if (session && session.refresh_token) {
332
+ session = await tokenRefresh(options);
333
+ return session.access_token;
334
+ }
335
+ throw new Error('not_logged_in');
336
+ }
337
+
338
+ module.exports = {
339
+ tokenLogin,
340
+ tokenStatus,
341
+ tokenRefresh,
342
+ tokenLogout,
343
+ getAccessToken,
344
+ requestJson,
345
+ resolveTokenBaseUrl,
346
+ };
@@ -0,0 +1,174 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ const TOKEN_FILE_PREFIX = 'auth-token';
7
+
8
+ function sanitizeEnvName(envName) {
9
+ return String(envName || 'public').replace(/[^a-zA-Z0-9._-]/g, '_');
10
+ }
11
+
12
+ function resolveProjectRoot(options = {}) {
13
+ if (options.projectRoot) {
14
+ return options.projectRoot;
15
+ }
16
+ const { findProjectRoot } = require('../core/utils');
17
+ return findProjectRoot();
18
+ }
19
+
20
+ function resolveEnvName(options = {}) {
21
+ if (options.envName) {
22
+ return sanitizeEnvName(options.envName);
23
+ }
24
+ try {
25
+ const { getCurrentEnvConfig, resolveEnvNameAlias } = require('../core/env-manager');
26
+ const { name } = getCurrentEnvConfig(resolveProjectRoot(options));
27
+ return sanitizeEnvName(resolveEnvNameAlias(name || process.env.OPENYIDA_ENV || 'public'));
28
+ } catch {
29
+ return sanitizeEnvName(process.env.OPENYIDA_ENV || 'public');
30
+ }
31
+ }
32
+
33
+ function getTokenFilePath(options = {}) {
34
+ const root = resolveProjectRoot(options);
35
+ const envName = resolveEnvName(options);
36
+ return path.join(root, '.cache', `${TOKEN_FILE_PREFIX}-${envName}.json`);
37
+ }
38
+
39
+ function normalizeBaseUrl(value) {
40
+ if (!value) {
41
+ return undefined;
42
+ }
43
+ try {
44
+ return new URL(String(value)).origin.replace(/\/+$/, '');
45
+ } catch {
46
+ return undefined;
47
+ }
48
+ }
49
+
50
+ function normalizeExpiresAt(session) {
51
+ if (!session) {
52
+ return undefined;
53
+ }
54
+ if (session.expires_at) {
55
+ const value = typeof session.expires_at === 'number'
56
+ ? session.expires_at
57
+ : Date.parse(session.expires_at);
58
+ return Number.isFinite(value) ? value : undefined;
59
+ }
60
+ if (session.expiresAt) {
61
+ const value = typeof session.expiresAt === 'number'
62
+ ? session.expiresAt
63
+ : Date.parse(session.expiresAt);
64
+ return Number.isFinite(value) ? value : undefined;
65
+ }
66
+ if (session.expires_in || session.expiresIn) {
67
+ const seconds = Number(session.expires_in || session.expiresIn);
68
+ if (Number.isFinite(seconds) && seconds > 0) {
69
+ return Date.now() + seconds * 1000;
70
+ }
71
+ }
72
+ return undefined;
73
+ }
74
+
75
+ function normalizeTokenSession(session = {}) {
76
+ const expiresAt = normalizeExpiresAt(session);
77
+ const baseUrl = normalizeBaseUrl(
78
+ session.base_url ||
79
+ session.baseUrl ||
80
+ session.token_endpoint ||
81
+ session.tokenEndpoint
82
+ );
83
+ const normalized = {
84
+ auth_mode: 'token',
85
+ token_type: session.token_type || session.tokenType || 'Bearer',
86
+ access_token: session.access_token || session.accessToken,
87
+ refresh_token: session.refresh_token || session.refreshToken,
88
+ expires_at: expiresAt,
89
+ issued_at: session.issued_at || session.issuedAt || new Date().toISOString(),
90
+ base_url: baseUrl,
91
+ client_id: session.client_id || session.clientId,
92
+ corp_id: session.corp_id || session.corpId,
93
+ user_id: session.user_id || session.userId,
94
+ user_name: session.user_name || session.userName,
95
+ open_user_id: session.open_user_id || session.openUserId,
96
+ scope: session.scope,
97
+ raw: session.raw,
98
+ };
99
+
100
+ Object.keys(normalized).forEach((key) => {
101
+ if (normalized[key] === undefined || normalized[key] === null || normalized[key] === '') {
102
+ delete normalized[key];
103
+ }
104
+ });
105
+ return normalized;
106
+ }
107
+
108
+ function saveTokenSession(session, options = {}) {
109
+ const tokenFile = getTokenFilePath(options);
110
+ const normalized = normalizeTokenSession(session);
111
+ fs.mkdirSync(path.dirname(tokenFile), { recursive: true });
112
+ fs.writeFileSync(tokenFile, JSON.stringify(normalized, null, 2), { mode: 0o600 });
113
+ try {
114
+ fs.chmodSync(tokenFile, 0o600);
115
+ } catch {
116
+ // chmod is best-effort on non-POSIX filesystems.
117
+ }
118
+ return normalized;
119
+ }
120
+
121
+ function loadTokenSession(options = {}) {
122
+ const tokenFile = getTokenFilePath(options);
123
+ if (!fs.existsSync(tokenFile)) {
124
+ return null;
125
+ }
126
+ try {
127
+ return normalizeTokenSession(JSON.parse(fs.readFileSync(tokenFile, 'utf8')));
128
+ } catch {
129
+ return null;
130
+ }
131
+ }
132
+
133
+ function clearTokenSession(options = {}) {
134
+ const tokenFile = getTokenFilePath(options);
135
+ try {
136
+ if (fs.existsSync(tokenFile)) {
137
+ fs.unlinkSync(tokenFile);
138
+ }
139
+ } catch {
140
+ // Logout should remain idempotent.
141
+ }
142
+ }
143
+
144
+ function isAccessTokenUsable(session, skewMs = 60 * 1000) {
145
+ if (!session || !session.access_token) {
146
+ return false;
147
+ }
148
+ if (!session.expires_at) {
149
+ return true;
150
+ }
151
+ return Number(session.expires_at) > Date.now() + skewMs;
152
+ }
153
+
154
+ function maskToken(token) {
155
+ if (!token) {
156
+ return undefined;
157
+ }
158
+ const value = String(token);
159
+ if (value.length <= 16) {
160
+ return `${value.slice(0, 4)}...`;
161
+ }
162
+ return `${value.slice(0, 8)}...${value.slice(-6)}`;
163
+ }
164
+
165
+ module.exports = {
166
+ getTokenFilePath,
167
+ loadTokenSession,
168
+ saveTokenSession,
169
+ clearTokenSession,
170
+ normalizeTokenSession,
171
+ isAccessTokenUsable,
172
+ maskToken,
173
+ resolveEnvName,
174
+ };
@@ -1,10 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  const {
4
- loadCookieData,
4
+ loadAuthData,
5
5
  triggerLogin,
6
6
  resolveBaseUrl,
7
- extractInfoFromCookies,
8
7
  } = require('../core/utils');
9
8
  const { createYidaClient } = require('../core/yida-client');
10
9
 
@@ -128,24 +127,24 @@ async function requestPost(authRef, path, params = {}, actionName = path) {
128
127
  }
129
128
 
130
129
  async function loadAuth() {
131
- let cookieData = loadCookieData();
132
- if (!cookieData) {
133
- cookieData = await triggerLogin();
130
+ let authData = loadAuthData();
131
+ if (!authData) {
132
+ authData = await triggerLogin();
134
133
  }
135
134
 
136
- const cookieInfo = extractInfoFromCookies(cookieData.cookies || []);
137
- const csrfToken = cookieData.csrf_token || cookieInfo.csrfToken;
135
+ const csrfToken = authData.csrf_token;
138
136
  if (!csrfToken) {
139
137
  throw new Error('Missing csrf token. Please run openyida login again.');
140
138
  }
141
139
 
142
140
  return {
143
- cookieData,
144
- cookies: cookieData.cookies || [],
141
+ authData,
145
142
  csrfToken,
146
- corpId: cookieInfo.corpId,
147
- userId: cookieInfo.userId,
148
- baseUrl: resolveBaseUrl(cookieData),
143
+ corpId: authData.corp_id || '',
144
+ userId: authData.user_id || '',
145
+ baseUrl: resolveBaseUrl(authData),
146
+ authMode: authData.auth_mode || '',
147
+ authSource: authData.auth_source || '',
149
148
  };
150
149
  }
151
150
 
@@ -23,16 +23,18 @@ const SAFE_DIAGNOSTIC_KEYS = [
23
23
  'currentEnv',
24
24
  'projectRootExists',
25
25
  'hasConfig',
26
- 'cookieFileFound',
27
- 'usedLegacyCookieFile',
28
26
  'cache_readable',
29
- 'cookies_array_found',
30
- 'csrf_token_found',
27
+ 'cacheReadable',
28
+ 'tokenFileFound',
29
+ 'tokenFound',
31
30
  'corp_id_found',
31
+ 'corpIdFound',
32
32
  'user_id_found',
33
+ 'userIdFound',
33
34
  'base_url_found',
35
+ 'baseUrlFound',
34
36
  'failure_reason',
35
- 'cookies_count',
37
+ 'failureReason',
36
38
  ];
37
39
 
38
40
  function printUsage() {
@@ -511,11 +513,11 @@ function sanitizeLoginResult(result = {}) {
511
513
  return {
512
514
  status,
513
515
  canAutoUse: !!(result.can_auto_use || result.canAutoUse),
514
- loggedIn: status === 'ok' || !!result.csrf_token,
516
+ loggedIn: status === 'ok',
517
+ authMode: result.auth_mode || result.authMode,
515
518
  baseUrlOrigin: originFromUrl(result.base_url || result.baseUrl),
516
519
  corpId: maskId(result.corp_id || result.corpId),
517
520
  userId: maskId(result.user_id || result.userId),
518
- cookiesCount: result.cookies_count || (Array.isArray(result.cookies) ? result.cookies.length : undefined),
519
521
  diagnostics: sanitizeDiagnostics(result.diagnostics || {}),
520
522
  message: result.message ? String(result.message).slice(0, 300) : undefined,
521
523
  };
@@ -549,9 +551,6 @@ function getBridgeInfo(state) {
549
551
  capabilities: [
550
552
  'pair',
551
553
  'login.check',
552
- 'login.start',
553
- 'login.poll',
554
- 'login.select-corp',
555
554
  'feedback.url',
556
555
  'openyida.app-list',
557
556
  'openyida.create-app',
@@ -560,32 +559,35 @@ function getBridgeInfo(state) {
560
559
  }
561
560
 
562
561
  function defaultCheckLogin() {
563
- const { checkLoginOnly } = require('../auth/login');
564
- return checkLoginOnly({ includeSecrets: false });
562
+ const { tokenStatus } = require('../auth/token-auth');
563
+ return tokenStatus({ includeSecrets: false });
565
564
  }
566
565
 
567
566
  async function defaultStartLogin(body = {}) {
568
- const { startCodexQrLogin } = require('../auth/qr-login');
569
- return startCodexQrLogin({
570
- corpId: body.corpId || body.corp_id,
571
- autoOpenImage: false,
572
- });
567
+ return {
568
+ status: 'token_login_required',
569
+ auth_mode: 'token',
570
+ can_auto_use: false,
571
+ message: 'Token-only auth does not support bridge QR login. Run openyida login first.',
572
+ };
573
573
  }
574
574
 
575
575
  async function defaultPollLogin(sessionFile, body = {}) {
576
- const { pollCodexQrLogin } = require('../auth/qr-login');
577
- return pollCodexQrLogin(sessionFile, {
578
- corpId: body.corpId || body.corp_id,
579
- maxAttempts: 1,
580
- pollIntervalMs: 0,
581
- });
576
+ return {
577
+ status: 'token_login_required',
578
+ auth_mode: 'token',
579
+ can_auto_use: false,
580
+ message: 'Token-only auth does not support bridge QR polling. Run openyida login first.',
581
+ };
582
582
  }
583
583
 
584
584
  async function defaultSelectCorp(sessionFile, body = {}) {
585
- const { selectCodexQrCorp } = require('../auth/qr-login');
586
- return selectCodexQrCorp(sessionFile, {
587
- corpId: body.corpId || body.corp_id,
588
- });
585
+ return {
586
+ status: 'token_login_required',
587
+ auth_mode: 'token',
588
+ can_auto_use: false,
589
+ message: 'Token-only auth does not support bridge organization selection.',
590
+ };
589
591
  }
590
592
 
591
593
  function defaultReadFeedbackConfig(configPath) {
@@ -13,7 +13,7 @@ const { createAuthRef, createYidaClient } = require('../core/yida-client');
13
13
 
14
14
  /**
15
15
  * 获取当前登录态,未登录则触发登录
16
- * @returns {{ csrfToken: string, cookies: Array, baseUrl: string, cookieData: object }}
16
+ * @returns {{ csrfToken: string, baseUrl: string, authData: object }}
17
17
  */
18
18
  function getAuthRef() {
19
19
  return createAuthRef();
@@ -80,15 +80,15 @@ function buildOperationsSummary(operations) {
80
80
  * 构建连接器描述(包含 openyida 元数据)
81
81
  * @param {string|null} userDesc - 用户自定义描述(可选)
82
82
  * @param {string|null} originalDesc - 原有描述(用于提取创建信息)
83
- * @param {object} authRef - 鉴权信息(含 cookieData
83
+ * @param {object} authRef - 鉴权信息(含 authData
84
84
  * @param {Array|null} operations - 当前所有动作列表
85
85
  * @returns {string}
86
86
  */
87
87
  function buildConnectorDesc(userDesc, originalDesc, authRef, operations) {
88
88
  const now = new Date();
89
89
  const updateTime = now.toLocaleString('zh-CN');
90
- const currentUserId = authRef.cookieData && authRef.cookieData.user_id
91
- ? authRef.cookieData.user_id
90
+ const currentUserId = authRef.userId || (authRef.authData && authRef.authData.user_id)
91
+ ? authRef.userId || authRef.authData.user_id
92
92
  : '';
93
93
 
94
94
  let createTime = updateTime;