@optima-chat/browser-cli 0.18.0 → 0.18.1

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 (2) hide show
  1. package/dist/index.js +55 -19
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4,6 +4,9 @@
4
4
  import { createRequire } from "module";
5
5
  import { Command } from "commander";
6
6
 
7
+ // src/api.ts
8
+ import { createHash } from "crypto";
9
+
7
10
  // src/config.ts
8
11
  import { readFileSync, existsSync } from "fs";
9
12
  import { join } from "path";
@@ -77,26 +80,41 @@ function getCurrentEnv() {
77
80
  }
78
81
  return "development";
79
82
  }
83
+ function resolveToken(required) {
84
+ for (const key of ["BROWSER_TOKEN", "OPTIMA_TOKEN"]) {
85
+ const value = process.env[key]?.trim();
86
+ if (value) return { token: value, source: key, required };
87
+ }
88
+ const noEnv = "\u672A\u8BBE\u7F6E BROWSER_TOKEN / OPTIMA_TOKEN";
89
+ const file = readOptimaToken();
90
+ if (!file?.access_token) {
91
+ return { token: null, source: null, required, missingReason: `${noEnv}\uFF0C~/.optima/token.json \u4E0D\u5B58\u5728\u6216\u6CA1\u6709 access_token` };
92
+ }
93
+ const expiresAt = typeof file.expires_at === "number" && Number.isFinite(file.expires_at) ? file.expires_at : void 0;
94
+ if (expiresAt !== void 0 && expiresAt <= Date.now()) {
95
+ return {
96
+ token: null,
97
+ source: null,
98
+ required,
99
+ missingReason: `${noEnv}\uFF0C~/.optima/token.json \u7684\u7968\u5DF2\u4E8E ${new Date(expiresAt).toISOString()} \u8FC7\u671F`
100
+ };
101
+ }
102
+ return { token: file.access_token, source: "token.json", expiresAt, required };
103
+ }
80
104
  function loadConfig() {
81
105
  const apiUrlOverride = process.env.BROWSER_API_URL;
82
106
  const env = apiUrlOverride ? void 0 : getCurrentEnv();
83
107
  const apiUrl = apiUrlOverride ?? ENV_CONFIG[env].apiUrl;
84
- let token = process.env.BROWSER_TOKEN || null;
85
- if (!token) {
86
- const optimaToken = readOptimaToken();
87
- if (optimaToken?.access_token) {
88
- token = optimaToken.access_token;
89
- }
90
- }
108
+ const auth = resolveToken(env !== void 0 && env !== "development");
91
109
  return {
92
110
  apiUrl,
93
- token,
111
+ auth,
94
112
  env
95
113
  };
96
114
  }
97
115
  var config = loadConfig();
98
116
  var BROWSER_API_URL = config.apiUrl;
99
- var ACCESS_TOKEN = config.token;
117
+ var AUTH = config.auth;
100
118
 
101
119
  // src/api.ts
102
120
  var BrowserAPIError = class extends Error {
@@ -117,15 +135,34 @@ function toAPIError(status, statusText, body) {
117
135
  }
118
136
  return new BrowserAPIError(status, "unknown", `HTTP ${status}: ${statusText}`);
119
137
  }
138
+ function authHeader() {
139
+ if (AUTH.token) return { Authorization: `Bearer ${AUTH.token}` };
140
+ if (AUTH.required) {
141
+ throw new Error(`\u65E0\u53EF\u7528\u51ED\u8BC1\uFF1A${AUTH.missingReason}\u3002\u8FD9\u662F Optima \u5E73\u53F0\u51ED\u8BC1\uFF0C\u4E0E\u5E97\u94FA/\u6D4F\u89C8\u5668\u7684\u767B\u5F55\u65E0\u5173\u3002`);
142
+ }
143
+ return {};
144
+ }
145
+ function withAuthContext(err) {
146
+ if (err.statusCode !== 401) return err;
147
+ if (!AUTH.token) {
148
+ err.message += `\uFF08\u672A\u5E26\u51ED\u8BC1\uFF1A${AUTH.missingReason}\uFF09`;
149
+ return err;
150
+ }
151
+ const fp = createHash("sha256").update(AUTH.token).digest("hex").slice(0, 12);
152
+ const exp = AUTH.expiresAt !== void 0 ? `\uFF0Cexpires_at=${new Date(AUTH.expiresAt).toISOString()}` : "";
153
+ err.message += `\uFF08\u51ED\u8BC1\u6765\u6E90 ${AUTH.source}${exp}\uFF0Cfp=${fp}\uFF09`;
154
+ return err;
155
+ }
120
156
  async function request(path, options = {}) {
121
157
  const url = `${BROWSER_API_URL}${path}`;
158
+ const auth = authHeader();
122
159
  let response;
123
160
  try {
124
161
  response = await fetch(url, {
125
162
  ...options,
126
163
  headers: {
127
164
  "Content-Type": "application/json",
128
- ...ACCESS_TOKEN ? { Authorization: `Bearer ${ACCESS_TOKEN}` } : {},
165
+ ...auth,
129
166
  ...options.headers
130
167
  }
131
168
  });
@@ -139,13 +176,13 @@ async function request(path, options = {}) {
139
176
  try {
140
177
  body = await response.json();
141
178
  } catch {
142
- throw new BrowserAPIError(
179
+ throw withAuthContext(new BrowserAPIError(
143
180
  response.status,
144
181
  "unknown",
145
182
  `HTTP ${response.status}: ${response.statusText}`
146
- );
183
+ ));
147
184
  }
148
- throw toAPIError(response.status, response.statusText, body);
185
+ throw withAuthContext(toAPIError(response.status, response.statusText, body));
149
186
  }
150
187
  if (response.status === 204) {
151
188
  return void 0;
@@ -154,12 +191,11 @@ async function request(path, options = {}) {
154
191
  }
155
192
  async function requestBinary(path) {
156
193
  const url = `${BROWSER_API_URL}${path}`;
194
+ const auth = authHeader();
157
195
  let response;
158
196
  try {
159
197
  response = await fetch(url, {
160
- headers: {
161
- ...ACCESS_TOKEN ? { Authorization: `Bearer ${ACCESS_TOKEN}` } : {}
162
- }
198
+ headers: auth
163
199
  });
164
200
  } catch {
165
201
  throw new Error(
@@ -171,13 +207,13 @@ async function requestBinary(path) {
171
207
  try {
172
208
  body = await response.json();
173
209
  } catch {
174
- throw new BrowserAPIError(
210
+ throw withAuthContext(new BrowserAPIError(
175
211
  response.status,
176
212
  "unknown",
177
213
  `HTTP ${response.status}: ${response.statusText}`
178
- );
214
+ ));
179
215
  }
180
- throw toAPIError(response.status, response.statusText, body);
216
+ throw withAuthContext(toAPIError(response.status, response.statusText, body));
181
217
  }
182
218
  const arrayBuffer = await response.arrayBuffer();
183
219
  return Buffer.from(arrayBuffer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optima-chat/browser-cli",
3
- "version": "0.18.0",
3
+ "version": "0.18.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {