@cloudbase/toolbox 0.7.17-beta.3 → 0.7.18

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.
@@ -47,6 +47,12 @@ export interface WebAuthOptions {
47
47
  getOAuthEndpoint?: DeviceFlowOptions['getOAuthEndpoint'];
48
48
  /** 静默模式,不打印任何日志 */
49
49
  silent?: boolean;
50
+ /**
51
+ * 自定义授权流程模式
52
+ * 为 true 时,device/code 和 token 接口的返回值没有外层 { code, result, reqId } 包装,
53
+ * 直接就是 result 本体;同时 verification_uri 直接使用接口返回值,不再由客户端拼接。
54
+ */
55
+ custom?: DeviceFlowOptions['custom'];
50
56
  }
51
57
  export interface LoginByApiSecretOptions {
52
58
  /**
package/lib/auth/index.js CHANGED
@@ -82,7 +82,7 @@ class AuthSupervisor {
82
82
  */
83
83
  loginByWebAuth(options = {}) {
84
84
  return __awaiter(this, void 0, void 0, function* () {
85
- const { getAuthUrl, throwError, noBrowser, callbackTimeout, flow = 'device', client_id, onDeviceCode, getOAuthEndpoint, silent } = options;
85
+ const { getAuthUrl, throwError, noBrowser, callbackTimeout, flow = 'device', client_id, onDeviceCode, getOAuthEndpoint, silent, custom } = options;
86
86
  if (this.cacheCredential && this.needCache && !this.isCacheExpire()) {
87
87
  return this.cacheCredential;
88
88
  }
@@ -100,7 +100,7 @@ class AuthSupervisor {
100
100
  });
101
101
  }
102
102
  else {
103
- credential = yield (0, oauth_1.getAuthTokenByDeviceFlow)({ client_id, onDeviceCode, getOAuthEndpoint, getAuthUrl, silent });
103
+ credential = yield (0, oauth_1.getAuthTokenByDeviceFlow)({ client_id, onDeviceCode, getOAuthEndpoint, getAuthUrl, silent, custom });
104
104
  }
105
105
  credential = (0, common_1.resolveCredential)(credential);
106
106
  try {
@@ -13,5 +13,11 @@ export interface DeviceFlowOptions {
13
13
  getAuthUrl?: (rawUrl: string) => string;
14
14
  /** 静默模式,不打印任何日志 */
15
15
  silent?: boolean;
16
+ /**
17
+ * 自定义授权流程模式
18
+ * 为 true 时,device/code 和 token 接口的返回值没有外层 { code, result, reqId } 包装,
19
+ * 直接就是 result 本体;同时 verification_uri 直接使用接口返回值,不再由客户端拼接。
20
+ */
21
+ custom?: boolean;
16
22
  }
17
23
  export declare function getAuthTokenByDeviceFlow(options?: DeviceFlowOptions): Promise<Credential>;
package/lib/auth/oauth.js CHANGED
@@ -51,25 +51,65 @@ function sleep(ms) {
51
51
  setTimeout(resolve, ms);
52
52
  });
53
53
  }
54
+ /**
55
+ * 将接口原始返回值归一化为裸数据。
56
+ * - 标准模式:从 { code, result, reqId } 中解包,校验 code
57
+ * - custom 模式:返回值本身即为裸数据,直接透传
58
+ */
59
+ function unwrapDeviceCodeResponse(raw, custom) {
60
+ console.log(raw);
61
+ if (custom) {
62
+ if (!raw || !raw.device_code) {
63
+ throw new error_1.CloudBaseError('Device Flow fetchDeviceCode failed (custom mode): 返回数据异常');
64
+ }
65
+ return { data: raw };
66
+ }
67
+ const resp = raw;
68
+ if (resp.code !== SUCCESS_CODE) {
69
+ throw new error_1.CloudBaseError('Device Flow fetchDeviceCode failed', {
70
+ code: resp.code,
71
+ requestId: resp.reqId,
72
+ });
73
+ }
74
+ return { data: resp.result, reqId: resp.reqId };
75
+ }
76
+ function unwrapTokenResponse(raw, custom) {
77
+ if (custom) {
78
+ return { data: raw };
79
+ }
80
+ const resp = raw;
81
+ // 标准模式下若外层 code 异常且无 result,直接抛错
82
+ if (resp.code !== SUCCESS_CODE && !resp.result) {
83
+ throw new error_1.CloudBaseError(`Device Flow 授权失败,错误码: ${resp.code}`, {
84
+ code: resp.code,
85
+ requestId: resp.reqId,
86
+ });
87
+ }
88
+ return { data: resp.result, reqId: resp.reqId };
89
+ }
54
90
  function getAuthTokenByDeviceFlow(options = {}) {
55
91
  return __awaiter(this, void 0, void 0, function* () {
56
- const { client_id, onDeviceCode, getOAuthEndpoint, getAuthUrl, silent } = options;
92
+ const { client_id, onDeviceCode, getOAuthEndpoint, getAuthUrl, silent, custom } = options;
57
93
  const endpoint = getOAuthEndpoint ? getOAuthEndpoint(OAUTH_ENDPOINT) : OAUTH_ENDPOINT;
58
- const deviceCodeResp = yield fetchDeviceCode({ client_id, endpoint });
59
- if (deviceCodeResp.code !== SUCCESS_CODE) {
60
- throw new error_1.CloudBaseError('Device Flow fetchDeviceCode failed', {
61
- code: deviceCodeResp.code,
62
- requestId: deviceCodeResp.reqId,
63
- });
94
+ // ---- 获取 device code ----
95
+ const deviceCodeRaw = yield fetchDeviceCode({ client_id, endpoint });
96
+ const { data: deviceCodeData } = unwrapDeviceCodeResponse(deviceCodeRaw, !!custom);
97
+ const { device_code, user_code, expires_in, interval } = deviceCodeData;
98
+ // ---- 构造 verification_uri ----
99
+ let verification_uri;
100
+ if (custom) {
101
+ // custom 模式直接使用接口返回的 verification_uri
102
+ const rawUri = deviceCodeData.verification_uri || '';
103
+ verification_uri = getAuthUrl ? getAuthUrl(rawUri) : rawUri;
104
+ }
105
+ else {
106
+ // 标准模式由客户端拼接 verification_uri
107
+ const defaultVerificationUri = `${web_auth_1.CLI_AUTH_BASE_URL}#/cli-auth`;
108
+ // from=cli 后续考虑改用 client_id,因为 toolbox 作为公共依赖,可能被不同 client 所引用
109
+ const rawVerificationUri = `${defaultVerificationUri}?user_code=${user_code}&from=cli&flow=device`;
110
+ verification_uri = getAuthUrl ? getAuthUrl(rawVerificationUri) : rawVerificationUri;
64
111
  }
65
- const { device_code, user_code, expires_in, interval } = deviceCodeResp.result;
66
- // 暂时不消费 verification_uri,由客户端控制跳转
67
- const defaultVerificationUri = `${web_auth_1.CLI_AUTH_BASE_URL}#/cli-auth`;
68
- // from=cli 后续考虑改用 client_id,因为 toolbox 作为公共依赖,可能被不同 client 所引用
69
- const rawVerificationUri = `${defaultVerificationUri}?user_code=${user_code}&from=cli&flow=device`;
70
- const verification_uri = getAuthUrl ? getAuthUrl(rawVerificationUri) : rawVerificationUri;
71
112
  if (!silent) {
72
- // 打印授权信息,引导用户操作
73
113
  console.log('\n\n若链接未自动打开,请手动复制至浏览器,或尝试其他登录方式:');
74
114
  console.log(`\n${verification_uri}`);
75
115
  console.log(`\n用户码: ${user_code}\n`);
@@ -79,21 +119,25 @@ function getAuthTokenByDeviceFlow(options = {}) {
79
119
  if (onDeviceCode) {
80
120
  onDeviceCode({ user_code, verification_uri, device_code, expires_in });
81
121
  }
122
+ // ---- 轮询 token ----
82
123
  let pollInterval = interval;
83
124
  const deadline = Date.now() + expires_in * 1000;
84
125
  while (Date.now() < deadline) {
85
126
  yield sleep(pollInterval * 1000);
86
- let resp;
127
+ let tokenData;
128
+ let reqId;
87
129
  try {
88
- resp = yield fetchPollToken({ device_code, interval: pollInterval, client_id, endpoint });
130
+ const tokenRaw = yield fetchPollToken({ device_code, interval: pollInterval, client_id, endpoint });
131
+ ({ data: tokenData, reqId } = unwrapTokenResponse(tokenRaw, !!custom));
89
132
  }
90
133
  catch (e) {
134
+ if (e instanceof error_1.CloudBaseError)
135
+ throw e;
91
136
  throw new error_1.CloudBaseError('Device Flow 轮询请求失败', { original: e });
92
137
  }
93
- const { code, result } = resp;
94
- // 服务端返回业务错误(result 中携带 error 字段)
95
- if (result && 'error' in result) {
96
- const { error, error_description } = result;
138
+ // 服务端返回业务错误(携带 error 字段)
139
+ if (tokenData && 'error' in tokenData) {
140
+ const { error, error_description } = tokenData;
97
141
  if (error === POLL_ERROR_CODES.AUTHORIZATION_PENDING) {
98
142
  continue;
99
143
  }
@@ -109,17 +153,14 @@ function getAuthTokenByDeviceFlow(options = {}) {
109
153
  }
110
154
  throw new error_1.CloudBaseError(error_description || `Device Flow 授权失败,错误: ${error}`, {
111
155
  code: error,
112
- requestId: resp.reqId,
156
+ requestId: reqId,
113
157
  });
114
158
  }
115
- // 服务端返回成功的 Credential
116
- if (code === SUCCESS_CODE && result) {
117
- return result;
159
+ // 成功拿到 Credential
160
+ if (tokenData) {
161
+ return tokenData;
118
162
  }
119
- throw new error_1.CloudBaseError(`Device Flow 授权失败,错误码: ${code}`, {
120
- code,
121
- requestId: resp.reqId,
122
- });
163
+ throw new error_1.CloudBaseError('Device Flow 授权失败:返回数据异常', { requestId: reqId });
123
164
  }
124
165
  throw new error_1.CloudBaseError('授权超时,用户未在有效期内完成授权,请重试');
125
166
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/toolbox",
3
- "version": "0.7.17-beta.3",
3
+ "version": "0.7.18",
4
4
  "description": "The toolbox for cloudbase",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -67,4 +67,4 @@
67
67
  }
68
68
  },
69
69
  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
70
- }
70
+ }