@uzqw/shared 0.1.7 → 0.1.9

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/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ interface RecolxConfig {
11
11
  tokenFile?: string;
12
12
  /** token 落盘目录;缺省 ~/.recolx */
13
13
  tokenDir?: string;
14
- /** 环境:local | staging | prod;缺省按 配置文件 > RECOLX_ENV > prod */
14
+ /** 环境:local | staging | prod;缺省按 配置文件 > RECOLX_ENV > staging */
15
15
  env?: RecolxEnv;
16
16
  /** 后端地址覆盖(自定义部署逃生舱);缺省按环境预设 */
17
17
  apiBase?: string;
@@ -51,7 +51,7 @@ declare function envConfigPath(): string;
51
51
  declare function readEnvConfig(): RecolxEnv | null;
52
52
  /** 写入环境配置文件(AI set_env / install --env 共用) */
53
53
  declare function writeEnvConfig(env: RecolxEnv): void;
54
- /** 解析最终环境:实例配置 > 配置文件 > RECOLX_ENV > prod */
54
+ /** 解析最终环境:实例配置 > 配置文件 > RECOLX_ENV > staging */
55
55
  declare function resolveEnv(env?: RecolxEnv): RecolxEnv;
56
56
  declare function resolveConfig(config: RecolxConfig): Required<Pick<RecolxConfig, "clientId" | "redirectUri" | "tokenFile" | "apiBase" | "authorizationUrl" | "tokenUrl" | "logtoEndpoint" | "logtoClientId">> & {
57
57
  env: RecolxEnv;
@@ -98,9 +98,18 @@ declare class OAuth {
98
98
  private logtoClientId;
99
99
  /** logto 模式端点校验:缺省抛错(prod 独立 Logto 未配置时明确报错,不静默连测试实例) */
100
100
  private logtoEndpoint;
101
+ /** 登出后「下次登录强制重新认证」标志文件(token 文件旁,按环境/实例隔离)。
102
+ * 解决:logout 只删本地 token,浏览器 Logto 会话仍在 → 下次 login SSO 秒过不弹页。
103
+ * 置标后下次 createAuthorizationRequest 自动带 prompt=login,登录成功(exchangeCode)自动清除。 */
104
+ forceLoginFlagPath(): string;
105
+ /** 是否存在待消费的强制认证标志 */
106
+ isForceLoginPending(): Promise<boolean>;
107
+ private setForceLoginPending;
108
+ private clearForceLoginFlag;
101
109
  /** 构造授权请求(PKCE S256)。extraParams 用于本地联调注入 user_id(developer 模式,env=local 才接受)
102
- * 或 logto 强制重新认证 prompt=login(force 登录换号)。 */
103
- createAuthorizationRequest(extraParams?: Record<string, string>): AuthorizationRequest;
110
+ * 或 logto 强制重新认证 prompt=login(force 登录换号)。
111
+ * 登出后遗留的强制认证标志也会自动加 prompt=login——用户无需知道 force。 */
112
+ createAuthorizationRequest(extraParams?: Record<string, string>): Promise<AuthorizationRequest>;
104
113
  /** 授权码换凭证并落盘;失败抛 Error(含状态码与响应体)。
105
114
  * developer 模式:直接换 developerOAuth JWT;
106
115
  * logto 模式:先换 Logto access token,再 POST /open/oauth/apikey 换 sk- 长期 key(落盘的是 sk- key)。 */
@@ -111,7 +120,7 @@ declare class OAuth {
111
120
  getAccessToken(): Promise<string | null>;
112
121
  /** 服务端撤销指定 token(RFC 7009:未知 token 也返回成功)。 */
113
122
  revoke(token: string, tokenTypeHint?: string): Promise<void>;
114
- /** 清空本地 token(logout 本地侧)。 */
123
+ /** 本地登出:删 token + 置「下次登录强制重新认证」标志(浏览器 Logto 会话由用户/换号时另处理)。 */
115
124
  logout(): Promise<void>;
116
125
  }
117
126
 
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { readFileSync, writeFileSync, mkdirSync } from "fs";
3
3
  import { join } from "path";
4
4
  import { homedir } from "os";
5
- var DEFAULT_ENV = "prod";
5
+ var DEFAULT_ENV = "staging";
6
6
  var DEFAULT_CLIENT_ID = process.env.RECOLX_MCP_CLIENT_ID ?? "recolx-mcp";
7
7
  var DEFAULT_REDIRECT_URI = "http://localhost:8199/auth/callback";
8
8
  var DEFAULT_LOGTO_ENDPOINT = process.env.RECOLX_LOGTO_ENDPOINT ?? "https://test-auth.recolx.ai";
@@ -109,6 +109,7 @@ var TOKENS_MCP_PATH = join2(homedir2(), ".recolx", "tokens-mcp.json");
109
109
 
110
110
  // src/oauth.ts
111
111
  import { createHash, randomBytes } from "crypto";
112
+ import { mkdir as mkdir2, readFile as readFile2, rm as rm2, writeFile as writeFile2 } from "fs/promises";
112
113
  function generateCodeVerifier() {
113
114
  return randomBytes(32).toString("base64url");
114
115
  }
@@ -159,9 +160,38 @@ var OAuth = class {
159
160
  }
160
161
  return ep;
161
162
  }
163
+ /** 登出后「下次登录强制重新认证」标志文件(token 文件旁,按环境/实例隔离)。
164
+ * 解决:logout 只删本地 token,浏览器 Logto 会话仍在 → 下次 login SSO 秒过不弹页。
165
+ * 置标后下次 createAuthorizationRequest 自动带 prompt=login,登录成功(exchangeCode)自动清除。 */
166
+ forceLoginFlagPath() {
167
+ return `${this.tokenStore.path}.force`;
168
+ }
169
+ /** 是否存在待消费的强制认证标志 */
170
+ async isForceLoginPending() {
171
+ try {
172
+ await readFile2(this.forceLoginFlagPath(), "utf8");
173
+ return true;
174
+ } catch {
175
+ return false;
176
+ }
177
+ }
178
+ async setForceLoginPending() {
179
+ await mkdir2(this.tokenStore.dir, { recursive: true });
180
+ await writeFile2(this.forceLoginFlagPath(), (/* @__PURE__ */ new Date()).toISOString() + "\n", "utf8");
181
+ }
182
+ async clearForceLoginFlag() {
183
+ try {
184
+ await rm2(this.forceLoginFlagPath());
185
+ } catch {
186
+ }
187
+ }
162
188
  /** 构造授权请求(PKCE S256)。extraParams 用于本地联调注入 user_id(developer 模式,env=local 才接受)
163
- * 或 logto 强制重新认证 prompt=login(force 登录换号)。 */
164
- createAuthorizationRequest(extraParams = {}) {
189
+ * 或 logto 强制重新认证 prompt=login(force 登录换号)。
190
+ * 登出后遗留的强制认证标志也会自动加 prompt=login——用户无需知道 force。 */
191
+ async createAuthorizationRequest(extraParams = {}) {
192
+ if (!extraParams.prompt && await this.isForceLoginPending()) {
193
+ extraParams = { ...extraParams, prompt: "login" };
194
+ }
165
195
  const codeVerifier = generateCodeVerifier();
166
196
  const state = generateState();
167
197
  if (this.mode === "logto") {
@@ -234,6 +264,7 @@ var OAuth = class {
234
264
  }
235
265
  const tokenSet2 = { access_token: apiKey, token_type: "Bearer" };
236
266
  await this.tokenStore.save(tokenSet2);
267
+ await this.clearForceLoginFlag();
237
268
  return tokenSet2;
238
269
  }
239
270
  const res = await this.fetchImpl(this.tokenUrl, {
@@ -246,6 +277,7 @@ var OAuth = class {
246
277
  }
247
278
  const tokenSet = toTokenSet(await res.json());
248
279
  await this.tokenStore.save(tokenSet);
280
+ await this.clearForceLoginFlag();
249
281
  return tokenSet;
250
282
  }
251
283
  /** 用 refresh_token 换新 token(后端滚动轮换);logto 模式无 refresh(sk- key 长期有效),恒返回 null。 */
@@ -288,9 +320,10 @@ var OAuth = class {
288
320
  body: new URLSearchParams(body)
289
321
  });
290
322
  }
291
- /** 清空本地 token(logout 本地侧)。 */
323
+ /** 本地登出:删 token + 置「下次登录强制重新认证」标志(浏览器 Logto 会话由用户/换号时另处理)。 */
292
324
  async logout() {
293
325
  await this.tokenStore.clear();
326
+ await this.setForceLoginPending();
294
327
  }
295
328
  };
296
329
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uzqw/shared",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Shared types, zod schemas, token store and API client for recolx MCP/CLI",
5
5
  "publishConfig": {
6
6
  "access": "public"