@uzqw/shared 0.1.6 → 0.1.8
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 +20 -4
- package/dist/index.js +42 -5
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -98,8 +98,18 @@ declare class OAuth {
|
|
|
98
98
|
private logtoClientId;
|
|
99
99
|
/** logto 模式端点校验:缺省抛错(prod 独立 Logto 未配置时明确报错,不静默连测试实例) */
|
|
100
100
|
private logtoEndpoint;
|
|
101
|
-
/**
|
|
102
|
-
|
|
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;
|
|
109
|
+
/** 构造授权请求(PKCE S256)。extraParams 用于本地联调注入 user_id(developer 模式,env=local 才接受)
|
|
110
|
+
* 或 logto 强制重新认证 prompt=login(force 登录换号)。
|
|
111
|
+
* 登出后遗留的强制认证标志也会自动加 prompt=login——用户无需知道 force。 */
|
|
112
|
+
createAuthorizationRequest(extraParams?: Record<string, string>): Promise<AuthorizationRequest>;
|
|
103
113
|
/** 授权码换凭证并落盘;失败抛 Error(含状态码与响应体)。
|
|
104
114
|
* developer 模式:直接换 developerOAuth JWT;
|
|
105
115
|
* logto 模式:先换 Logto access token,再 POST /open/oauth/apikey 换 sk- 长期 key(落盘的是 sk- key)。 */
|
|
@@ -110,7 +120,7 @@ declare class OAuth {
|
|
|
110
120
|
getAccessToken(): Promise<string | null>;
|
|
111
121
|
/** 服务端撤销指定 token(RFC 7009:未知 token 也返回成功)。 */
|
|
112
122
|
revoke(token: string, tokenTypeHint?: string): Promise<void>;
|
|
113
|
-
/**
|
|
123
|
+
/** 本地登出:删 token + 置「下次登录强制重新认证」标志(浏览器 Logto 会话由用户/换号时另处理)。 */
|
|
114
124
|
logout(): Promise<void>;
|
|
115
125
|
}
|
|
116
126
|
|
|
@@ -667,7 +677,13 @@ declare const FileDetailSchema: z.ZodObject<{
|
|
|
667
677
|
} | undefined;
|
|
668
678
|
}>;
|
|
669
679
|
type RecolxFileDetail = z.infer<typeof FileDetailSchema>;
|
|
670
|
-
declare const LoginInput: z.ZodOptional<z.ZodObject<{
|
|
680
|
+
declare const LoginInput: z.ZodOptional<z.ZodObject<{
|
|
681
|
+
force: z.ZodOptional<z.ZodBoolean>;
|
|
682
|
+
}, "strip", z.ZodTypeAny, {
|
|
683
|
+
force?: boolean | undefined;
|
|
684
|
+
}, {
|
|
685
|
+
force?: boolean | undefined;
|
|
686
|
+
}>>;
|
|
671
687
|
declare const LogoutInput: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
|
|
672
688
|
declare const GetCurrentUserInput: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
|
|
673
689
|
declare const SetEnvInput: z.ZodObject<{
|
package/dist/index.js
CHANGED
|
@@ -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,8 +160,38 @@ var OAuth = class {
|
|
|
159
160
|
}
|
|
160
161
|
return ep;
|
|
161
162
|
}
|
|
162
|
-
/**
|
|
163
|
-
|
|
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
|
+
}
|
|
188
|
+
/** 构造授权请求(PKCE S256)。extraParams 用于本地联调注入 user_id(developer 模式,env=local 才接受)
|
|
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
|
+
}
|
|
164
195
|
const codeVerifier = generateCodeVerifier();
|
|
165
196
|
const state = generateState();
|
|
166
197
|
if (this.mode === "logto") {
|
|
@@ -174,7 +205,8 @@ var OAuth = class {
|
|
|
174
205
|
scope: "openid profile email",
|
|
175
206
|
code_challenge: generateCodeChallenge(codeVerifier),
|
|
176
207
|
code_challenge_method: "S256",
|
|
177
|
-
state
|
|
208
|
+
state,
|
|
209
|
+
...extraParams
|
|
178
210
|
});
|
|
179
211
|
return { url: `${logtoEndpoint}/oidc/auth?${params2.toString()}`, codeVerifier, state };
|
|
180
212
|
}
|
|
@@ -232,6 +264,7 @@ var OAuth = class {
|
|
|
232
264
|
}
|
|
233
265
|
const tokenSet2 = { access_token: apiKey, token_type: "Bearer" };
|
|
234
266
|
await this.tokenStore.save(tokenSet2);
|
|
267
|
+
await this.clearForceLoginFlag();
|
|
235
268
|
return tokenSet2;
|
|
236
269
|
}
|
|
237
270
|
const res = await this.fetchImpl(this.tokenUrl, {
|
|
@@ -244,6 +277,7 @@ var OAuth = class {
|
|
|
244
277
|
}
|
|
245
278
|
const tokenSet = toTokenSet(await res.json());
|
|
246
279
|
await this.tokenStore.save(tokenSet);
|
|
280
|
+
await this.clearForceLoginFlag();
|
|
247
281
|
return tokenSet;
|
|
248
282
|
}
|
|
249
283
|
/** 用 refresh_token 换新 token(后端滚动轮换);logto 模式无 refresh(sk- key 长期有效),恒返回 null。 */
|
|
@@ -286,9 +320,10 @@ var OAuth = class {
|
|
|
286
320
|
body: new URLSearchParams(body)
|
|
287
321
|
});
|
|
288
322
|
}
|
|
289
|
-
/**
|
|
323
|
+
/** 本地登出:删 token + 置「下次登录强制重新认证」标志(浏览器 Logto 会话由用户/换号时另处理)。 */
|
|
290
324
|
async logout() {
|
|
291
325
|
await this.tokenStore.clear();
|
|
326
|
+
await this.setForceLoginPending();
|
|
292
327
|
}
|
|
293
328
|
};
|
|
294
329
|
|
|
@@ -458,7 +493,9 @@ var FileDetailSchema = FileSchema.extend({
|
|
|
458
493
|
presigned_url_expires_at: z.number(),
|
|
459
494
|
transcript: TranscriptSchema.optional()
|
|
460
495
|
});
|
|
461
|
-
var LoginInput = z.object({
|
|
496
|
+
var LoginInput = z.object({
|
|
497
|
+
force: z.boolean().optional().describe("true \u65F6\u5F3A\u5236\u91CD\u65B0\u8BA4\u8BC1\uFF1A\u5373\u4FBF\u6D4F\u89C8\u5668\u5DF2\u6709 Logto \u4F1A\u8BDD\uFF08\u767B\u51FA\u540E\u4ECD\u79D2\u8FC7\uFF09\u4E5F\u5F39\u51FA\u767B\u5F55\u9875\uFF0C\u53EF\u5207\u6362\u8D26\u53F7\uFF1B\u7F3A\u7701 false \u590D\u7528\u6D4F\u89C8\u5668\u4F1A\u8BDD")
|
|
498
|
+
}).optional();
|
|
462
499
|
var LogoutInput = z.object({}).optional();
|
|
463
500
|
var GetCurrentUserInput = z.object({}).optional();
|
|
464
501
|
var SetEnvInput = z.object({
|