codex-multi-auth 0.1.0

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 (327) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +162 -0
  3. package/assets/opencode-logo-ornate-dark.svg +18 -0
  4. package/assets/readme-hero.svg +31 -0
  5. package/config/README.md +87 -0
  6. package/config/minimal-opencode.json +13 -0
  7. package/config/opencode-legacy.json +571 -0
  8. package/config/opencode-modern.json +239 -0
  9. package/dist/index.d.ts +45 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +3160 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/lib/accounts/rate-limits.d.ts +22 -0
  14. package/dist/lib/accounts/rate-limits.d.ts.map +1 -0
  15. package/dist/lib/accounts/rate-limits.js +63 -0
  16. package/dist/lib/accounts/rate-limits.js.map +1 -0
  17. package/dist/lib/accounts.d.ts +95 -0
  18. package/dist/lib/accounts.d.ts.map +1 -0
  19. package/dist/lib/accounts.js +668 -0
  20. package/dist/lib/accounts.js.map +1 -0
  21. package/dist/lib/audit.d.ts +45 -0
  22. package/dist/lib/audit.d.ts.map +1 -0
  23. package/dist/lib/audit.js +131 -0
  24. package/dist/lib/audit.js.map +1 -0
  25. package/dist/lib/auth/auth.d.ts +56 -0
  26. package/dist/lib/auth/auth.d.ts.map +1 -0
  27. package/dist/lib/auth/auth.js +214 -0
  28. package/dist/lib/auth/auth.js.map +1 -0
  29. package/dist/lib/auth/browser.d.ts +34 -0
  30. package/dist/lib/auth/browser.d.ts.map +1 -0
  31. package/dist/lib/auth/browser.js +185 -0
  32. package/dist/lib/auth/browser.js.map +1 -0
  33. package/dist/lib/auth/server.d.ts +24 -0
  34. package/dist/lib/auth/server.d.ts.map +1 -0
  35. package/dist/lib/auth/server.js +116 -0
  36. package/dist/lib/auth/server.js.map +1 -0
  37. package/dist/lib/auth/token-utils.d.ts +59 -0
  38. package/dist/lib/auth/token-utils.d.ts.map +1 -0
  39. package/dist/lib/auth/token-utils.js +331 -0
  40. package/dist/lib/auth/token-utils.js.map +1 -0
  41. package/dist/lib/auth-rate-limit.d.ts +20 -0
  42. package/dist/lib/auth-rate-limit.d.ts.map +1 -0
  43. package/dist/lib/auth-rate-limit.js +91 -0
  44. package/dist/lib/auth-rate-limit.js.map +1 -0
  45. package/dist/lib/auto-update-checker.d.ts +10 -0
  46. package/dist/lib/auto-update-checker.d.ts.map +1 -0
  47. package/dist/lib/auto-update-checker.js +216 -0
  48. package/dist/lib/auto-update-checker.js.map +1 -0
  49. package/dist/lib/capability-policy.d.ts +18 -0
  50. package/dist/lib/capability-policy.d.ts.map +1 -0
  51. package/dist/lib/capability-policy.js +150 -0
  52. package/dist/lib/capability-policy.js.map +1 -0
  53. package/dist/lib/circuit-breaker.d.ts +34 -0
  54. package/dist/lib/circuit-breaker.d.ts.map +1 -0
  55. package/dist/lib/circuit-breaker.js +124 -0
  56. package/dist/lib/circuit-breaker.js.map +1 -0
  57. package/dist/lib/cli.d.ts +64 -0
  58. package/dist/lib/cli.d.ts.map +1 -0
  59. package/dist/lib/cli.js +274 -0
  60. package/dist/lib/cli.js.map +1 -0
  61. package/dist/lib/codex-cli/observability.d.ts +22 -0
  62. package/dist/lib/codex-cli/observability.d.ts.map +1 -0
  63. package/dist/lib/codex-cli/observability.js +36 -0
  64. package/dist/lib/codex-cli/observability.js.map +1 -0
  65. package/dist/lib/codex-cli/state.d.ts +86 -0
  66. package/dist/lib/codex-cli/state.d.ts.map +1 -0
  67. package/dist/lib/codex-cli/state.js +470 -0
  68. package/dist/lib/codex-cli/state.js.map +1 -0
  69. package/dist/lib/codex-cli/sync.d.ts +27 -0
  70. package/dist/lib/codex-cli/sync.d.ts.map +1 -0
  71. package/dist/lib/codex-cli/sync.js +325 -0
  72. package/dist/lib/codex-cli/sync.js.map +1 -0
  73. package/dist/lib/codex-cli/writer.d.ts +12 -0
  74. package/dist/lib/codex-cli/writer.d.ts.map +1 -0
  75. package/dist/lib/codex-cli/writer.js +388 -0
  76. package/dist/lib/codex-cli/writer.js.map +1 -0
  77. package/dist/lib/codex-manager.d.ts +2 -0
  78. package/dist/lib/codex-manager.d.ts.map +1 -0
  79. package/dist/lib/codex-manager.js +4841 -0
  80. package/dist/lib/codex-manager.js.map +1 -0
  81. package/dist/lib/config.d.ts +269 -0
  82. package/dist/lib/config.d.ts.map +1 -0
  83. package/dist/lib/config.js +789 -0
  84. package/dist/lib/config.js.map +1 -0
  85. package/dist/lib/constants.d.ts +78 -0
  86. package/dist/lib/constants.d.ts.map +1 -0
  87. package/dist/lib/constants.js +78 -0
  88. package/dist/lib/constants.js.map +1 -0
  89. package/dist/lib/context-overflow.d.ts +27 -0
  90. package/dist/lib/context-overflow.d.ts.map +1 -0
  91. package/dist/lib/context-overflow.js +124 -0
  92. package/dist/lib/context-overflow.js.map +1 -0
  93. package/dist/lib/dashboard-settings.d.ts +90 -0
  94. package/dist/lib/dashboard-settings.d.ts.map +1 -0
  95. package/dist/lib/dashboard-settings.js +327 -0
  96. package/dist/lib/dashboard-settings.js.map +1 -0
  97. package/dist/lib/entitlement-cache.d.ts +41 -0
  98. package/dist/lib/entitlement-cache.d.ts.map +1 -0
  99. package/dist/lib/entitlement-cache.js +137 -0
  100. package/dist/lib/entitlement-cache.js.map +1 -0
  101. package/dist/lib/errors.d.ts +113 -0
  102. package/dist/lib/errors.d.ts.map +1 -0
  103. package/dist/lib/errors.js +103 -0
  104. package/dist/lib/errors.js.map +1 -0
  105. package/dist/lib/forecast.d.ts +42 -0
  106. package/dist/lib/forecast.d.ts.map +1 -0
  107. package/dist/lib/forecast.js +256 -0
  108. package/dist/lib/forecast.js.map +1 -0
  109. package/dist/lib/health.d.ts +33 -0
  110. package/dist/lib/health.d.ts.map +1 -0
  111. package/dist/lib/health.js +70 -0
  112. package/dist/lib/health.js.map +1 -0
  113. package/dist/lib/index.d.ts +32 -0
  114. package/dist/lib/index.d.ts.map +1 -0
  115. package/dist/lib/index.js +32 -0
  116. package/dist/lib/index.js.map +1 -0
  117. package/dist/lib/live-account-sync.d.ts +39 -0
  118. package/dist/lib/live-account-sync.d.ts.map +1 -0
  119. package/dist/lib/live-account-sync.js +196 -0
  120. package/dist/lib/live-account-sync.js.map +1 -0
  121. package/dist/lib/logger.d.ts +40 -0
  122. package/dist/lib/logger.d.ts.map +1 -0
  123. package/dist/lib/logger.js +364 -0
  124. package/dist/lib/logger.js.map +1 -0
  125. package/dist/lib/oauth-success.html +338 -0
  126. package/dist/lib/parallel-probe.d.ts +28 -0
  127. package/dist/lib/parallel-probe.d.ts.map +1 -0
  128. package/dist/lib/parallel-probe.js +97 -0
  129. package/dist/lib/parallel-probe.js.map +1 -0
  130. package/dist/lib/preemptive-quota-scheduler.d.ts +53 -0
  131. package/dist/lib/preemptive-quota-scheduler.d.ts.map +1 -0
  132. package/dist/lib/preemptive-quota-scheduler.js +220 -0
  133. package/dist/lib/preemptive-quota-scheduler.js.map +1 -0
  134. package/dist/lib/proactive-refresh.d.ts +66 -0
  135. package/dist/lib/proactive-refresh.d.ts.map +1 -0
  136. package/dist/lib/proactive-refresh.js +143 -0
  137. package/dist/lib/proactive-refresh.js.map +1 -0
  138. package/dist/lib/prompts/codex-opencode-bridge.d.ts +19 -0
  139. package/dist/lib/prompts/codex-opencode-bridge.d.ts.map +1 -0
  140. package/dist/lib/prompts/codex-opencode-bridge.js +169 -0
  141. package/dist/lib/prompts/codex-opencode-bridge.js.map +1 -0
  142. package/dist/lib/prompts/codex.d.ts +41 -0
  143. package/dist/lib/prompts/codex.d.ts.map +1 -0
  144. package/dist/lib/prompts/codex.js +383 -0
  145. package/dist/lib/prompts/codex.js.map +1 -0
  146. package/dist/lib/prompts/opencode-codex.d.ts +25 -0
  147. package/dist/lib/prompts/opencode-codex.d.ts.map +1 -0
  148. package/dist/lib/prompts/opencode-codex.js +270 -0
  149. package/dist/lib/prompts/opencode-codex.js.map +1 -0
  150. package/dist/lib/quota-cache.d.ts +68 -0
  151. package/dist/lib/quota-cache.d.ts.map +1 -0
  152. package/dist/lib/quota-cache.js +224 -0
  153. package/dist/lib/quota-cache.js.map +1 -0
  154. package/dist/lib/quota-probe.d.ts +49 -0
  155. package/dist/lib/quota-probe.d.ts.map +1 -0
  156. package/dist/lib/quota-probe.js +368 -0
  157. package/dist/lib/quota-probe.js.map +1 -0
  158. package/dist/lib/recovery/constants.d.ts +12 -0
  159. package/dist/lib/recovery/constants.d.ts.map +1 -0
  160. package/dist/lib/recovery/constants.js +31 -0
  161. package/dist/lib/recovery/constants.js.map +1 -0
  162. package/dist/lib/recovery/index.d.ts +12 -0
  163. package/dist/lib/recovery/index.d.ts.map +1 -0
  164. package/dist/lib/recovery/index.js +12 -0
  165. package/dist/lib/recovery/index.js.map +1 -0
  166. package/dist/lib/recovery/storage.d.ts +24 -0
  167. package/dist/lib/recovery/storage.d.ts.map +1 -0
  168. package/dist/lib/recovery/storage.js +362 -0
  169. package/dist/lib/recovery/storage.js.map +1 -0
  170. package/dist/lib/recovery/types.d.ts +116 -0
  171. package/dist/lib/recovery/types.d.ts.map +1 -0
  172. package/dist/lib/recovery/types.js +7 -0
  173. package/dist/lib/recovery/types.js.map +1 -0
  174. package/dist/lib/recovery.d.ts +31 -0
  175. package/dist/lib/recovery.d.ts.map +1 -0
  176. package/dist/lib/recovery.js +313 -0
  177. package/dist/lib/recovery.js.map +1 -0
  178. package/dist/lib/refresh-guardian.d.ts +31 -0
  179. package/dist/lib/refresh-guardian.d.ts.map +1 -0
  180. package/dist/lib/refresh-guardian.js +151 -0
  181. package/dist/lib/refresh-guardian.js.map +1 -0
  182. package/dist/lib/refresh-lease.d.ts +37 -0
  183. package/dist/lib/refresh-lease.d.ts.map +1 -0
  184. package/dist/lib/refresh-lease.js +335 -0
  185. package/dist/lib/refresh-lease.js.map +1 -0
  186. package/dist/lib/refresh-queue.d.ts +117 -0
  187. package/dist/lib/refresh-queue.d.ts.map +1 -0
  188. package/dist/lib/refresh-queue.js +297 -0
  189. package/dist/lib/refresh-queue.js.map +1 -0
  190. package/dist/lib/request/failure-policy.d.ts +42 -0
  191. package/dist/lib/request/failure-policy.d.ts.map +1 -0
  192. package/dist/lib/request/failure-policy.js +133 -0
  193. package/dist/lib/request/failure-policy.js.map +1 -0
  194. package/dist/lib/request/fetch-helpers.d.ts +152 -0
  195. package/dist/lib/request/fetch-helpers.d.ts.map +1 -0
  196. package/dist/lib/request/fetch-helpers.js +704 -0
  197. package/dist/lib/request/fetch-helpers.js.map +1 -0
  198. package/dist/lib/request/helpers/input-utils.d.ts +7 -0
  199. package/dist/lib/request/helpers/input-utils.d.ts.map +1 -0
  200. package/dist/lib/request/helpers/input-utils.js +214 -0
  201. package/dist/lib/request/helpers/input-utils.js.map +1 -0
  202. package/dist/lib/request/helpers/model-map.d.ts +28 -0
  203. package/dist/lib/request/helpers/model-map.d.ts.map +1 -0
  204. package/dist/lib/request/helpers/model-map.js +133 -0
  205. package/dist/lib/request/helpers/model-map.js.map +1 -0
  206. package/dist/lib/request/helpers/tool-utils.d.ts +29 -0
  207. package/dist/lib/request/helpers/tool-utils.d.ts.map +1 -0
  208. package/dist/lib/request/helpers/tool-utils.js +117 -0
  209. package/dist/lib/request/helpers/tool-utils.js.map +1 -0
  210. package/dist/lib/request/rate-limit-backoff.d.ts +17 -0
  211. package/dist/lib/request/rate-limit-backoff.d.ts.map +1 -0
  212. package/dist/lib/request/rate-limit-backoff.js +83 -0
  213. package/dist/lib/request/rate-limit-backoff.js.map +1 -0
  214. package/dist/lib/request/request-transformer.d.ts +107 -0
  215. package/dist/lib/request/request-transformer.d.ts.map +1 -0
  216. package/dist/lib/request/request-transformer.js +814 -0
  217. package/dist/lib/request/request-transformer.js.map +1 -0
  218. package/dist/lib/request/response-handler.d.ts +23 -0
  219. package/dist/lib/request/response-handler.d.ts.map +1 -0
  220. package/dist/lib/request/response-handler.js +155 -0
  221. package/dist/lib/request/response-handler.js.map +1 -0
  222. package/dist/lib/request/stream-failover.d.ts +21 -0
  223. package/dist/lib/request/stream-failover.d.ts.map +1 -0
  224. package/dist/lib/request/stream-failover.js +204 -0
  225. package/dist/lib/request/stream-failover.js.map +1 -0
  226. package/dist/lib/rotation.d.ts +146 -0
  227. package/dist/lib/rotation.d.ts.map +1 -0
  228. package/dist/lib/rotation.js +321 -0
  229. package/dist/lib/rotation.js.map +1 -0
  230. package/dist/lib/runtime-paths.d.ts +58 -0
  231. package/dist/lib/runtime-paths.d.ts.map +1 -0
  232. package/dist/lib/runtime-paths.js +164 -0
  233. package/dist/lib/runtime-paths.js.map +1 -0
  234. package/dist/lib/schemas.d.ts +435 -0
  235. package/dist/lib/schemas.d.ts.map +1 -0
  236. package/dist/lib/schemas.js +268 -0
  237. package/dist/lib/schemas.js.map +1 -0
  238. package/dist/lib/session-affinity.d.ts +23 -0
  239. package/dist/lib/session-affinity.d.ts.map +1 -0
  240. package/dist/lib/session-affinity.js +127 -0
  241. package/dist/lib/session-affinity.js.map +1 -0
  242. package/dist/lib/shutdown.d.ts +7 -0
  243. package/dist/lib/shutdown.d.ts.map +1 -0
  244. package/dist/lib/shutdown.js +43 -0
  245. package/dist/lib/shutdown.js.map +1 -0
  246. package/dist/lib/storage/migrations.d.ts +59 -0
  247. package/dist/lib/storage/migrations.d.ts.map +1 -0
  248. package/dist/lib/storage/migrations.js +41 -0
  249. package/dist/lib/storage/migrations.js.map +1 -0
  250. package/dist/lib/storage/paths.d.ts +51 -0
  251. package/dist/lib/storage/paths.d.ts.map +1 -0
  252. package/dist/lib/storage/paths.js +152 -0
  253. package/dist/lib/storage/paths.js.map +1 -0
  254. package/dist/lib/storage.d.ts +106 -0
  255. package/dist/lib/storage.d.ts.map +1 -0
  256. package/dist/lib/storage.js +896 -0
  257. package/dist/lib/storage.js.map +1 -0
  258. package/dist/lib/table-formatter.d.ts +32 -0
  259. package/dist/lib/table-formatter.d.ts.map +1 -0
  260. package/dist/lib/table-formatter.js +44 -0
  261. package/dist/lib/table-formatter.js.map +1 -0
  262. package/dist/lib/tools/hashline-tools.d.ts +51 -0
  263. package/dist/lib/tools/hashline-tools.d.ts.map +1 -0
  264. package/dist/lib/tools/hashline-tools.js +456 -0
  265. package/dist/lib/tools/hashline-tools.js.map +1 -0
  266. package/dist/lib/types.d.ts +130 -0
  267. package/dist/lib/types.d.ts.map +1 -0
  268. package/dist/lib/types.js +2 -0
  269. package/dist/lib/types.js.map +1 -0
  270. package/dist/lib/ui/ansi.d.ts +40 -0
  271. package/dist/lib/ui/ansi.d.ts.map +1 -0
  272. package/dist/lib/ui/ansi.js +68 -0
  273. package/dist/lib/ui/ansi.js.map +1 -0
  274. package/dist/lib/ui/auth-menu.d.ts +76 -0
  275. package/dist/lib/ui/auth-menu.d.ts.map +1 -0
  276. package/dist/lib/ui/auth-menu.js +590 -0
  277. package/dist/lib/ui/auth-menu.js.map +1 -0
  278. package/dist/lib/ui/confirm.d.ts +11 -0
  279. package/dist/lib/ui/confirm.d.ts.map +1 -0
  280. package/dist/lib/ui/confirm.js +29 -0
  281. package/dist/lib/ui/confirm.js.map +1 -0
  282. package/dist/lib/ui/copy.d.ts +123 -0
  283. package/dist/lib/ui/copy.d.ts.map +1 -0
  284. package/dist/lib/ui/copy.js +127 -0
  285. package/dist/lib/ui/copy.js.map +1 -0
  286. package/dist/lib/ui/format.d.ts +62 -0
  287. package/dist/lib/ui/format.d.ts.map +1 -0
  288. package/dist/lib/ui/format.js +205 -0
  289. package/dist/lib/ui/format.js.map +1 -0
  290. package/dist/lib/ui/runtime.d.ts +43 -0
  291. package/dist/lib/ui/runtime.d.ts.map +1 -0
  292. package/dist/lib/ui/runtime.js +69 -0
  293. package/dist/lib/ui/runtime.js.map +1 -0
  294. package/dist/lib/ui/select.d.ts +60 -0
  295. package/dist/lib/ui/select.d.ts.map +1 -0
  296. package/dist/lib/ui/select.js +467 -0
  297. package/dist/lib/ui/select.js.map +1 -0
  298. package/dist/lib/ui/theme.d.ts +56 -0
  299. package/dist/lib/ui/theme.d.ts.map +1 -0
  300. package/dist/lib/ui/theme.js +186 -0
  301. package/dist/lib/ui/theme.js.map +1 -0
  302. package/dist/lib/unified-settings.d.ts +71 -0
  303. package/dist/lib/unified-settings.d.ts.map +1 -0
  304. package/dist/lib/unified-settings.js +299 -0
  305. package/dist/lib/unified-settings.js.map +1 -0
  306. package/dist/lib/utils.d.ts +29 -0
  307. package/dist/lib/utils.d.ts.map +1 -0
  308. package/dist/lib/utils.js +54 -0
  309. package/dist/lib/utils.js.map +1 -0
  310. package/package.json +115 -0
  311. package/scripts/audit-dev-allowlist.js +128 -0
  312. package/scripts/bench-format/hashline-v2.mjs +642 -0
  313. package/scripts/bench-format/models.mjs +105 -0
  314. package/scripts/bench-format/opencode.mjs +205 -0
  315. package/scripts/bench-format/render.mjs +496 -0
  316. package/scripts/bench-format/stats.mjs +54 -0
  317. package/scripts/bench-format/tasks.mjs +151 -0
  318. package/scripts/benchmark-edit-formats.mjs +1161 -0
  319. package/scripts/benchmark-render-dashboard.mjs +49 -0
  320. package/scripts/codex-multi-auth.js +6 -0
  321. package/scripts/codex-routing.js +34 -0
  322. package/scripts/codex.js +122 -0
  323. package/scripts/copy-oauth-success.js +37 -0
  324. package/scripts/install-opencode-codex-auth.js +193 -0
  325. package/scripts/test-all-models.sh +7 -0
  326. package/scripts/test-model-matrix.js +424 -0
  327. package/scripts/validate-model-map.sh +7 -0
@@ -0,0 +1,335 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync, promises as fs } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { createLogger } from "./logger.js";
5
+ import { getCodexMultiAuthDir } from "./runtime-paths.js";
6
+ import { safeParseTokenResult } from "./schemas.js";
7
+ const log = createLogger("refresh-lease");
8
+ const DEFAULT_LEASE_TTL_MS = 30_000;
9
+ const DEFAULT_WAIT_TIMEOUT_MS = 35_000;
10
+ const DEFAULT_POLL_INTERVAL_MS = 150;
11
+ const DEFAULT_RESULT_TTL_MS = 20_000;
12
+ const RETRYABLE_IO_ERRORS = new Set(["EBUSY", "EPERM", "EMFILE", "ENFILE"]);
13
+ function parseBooleanEnv(value) {
14
+ if (value === undefined)
15
+ return undefined;
16
+ const normalized = value.trim().toLowerCase();
17
+ if (normalized === "1" || normalized === "true" || normalized === "yes")
18
+ return true;
19
+ if (normalized === "0" || normalized === "false" || normalized === "no")
20
+ return false;
21
+ return undefined;
22
+ }
23
+ function parseEnvInt(value) {
24
+ if (value === undefined)
25
+ return undefined;
26
+ const parsed = Number.parseInt(value, 10);
27
+ return Number.isFinite(parsed) ? parsed : undefined;
28
+ }
29
+ function sleep(delayMs) {
30
+ return new Promise((resolve) => {
31
+ setTimeout(resolve, delayMs);
32
+ });
33
+ }
34
+ function hashRefreshToken(refreshToken) {
35
+ return createHash("sha256").update(refreshToken).digest("hex");
36
+ }
37
+ function isRecord(value) {
38
+ return value !== null && typeof value === "object";
39
+ }
40
+ function parseLeasePayload(raw) {
41
+ if (!isRecord(raw))
42
+ return null;
43
+ const tokenHash = typeof raw.tokenHash === "string" ? raw.tokenHash : "";
44
+ const pid = typeof raw.pid === "number" ? raw.pid : Number.NaN;
45
+ const acquiredAt = typeof raw.acquiredAt === "number" ? raw.acquiredAt : Number.NaN;
46
+ const expiresAt = typeof raw.expiresAt === "number" ? raw.expiresAt : Number.NaN;
47
+ if (tokenHash.length === 0 ||
48
+ !Number.isFinite(pid) ||
49
+ !Number.isFinite(acquiredAt) ||
50
+ !Number.isFinite(expiresAt)) {
51
+ return null;
52
+ }
53
+ return {
54
+ tokenHash,
55
+ pid: Math.floor(pid),
56
+ acquiredAt: Math.floor(acquiredAt),
57
+ expiresAt: Math.floor(expiresAt),
58
+ };
59
+ }
60
+ function parseResultPayload(raw) {
61
+ if (!isRecord(raw))
62
+ return null;
63
+ const tokenHash = typeof raw.tokenHash === "string" ? raw.tokenHash : "";
64
+ const createdAt = typeof raw.createdAt === "number" ? raw.createdAt : Number.NaN;
65
+ const result = safeParseTokenResult(raw.result);
66
+ if (tokenHash.length === 0 || !Number.isFinite(createdAt) || !result)
67
+ return null;
68
+ return {
69
+ tokenHash,
70
+ createdAt: Math.floor(createdAt),
71
+ result,
72
+ };
73
+ }
74
+ async function readJson(path, fsOps) {
75
+ try {
76
+ const content = await fsOps.readFile(path, "utf8");
77
+ return JSON.parse(content);
78
+ }
79
+ catch {
80
+ return null;
81
+ }
82
+ }
83
+ async function safeUnlink(path, options, fsOps = fs) {
84
+ const attempts = Math.max(1, Math.floor(options?.attempts ?? 4));
85
+ const baseDelayMs = Math.max(5, Math.floor(options?.baseDelayMs ?? 15));
86
+ for (let attempt = 0; attempt < attempts; attempt++) {
87
+ try {
88
+ await fsOps.unlink(path);
89
+ return true;
90
+ }
91
+ catch (error) {
92
+ const code = error.code;
93
+ if (code === "ENOENT")
94
+ return true;
95
+ const canRetry = RETRYABLE_IO_ERRORS.has(code ?? "");
96
+ if (canRetry && attempt + 1 < attempts) {
97
+ await sleep(baseDelayMs * (2 ** attempt));
98
+ continue;
99
+ }
100
+ log.debug("Failed to remove lease artifact", {
101
+ path,
102
+ error: error instanceof Error ? error.message : String(error),
103
+ code,
104
+ });
105
+ return false;
106
+ }
107
+ }
108
+ return false;
109
+ }
110
+ function isRetryableFsCode(code) {
111
+ return RETRYABLE_IO_ERRORS.has(code ?? "");
112
+ }
113
+ export class RefreshLeaseCoordinator {
114
+ enabled;
115
+ leaseDir;
116
+ leaseTtlMs;
117
+ waitTimeoutMs;
118
+ pollIntervalMs;
119
+ resultTtlMs;
120
+ fsOps;
121
+ constructor(options = {}) {
122
+ this.enabled = options.enabled ?? true;
123
+ this.leaseDir = options.leaseDir ?? join(getCodexMultiAuthDir(), "refresh-leases");
124
+ this.leaseTtlMs = Math.max(1_000, Math.floor(options.leaseTtlMs ?? DEFAULT_LEASE_TTL_MS));
125
+ this.waitTimeoutMs = Math.max(0, Math.floor(options.waitTimeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS));
126
+ this.pollIntervalMs = Math.max(50, Math.floor(options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS));
127
+ this.resultTtlMs = Math.max(1_000, Math.floor(options.resultTtlMs ?? DEFAULT_RESULT_TTL_MS));
128
+ this.fsOps = options.fsOps ?? fs;
129
+ }
130
+ static fromEnvironment() {
131
+ const testMode = process.env.VITEST === "true" || process.env.NODE_ENV === "test";
132
+ const enabled = parseBooleanEnv(process.env.CODEX_AUTH_REFRESH_LEASE) ??
133
+ (testMode ? false : true);
134
+ return new RefreshLeaseCoordinator({
135
+ enabled,
136
+ leaseDir: (process.env.CODEX_AUTH_REFRESH_LEASE_DIR ?? "").trim() || undefined,
137
+ leaseTtlMs: parseEnvInt(process.env.CODEX_AUTH_REFRESH_LEASE_TTL_MS),
138
+ waitTimeoutMs: parseEnvInt(process.env.CODEX_AUTH_REFRESH_LEASE_WAIT_MS),
139
+ pollIntervalMs: parseEnvInt(process.env.CODEX_AUTH_REFRESH_LEASE_POLL_MS),
140
+ resultTtlMs: parseEnvInt(process.env.CODEX_AUTH_REFRESH_LEASE_RESULT_TTL_MS),
141
+ });
142
+ }
143
+ async acquire(refreshToken) {
144
+ if (!this.enabled) {
145
+ return this.createBypassHandle("disabled");
146
+ }
147
+ if (refreshToken.trim().length === 0) {
148
+ return this.createBypassHandle("empty-token");
149
+ }
150
+ const tokenHash = hashRefreshToken(refreshToken);
151
+ const lockPath = join(this.leaseDir, `${tokenHash}.lock`);
152
+ const resultPath = join(this.leaseDir, `${tokenHash}.result.json`);
153
+ await this.fsOps.mkdir(this.leaseDir, { recursive: true });
154
+ void this.pruneExpiredArtifacts();
155
+ const deadline = Date.now() + this.waitTimeoutMs;
156
+ while (true) {
157
+ const cachedResult = await this.readFreshResult(resultPath, tokenHash);
158
+ if (cachedResult) {
159
+ return {
160
+ role: "follower",
161
+ result: cachedResult,
162
+ release: async () => {
163
+ // Follower does not own lock.
164
+ },
165
+ };
166
+ }
167
+ try {
168
+ const handle = await this.fsOps.open(lockPath, "wx");
169
+ try {
170
+ const now = Date.now();
171
+ const payload = {
172
+ tokenHash,
173
+ pid: process.pid,
174
+ acquiredAt: now,
175
+ expiresAt: now + this.leaseTtlMs,
176
+ };
177
+ await handle.writeFile(`${JSON.stringify(payload)}\n`, "utf8");
178
+ }
179
+ finally {
180
+ await handle.close();
181
+ }
182
+ return this.createOwnerHandle(tokenHash, lockPath, resultPath);
183
+ }
184
+ catch (error) {
185
+ const code = error.code;
186
+ if (code !== "EEXIST") {
187
+ log.warn("Refresh lease acquisition failed; proceeding without lease", {
188
+ error: error instanceof Error ? error.message : String(error),
189
+ });
190
+ return this.createBypassHandle("acquire-error");
191
+ }
192
+ const stale = await this.assessLockStaleness(lockPath, tokenHash);
193
+ if (stale.state === "stale") {
194
+ const removed = await safeUnlink(lockPath, undefined, this.fsOps);
195
+ if (removed)
196
+ continue;
197
+ if (Date.now() >= deadline) {
198
+ log.warn("Refresh lease wait timeout while stale lock could not be removed", {
199
+ waitTimeoutMs: this.waitTimeoutMs,
200
+ });
201
+ return this.createBypassHandle("wait-timeout");
202
+ }
203
+ await sleep(this.pollIntervalMs);
204
+ continue;
205
+ }
206
+ if (Date.now() >= deadline) {
207
+ log.warn("Refresh lease wait timeout; proceeding without lease", {
208
+ waitTimeoutMs: this.waitTimeoutMs,
209
+ });
210
+ return this.createBypassHandle("wait-timeout");
211
+ }
212
+ await sleep(this.pollIntervalMs);
213
+ }
214
+ }
215
+ }
216
+ createBypassHandle(reason) {
217
+ log.debug("Bypassing refresh lease", { reason });
218
+ return {
219
+ role: "bypass",
220
+ release: async () => {
221
+ // No-op
222
+ },
223
+ };
224
+ }
225
+ createOwnerHandle(tokenHash, lockPath, resultPath) {
226
+ let released = false;
227
+ return {
228
+ role: "owner",
229
+ release: async (result) => {
230
+ if (released)
231
+ return;
232
+ released = true;
233
+ try {
234
+ if (result) {
235
+ await this.writeResult(resultPath, tokenHash, result);
236
+ }
237
+ }
238
+ finally {
239
+ await safeUnlink(lockPath, undefined, this.fsOps);
240
+ }
241
+ },
242
+ };
243
+ }
244
+ async writeResult(resultPath, tokenHash, result) {
245
+ const payload = {
246
+ tokenHash,
247
+ createdAt: Date.now(),
248
+ result,
249
+ };
250
+ const tempPath = `${resultPath}.${process.pid}.${Date.now()}.tmp`;
251
+ try {
252
+ await this.fsOps.writeFile(tempPath, `${JSON.stringify(payload)}\n`, "utf8");
253
+ await this.fsOps.rename(tempPath, resultPath);
254
+ }
255
+ finally {
256
+ await safeUnlink(tempPath, undefined, this.fsOps);
257
+ }
258
+ }
259
+ async readFreshResult(resultPath, tokenHash) {
260
+ if (!existsSync(resultPath))
261
+ return null;
262
+ const parsed = parseResultPayload(await readJson(resultPath, this.fsOps));
263
+ if (!parsed || parsed.tokenHash !== tokenHash) {
264
+ return null;
265
+ }
266
+ const ageMs = Date.now() - parsed.createdAt;
267
+ if (ageMs > this.resultTtlMs) {
268
+ await safeUnlink(resultPath, undefined, this.fsOps);
269
+ return null;
270
+ }
271
+ return parsed.result;
272
+ }
273
+ async assessLockStaleness(lockPath, tokenHash) {
274
+ const raw = await readJson(lockPath, this.fsOps);
275
+ if (raw === null) {
276
+ if (!existsSync(lockPath)) {
277
+ return { state: "stale", reason: "missing" };
278
+ }
279
+ return { state: "unknown", reason: "unreadable" };
280
+ }
281
+ const parsed = parseLeasePayload(raw);
282
+ if (!parsed) {
283
+ return { state: "unknown", reason: "invalid-payload" };
284
+ }
285
+ if (parsed.tokenHash !== tokenHash) {
286
+ return { state: "unknown", reason: "token-mismatch" };
287
+ }
288
+ if (parsed.expiresAt <= Date.now()) {
289
+ return { state: "stale", reason: "expired" };
290
+ }
291
+ try {
292
+ const stat = await this.fsOps.stat(lockPath);
293
+ if (Date.now() - stat.mtimeMs > this.leaseTtlMs) {
294
+ return { state: "stale", reason: "mtime-expired" };
295
+ }
296
+ return { state: "active", reason: "fresh" };
297
+ }
298
+ catch (error) {
299
+ const code = error.code;
300
+ if (code === "ENOENT")
301
+ return { state: "stale", reason: "missing" };
302
+ if (isRetryableFsCode(code) || code === "EACCES") {
303
+ return { state: "unknown", reason: `stat-${String(code).toLowerCase()}` };
304
+ }
305
+ return { state: "unknown", reason: "stat-error" };
306
+ }
307
+ }
308
+ async pruneExpiredArtifacts() {
309
+ try {
310
+ const entries = await this.fsOps.readdir(this.leaseDir, { withFileTypes: true });
311
+ const now = Date.now();
312
+ const maxAgeMs = Math.max(this.leaseTtlMs, this.resultTtlMs) * 2;
313
+ for (const entry of entries) {
314
+ if (!entry.isFile())
315
+ continue;
316
+ if (!entry.name.endsWith(".lock") && !entry.name.endsWith(".result.json"))
317
+ continue;
318
+ const fullPath = join(this.leaseDir, entry.name);
319
+ try {
320
+ const stat = await this.fsOps.stat(fullPath);
321
+ if (now - stat.mtimeMs > maxAgeMs) {
322
+ await safeUnlink(fullPath, undefined, this.fsOps);
323
+ }
324
+ }
325
+ catch {
326
+ // Best effort.
327
+ }
328
+ }
329
+ }
330
+ catch {
331
+ // Best effort.
332
+ }
333
+ }
334
+ }
335
+ //# sourceMappingURL=refresh-lease.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh-lease.js","sourceRoot":"","sources":["../../lib/refresh-lease.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Refresh Queue Module
3
+ *
4
+ * Prevents race conditions when multiple concurrent requests try to refresh
5
+ * the same account's token simultaneously. Instead of firing parallel refresh
6
+ * requests, subsequent callers await the existing in-flight refresh.
7
+ *
8
+ * Ported from antigravity-auth refresh-queue.ts pattern.
9
+ */
10
+ import type { TokenResult } from "./types.js";
11
+ import { RefreshLeaseCoordinator } from "./refresh-lease.js";
12
+ /**
13
+ * Manages queued token refresh operations to prevent race conditions.
14
+ *
15
+ * When multiple concurrent requests need to refresh the same account's token,
16
+ * only the first request triggers the actual refresh. Subsequent requests
17
+ * await the same promise, ensuring:
18
+ * - No duplicate refresh API calls for the same refresh token
19
+ * - Consistent token state across all waiting callers
20
+ * - Reduced load on OpenAI's token endpoint
21
+ *
22
+ * Token Rotation Handling:
23
+ * When OpenAI rotates the refresh token during a refresh operation, we maintain
24
+ * a mapping from old token → new token. This ensures that requests arriving with
25
+ * either the old or new token will find the in-flight refresh and not trigger
26
+ * duplicate refreshes.
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * const queue = new RefreshQueue();
31
+ *
32
+ * // These three concurrent calls will only trigger ONE actual refresh
33
+ * const [result1, result2, result3] = await Promise.all([
34
+ * queue.refresh(refreshToken),
35
+ * queue.refresh(refreshToken),
36
+ * queue.refresh(refreshToken),
37
+ * ]);
38
+ *
39
+ * // All three get the same result
40
+ * console.log(result1 === result2); // true (same object reference)
41
+ * ```
42
+ */
43
+ export declare class RefreshQueue {
44
+ private pending;
45
+ private readonly leaseCoordinator;
46
+ /**
47
+ * Maps old refresh tokens to new tokens after rotation.
48
+ * This allows lookups with either old or new token to find the same entry.
49
+ * Format: oldToken → newToken
50
+ */
51
+ private tokenRotationMap;
52
+ /**
53
+ * Maximum time to keep a refresh entry in the queue (prevents memory leaks
54
+ * from stuck requests). After this timeout, the entry is removed and new
55
+ * callers will trigger a fresh refresh.
56
+ */
57
+ private readonly maxEntryAgeMs;
58
+ /**
59
+ * Create a new RefreshQueue instance.
60
+ * @param maxEntryAgeMs - Maximum age for pending entries before cleanup (default: 30s)
61
+ */
62
+ constructor(maxEntryAgeMs?: number, leaseCoordinator?: RefreshLeaseCoordinator);
63
+ /**
64
+ * Refresh a token, deduplicating concurrent requests for the same refresh token.
65
+ *
66
+ * If a refresh is already in-flight for this token, returns the existing promise.
67
+ * Otherwise, initiates a new refresh and caches the promise for other callers.
68
+ *
69
+ * @param refreshToken - The refresh token to use
70
+ * @returns Token result (success with new tokens, or failure)
71
+ */
72
+ refresh(refreshToken: string): Promise<TokenResult>;
73
+ private findOriginalToken;
74
+ private cleanupRotationMapping;
75
+ private executeRefreshWithRotationTracking;
76
+ /**
77
+ * Execute the actual refresh and log results.
78
+ */
79
+ private executeRefresh;
80
+ /**
81
+ * Remove stale entries that have been pending too long.
82
+ * This prevents memory leaks from stuck or abandoned refresh operations.
83
+ */
84
+ private cleanup;
85
+ /**
86
+ * Check if there's an in-flight refresh for a given token.
87
+ * @param refreshToken - The refresh token to check
88
+ * @returns True if refresh is in progress
89
+ */
90
+ isRefreshing(refreshToken: string): boolean;
91
+ /**
92
+ * Get the number of pending refresh operations.
93
+ * Useful for debugging and monitoring.
94
+ */
95
+ get pendingCount(): number;
96
+ /**
97
+ * Clear all pending entries (primarily for testing).
98
+ */
99
+ clear(): void;
100
+ }
101
+ /**
102
+ * Get the singleton RefreshQueue instance.
103
+ * @param maxEntryAgeMs - Maximum age for pending entries (only used on first call)
104
+ * @returns The global RefreshQueue instance
105
+ */
106
+ export declare function getRefreshQueue(maxEntryAgeMs?: number): RefreshQueue;
107
+ /**
108
+ * Reset the singleton instance (primarily for testing).
109
+ */
110
+ export declare function resetRefreshQueue(): void;
111
+ /**
112
+ * Convenience function to refresh a token using the singleton queue.
113
+ * @param refreshToken - The refresh token to use
114
+ * @returns Token result
115
+ */
116
+ export declare function queuedRefresh(refreshToken: string): Promise<TokenResult>;
117
+ //# sourceMappingURL=refresh-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh-queue.d.ts","sourceRoot":"","sources":["../../lib/refresh-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAY7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAwC;IACvD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA0B;IAE3D;;;;OAIG;IACH,OAAO,CAAC,gBAAgB,CAAkC;IAE1D;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IAEvC;;;OAGG;gBAED,aAAa,GAAE,MAAe,EAC9B,gBAAgB,GAAE,uBAAmE;IAMvF;;;;;;;;OAQG;IACG,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAiFzD,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,sBAAsB;YAShB,kCAAkC;IAchD;;OAEG;YACW,cAAc;IAsC5B;;;OAGG;IACH,OAAO,CAAC,OAAO;IAqBf;;;;OAIG;IACH,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAI3C;;;OAGG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;OAEG;IACH,KAAK,IAAI,IAAI;CAId;AAQD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,YAAY,CAKpE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAE9E"}