@optima-chat/ads-cli 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/commands/account/check.d.ts.map +1 -1
  2. package/dist/commands/account/check.js +26 -123
  3. package/dist/commands/account/check.js.map +1 -1
  4. package/dist/commands/account/create.d.ts.map +1 -1
  5. package/dist/commands/account/create.js +0 -40
  6. package/dist/commands/account/create.js.map +1 -1
  7. package/dist/commands/ad/create.js +2 -2
  8. package/dist/commands/ad/create.js.map +1 -1
  9. package/dist/commands/ad/delete.js +2 -2
  10. package/dist/commands/ad/delete.js.map +1 -1
  11. package/dist/commands/ad/info.js +2 -2
  12. package/dist/commands/ad/info.js.map +1 -1
  13. package/dist/commands/ad/list.js +2 -2
  14. package/dist/commands/ad/list.js.map +1 -1
  15. package/dist/commands/ad/update.d.ts +1 -1
  16. package/dist/commands/ad/update.js +3 -3
  17. package/dist/commands/ad/update.js.map +1 -1
  18. package/dist/commands/ad-group/create.d.ts.map +1 -1
  19. package/dist/commands/ad-group/create.js +10 -16
  20. package/dist/commands/ad-group/create.js.map +1 -1
  21. package/dist/commands/ad-group/delete.js +2 -2
  22. package/dist/commands/ad-group/delete.js.map +1 -1
  23. package/dist/commands/ad-group/info.js +2 -2
  24. package/dist/commands/ad-group/info.js.map +1 -1
  25. package/dist/commands/ad-group/list.d.ts.map +1 -1
  26. package/dist/commands/ad-group/list.js +4 -3
  27. package/dist/commands/ad-group/list.js.map +1 -1
  28. package/dist/commands/ad-group/update.js +2 -2
  29. package/dist/commands/ad-group/update.js.map +1 -1
  30. package/dist/commands/auth/login.d.ts +2 -4
  31. package/dist/commands/auth/login.d.ts.map +1 -1
  32. package/dist/commands/auth/login.js +68 -135
  33. package/dist/commands/auth/login.js.map +1 -1
  34. package/dist/commands/auth/logout.d.ts +2 -0
  35. package/dist/commands/auth/logout.d.ts.map +1 -1
  36. package/dist/commands/auth/logout.js +19 -17
  37. package/dist/commands/auth/logout.js.map +1 -1
  38. package/dist/commands/auth/status.d.ts +2 -0
  39. package/dist/commands/auth/status.d.ts.map +1 -1
  40. package/dist/commands/auth/status.js +36 -21
  41. package/dist/commands/auth/status.js.map +1 -1
  42. package/dist/commands/campaign/create.d.ts.map +1 -1
  43. package/dist/commands/campaign/create.js +9 -15
  44. package/dist/commands/campaign/create.js.map +1 -1
  45. package/dist/commands/campaign/delete.js +2 -2
  46. package/dist/commands/campaign/delete.js.map +1 -1
  47. package/dist/commands/campaign/info.js +2 -2
  48. package/dist/commands/campaign/info.js.map +1 -1
  49. package/dist/commands/campaign/list.js +2 -2
  50. package/dist/commands/campaign/list.js.map +1 -1
  51. package/dist/commands/campaign/update.js +2 -2
  52. package/dist/commands/campaign/update.js.map +1 -1
  53. package/dist/commands/keyword/add.d.ts.map +1 -1
  54. package/dist/commands/keyword/add.js +7 -6
  55. package/dist/commands/keyword/add.js.map +1 -1
  56. package/dist/commands/keyword/delete.js +2 -2
  57. package/dist/commands/keyword/delete.js.map +1 -1
  58. package/dist/commands/keyword/list.d.ts.map +1 -1
  59. package/dist/commands/keyword/list.js +4 -3
  60. package/dist/commands/keyword/list.js.map +1 -1
  61. package/dist/commands/keyword/update.js +2 -2
  62. package/dist/commands/keyword/update.js.map +1 -1
  63. package/dist/commands/query.js +2 -2
  64. package/dist/commands/query.js.map +1 -1
  65. package/dist/lib/api-client.d.ts +2 -1
  66. package/dist/lib/api-client.d.ts.map +1 -1
  67. package/dist/lib/api-client.js +7 -9
  68. package/dist/lib/api-client.js.map +1 -1
  69. package/dist/lib/auth-types.d.ts +74 -0
  70. package/dist/lib/auth-types.d.ts.map +1 -0
  71. package/dist/lib/auth-types.js +24 -0
  72. package/dist/lib/auth-types.js.map +1 -0
  73. package/dist/lib/device-flow.d.ts +11 -0
  74. package/dist/lib/device-flow.d.ts.map +1 -0
  75. package/dist/lib/device-flow.js +111 -0
  76. package/dist/lib/device-flow.js.map +1 -0
  77. package/dist/lib/token-store.d.ts +43 -32
  78. package/dist/lib/token-store.d.ts.map +1 -1
  79. package/dist/lib/token-store.js +183 -81
  80. package/dist/lib/token-store.js.map +1 -1
  81. package/package.json +1 -1
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Auth Types - 认证相关类型定义
3
+ */
4
+ /**
5
+ * 环境配置
6
+ */
7
+ export const ENV_CONFIG = {
8
+ ci: {
9
+ authUrl: 'https://auth.optima.chat',
10
+ clientId: 'google-ads-cli-dev',
11
+ adsApiUrl: 'https://ads-api.optima.onl', // CI 环境用 prod API
12
+ },
13
+ stage: {
14
+ authUrl: 'https://auth.stage.optima.onl',
15
+ clientId: 'google-ads-cli-stage',
16
+ adsApiUrl: 'https://ads-api.stage.optima.onl',
17
+ },
18
+ prod: {
19
+ authUrl: 'https://auth.optima.onl',
20
+ clientId: 'google-ads-cli-prod',
21
+ adsApiUrl: 'https://ads-api.optima.onl',
22
+ },
23
+ };
24
+ //# sourceMappingURL=auth-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-types.js","sourceRoot":"","sources":["../../src/lib/auth-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAGnB;IACF,EAAE,EAAE;QACF,OAAO,EAAE,0BAA0B;QACnC,QAAQ,EAAE,oBAAoB;QAC9B,SAAS,EAAE,4BAA4B,EAAE,kBAAkB;KAC5D;IACD,KAAK,EAAE;QACL,OAAO,EAAE,+BAA+B;QACxC,QAAQ,EAAE,sBAAsB;QAChC,SAAS,EAAE,kCAAkC;KAC9C;IACD,IAAI,EAAE;QACJ,OAAO,EAAE,yBAAyB;QAClC,QAAQ,EAAE,qBAAqB;QAC/B,SAAS,EAAE,4BAA4B;KACxC;CACF,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Device Flow - OAuth2 设备授权流程
3
+ *
4
+ * 参考 optima-agent 实现,使用 Device Flow 进行登录
5
+ */
6
+ import type { DeviceFlowCallbacks, Environment } from './auth-types.js';
7
+ /**
8
+ * 启动 Device Flow 登录
9
+ */
10
+ export declare function startDeviceFlow(env: Environment, callbacks: DeviceFlowCallbacks, signal?: AbortSignal): Promise<void>;
11
+ //# sourceMappingURL=device-flow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-flow.d.ts","sourceRoot":"","sources":["../../src/lib/device-flow.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAGV,mBAAmB,EACnB,WAAW,EACZ,MAAM,iBAAiB,CAAC;AAazB;;GAEG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,mBAAmB,EAC9B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAsHf"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Device Flow - OAuth2 设备授权流程
3
+ *
4
+ * 参考 optima-agent 实现,使用 Device Flow 进行登录
5
+ */
6
+ import { ENV_CONFIG } from './auth-types.js';
7
+ import { saveToken, fetchUserInfo } from './token-store.js';
8
+ function sleep(ms) {
9
+ return new Promise((resolve) => setTimeout(resolve, ms));
10
+ }
11
+ /**
12
+ * 启动 Device Flow 登录
13
+ */
14
+ export async function startDeviceFlow(env, callbacks, signal) {
15
+ const { authUrl, clientId } = ENV_CONFIG[env];
16
+ // 1. 请求 device code
17
+ const codeRes = await fetch(`${authUrl}/api/v1/oauth/device/authorize`, {
18
+ method: 'POST',
19
+ headers: { 'Content-Type': 'application/json' },
20
+ body: JSON.stringify({ client_id: clientId }),
21
+ signal,
22
+ });
23
+ if (!codeRes.ok) {
24
+ const errorText = await codeRes.text();
25
+ throw new Error(`Failed to get device code: ${codeRes.status} ${errorText}`);
26
+ }
27
+ const codeData = (await codeRes.json());
28
+ // 2. 通知 UI 显示 code(优先使用带 code 的完整 URL)
29
+ const verificationUrl = codeData.verification_uri_complete || codeData.verification_uri;
30
+ callbacks.onCodeReceived(codeData.user_code, verificationUrl);
31
+ // 3. 轮询获取 token
32
+ const pollInterval = (codeData.interval || 5) * 1000;
33
+ const expiresAt = Date.now() + codeData.expires_in * 1000;
34
+ while (Date.now() < expiresAt) {
35
+ if (signal?.aborted) {
36
+ throw new Error('Login cancelled');
37
+ }
38
+ callbacks.onPolling?.();
39
+ await sleep(pollInterval);
40
+ if (signal?.aborted) {
41
+ throw new Error('Login cancelled');
42
+ }
43
+ const tokenRes = await fetch(`${authUrl}/api/v1/oauth/device/token`, {
44
+ method: 'POST',
45
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
46
+ body: new URLSearchParams({
47
+ device_code: codeData.device_code,
48
+ client_id: clientId,
49
+ grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
50
+ }),
51
+ signal,
52
+ });
53
+ // 解析响应
54
+ let responseBody;
55
+ try {
56
+ responseBody = await tokenRes.text();
57
+ }
58
+ catch {
59
+ responseBody = '';
60
+ }
61
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
+ let data;
63
+ try {
64
+ data = JSON.parse(responseBody);
65
+ }
66
+ catch {
67
+ callbacks.onError(`Invalid response: ${responseBody}`);
68
+ return;
69
+ }
70
+ // 成功获取 token(有 access_token 且无 error)
71
+ if (data.access_token && !data.error) {
72
+ const tokenData = data;
73
+ // 获取用户信息
74
+ let userInfo;
75
+ try {
76
+ userInfo = await fetchUserInfo(tokenData.access_token, env);
77
+ }
78
+ catch {
79
+ // 用户信息获取失败不影响登录
80
+ }
81
+ // 保存 token
82
+ saveToken(tokenData, env, userInfo);
83
+ callbacks.onSuccess(userInfo || { id: '', email: '' });
84
+ return;
85
+ }
86
+ // 处理错误响应
87
+ const error = data;
88
+ // authorization_pending 是正常状态,继续轮询
89
+ if (error.error === 'authorization_pending') {
90
+ continue;
91
+ }
92
+ if (error.error === 'slow_down') {
93
+ await sleep(5000); // 额外等待
94
+ continue;
95
+ }
96
+ if (error.error === 'expired_token') {
97
+ callbacks.onError('登录超时,请重试');
98
+ return;
99
+ }
100
+ if (error.error === 'access_denied') {
101
+ callbacks.onError('登录被拒绝');
102
+ return;
103
+ }
104
+ // 其他错误,显示详情
105
+ const errorMsg = error.error_description || error.error || `HTTP ${tokenRes.status}`;
106
+ callbacks.onError(errorMsg);
107
+ return;
108
+ }
109
+ callbacks.onError('登录超时');
110
+ }
111
+ //# sourceMappingURL=device-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-flow.js","sourceRoot":"","sources":["../../src/lib/device-flow.ts"],"names":[],"mappings":"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"}
@@ -1,43 +1,54 @@
1
1
  /**
2
2
  * Token Store - Optima JWT Token 存储和管理
3
3
  *
4
- * 支持从以下位置读取 token
5
- * 1. 环境变量 OPTIMA_TOKEN
6
- * 2. ~/.optima/token.json 文件
4
+ * Token 存储位置:~/.optima/token.json
5
+ * optima-agent 兼容
7
6
  */
8
- export declare class TokenStore {
9
- private tokenFilePath;
10
- constructor();
11
- /**
12
- * 获取 JWT access token
13
- */
14
- getToken(): Promise<string | null>;
15
- /**
16
- * 检查是否已有 token
17
- */
18
- hasToken(): Promise<boolean>;
19
- /**
20
- * 保存 token 到文件
21
- */
22
- saveToken(accessToken: string, refreshToken?: string): Promise<void>;
23
- /**
24
- * 清除 token
25
- */
26
- clearToken(): Promise<void>;
27
- }
28
- import { OAuth2Token } from '../config.js';
7
+ import type { TokenData, TokenResponse, UserInfo, AuthStatus, Environment } from './auth-types.js';
8
+ /**
9
+ * 确保 ~/.optima 目录存在
10
+ */
11
+ export declare function ensureOptimaDir(): void;
12
+ /**
13
+ * 保存 Token
14
+ */
15
+ export declare function saveToken(response: TokenResponse, env: Environment, user?: UserInfo): void;
16
+ /**
17
+ * 读取 Token(按优先级)
18
+ */
19
+ export declare function getToken(): string | null;
20
+ /**
21
+ * 读取完整 Token 数据
22
+ */
23
+ export declare function getTokenData(): TokenData | null;
24
+ /**
25
+ * 清除 Token
26
+ */
27
+ export declare function clearToken(): void;
28
+ /**
29
+ * 检查 Token 是否过期
30
+ */
31
+ export declare function isTokenExpired(data?: TokenData | null): boolean;
32
+ /**
33
+ * 获取用户信息
34
+ */
35
+ export declare function fetchUserInfo(accessToken: string, env: Environment): Promise<UserInfo>;
29
36
  /**
30
- * 加载 Google Ads refresh token(从环境变量)
31
- * @deprecated 使用 TokenStore 类替代
37
+ * 获取认证状态
32
38
  */
33
- export declare function loadToken(): OAuth2Token | null;
39
+ export declare function getAuthStatus(): Promise<AuthStatus>;
34
40
  /**
35
- * 检查是否已有 Google Ads token
36
- * @deprecated 使用 TokenStore 类替代
41
+ * 刷新 Token
37
42
  */
38
- export declare function hasToken(): boolean;
43
+ export declare function refreshToken(): Promise<boolean>;
39
44
  /**
40
- * 检查 token 是否过期
45
+ * 获取当前环境的 Ads API URL
41
46
  */
42
- export declare function isTokenExpired(token: OAuth2Token): boolean;
47
+ export declare function getAdsApiUrl(): string;
48
+ export declare class TokenStore {
49
+ getToken(): Promise<string | null>;
50
+ hasToken(): Promise<boolean>;
51
+ saveToken(accessToken: string, refreshToken?: string): Promise<void>;
52
+ clearToken(): Promise<void>;
53
+ }
43
54
  //# sourceMappingURL=token-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"token-store.d.ts","sourceRoot":"","sources":["../../src/lib/token-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAeH,qBAAa,UAAU;IACrB,OAAO,CAAC,aAAa,CAAS;;IAM9B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAyBxC;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAKlC;;OAEG;IACG,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAe1E;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAKlC;AAID,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C;;;GAGG;AACH,wBAAgB,SAAS,IAAI,WAAW,GAAG,IAAI,CAc9C;AAED;;;GAGG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAElC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAG1D"}
1
+ {"version":3,"file":"token-store.d.ts","sourceRoot":"","sources":["../../src/lib/token-store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EACV,SAAS,EACT,aAAa,EACb,QAAQ,EACR,UAAU,EACV,WAAW,EACZ,MAAM,iBAAiB,CAAC;AAMzB;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAItC;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,WAAW,EAChB,IAAI,CAAC,EAAE,QAAQ,GACd,IAAI,CAaN;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI,MAAM,GAAG,IAAI,CAaxC;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,SAAS,GAAG,IAAI,CAqB/C;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAIjC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,OAAO,CAM/D;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,QAAQ,CAAC,CAYnB;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC,CAuCzD;AAED;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC,CA6BrD;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAIrC;AAID,qBAAa,UAAU;IACf,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIlC,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAI5B,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcpE,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAGlC"}
@@ -1,103 +1,205 @@
1
1
  /**
2
2
  * Token Store - Optima JWT Token 存储和管理
3
3
  *
4
- * 支持从以下位置读取 token
5
- * 1. 环境变量 OPTIMA_TOKEN
6
- * 2. ~/.optima/token.json 文件
4
+ * Token 存储位置:~/.optima/token.json
5
+ * optima-agent 兼容
7
6
  */
8
- import * as fs from 'fs';
9
- import * as path from 'path';
10
- import * as os from 'os';
11
- export class TokenStore {
12
- tokenFilePath;
13
- constructor() {
14
- this.tokenFilePath = path.join(os.homedir(), '.optima', 'token.json');
7
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from 'fs';
8
+ import { join } from 'path';
9
+ import { homedir } from 'os';
10
+ import { ENV_CONFIG } from './auth-types.js';
11
+ const OPTIMA_DIR = join(homedir(), '.optima');
12
+ const TOKEN_FILE = join(OPTIMA_DIR, 'token.json');
13
+ /**
14
+ * 确保 ~/.optima 目录存在
15
+ */
16
+ export function ensureOptimaDir() {
17
+ if (!existsSync(OPTIMA_DIR)) {
18
+ mkdirSync(OPTIMA_DIR, { recursive: true, mode: 0o700 });
15
19
  }
16
- /**
17
- * 获取 JWT access token
18
- */
19
- async getToken() {
20
- // 1. 尝试从环境变量读取
21
- if (process.env.OPTIMA_TOKEN) {
22
- return process.env.OPTIMA_TOKEN;
23
- }
24
- // 2. 尝试从文件读取
25
- try {
26
- if (fs.existsSync(this.tokenFilePath)) {
27
- const content = fs.readFileSync(this.tokenFilePath, 'utf-8');
28
- const token = JSON.parse(content);
29
- // 支持两种格式:camelCase 和 snake_case
30
- const accessToken = token.accessToken || token.access_token;
31
- if (accessToken) {
32
- return accessToken;
33
- }
34
- }
35
- }
36
- catch {
37
- // 忽略文件读取错误
38
- }
39
- return null;
20
+ }
21
+ /**
22
+ * 保存 Token
23
+ */
24
+ export function saveToken(response, env, user) {
25
+ ensureOptimaDir();
26
+ const tokenData = {
27
+ env,
28
+ access_token: response.access_token,
29
+ refresh_token: response.refresh_token,
30
+ token_type: response.token_type,
31
+ expires_at: Date.now() + response.expires_in * 1000,
32
+ user,
33
+ };
34
+ writeFileSync(TOKEN_FILE, JSON.stringify(tokenData, null, 2), { mode: 0o600 });
35
+ }
36
+ /**
37
+ * 读取 Token(按优先级)
38
+ */
39
+ export function getToken() {
40
+ // 1. 环境变量
41
+ if (process.env.OPTIMA_TOKEN) {
42
+ return process.env.OPTIMA_TOKEN;
40
43
  }
41
- /**
42
- * 检查是否已有 token
43
- */
44
- async hasToken() {
45
- const token = await this.getToken();
46
- return !!token;
44
+ // 2. token.json 文件
45
+ const data = getTokenData();
46
+ if (data) {
47
+ return data.access_token;
47
48
  }
48
- /**
49
- * 保存 token 到文件
50
- */
51
- async saveToken(accessToken, refreshToken) {
52
- const dir = path.dirname(this.tokenFilePath);
53
- if (!fs.existsSync(dir)) {
54
- fs.mkdirSync(dir, { recursive: true });
55
- }
56
- const token = {
57
- accessToken,
58
- refreshToken,
59
- expiresAt: Date.now() + 24 * 60 * 60 * 1000, // 24 hours
49
+ return null;
50
+ }
51
+ /**
52
+ * 读取完整 Token 数据
53
+ */
54
+ export function getTokenData() {
55
+ if (!existsSync(TOKEN_FILE)) {
56
+ return null;
57
+ }
58
+ try {
59
+ const content = readFileSync(TOKEN_FILE, 'utf-8');
60
+ const data = JSON.parse(content);
61
+ // 兼容两种格式
62
+ return {
63
+ env: data.env || 'prod',
64
+ access_token: data.access_token || data.accessToken,
65
+ refresh_token: data.refresh_token || data.refreshToken,
66
+ token_type: data.token_type || 'Bearer',
67
+ expires_at: data.expires_at || data.expiresAt || 0,
68
+ user: data.user,
60
69
  };
61
- fs.writeFileSync(this.tokenFilePath, JSON.stringify(token, null, 2));
62
70
  }
63
- /**
64
- * 清除 token
65
- */
66
- async clearToken() {
67
- if (fs.existsSync(this.tokenFilePath)) {
68
- fs.unlinkSync(this.tokenFilePath);
69
- }
71
+ catch {
72
+ return null;
70
73
  }
71
74
  }
72
75
  /**
73
- * 加载 Google Ads refresh token(从环境变量)
74
- * @deprecated 使用 TokenStore 类替代
76
+ * 清除 Token
75
77
  */
76
- export function loadToken() {
77
- const refreshToken = process.env.GOOGLE_ADS_REFRESH_TOKEN;
78
- if (!refreshToken) {
79
- return null;
78
+ export function clearToken() {
79
+ if (existsSync(TOKEN_FILE)) {
80
+ unlinkSync(TOKEN_FILE);
80
81
  }
81
- return {
82
- access_token: '',
83
- refresh_token: refreshToken,
84
- expires_at: 0,
85
- scope: 'https://www.googleapis.com/auth/adwords',
86
- token_type: 'Bearer',
87
- };
88
82
  }
89
83
  /**
90
- * 检查是否已有 Google Ads token
91
- * @deprecated 使用 TokenStore 类替代
84
+ * 检查 Token 是否过期
92
85
  */
93
- export function hasToken() {
94
- return !!process.env.GOOGLE_ADS_REFRESH_TOKEN;
86
+ export function isTokenExpired(data) {
87
+ const tokenData = data ?? getTokenData();
88
+ if (!tokenData)
89
+ return true;
90
+ // 提前 5 分钟视为过期
91
+ return Date.now() > tokenData.expires_at - 5 * 60 * 1000;
95
92
  }
96
93
  /**
97
- * 检查 token 是否过期
94
+ * 获取用户信息
98
95
  */
99
- export function isTokenExpired(token) {
100
- const expiryBuffer = 5 * 60 * 1000;
101
- return Date.now() >= token.expires_at - expiryBuffer;
96
+ export async function fetchUserInfo(accessToken, env) {
97
+ const { authUrl } = ENV_CONFIG[env];
98
+ const res = await fetch(`${authUrl}/api/v1/users/me`, {
99
+ headers: { Authorization: `Bearer ${accessToken}` },
100
+ });
101
+ if (!res.ok) {
102
+ throw new Error('Failed to fetch user info');
103
+ }
104
+ return (await res.json());
105
+ }
106
+ /**
107
+ * 获取认证状态
108
+ */
109
+ export async function getAuthStatus() {
110
+ const data = getTokenData();
111
+ if (!data) {
112
+ return { loggedIn: false };
113
+ }
114
+ if (isTokenExpired(data)) {
115
+ return { loggedIn: false };
116
+ }
117
+ // 如果有缓存的用户信息,直接使用
118
+ if (data.user) {
119
+ return {
120
+ loggedIn: true,
121
+ env: data.env,
122
+ user: data.user,
123
+ expiresAt: data.expires_at,
124
+ };
125
+ }
126
+ // 否则从服务端获取
127
+ try {
128
+ const user = await fetchUserInfo(data.access_token, data.env);
129
+ // 更新缓存
130
+ const updatedData = { ...data, user };
131
+ writeFileSync(TOKEN_FILE, JSON.stringify(updatedData, null, 2), {
132
+ mode: 0o600,
133
+ });
134
+ return {
135
+ loggedIn: true,
136
+ env: data.env,
137
+ user,
138
+ expiresAt: data.expires_at,
139
+ };
140
+ }
141
+ catch {
142
+ return { loggedIn: false };
143
+ }
144
+ }
145
+ /**
146
+ * 刷新 Token
147
+ */
148
+ export async function refreshToken() {
149
+ const data = getTokenData();
150
+ if (!data?.refresh_token) {
151
+ return false;
152
+ }
153
+ const { authUrl, clientId } = ENV_CONFIG[data.env];
154
+ try {
155
+ const res = await fetch(`${authUrl}/api/v1/oauth/token`, {
156
+ method: 'POST',
157
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
158
+ body: new URLSearchParams({
159
+ grant_type: 'refresh_token',
160
+ refresh_token: data.refresh_token,
161
+ client_id: clientId,
162
+ }),
163
+ });
164
+ if (!res.ok) {
165
+ return false;
166
+ }
167
+ const tokenResponse = (await res.json());
168
+ saveToken(tokenResponse, data.env, data.user);
169
+ return true;
170
+ }
171
+ catch {
172
+ return false;
173
+ }
174
+ }
175
+ /**
176
+ * 获取当前环境的 Ads API URL
177
+ */
178
+ export function getAdsApiUrl() {
179
+ const data = getTokenData();
180
+ const env = data?.env || 'prod';
181
+ return process.env.ADS_BACKEND_URL || ENV_CONFIG[env].adsApiUrl;
182
+ }
183
+ // ============ TokenStore class for backward compatibility ============
184
+ export class TokenStore {
185
+ async getToken() {
186
+ return getToken();
187
+ }
188
+ async hasToken() {
189
+ return !!getToken();
190
+ }
191
+ async saveToken(accessToken, refreshToken) {
192
+ const data = getTokenData();
193
+ const env = data?.env || 'prod';
194
+ saveToken({
195
+ access_token: accessToken,
196
+ refresh_token: refreshToken,
197
+ token_type: 'Bearer',
198
+ expires_in: 24 * 60 * 60, // 24 hours
199
+ }, env);
200
+ }
201
+ async clearToken() {
202
+ clearToken();
203
+ }
102
204
  }
103
205
  //# sourceMappingURL=token-store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"token-store.js","sourceRoot":"","sources":["../../src/lib/token-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"token-store.js","sourceRoot":"","sources":["../../src/lib/token-store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACpF,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAQ7B,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;AAElD;;GAEG;AACH,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CACvB,QAAuB,EACvB,GAAgB,EAChB,IAAe;IAEf,eAAe,EAAE,CAAC;IAElB,MAAM,SAAS,GAAc;QAC3B,GAAG;QACH,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,aAAa,EAAE,QAAQ,CAAC,aAAa;QACrC,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,UAAU,GAAG,IAAI;QACnD,IAAI;KACL,CAAC;IAEF,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACjF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ;IACtB,UAAU;IACV,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAC7B,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAClC,CAAC;IAED,mBAAmB;IACnB,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;IAC5B,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAEjC,SAAS;QACT,OAAO;YACL,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,MAAM;YACvB,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,WAAW;YACnD,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,YAAY;YACtD,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,QAAQ;YACvC,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC;YAClD,IAAI,EAAE,IAAI,CAAC,IAAI;SAChB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,UAAU,CAAC,UAAU,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,IAAuB;IACpD,MAAM,SAAS,GAAG,IAAI,IAAI,YAAY,EAAE,CAAC;IACzC,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAE5B,cAAc;IACd,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,UAAU,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAC3D,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,WAAmB,EACnB,GAAgB;IAEhB,MAAM,EAAE,OAAO,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAEpC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,kBAAkB,EAAE;QACpD,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,WAAW,EAAE,EAAE;KACpD,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAa,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;IAE5B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC7B,CAAC;IAED,IAAI,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC7B,CAAC;IAED,kBAAkB;IAClB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO;YACL,QAAQ,EAAE,IAAI;YACd,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,SAAS,EAAE,IAAI,CAAC,UAAU;SAC3B,CAAC;IACJ,CAAC;IAED,WAAW;IACX,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9D,OAAO;QACP,MAAM,WAAW,GAAG,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC;QACtC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;YAC9D,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;QAEH,OAAO;YACL,QAAQ,EAAE,IAAI;YACd,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,UAAU;SAC3B,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC7B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;IAC5B,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEnD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,qBAAqB,EAAE;YACvD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;YAChE,IAAI,EAAE,IAAI,eAAe,CAAC;gBACxB,UAAU,EAAE,eAAe;gBAC3B,aAAa,EAAE,IAAI,CAAC,aAAa;gBACjC,SAAS,EAAE,QAAQ;aACpB,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,aAAa,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAkB,CAAC;QAC1D,SAAS,CAAC,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;IAC5B,MAAM,GAAG,GAAG,IAAI,EAAE,GAAG,IAAI,MAAM,CAAC;IAChC,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC;AAClE,CAAC;AAED,wEAAwE;AAExE,MAAM,OAAO,UAAU;IACrB,KAAK,CAAC,QAAQ;QACZ,OAAO,QAAQ,EAAE,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,WAAmB,EAAE,YAAqB;QACxD,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,IAAI,EAAE,GAAG,IAAI,MAAM,CAAC;QAChC,SAAS,CACP;YACE,YAAY,EAAE,WAAW;YACzB,aAAa,EAAE,YAAY;YAC3B,UAAU,EAAE,QAAQ;YACpB,UAAU,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,WAAW;SACtC,EACD,GAAG,CACJ,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,UAAU;QACd,UAAU,EAAE,CAAC;IACf,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optima-chat/ads-cli",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "用自然语言管理 Google Ads 广告投放 - 专为 Claude Code 设计的对话式 CLI 工具",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",