@xfe-repo/cli-plugin-oauth 2.0.8 → 2.0.10

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @xfe-repo/cli-plugin-oauth
2
2
 
3
+ ## 2.0.10
4
+
5
+ ### Patch Changes
6
+
7
+ - 优化插件性能
8
+
9
+ ## 2.0.9
10
+
11
+ ### Patch Changes
12
+
13
+ - 优化回调
14
+
3
15
  ## 2.0.8
4
16
 
5
17
  ### Patch Changes
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @xfe-repo/cli-plugin-oauth - OAuth 回调服务
3
3
  *
4
- * 基于 Hono 启动临时本地 HTTP 服务,等待 OAuth 授权服务器回跳 redirectUri。
4
+ * 基于 Node HTTP 启动临时本地服务,等待 OAuth 授权服务器回跳 redirectUri。
5
5
  */
6
6
  export interface OAuthCallbackServer {
7
7
  waitForCallback(): Promise<URL>;
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * @xfe-repo/cli-plugin-oauth - OAuth 回调服务
3
3
  *
4
- * 基于 Hono 启动临时本地 HTTP 服务,等待 OAuth 授权服务器回跳 redirectUri。
4
+ * 基于 Node HTTP 启动临时本地服务,等待 OAuth 授权服务器回跳 redirectUri。
5
5
  */
6
- import { serve } from '@hono/node-server';
7
- import { Hono } from 'hono';
6
+ import { createServer } from 'node:http';
8
7
  // ─── Constants ─────────────────────────────────────────────
9
8
  const CALLBACK_TIMEOUT_MS = 300000;
10
9
  const HTTP_OK = 200;
11
10
  const HTTP_BAD_REQUEST = 400;
12
11
  const HTTP_NOT_FOUND = 404;
12
+ const HTML_CONTENT_TYPE = 'text/html; charset=utf-8';
13
13
  const SUCCESS_HTML = '<!doctype html><html lang="zh"><body>OAuth 登录完成,可以关闭此窗口。</body></html>';
14
14
  const FAILURE_HTML = '<!doctype html><html lang="zh"><body>OAuth 登录失败,请回到终端查看错误。</body></html>';
15
15
  // ─── Public API ────────────────────────────────────────────
@@ -32,23 +32,31 @@ export async function startOAuthCallbackServer(redirectUri) {
32
32
  resolveCallback = resolve;
33
33
  rejectCallback = reject;
34
34
  });
35
- const app = new Hono();
36
- app.get(redirectUrl.pathname, (ctx) => {
37
- const currentUrl = new URL(ctx.req.url);
35
+ const httpServer = createServer((request, response) => {
36
+ const currentUrl = new URL(request.url ?? '/', redirectUrl.origin);
37
+ if (currentUrl.pathname !== redirectUrl.pathname) {
38
+ writeHtml(response, HTTP_NOT_FOUND, FAILURE_HTML);
39
+ return;
40
+ }
38
41
  const error = currentUrl.searchParams.get('error');
39
42
  if (error) {
40
43
  const description = currentUrl.searchParams.get('error_description');
41
44
  rejectCallback(new Error(description ? `${error}: ${description}` : error));
42
- return ctx.html(FAILURE_HTML, HTTP_BAD_REQUEST);
45
+ writeHtml(response, HTTP_BAD_REQUEST, FAILURE_HTML);
46
+ return;
43
47
  }
44
48
  resolveCallback(currentUrl);
45
- return ctx.html(SUCCESS_HTML, HTTP_OK);
49
+ writeHtml(response, HTTP_OK, SUCCESS_HTML);
46
50
  });
47
- app.notFound((ctx) => ctx.html(FAILURE_HTML, HTTP_NOT_FOUND));
48
- const httpServer = serve({
49
- fetch: app.fetch,
50
- hostname: redirectUrl.hostname,
51
- port,
51
+ await new Promise((resolve, reject) => {
52
+ const handleError = (error) => {
53
+ reject(error);
54
+ };
55
+ httpServer.once('error', handleError);
56
+ httpServer.listen(port, redirectUrl.hostname, () => {
57
+ httpServer.off('error', handleError);
58
+ resolve();
59
+ });
52
60
  });
53
61
  const timeout = setTimeout(() => {
54
62
  rejectCallback(new Error('OAuth 登录超时,请重新执行 oauth:login'));
@@ -61,14 +69,17 @@ export async function startOAuthCallbackServer(redirectUri) {
61
69
  hasClosed = true;
62
70
  clearTimeout(timeout);
63
71
  rejectCallback(new Error('OAuth 回调服务已关闭'));
64
- const closableServer = httpServer;
65
72
  await new Promise((resolve) => {
66
73
  httpServer.close(() => {
67
74
  resolve();
68
75
  });
69
- closableServer.closeAllConnections?.();
76
+ httpServer.closeAllConnections();
70
77
  });
71
78
  },
72
79
  };
73
80
  }
81
+ function writeHtml(response, status, html) {
82
+ response.writeHead(status, { 'Content-Type': HTML_CONTENT_TYPE });
83
+ response.end(html);
84
+ }
74
85
  //# sourceMappingURL=callback-server.js.map
package/dist/index.d.ts CHANGED
@@ -2,13 +2,13 @@
2
2
  * @xfe-repo/cli-plugin-oauth - OAuth 登录插件
3
3
  *
4
4
  * 通过 openid-client 对接 OIDC/OAuth 登录,保存本地 token 状态,
5
- * 并向其他插件提供 auth/login/getToken/logout 能力。
5
+ * 并向其他插件提供 login/getToken/getUser/logout 能力。
6
6
  */
7
7
  import type { XfePlugin } from '@xfe-repo/cli-core';
8
- import { type OAuthCapability, type OAuthConfig, type OAuthStoreState, type OAuthTokenState, type OAuthUserState } from './types.js';
9
- export type { OAuthCapability, OAuthConfig, OAuthLoginOptions, OAuthSessionState, OAuthStoreState, OAuthTokenState, OAuthUserState, } from './types.js';
8
+ import { type OAuthCapability, type OAuthStoreState } from './types.js';
9
+ export type { OAuthCapability, OAuthConfig, OAuthLoginOptions, OAuthSessionState, OAuthStoreState, OAuthUserState, } from './types.js';
10
10
  export { OAuthClientAuthMethod } from './types.js';
11
- export declare const oauthStoreInitial: OAuthStoreState;
11
+ declare const oauthStoreInitial: OAuthStoreState;
12
12
  declare module '@xfe-repo/cli-core' {
13
13
  interface XfePluginRegistry {
14
14
  oauth: XfePlugin<typeof oauthStoreInitial, OAuthCapability>;
@@ -16,7 +16,4 @@ declare module '@xfe-repo/cli-core' {
16
16
  }
17
17
  export declare function oauthPlugin(): XfePlugin<typeof oauthStoreInitial, OAuthCapability>;
18
18
  export default oauthPlugin;
19
- export declare function resolveOAuthStateForConfig(config: OAuthConfig, state?: Partial<OAuthStoreState>): OAuthTokenState;
20
- export declare function resolveOAuthConfigKey(config: OAuthConfig): string;
21
- export declare function normalizeOAuthUserInfo(input: unknown): OAuthUserState;
22
19
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * @xfe-repo/cli-plugin-oauth - OAuth 登录插件
3
3
  *
4
4
  * 通过 openid-client 对接 OIDC/OAuth 登录,保存本地 token 状态,
5
- * 并向其他插件提供 auth/login/getToken/logout 能力。
5
+ * 并向其他插件提供 login/getToken/getUser/logout 能力。
6
6
  */
7
7
  import { createHash } from 'node:crypto';
8
8
  import * as oauthClient from 'openid-client';
@@ -25,7 +25,7 @@ const OAUTH_CONFIG_KEY_VERSION = 'v1';
25
25
  const OAUTH_CONFIG_KEY_SEPARATOR = '\n';
26
26
  const OAUTH_CONFIG_HASH_ALGORITHM = 'sha256';
27
27
  const OAUTH_CONFIG_HASH_ENCODING = 'hex';
28
- export const oauthStoreInitial = {};
28
+ const oauthStoreInitial = {};
29
29
  const oauthConfigSchema = z
30
30
  .object({
31
31
  name: z.string().trim().min(1).default(DEFAULT_OAUTH_NAME),
@@ -59,19 +59,15 @@ export function oauthPlugin() {
59
59
  slot: ['footer'],
60
60
  value: (state) => {
61
61
  const currentSession = resolveOptionalOAuthState(state.xfe, state.oauth);
62
- return currentSession ? `Oauth ${currentSession.isAuthenticated ? '已登录' : '未登录'}` : undefined;
62
+ const isAuthenticated = currentSession && isOAuthAccessTokenValid(currentSession, Math.floor(Date.now() / MILLISECONDS_PER_SECOND));
63
+ return currentSession ? `Oauth ${isAuthenticated ? '已登录' : '未登录'}` : undefined;
63
64
  },
64
65
  color: (state) => {
65
66
  const currentSession = resolveOptionalOAuthState(state.xfe, state.oauth);
66
- return currentSession?.isAuthenticated ? 'cyan' : 'yellow';
67
+ const isAuthenticated = currentSession && isOAuthAccessTokenValid(currentSession, Math.floor(Date.now() / MILLISECONDS_PER_SECOND));
68
+ return isAuthenticated ? 'cyan' : 'yellow';
67
69
  },
68
70
  });
69
- hooks.onProjectInit.tap(OAUTH_PLUGIN_NAME, async (ctx) => {
70
- const config = parseOptionalOAuthConfig(ctx.store.getState().xfe);
71
- if (!config)
72
- return;
73
- replaceOAuthStoreState(ctx, createOAuthStoreState(ctx.store.getState().oauth));
74
- });
75
71
  hooks.registerCommand({
76
72
  name: 'oauth:login',
77
73
  simpleDescription: '登录 OAuth 平台',
@@ -89,7 +85,6 @@ export function oauthPlugin() {
89
85
  },
90
86
  });
91
87
  hooks.provide('oauth', {
92
- auth: (ctx, options) => login(ctx, options, runtime),
93
88
  login: (ctx, options) => login(ctx, options, runtime),
94
89
  getToken: (ctx) => getToken(ctx, runtime),
95
90
  getUser: (ctx) => getUser(ctx, runtime),
@@ -108,12 +103,9 @@ export default oauthPlugin;
108
103
  // ─── Capability Handlers ───────────────────────────────────
109
104
  async function login(ctx, options, runtime) {
110
105
  const config = parseOAuthConfig(ctx.store.getState().xfe);
111
- const current = activateOAuthState(ctx, config);
106
+ const current = resolveOAuthStateForConfig(config, ctx.store.getState().oauth);
112
107
  const now = Math.floor(Date.now() / MILLISECONDS_PER_SECOND);
113
- if (!options?.force &&
114
- current.isAuthenticated &&
115
- current.accessToken &&
116
- (!current.expiresAt || current.expiresAt - TOKEN_EXPIRY_SKEW_SECONDS > now)) {
108
+ if (!options?.force && isOAuthAccessTokenValid(current, now)) {
117
109
  return current;
118
110
  }
119
111
  const spinner = ctx.spinner.create(`正在登录 ${config.name}...`);
@@ -151,19 +143,7 @@ async function login(ctx, options, runtime) {
151
143
  }
152
144
  if (!tokenResponse.access_token)
153
145
  throw new Error('OAuth token 响应缺少 access_token');
154
- const expiresIn = tokenResponse.expiresIn();
155
- const tokenState = {
156
- name: config.name,
157
- accessToken: tokenResponse.access_token,
158
- refreshToken: tokenResponse.refresh_token || '',
159
- idToken: tokenResponse.id_token || '',
160
- tokenType: tokenResponse.token_type || DEFAULT_TOKEN_TYPE,
161
- scope: tokenResponse.scope || '',
162
- expiresAt: expiresIn ? now + expiresIn : 0,
163
- isAuthenticated: true,
164
- userId: 0,
165
- userName: '',
166
- };
146
+ const tokenState = createOAuthSessionFromToken(config, tokenResponse, now);
167
147
  saveOAuthSession(ctx, config, tokenState);
168
148
  spinner.succeed(`${config.name} 登录成功`);
169
149
  return resolveOAuthStateForConfig(config, ctx.store.getState().oauth);
@@ -176,9 +156,9 @@ async function login(ctx, options, runtime) {
176
156
  }
177
157
  async function getToken(ctx, runtime) {
178
158
  const config = parseOAuthConfig(ctx.store.getState().xfe);
179
- const current = activateOAuthState(ctx, config);
159
+ const current = resolveOAuthStateForConfig(config, ctx.store.getState().oauth);
180
160
  const now = Math.floor(Date.now() / MILLISECONDS_PER_SECOND);
181
- if (current.isAuthenticated && current.accessToken && (!current.expiresAt || current.expiresAt - TOKEN_EXPIRY_SKEW_SECONDS > now)) {
161
+ if (isOAuthAccessTokenValid(current, now)) {
182
162
  return current.accessToken;
183
163
  }
184
164
  if (current.refreshToken) {
@@ -187,19 +167,7 @@ async function getToken(ctx, runtime) {
187
167
  const tokenResponse = await oauthClient.refreshTokenGrant(clientConfig, current.refreshToken);
188
168
  if (!tokenResponse.access_token)
189
169
  throw new Error('OAuth token 响应缺少 access_token');
190
- const expiresIn = tokenResponse.expiresIn();
191
- const tokenState = {
192
- name: config.name,
193
- accessToken: tokenResponse.access_token,
194
- refreshToken: tokenResponse.refresh_token || current.refreshToken,
195
- idToken: tokenResponse.id_token || '',
196
- tokenType: tokenResponse.token_type || DEFAULT_TOKEN_TYPE,
197
- scope: tokenResponse.scope || '',
198
- expiresAt: expiresIn ? now + expiresIn : 0,
199
- isAuthenticated: true,
200
- userId: 0,
201
- userName: '',
202
- };
170
+ const tokenState = createOAuthSessionFromToken(config, tokenResponse, now, current.refreshToken);
203
171
  saveOAuthSession(ctx, config, tokenState);
204
172
  return tokenState.accessToken;
205
173
  }
@@ -213,7 +181,7 @@ async function getToken(ctx, runtime) {
213
181
  }
214
182
  async function getUser(ctx, runtime) {
215
183
  const config = parseOAuthConfig(ctx.store.getState().xfe);
216
- const current = activateOAuthState(ctx, config);
184
+ const current = resolveOAuthStateForConfig(config, ctx.store.getState().oauth);
217
185
  if (current.userId > 0 && current.userName)
218
186
  return { userId: current.userId, userName: current.userName };
219
187
  if (!config.userInfoUrl)
@@ -231,24 +199,34 @@ async function getUser(ctx, runtime) {
231
199
  }
232
200
  const user = normalizeOAuthUserInfo(await response.json());
233
201
  const latest = resolveOAuthStateForConfig(config, ctx.store.getState().oauth);
234
- saveOAuthSession(ctx, config, { ...toOAuthSessionState(latest, config.name), ...user });
202
+ saveOAuthSession(ctx, config, { ...latest, ...user });
235
203
  return user;
236
204
  }
237
205
  async function logout(ctx) {
238
206
  const config = parseOptionalOAuthConfig(ctx.store.getState().xfe);
239
207
  const current = config ? resolveOAuthStateForConfig(config, ctx.store.getState().oauth) : undefined;
240
208
  const name = config?.name || current?.name || DEFAULT_OAUTH_NAME;
241
- const storeState = createOAuthStoreState(ctx.store.getState().oauth);
242
- if (config)
243
- delete storeState[resolveOAuthConfigKey(config)];
244
- replaceOAuthStoreState(ctx, storeState);
209
+ const storeState = ctx.store.getState().oauth ?? oauthStoreInitial;
210
+ const currentConfigKey = config ? resolveOAuthConfigKey(config) : undefined;
211
+ const nextStoreState = currentConfigKey
212
+ ? Object.fromEntries(Object.entries(storeState).filter(([configKey]) => configKey !== currentConfigKey))
213
+ : storeState;
214
+ ctx.store.setState({ oauth: nextStoreState });
245
215
  ctx.logger.success(`${name} 已退出登录`);
246
216
  }
247
217
  // ─── Config And State ──────────────────────────────────────
248
- export function resolveOAuthStateForConfig(config, state) {
218
+ function resolveOAuthStateForConfig(config, state) {
249
219
  const configKey = resolveOAuthConfigKey(config);
250
220
  const session = state?.[configKey];
251
- return session ? toOAuthSessionState(session, config.name) : createEmptyOAuthSession(config.name);
221
+ return {
222
+ name: session?.name || config.name,
223
+ accessToken: session?.accessToken || '',
224
+ refreshToken: session?.refreshToken || '',
225
+ tokenType: session?.tokenType || DEFAULT_TOKEN_TYPE,
226
+ expiresAt: session?.expiresAt ?? 0,
227
+ userId: session?.userId ?? 0,
228
+ userName: session?.userName || '',
229
+ };
252
230
  }
253
231
  function parseOAuthConfig(xfeConfig) {
254
232
  const config = parseOptionalOAuthConfig(xfeConfig);
@@ -267,19 +245,11 @@ function parseOptionalOAuthConfig(xfeConfig) {
267
245
  }
268
246
  return result.data;
269
247
  }
270
- function activateOAuthState(ctx, config) {
271
- const storeState = createOAuthStoreState(ctx.store.getState().oauth);
272
- replaceOAuthStoreState(ctx, storeState);
273
- return resolveOAuthStateForConfig(config, storeState);
274
- }
275
248
  function saveOAuthSession(ctx, config, session) {
276
249
  const configKey = resolveOAuthConfigKey(config);
277
- const storeState = createOAuthStoreState(ctx.store.getState().oauth);
278
- storeState[configKey] = toOAuthSessionState(session, config.name);
279
- replaceOAuthStoreState(ctx, storeState);
280
- }
281
- function replaceOAuthStoreState(ctx, state) {
282
- ctx.store.setState({ oauth: state });
250
+ const storeState = { ...(ctx.store.getState().oauth ?? oauthStoreInitial) };
251
+ storeState[configKey] = session;
252
+ ctx.store.setState({ oauth: storeState });
283
253
  }
284
254
  function resolveOptionalOAuthState(xfeConfig, state) {
285
255
  const config = parseOptionalOAuthConfig(xfeConfig);
@@ -287,10 +257,7 @@ function resolveOptionalOAuthState(xfeConfig, state) {
287
257
  return undefined;
288
258
  return resolveOAuthStateForConfig(config, state);
289
259
  }
290
- function createOAuthStoreState(state) {
291
- return cloneOAuthState(state);
292
- }
293
- export function resolveOAuthConfigKey(config) {
260
+ function resolveOAuthConfigKey(config) {
294
261
  const payload = [
295
262
  OAUTH_CONFIG_KEY_VERSION,
296
263
  config.discoveryUrl ?? '',
@@ -305,37 +272,22 @@ export function resolveOAuthConfigKey(config) {
305
272
  const digest = createHash(OAUTH_CONFIG_HASH_ALGORITHM).update(payload).digest(OAUTH_CONFIG_HASH_ENCODING);
306
273
  return `${OAUTH_CONFIG_KEY_PREFIX}:${digest}`;
307
274
  }
308
- function cloneOAuthState(stateMap) {
309
- if (!stateMap)
310
- return {};
311
- return Object.fromEntries(Object.entries(stateMap)
312
- .filter((entry) => isOAuthSessionState(entry[1]))
313
- .map(([configKey, session]) => [configKey, toOAuthSessionState(session, session.name)]));
275
+ function isOAuthAccessTokenValid(state, now) {
276
+ return !!state.accessToken && (!state.expiresAt || state.expiresAt - TOKEN_EXPIRY_SKEW_SECONDS > now);
314
277
  }
315
- function isOAuthSessionState(value) {
316
- if (typeof value !== 'object' || value === null || Array.isArray(value))
317
- return false;
318
- const record = value;
319
- return typeof record.name === 'string';
320
- }
321
- function createEmptyOAuthSession(name) {
322
- return toOAuthSessionState(undefined, name);
323
- }
324
- function toOAuthSessionState(state, name) {
278
+ function createOAuthSessionFromToken(config, tokenResponse, now, fallbackRefreshToken = '') {
279
+ const expiresIn = tokenResponse.expiresIn();
325
280
  return {
326
- name: state?.name || name,
327
- accessToken: state?.accessToken || '',
328
- refreshToken: state?.refreshToken || '',
329
- idToken: state?.idToken || '',
330
- tokenType: state?.tokenType || DEFAULT_TOKEN_TYPE,
331
- scope: state?.scope || '',
332
- expiresAt: state?.expiresAt ?? 0,
333
- isAuthenticated: state?.isAuthenticated ?? false,
334
- userId: state?.userId ?? 0,
335
- userName: state?.userName || '',
281
+ name: config.name,
282
+ accessToken: tokenResponse.access_token ?? '',
283
+ refreshToken: tokenResponse.refresh_token || fallbackRefreshToken,
284
+ tokenType: tokenResponse.token_type || DEFAULT_TOKEN_TYPE,
285
+ expiresAt: expiresIn ? now + expiresIn : 0,
286
+ userId: 0,
287
+ userName: '',
336
288
  };
337
289
  }
338
- export function normalizeOAuthUserInfo(input) {
290
+ function normalizeOAuthUserInfo(input) {
339
291
  if (typeof input !== 'object' || input === null || Array.isArray(input)) {
340
292
  throw new Error('OAuth 用户信息响应格式无效');
341
293
  }
@@ -344,31 +296,16 @@ export function normalizeOAuthUserInfo(input) {
344
296
  const userRecord = nestedRecord ?? rootRecord;
345
297
  const userIdKeys = ['userId', 'user_id', 'UserId', 'id', 'uid'];
346
298
  const userNameKeys = ['name', 'userName', 'user_name', 'UserName', 'username', 'nickName', 'nikeName', 'nickname'];
347
- let userId = 0;
348
- let userName = '';
349
- for (const key of userIdKeys) {
350
- const value = userRecord[key];
351
- if (typeof value === 'number' && Number.isInteger(value)) {
352
- userId = value;
353
- break;
354
- }
355
- if (typeof value === 'string' && value.trim()) {
356
- const parsed = Number.parseInt(value, 10);
357
- if (!Number.isNaN(parsed)) {
358
- userId = parsed;
359
- break;
360
- }
361
- }
362
- }
299
+ const userId = userIdKeys
300
+ .map((key) => userRecord[key])
301
+ .map((value) => (typeof value === 'number' ? value : typeof value === 'string' ? Number.parseInt(value, 10) : Number.NaN))
302
+ .find(Number.isInteger) ?? 0;
363
303
  if (!userId)
364
304
  throw new Error('OAuth 用户信息缺少 userId');
365
- for (const key of userNameKeys) {
366
- const value = userRecord[key];
367
- if (typeof value === 'string' && value.trim()) {
368
- userName = value.trim();
369
- break;
370
- }
371
- }
305
+ const userName = userNameKeys
306
+ .map((key) => userRecord[key])
307
+ .find((value) => typeof value === 'string' && !!value.trim())
308
+ ?.trim();
372
309
  if (!userName)
373
310
  throw new Error('OAuth 用户信息缺少 userName');
374
311
  return { userId, userName };
package/dist/types.d.ts CHANGED
@@ -24,16 +24,12 @@ export interface OAuthSessionState {
24
24
  name: string;
25
25
  accessToken: string;
26
26
  refreshToken: string;
27
- idToken: string;
28
27
  tokenType: string;
29
- scope: string;
30
28
  expiresAt: number;
31
- isAuthenticated: boolean;
32
29
  userId: number;
33
30
  userName: string;
34
31
  }
35
32
  export type OAuthStoreState = Record<string, OAuthSessionState>;
36
- export type OAuthTokenState = OAuthSessionState;
37
33
  export interface OAuthLoginOptions {
38
34
  force?: boolean;
39
35
  }
@@ -42,8 +38,7 @@ export interface OAuthUserState {
42
38
  userName: string;
43
39
  }
44
40
  export interface OAuthCapability {
45
- auth(ctx: PluginContext, options?: OAuthLoginOptions): Promise<OAuthTokenState>;
46
- login(ctx: PluginContext, options?: OAuthLoginOptions): Promise<OAuthTokenState>;
41
+ login(ctx: PluginContext, options?: OAuthLoginOptions): Promise<OAuthSessionState>;
47
42
  getToken(ctx: PluginContext): Promise<string>;
48
43
  getUser(ctx: PluginContext): Promise<OAuthUserState>;
49
44
  logout(ctx: PluginContext): Promise<void>;
package/package.json CHANGED
@@ -1,13 +1,11 @@
1
1
  {
2
2
  "name": "@xfe-repo/cli-plugin-oauth",
3
- "version": "2.0.8",
3
+ "version": "2.0.10",
4
4
  "description": "XFE OAuth plugin - login through OIDC/OAuth and expose token state",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
8
8
  "dependencies": {
9
- "@hono/node-server": "^1.14.0",
10
- "hono": "^4.7.0",
11
9
  "openid-client": "^6.8.1",
12
10
  "open": "^10.2.0",
13
11
  "zod": "^4.3.6",
@@ -15,8 +13,7 @@
15
13
  },
16
14
  "devDependencies": {
17
15
  "@types/node": "^24.3.0",
18
- "typescript": "^5.9.2",
19
- "vitest": "^3.1.0"
16
+ "typescript": "^5.9.2"
20
17
  },
21
18
  "files": [
22
19
  "dist",
@@ -26,8 +23,7 @@
26
23
  "license": "ISC",
27
24
  "scripts": {
28
25
  "dev": "tsc -p tsconfig.json -w",
29
- "build": "tsc -p tsconfig.json",
30
- "test": "vitest run",
26
+ "build": "pnpm clean && tsc -p tsconfig.json",
31
27
  "clean": "rm -rf dist"
32
28
  }
33
29
  }
@@ -1,8 +0,0 @@
1
- /**
2
- * @xfe-repo/cli-plugin-oauth - OAuth 回调子进程
3
- *
4
- * 在独立 Node 进程中等待本地 OAuth 回调,让 CLI session 的 Ctrl+C
5
- * 可以通过 ctx.exec 终止等待中的回调服务。
6
- */
7
- export {};
8
- //# sourceMappingURL=callback-runner.d.ts.map
@@ -1,26 +0,0 @@
1
- /**
2
- * @xfe-repo/cli-plugin-oauth - OAuth 回调子进程
3
- *
4
- * 在独立 Node 进程中等待本地 OAuth 回调,让 CLI session 的 Ctrl+C
5
- * 可以通过 ctx.exec 终止等待中的回调服务。
6
- */
7
- import { OAUTH_CALLBACK_URL_PREFIX, startOAuthCallbackServer } from './callback-server.js';
8
- async function main() {
9
- const redirectUri = process.argv[2];
10
- if (!redirectUri)
11
- throw new Error('缺少 OAuth redirectUri 参数');
12
- const callbackServer = await startOAuthCallbackServer(redirectUri);
13
- try {
14
- const callbackUrl = await callbackServer.waitForCallback();
15
- process.stdout.write(`${OAUTH_CALLBACK_URL_PREFIX}${callbackUrl.href}\n`);
16
- }
17
- finally {
18
- await callbackServer.close();
19
- }
20
- }
21
- main().catch((error) => {
22
- const message = error instanceof Error ? error.message : String(error);
23
- process.stderr.write(`${message}\n`);
24
- process.exitCode = 1;
25
- });
26
- //# sourceMappingURL=callback-runner.js.map