@tnnevol/dsh-codex-auth 0.1.2-rc.1.4 → 0.1.7-rc.2

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/lib/index.d.ts CHANGED
@@ -100,10 +100,24 @@ declare class CodexWebAuth {
100
100
  private challenge;
101
101
  private challengeWaiters;
102
102
  private challengeTimer;
103
+ /** 用户点「取消」后由 `cancel()` 独占最终状态写入。 */
104
+ private cancelled;
103
105
  constructor(store: CodexCredentialStore, challengeTimeoutMs?: number, mirror?: CodexCredentialMirror | undefined);
104
106
  status(): Promise<CodexWebAuthStatus>;
105
107
  signIn(): Promise<CodexLoginChallenge>;
106
108
  signOut(): Promise<void>;
109
+ /**
110
+ * Stop an in-flight sign-in without touching stored credentials.
111
+ *
112
+ * 与 `signOut()` 的区别:这里只回收本次未完成的授权(中止 device-code
113
+ * 轮询、拒绝还在等的 challenge 请求、清掉一次性授权码),不删除已保存的
114
+ * 凭据。用户点「取消」时走这条路径——他们放弃的是**这次**登录,不是已经
115
+ * 登录的账号。
116
+ *
117
+ * 只有用户主动取消才会调用它。授权窗口自行关闭**不是**放弃信号:授权成功
118
+ * 后授权页会自己关闭,若据此取消就会中止正在进行的轮询并丢掉刚取得的凭据。
119
+ */
120
+ cancel(): Promise<void>;
107
121
  dispose(): Promise<void>;
108
122
  private start;
109
123
  private onEvent;
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { a as CodexCredentialStore, i as CODEX_PROVIDER, n as loginCodex, r as logoutCodex, t as codexAuthStatus } from "./auth-DQlapSCa.js";
2
- import { CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_STATUS_PATH, CODEX_GLOBAL_MODEL_PATH, CODEX_MODEL_REFRESH_PATH, CODEX_USAGE_PATH } from "./auth-paths.js";
1
+ import { a as CODEX_PROVIDER, i as CodexCredentialStore, n as loginCodex, r as logoutCodex, t as codexAuthStatus } from "./auth-BQNZ__ZK.js";
2
+ import { CODEX_AUTH_CANCEL_PATH, CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_STATUS_PATH, CODEX_GLOBAL_MODEL_PATH, CODEX_MODEL_REFRESH_PATH, CODEX_USAGE_PATH } from "./auth-paths.js";
3
3
  import { createModels, defaultProviderAuthContext } from "@earendil-works/pi-ai";
4
4
  import { openaiCodexProvider } from "@earendil-works/pi-ai/providers/openai-codex";
5
5
  import { credentialRef } from "@deepseek-ai/dsh-credentials";
@@ -332,7 +332,13 @@ async function refreshCodexModelCatalog(store, fetchImpl = fetch) {
332
332
  }
333
333
  //#endregion
334
334
  //#region src/host/auth-routes.ts
335
- const CODEX_AUTH_URL_TIMEOUT_MS = 3e4;
335
+ /**
336
+ * 等 OpenAI 返回设备授权码(授权 URL)的上限。
337
+ *
338
+ * 拿到设备码后这个计时器就清掉了(见 `onEvent`),因此它**不**约束用户在浏览器
339
+ * 里完成授权的时间——那段由 pi-ai 自己的设备码轮询窗口兜底。
340
+ */
341
+ const CODEX_AUTH_URL_TIMEOUT_MS = 12e4;
336
342
  const REMOTE_WEB_ORIGIN_NOT_TRUSTED = "remote-web-origin-not-trusted";
337
343
  const CODEX_USAGE_UNAVAILABLE = "codex-usage-unavailable";
338
344
  const CODEX_GLOBAL_MODEL_INVALID = "codex-global-model-invalid";
@@ -368,6 +374,8 @@ var CodexWebAuth = class {
368
374
  challenge;
369
375
  challengeWaiters = [];
370
376
  challengeTimer;
377
+ /** 用户点「取消」后由 `cancel()` 独占最终状态写入。 */
378
+ cancelled = false;
371
379
  constructor(store, challengeTimeoutMs = CODEX_AUTH_URL_TIMEOUT_MS, mirror) {
372
380
  this.store = store;
373
381
  this.challengeTimeoutMs = challengeTimeoutMs;
@@ -396,13 +404,30 @@ var CodexWebAuth = class {
396
404
  });
397
405
  }
398
406
  async signOut() {
399
- this.cancelSignIn(/* @__PURE__ */ new Error("Codex sign-in cancelled"));
400
- await this.operation?.catch(() => void 0);
407
+ await this.cancel();
401
408
  await logoutCodex(this.store);
402
409
  await this.mirror?.clear();
403
- this.challenge = void 0;
404
410
  this.state = { status: "signed-out" };
405
411
  }
412
+ /**
413
+ * Stop an in-flight sign-in without touching stored credentials.
414
+ *
415
+ * 与 `signOut()` 的区别:这里只回收本次未完成的授权(中止 device-code
416
+ * 轮询、拒绝还在等的 challenge 请求、清掉一次性授权码),不删除已保存的
417
+ * 凭据。用户点「取消」时走这条路径——他们放弃的是**这次**登录,不是已经
418
+ * 登录的账号。
419
+ *
420
+ * 只有用户主动取消才会调用它。授权窗口自行关闭**不是**放弃信号:授权成功
421
+ * 后授权页会自己关闭,若据此取消就会中止正在进行的轮询并丢掉刚取得的凭据。
422
+ */
423
+ async cancel() {
424
+ this.cancelled = true;
425
+ this.cancelSignIn(/* @__PURE__ */ new Error("Codex sign-in cancelled"));
426
+ this.challenge = void 0;
427
+ await this.operation?.catch(() => void 0);
428
+ const stored = await codexAuthStatus(this.store);
429
+ this.state = stored.authenticated ? signedInStatus(stored.expiresAt) : { status: "signed-out" };
430
+ }
406
431
  async dispose() {
407
432
  this.cancelSignIn(/* @__PURE__ */ new Error("Codex auth plugin disposed"));
408
433
  await this.operation?.catch(() => void 0);
@@ -410,6 +435,7 @@ var CodexWebAuth = class {
410
435
  start() {
411
436
  const cancellation = new AbortController();
412
437
  this.cancellation = cancellation;
438
+ this.cancelled = false;
413
439
  this.challenge = void 0;
414
440
  this.state = { status: "signing-in" };
415
441
  this.challengeTimer = setTimeout(() => {
@@ -426,6 +452,7 @@ var CodexWebAuth = class {
426
452
  this.onEvent(event);
427
453
  }
428
454
  }, this.store).then(async () => {
455
+ if (this.cancelled) return;
429
456
  if (this.challenge === void 0) {
430
457
  const error = /* @__PURE__ */ new Error("Codex sign-in finished without an authorization code");
431
458
  this.rejectChallenge(error);
@@ -440,6 +467,7 @@ var CodexWebAuth = class {
440
467
  this.state = stored.authenticated ? signedInStatus(stored.expiresAt) : { status: "signed-out" };
441
468
  }, (error) => {
442
469
  this.rejectChallenge(error);
470
+ if (this.cancelled) return;
443
471
  this.state = {
444
472
  status: "error",
445
473
  message: safeMessage(error)
@@ -691,6 +719,20 @@ function registerCodexAuthRoutes(ctx, store, mirror) {
691
719
  }
692
720
  }
693
721
  }),
722
+ ctx.webServer.register({
723
+ kind: "exact",
724
+ path: CODEX_AUTH_CANCEL_PATH,
725
+ handler: async (req, res) => {
726
+ if (req.method !== "POST") return json(res, 405, { error: "method not allowed" });
727
+ if (!authorize(req, res)) return;
728
+ try {
729
+ await auth.cancel();
730
+ json(res, 200, { ok: true });
731
+ } catch (error) {
732
+ json(res, 500, { error: safeMessage(error) });
733
+ }
734
+ }
735
+ }),
694
736
  ctx.webServer.register({
695
737
  kind: "exact",
696
738
  path: CODEX_AUTH_LOGOUT_PATH,
@@ -823,7 +865,8 @@ function createCodexAdapter(credentials, resolveAttachments) {
823
865
  requestImageMaxBytes: CODEX_REQUEST_IMAGE_MAX_BYTES,
824
866
  retryPolicy: resolveRetryPolicy(void 0, "dsh-codex-auth-plugin retryPolicy"),
825
867
  configuredMaxTokens: /* @__PURE__ */ new Map(),
826
- piProvider: requestProvider(provider)
868
+ piProvider: requestProvider(provider),
869
+ modelErrors: /* @__PURE__ */ new Map()
827
870
  }]]);
828
871
  const models = createModels({ credentials });
829
872
  models.setProvider(provider);