oc-codex-multi-auth 6.0.0 → 6.1.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 (284) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +56 -18
  3. package/assets/readme-hero.svg +10 -10
  4. package/config/README.md +1 -1
  5. package/config/minimal-opencode.json +1 -1
  6. package/config/opencode-legacy.json +1 -1
  7. package/config/opencode-modern.json +1 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +112 -2525
  11. package/dist/index.js.map +1 -1
  12. package/dist/lib/accounts/persistence.d.ts +34 -0
  13. package/dist/lib/accounts/persistence.d.ts.map +1 -0
  14. package/dist/lib/accounts/persistence.js +153 -0
  15. package/dist/lib/accounts/persistence.js.map +1 -0
  16. package/dist/lib/accounts/recovery.d.ts +59 -0
  17. package/dist/lib/accounts/recovery.d.ts.map +1 -0
  18. package/dist/lib/accounts/recovery.js +229 -0
  19. package/dist/lib/accounts/recovery.js.map +1 -0
  20. package/dist/lib/accounts/rotation.d.ts +40 -0
  21. package/dist/lib/accounts/rotation.d.ts.map +1 -0
  22. package/dist/lib/accounts/rotation.js +204 -0
  23. package/dist/lib/accounts/rotation.js.map +1 -0
  24. package/dist/lib/accounts/state.d.ts +92 -0
  25. package/dist/lib/accounts/state.d.ts.map +1 -0
  26. package/dist/lib/accounts/state.js +366 -0
  27. package/dist/lib/accounts/state.js.map +1 -0
  28. package/dist/lib/accounts.d.ts +48 -91
  29. package/dist/lib/accounts.d.ts.map +1 -1
  30. package/dist/lib/accounts.js +121 -699
  31. package/dist/lib/accounts.js.map +1 -1
  32. package/dist/lib/auth/auth.d.ts +1 -1
  33. package/dist/lib/auth/auth.d.ts.map +1 -1
  34. package/dist/lib/auth/auth.js +5 -2
  35. package/dist/lib/auth/auth.js.map +1 -1
  36. package/dist/lib/auth/login-runner.d.ts +32 -0
  37. package/dist/lib/auth/login-runner.d.ts.map +1 -1
  38. package/dist/lib/auth/login-runner.js +79 -64
  39. package/dist/lib/auth/login-runner.js.map +1 -1
  40. package/dist/lib/auth/server.d.ts.map +1 -1
  41. package/dist/lib/auth/server.js +3 -8
  42. package/dist/lib/auth/server.js.map +1 -1
  43. package/dist/lib/circuit-breaker.d.ts +53 -2
  44. package/dist/lib/circuit-breaker.d.ts.map +1 -1
  45. package/dist/lib/circuit-breaker.js +65 -6
  46. package/dist/lib/circuit-breaker.js.map +1 -1
  47. package/dist/lib/config.d.ts.map +1 -1
  48. package/dist/lib/config.js +77 -32
  49. package/dist/lib/config.js.map +1 -1
  50. package/dist/lib/error-sentinels.d.ts +20 -0
  51. package/dist/lib/error-sentinels.d.ts.map +1 -0
  52. package/dist/lib/error-sentinels.js +28 -0
  53. package/dist/lib/error-sentinels.js.map +1 -0
  54. package/dist/lib/errors.d.ts +100 -1
  55. package/dist/lib/errors.d.ts.map +1 -1
  56. package/dist/lib/errors.js +116 -1
  57. package/dist/lib/errors.js.map +1 -1
  58. package/dist/lib/logger.d.ts +14 -1
  59. package/dist/lib/logger.d.ts.map +1 -1
  60. package/dist/lib/logger.js +65 -5
  61. package/dist/lib/logger.js.map +1 -1
  62. package/dist/lib/oauth-constants.d.ts +18 -0
  63. package/dist/lib/oauth-constants.d.ts.map +1 -0
  64. package/dist/lib/oauth-constants.js +18 -0
  65. package/dist/lib/oauth-constants.js.map +1 -0
  66. package/dist/lib/oauth-success.d.ts +2 -0
  67. package/dist/lib/oauth-success.d.ts.map +1 -0
  68. package/dist/lib/oauth-success.html +711 -711
  69. package/dist/lib/oauth-success.js +714 -0
  70. package/dist/lib/oauth-success.js.map +1 -0
  71. package/dist/lib/prompts/codex.d.ts.map +1 -1
  72. package/dist/lib/prompts/codex.js +12 -3
  73. package/dist/lib/prompts/codex.js.map +1 -1
  74. package/dist/lib/prompts/opencode-codex.d.ts.map +1 -1
  75. package/dist/lib/prompts/opencode-codex.js +3 -2
  76. package/dist/lib/prompts/opencode-codex.js.map +1 -1
  77. package/dist/lib/recovery/hook.d.ts +43 -0
  78. package/dist/lib/recovery/hook.d.ts.map +1 -0
  79. package/dist/lib/recovery/hook.js +325 -0
  80. package/dist/lib/recovery/hook.js.map +1 -0
  81. package/dist/lib/recovery/index.d.ts +1 -0
  82. package/dist/lib/recovery/index.d.ts.map +1 -1
  83. package/dist/lib/recovery/index.js +1 -0
  84. package/dist/lib/recovery/index.js.map +1 -1
  85. package/dist/lib/recovery/storage.d.ts.map +1 -1
  86. package/dist/lib/recovery/storage.js +5 -1
  87. package/dist/lib/recovery/storage.js.map +1 -1
  88. package/dist/lib/recovery.d.ts +15 -30
  89. package/dist/lib/recovery.d.ts.map +1 -1
  90. package/dist/lib/recovery.js +14 -312
  91. package/dist/lib/recovery.js.map +1 -1
  92. package/dist/lib/request/fetch-helpers.d.ts +1 -0
  93. package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
  94. package/dist/lib/request/fetch-helpers.js +58 -10
  95. package/dist/lib/request/fetch-helpers.js.map +1 -1
  96. package/dist/lib/request/response-handler.d.ts.map +1 -1
  97. package/dist/lib/request/response-handler.js +8 -2
  98. package/dist/lib/request/response-handler.js.map +1 -1
  99. package/dist/lib/runtime.d.ts +101 -0
  100. package/dist/lib/runtime.d.ts.map +1 -0
  101. package/dist/lib/runtime.js +77 -0
  102. package/dist/lib/runtime.js.map +1 -0
  103. package/dist/lib/schemas.d.ts +164 -1
  104. package/dist/lib/schemas.d.ts.map +1 -1
  105. package/dist/lib/schemas.js +251 -0
  106. package/dist/lib/schemas.js.map +1 -1
  107. package/dist/lib/storage/atomic-write.d.ts +31 -0
  108. package/dist/lib/storage/atomic-write.d.ts.map +1 -0
  109. package/dist/lib/storage/atomic-write.js +75 -0
  110. package/dist/lib/storage/atomic-write.js.map +1 -0
  111. package/dist/lib/storage/backup.d.ts +13 -0
  112. package/dist/lib/storage/backup.d.ts.map +1 -0
  113. package/dist/lib/storage/backup.js +59 -0
  114. package/dist/lib/storage/backup.js.map +1 -0
  115. package/dist/lib/storage/errors.d.ts +17 -0
  116. package/dist/lib/storage/errors.d.ts.map +1 -0
  117. package/dist/lib/storage/errors.js +38 -0
  118. package/dist/lib/storage/errors.js.map +1 -0
  119. package/dist/lib/storage/export-import.d.ts +84 -0
  120. package/dist/lib/storage/export-import.d.ts.map +1 -0
  121. package/dist/lib/storage/export-import.js +222 -0
  122. package/dist/lib/storage/export-import.js.map +1 -0
  123. package/dist/lib/storage/flagged.d.ts +29 -0
  124. package/dist/lib/storage/flagged.d.ts.map +1 -0
  125. package/dist/lib/storage/flagged.js +207 -0
  126. package/dist/lib/storage/flagged.js.map +1 -0
  127. package/dist/lib/storage/identity.d.ts +72 -0
  128. package/dist/lib/storage/identity.d.ts.map +1 -0
  129. package/dist/lib/storage/identity.js +230 -0
  130. package/dist/lib/storage/identity.js.map +1 -0
  131. package/dist/lib/storage/keychain.d.ts +146 -0
  132. package/dist/lib/storage/keychain.d.ts.map +1 -0
  133. package/dist/lib/storage/keychain.js +278 -0
  134. package/dist/lib/storage/keychain.js.map +1 -0
  135. package/dist/lib/storage/load-save.d.ts +61 -0
  136. package/dist/lib/storage/load-save.d.ts.map +1 -0
  137. package/dist/lib/storage/load-save.js +606 -0
  138. package/dist/lib/storage/load-save.js.map +1 -0
  139. package/dist/lib/storage/migrations.d.ts +35 -0
  140. package/dist/lib/storage/migrations.d.ts.map +1 -1
  141. package/dist/lib/storage/migrations.js +37 -0
  142. package/dist/lib/storage/migrations.js.map +1 -1
  143. package/dist/lib/storage/normalize.d.ts +22 -0
  144. package/dist/lib/storage/normalize.d.ts.map +1 -0
  145. package/dist/lib/storage/normalize.js +114 -0
  146. package/dist/lib/storage/normalize.js.map +1 -0
  147. package/dist/lib/storage/paths.d.ts.map +1 -1
  148. package/dist/lib/storage/paths.js +2 -1
  149. package/dist/lib/storage/paths.js.map +1 -1
  150. package/dist/lib/storage/state.d.ts +46 -0
  151. package/dist/lib/storage/state.d.ts.map +1 -0
  152. package/dist/lib/storage/state.js +100 -0
  153. package/dist/lib/storage/state.js.map +1 -0
  154. package/dist/lib/storage/worktree-lock.d.ts +79 -0
  155. package/dist/lib/storage/worktree-lock.d.ts.map +1 -0
  156. package/dist/lib/storage/worktree-lock.js +265 -0
  157. package/dist/lib/storage/worktree-lock.js.map +1 -0
  158. package/dist/lib/storage.d.ts +21 -155
  159. package/dist/lib/storage.d.ts.map +1 -1
  160. package/dist/lib/storage.js +24 -1167
  161. package/dist/lib/storage.js.map +1 -1
  162. package/dist/lib/tools/_shared.d.ts +16 -0
  163. package/dist/lib/tools/_shared.d.ts.map +1 -0
  164. package/dist/lib/tools/_shared.js +21 -0
  165. package/dist/lib/tools/_shared.js.map +1 -0
  166. package/dist/lib/tools/codex-dashboard.d.ts +8 -0
  167. package/dist/lib/tools/codex-dashboard.d.ts.map +1 -0
  168. package/dist/lib/tools/codex-dashboard.js +176 -0
  169. package/dist/lib/tools/codex-dashboard.js.map +1 -0
  170. package/dist/lib/tools/codex-diag.d.ts +19 -0
  171. package/dist/lib/tools/codex-diag.d.ts.map +1 -0
  172. package/dist/lib/tools/codex-diag.js +139 -0
  173. package/dist/lib/tools/codex-diag.js.map +1 -0
  174. package/dist/lib/tools/codex-diff.d.ts +44 -0
  175. package/dist/lib/tools/codex-diff.d.ts.map +1 -0
  176. package/dist/lib/tools/codex-diff.js +284 -0
  177. package/dist/lib/tools/codex-diff.js.map +1 -0
  178. package/dist/lib/tools/codex-doctor.d.ts +8 -0
  179. package/dist/lib/tools/codex-doctor.d.ts.map +1 -0
  180. package/dist/lib/tools/codex-doctor.js +284 -0
  181. package/dist/lib/tools/codex-doctor.js.map +1 -0
  182. package/dist/lib/tools/codex-export.d.ts +8 -0
  183. package/dist/lib/tools/codex-export.d.ts.map +1 -0
  184. package/dist/lib/tools/codex-export.js +63 -0
  185. package/dist/lib/tools/codex-export.js.map +1 -0
  186. package/dist/lib/tools/codex-health.d.ts +8 -0
  187. package/dist/lib/tools/codex-health.d.ts.map +1 -0
  188. package/dist/lib/tools/codex-health.js +124 -0
  189. package/dist/lib/tools/codex-health.js.map +1 -0
  190. package/dist/lib/tools/codex-help.d.ts +8 -0
  191. package/dist/lib/tools/codex-help.d.ts.map +1 -0
  192. package/dist/lib/tools/codex-help.js +127 -0
  193. package/dist/lib/tools/codex-help.js.map +1 -0
  194. package/dist/lib/tools/codex-import.d.ts +8 -0
  195. package/dist/lib/tools/codex-import.d.ts.map +1 -0
  196. package/dist/lib/tools/codex-import.js +97 -0
  197. package/dist/lib/tools/codex-import.js.map +1 -0
  198. package/dist/lib/tools/codex-keychain.d.ts +36 -0
  199. package/dist/lib/tools/codex-keychain.d.ts.map +1 -0
  200. package/dist/lib/tools/codex-keychain.js +289 -0
  201. package/dist/lib/tools/codex-keychain.js.map +1 -0
  202. package/dist/lib/tools/codex-label.d.ts +8 -0
  203. package/dist/lib/tools/codex-label.d.ts.map +1 -0
  204. package/dist/lib/tools/codex-label.js +143 -0
  205. package/dist/lib/tools/codex-label.js.map +1 -0
  206. package/dist/lib/tools/codex-limits.d.ts +8 -0
  207. package/dist/lib/tools/codex-limits.d.ts.map +1 -0
  208. package/dist/lib/tools/codex-limits.js +497 -0
  209. package/dist/lib/tools/codex-limits.js.map +1 -0
  210. package/dist/lib/tools/codex-list.d.ts +8 -0
  211. package/dist/lib/tools/codex-list.d.ts.map +1 -0
  212. package/dist/lib/tools/codex-list.js +260 -0
  213. package/dist/lib/tools/codex-list.js.map +1 -0
  214. package/dist/lib/tools/codex-metrics.d.ts +8 -0
  215. package/dist/lib/tools/codex-metrics.d.ts.map +1 -0
  216. package/dist/lib/tools/codex-metrics.js +180 -0
  217. package/dist/lib/tools/codex-metrics.js.map +1 -0
  218. package/dist/lib/tools/codex-next.d.ts +8 -0
  219. package/dist/lib/tools/codex-next.d.ts.map +1 -0
  220. package/dist/lib/tools/codex-next.js +54 -0
  221. package/dist/lib/tools/codex-next.js.map +1 -0
  222. package/dist/lib/tools/codex-note.d.ts +8 -0
  223. package/dist/lib/tools/codex-note.d.ts.map +1 -0
  224. package/dist/lib/tools/codex-note.js +79 -0
  225. package/dist/lib/tools/codex-note.js.map +1 -0
  226. package/dist/lib/tools/codex-refresh.d.ts +8 -0
  227. package/dist/lib/tools/codex-refresh.d.ts.map +1 -0
  228. package/dist/lib/tools/codex-refresh.js +78 -0
  229. package/dist/lib/tools/codex-refresh.js.map +1 -0
  230. package/dist/lib/tools/codex-remove.d.ts +8 -0
  231. package/dist/lib/tools/codex-remove.d.ts.map +1 -0
  232. package/dist/lib/tools/codex-remove.js +184 -0
  233. package/dist/lib/tools/codex-remove.js.map +1 -0
  234. package/dist/lib/tools/codex-setup.d.ts +8 -0
  235. package/dist/lib/tools/codex-setup.d.ts.map +1 -0
  236. package/dist/lib/tools/codex-setup.js +26 -0
  237. package/dist/lib/tools/codex-setup.js.map +1 -0
  238. package/dist/lib/tools/codex-status.d.ts +8 -0
  239. package/dist/lib/tools/codex-status.d.ts.map +1 -0
  240. package/dist/lib/tools/codex-status.js +263 -0
  241. package/dist/lib/tools/codex-status.js.map +1 -0
  242. package/dist/lib/tools/codex-switch.d.ts +8 -0
  243. package/dist/lib/tools/codex-switch.d.ts.map +1 -0
  244. package/dist/lib/tools/codex-switch.js +122 -0
  245. package/dist/lib/tools/codex-switch.js.map +1 -0
  246. package/dist/lib/tools/codex-tag.d.ts +8 -0
  247. package/dist/lib/tools/codex-tag.d.ts.map +1 -0
  248. package/dist/lib/tools/codex-tag.js +101 -0
  249. package/dist/lib/tools/codex-tag.js.map +1 -0
  250. package/dist/lib/tools/index.d.ts +143 -0
  251. package/dist/lib/tools/index.d.ts.map +1 -0
  252. package/dist/lib/tools/index.js +67 -0
  253. package/dist/lib/tools/index.js.map +1 -0
  254. package/dist/lib/ui/format.d.ts.map +1 -1
  255. package/dist/lib/ui/format.js +5 -0
  256. package/dist/lib/ui/format.js.map +1 -1
  257. package/dist/lib/ui/runtime.d.ts +10 -0
  258. package/dist/lib/ui/runtime.d.ts.map +1 -1
  259. package/dist/lib/ui/runtime.js +16 -11
  260. package/dist/lib/ui/runtime.js.map +1 -1
  261. package/dist/lib/ui/select.d.ts.map +1 -1
  262. package/dist/lib/ui/select.js +12 -3
  263. package/dist/lib/ui/select.js.map +1 -1
  264. package/dist/lib/ui/theme.d.ts +19 -0
  265. package/dist/lib/ui/theme.d.ts.map +1 -1
  266. package/dist/lib/ui/theme.js +27 -0
  267. package/dist/lib/ui/theme.js.map +1 -1
  268. package/package.json +24 -16
  269. package/scripts/copy-oauth-success.js +16 -6
  270. package/scripts/install-oc-codex-multi-auth-core.js +462 -381
  271. package/scripts/install-oc-codex-multi-auth.js +15 -15
  272. package/scripts/test-all-models.sh +1 -1
  273. package/dist/lib/audit.d.ts +0 -45
  274. package/dist/lib/audit.d.ts.map +0 -1
  275. package/dist/lib/audit.js +0 -154
  276. package/dist/lib/audit.js.map +0 -1
  277. package/dist/lib/auth-rate-limit.d.ts +0 -20
  278. package/dist/lib/auth-rate-limit.d.ts.map +0 -1
  279. package/dist/lib/auth-rate-limit.js +0 -91
  280. package/dist/lib/auth-rate-limit.js.map +0 -1
  281. package/dist/lib/runtime-contracts.d.ts +0 -16
  282. package/dist/lib/runtime-contracts.d.ts.map +0 -1
  283. package/dist/lib/runtime-contracts.js +0 -24
  284. package/dist/lib/runtime-contracts.js.map +0 -1
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Persistence surface for {@link AccountManager}: debounced disk saves,
3
+ * pending-save coalescing, and shutdown-flush registration.
4
+ *
5
+ * All on-disk format concerns live in `lib/storage.ts`. This module owns the
6
+ * *lifecycle* (when to save, how to flush before exit, how to dispose the
7
+ * shutdown hook) rather than the serialization shape itself.
8
+ */
9
+ import type { AccountState } from "./state.js";
10
+ export declare class AccountPersistence {
11
+ private readonly state;
12
+ private saveDebounceTimer;
13
+ private pendingSave;
14
+ private shutdownHandler;
15
+ constructor(state: AccountState);
16
+ saveToDisk(): Promise<void>;
17
+ saveToDiskDebounced(delayMs?: number): void;
18
+ flushPendingSave(): Promise<void>;
19
+ /**
20
+ * Registers a process-shutdown cleanup that awaits any pending debounced
21
+ * save. Without this, a rotation queued inside the 500ms debounce window
22
+ * would be lost when SIGINT/SIGTERM fires before the timer resolves.
23
+ * Registration is lazy (only when `saveToDiskDebounced` is first invoked)
24
+ * so idle managers do not leak handlers into the shutdown queue.
25
+ */
26
+ private ensureShutdownFlushRegistered;
27
+ /**
28
+ * Removes this manager's shutdown cleanup registration. Call this when
29
+ * replacing an `AccountManager` instance (e.g., on cache invalidation)
30
+ * to avoid unbounded growth of the global cleanup queue.
31
+ */
32
+ disposeShutdownHandler(): void;
33
+ }
34
+ //# sourceMappingURL=persistence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../../lib/accounts/persistence.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAU/C,qBAAa,kBAAkB;IAKlB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAJlC,OAAO,CAAC,iBAAiB,CAA8C;IACvE,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,eAAe,CAAsC;gBAEhC,KAAK,EAAE,YAAY;IAE1C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAwCjC,mBAAmB,CAAC,OAAO,SAAM,GAAG,IAAI;IA0BlC,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAWvC;;;;;;OAMG;IACH,OAAO,CAAC,6BAA6B;IAoCrC;;;;OAIG;IACH,sBAAsB,IAAI,IAAI;CAK9B"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Persistence surface for {@link AccountManager}: debounced disk saves,
3
+ * pending-save coalescing, and shutdown-flush registration.
4
+ *
5
+ * All on-disk format concerns live in `lib/storage.ts`. This module owns the
6
+ * *lifecycle* (when to save, how to flush before exit, how to dispose the
7
+ * shutdown hook) rather than the serialization shape itself.
8
+ */
9
+ import { createLogger } from "../logger.js";
10
+ import { MODEL_FAMILIES } from "../prompts/codex.js";
11
+ import { registerCleanup, unregisterCleanup } from "../shutdown.js";
12
+ import { saveAccounts } from "../storage.js";
13
+ import { clampNonNegativeInt } from "./rate-limits.js";
14
+ const log = createLogger("accounts");
15
+ /**
16
+ * Upper bound the shutdown handler will wait for `flushPendingSave` so that a
17
+ * jammed save cannot stall SIGINT/SIGTERM indefinitely.
18
+ */
19
+ const SHUTDOWN_FLUSH_TIMEOUT_MS = 5_000;
20
+ export class AccountPersistence {
21
+ state;
22
+ saveDebounceTimer = null;
23
+ pendingSave = null;
24
+ shutdownHandler = null;
25
+ constructor(state) {
26
+ this.state = state;
27
+ }
28
+ async saveToDisk() {
29
+ const activeIndexByFamily = {};
30
+ for (const family of MODEL_FAMILIES) {
31
+ const raw = this.state.currentAccountIndexByFamily[family];
32
+ activeIndexByFamily[family] = clampNonNegativeInt(raw, 0);
33
+ }
34
+ const activeIndex = clampNonNegativeInt(activeIndexByFamily.codex, 0);
35
+ const storage = {
36
+ version: 3,
37
+ accounts: this.state.accounts.map((account) => ({
38
+ accountId: account.accountId,
39
+ organizationId: account.organizationId,
40
+ accountIdSource: account.accountIdSource,
41
+ accountLabel: account.accountLabel,
42
+ accountTags: account.accountTags,
43
+ accountNote: account.accountNote,
44
+ email: account.email,
45
+ refreshToken: account.refreshToken,
46
+ accessToken: account.access,
47
+ expiresAt: account.expires,
48
+ enabled: account.enabled === false ? false : undefined,
49
+ addedAt: account.addedAt,
50
+ lastUsed: account.lastUsed,
51
+ lastSwitchReason: account.lastSwitchReason,
52
+ rateLimitResetTimes: Object.keys(account.rateLimitResetTimes).length > 0
53
+ ? account.rateLimitResetTimes
54
+ : undefined,
55
+ coolingDownUntil: account.coolingDownUntil,
56
+ cooldownReason: account.cooldownReason,
57
+ })),
58
+ activeIndex,
59
+ activeIndexByFamily,
60
+ };
61
+ await saveAccounts(storage);
62
+ }
63
+ saveToDiskDebounced(delayMs = 500) {
64
+ this.ensureShutdownFlushRegistered();
65
+ if (this.saveDebounceTimer) {
66
+ clearTimeout(this.saveDebounceTimer);
67
+ }
68
+ this.saveDebounceTimer = setTimeout(() => {
69
+ this.saveDebounceTimer = null;
70
+ const doSave = async () => {
71
+ try {
72
+ if (this.pendingSave) {
73
+ await this.pendingSave;
74
+ }
75
+ this.pendingSave = this.saveToDisk().finally(() => {
76
+ this.pendingSave = null;
77
+ });
78
+ await this.pendingSave;
79
+ }
80
+ catch (error) {
81
+ log.warn("Debounced save failed", {
82
+ error: error instanceof Error ? error.message : String(error),
83
+ });
84
+ }
85
+ };
86
+ void doSave();
87
+ }, delayMs);
88
+ }
89
+ async flushPendingSave() {
90
+ if (this.saveDebounceTimer) {
91
+ clearTimeout(this.saveDebounceTimer);
92
+ this.saveDebounceTimer = null;
93
+ await this.saveToDisk();
94
+ }
95
+ if (this.pendingSave) {
96
+ await this.pendingSave;
97
+ }
98
+ }
99
+ /**
100
+ * Registers a process-shutdown cleanup that awaits any pending debounced
101
+ * save. Without this, a rotation queued inside the 500ms debounce window
102
+ * would be lost when SIGINT/SIGTERM fires before the timer resolves.
103
+ * Registration is lazy (only when `saveToDiskDebounced` is first invoked)
104
+ * so idle managers do not leak handlers into the shutdown queue.
105
+ */
106
+ ensureShutdownFlushRegistered() {
107
+ if (this.shutdownHandler)
108
+ return;
109
+ const handler = async () => {
110
+ // One-shot: clear the slot first so that if `runCleanup()` fires
111
+ // externally (e.g. tests reusing a manager across cycles, or any
112
+ // other caller that drains the global cleanup queue), a subsequent
113
+ // `saveToDiskDebounced()` can re-register a fresh handler. Without
114
+ // this the guard above returns early and the next pending save
115
+ // goes unprotected on shutdown.
116
+ this.shutdownHandler = null;
117
+ let timeoutTimer = null;
118
+ try {
119
+ await Promise.race([
120
+ this.flushPendingSave(),
121
+ new Promise((_resolve, reject) => {
122
+ timeoutTimer = setTimeout(() => {
123
+ reject(new Error(`flushPendingSave timed out after ${SHUTDOWN_FLUSH_TIMEOUT_MS}ms`));
124
+ }, SHUTDOWN_FLUSH_TIMEOUT_MS);
125
+ }),
126
+ ]);
127
+ }
128
+ catch (error) {
129
+ log.warn("Shutdown flush failed", {
130
+ error: error instanceof Error ? error.message : String(error),
131
+ });
132
+ }
133
+ finally {
134
+ if (timeoutTimer)
135
+ clearTimeout(timeoutTimer);
136
+ }
137
+ };
138
+ this.shutdownHandler = handler;
139
+ registerCleanup(handler);
140
+ }
141
+ /**
142
+ * Removes this manager's shutdown cleanup registration. Call this when
143
+ * replacing an `AccountManager` instance (e.g., on cache invalidation)
144
+ * to avoid unbounded growth of the global cleanup queue.
145
+ */
146
+ disposeShutdownHandler() {
147
+ if (!this.shutdownHandler)
148
+ return;
149
+ unregisterCleanup(this.shutdownHandler);
150
+ this.shutdownHandler = null;
151
+ }
152
+ }
153
+ //# sourceMappingURL=persistence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistence.js","sourceRoot":"","sources":["../../../lib/accounts/persistence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Recovery + hydration surface for {@link AccountManager}.
3
+ *
4
+ * Covers:
5
+ * - auth-failure counter bookkeeping (per refresh token, serialized)
6
+ * - cross-process hydration from the Codex CLI `~/.codex/accounts.json`
7
+ * - merge-safe removal of all accounts sharing a refresh token
8
+ */
9
+ import type { AccountPersistence } from "./persistence.js";
10
+ import type { AccountState, ManagedAccount } from "./state.js";
11
+ export type CodexCliTokenCacheEntry = {
12
+ accessToken: string;
13
+ expiresAt?: number;
14
+ refreshToken?: string;
15
+ accountId?: string;
16
+ };
17
+ export declare function lookupCodexCliTokensByEmail(email: string | undefined): Promise<CodexCliTokenCacheEntry | null>;
18
+ export declare class AccountRecovery {
19
+ private readonly state;
20
+ private readonly persistence;
21
+ constructor(state: AccountState, persistence: AccountPersistence);
22
+ hydrateFromCodexCli(): Promise<void>;
23
+ /**
24
+ * Atomically increment the auth-failure counter for the account's refresh
25
+ * token and return the post-increment value.
26
+ *
27
+ * The read-modify-write is serialized through a per-refresh-token promise
28
+ * chain so that concurrent callers (for example, two org-variant accounts
29
+ * sharing a refresh token that fail auth simultaneously) cannot lose an
30
+ * increment. Without serialization both callers could read the same stale
31
+ * value, both compute `+1`, and both write the same result — masking a hard
32
+ * auth failure and causing the manager to keep hammering a dead token.
33
+ *
34
+ * Callers must `await` the returned promise before branching on the
35
+ * threshold (see `index.ts` auth-refresh failure path).
36
+ */
37
+ incrementAuthFailures(account: ManagedAccount): Promise<number>;
38
+ /**
39
+ * Return the current auth-failure counter for the account's refresh token
40
+ * without mutating state. Intended for tests and diagnostics.
41
+ */
42
+ getAuthFailures(account: ManagedAccount): number;
43
+ /**
44
+ * Clear the authentication failure counter for the given account's refresh token.
45
+ *
46
+ * Notes:
47
+ * - Failure counts are tracked per refresh token (not per account), so this clears
48
+ * shared failure state for all org variants that reuse the same token.
49
+ * - Failure counts are in-memory only for the current AccountManager instance.
50
+ */
51
+ clearAuthFailures(account: ManagedAccount): void;
52
+ /**
53
+ * Remove all accounts that share the same refreshToken as the given account.
54
+ * This is used when auth refresh fails to remove all org variants together.
55
+ * @returns Number of accounts removed
56
+ */
57
+ removeAccountsWithSameRefreshToken(account: ManagedAccount): number;
58
+ }
59
+ //# sourceMappingURL=recovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../../../lib/accounts/recovery.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAaH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAI/D,MAAM,MAAM,uBAAuB,GAAG;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAmGF,wBAAsB,2BAA2B,CAChD,KAAK,EAAE,MAAM,GAAG,SAAS,GACvB,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAMzC;AAED,qBAAa,eAAe;IAE1B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,WAAW;gBADX,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,kBAAkB;IAG3C,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAkD1C;;;;;;;;;;;;;OAaG;IACG,qBAAqB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IAoBrE;;;OAGG;IACH,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM;IAIhD;;;;;;;OAOG;IACH,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAIhD;;;;OAIG;IACH,kCAAkC,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM;CAmBnE"}
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Recovery + hydration surface for {@link AccountManager}.
3
+ *
4
+ * Covers:
5
+ * - auth-failure counter bookkeeping (per refresh token, serialized)
6
+ * - cross-process hydration from the Codex CLI `~/.codex/accounts.json`
7
+ * - merge-safe removal of all accounts sharing a refresh token
8
+ */
9
+ import { existsSync, promises as fs } from "node:fs";
10
+ import { homedir } from "node:os";
11
+ import { join } from "node:path";
12
+ import { sanitizeEmail, shouldUpdateAccountIdFromToken, } from "../auth/token-utils.js";
13
+ import { decodeJWT } from "../auth/auth.js";
14
+ import { createLogger } from "../logger.js";
15
+ import { CodexCliAccountsSchema } from "../schemas.js";
16
+ import { nowMs } from "../utils.js";
17
+ const log = createLogger("accounts");
18
+ const CODEX_CLI_ACCOUNTS_PATH = join(homedir(), ".codex", "accounts.json");
19
+ const CODEX_CLI_CACHE_TTL_MS = 5_000;
20
+ let codexCliTokenCache = null;
21
+ let codexCliTokenCacheLoadedAt = 0;
22
+ function extractExpiresAtFromAccessToken(accessToken) {
23
+ const decoded = decodeJWT(accessToken);
24
+ const exp = decoded?.exp;
25
+ if (typeof exp === "number" && Number.isFinite(exp)) {
26
+ // JWT exp is in seconds since epoch.
27
+ return exp * 1000;
28
+ }
29
+ return undefined;
30
+ }
31
+ async function getCodexCliTokenCache() {
32
+ const syncEnabled = process.env.CODEX_AUTH_SYNC_CODEX_CLI !== "0";
33
+ const skip = !syncEnabled ||
34
+ process.env.VITEST_WORKER_ID !== undefined ||
35
+ process.env.NODE_ENV === "test";
36
+ if (skip)
37
+ return null;
38
+ const now = nowMs();
39
+ if (codexCliTokenCache && now - codexCliTokenCacheLoadedAt < CODEX_CLI_CACHE_TTL_MS) {
40
+ return codexCliTokenCache;
41
+ }
42
+ codexCliTokenCacheLoadedAt = now;
43
+ if (!existsSync(CODEX_CLI_ACCOUNTS_PATH)) {
44
+ codexCliTokenCache = null;
45
+ return null;
46
+ }
47
+ try {
48
+ const raw = await fs.readFile(CODEX_CLI_ACCOUNTS_PATH, "utf-8");
49
+ const rawParsed = JSON.parse(raw);
50
+ // Cross-process trust boundary: the Codex CLI accounts file is produced
51
+ // by a separate process on disk and may be stale, truncated, tampered
52
+ // with, or produced by a version whose shape we do not recognise. We
53
+ // MUST validate through the Zod schema before reading any field; a
54
+ // parse failure is a warn+skip, never a throw (audit top-20 #11).
55
+ const validation = CodexCliAccountsSchema.safeParse(rawParsed);
56
+ if (!validation.success) {
57
+ log.warn("Codex CLI accounts cache failed validation; ignoring", {
58
+ issues: validation.error.issues.length,
59
+ firstPath: validation.error.issues[0]?.path.join(".") ?? "(root)",
60
+ });
61
+ codexCliTokenCache = null;
62
+ return null;
63
+ }
64
+ const validated = validation.data;
65
+ const entries = Array.isArray(validated.accounts) ? validated.accounts : [];
66
+ const next = new Map();
67
+ for (const entry of entries) {
68
+ const email = sanitizeEmail(typeof entry.email === "string" ? entry.email : undefined);
69
+ if (!email)
70
+ continue;
71
+ const accountId = typeof entry.accountId === "string" && entry.accountId.trim()
72
+ ? entry.accountId.trim()
73
+ : undefined;
74
+ const tokens = entry.auth?.tokens;
75
+ const accessToken = typeof tokens?.access_token === "string" && tokens.access_token.trim()
76
+ ? tokens.access_token.trim()
77
+ : undefined;
78
+ const refreshToken = typeof tokens?.refresh_token === "string" && tokens.refresh_token.trim()
79
+ ? tokens.refresh_token.trim()
80
+ : undefined;
81
+ if (!accessToken)
82
+ continue;
83
+ next.set(email, {
84
+ accessToken,
85
+ expiresAt: extractExpiresAtFromAccessToken(accessToken),
86
+ refreshToken,
87
+ accountId,
88
+ });
89
+ }
90
+ codexCliTokenCache = next;
91
+ return codexCliTokenCache;
92
+ }
93
+ catch (error) {
94
+ log.debug("Failed to read Codex CLI accounts cache", { error: String(error) });
95
+ codexCliTokenCache = null;
96
+ return null;
97
+ }
98
+ }
99
+ export async function lookupCodexCliTokensByEmail(email) {
100
+ const normalized = sanitizeEmail(email);
101
+ if (!normalized)
102
+ return null;
103
+ const cache = await getCodexCliTokenCache();
104
+ const cached = cache?.get(normalized);
105
+ return cached ? { ...cached } : null;
106
+ }
107
+ export class AccountRecovery {
108
+ state;
109
+ persistence;
110
+ constructor(state, persistence) {
111
+ this.state = state;
112
+ this.persistence = persistence;
113
+ }
114
+ async hydrateFromCodexCli() {
115
+ const cache = await getCodexCliTokenCache();
116
+ if (!cache || cache.size === 0)
117
+ return;
118
+ const now = nowMs();
119
+ let changed = false;
120
+ for (const account of this.state.accounts) {
121
+ const email = sanitizeEmail(account.email);
122
+ if (!email)
123
+ continue;
124
+ const cached = cache.get(email);
125
+ if (!cached)
126
+ continue;
127
+ if (typeof cached.expiresAt === "number" && cached.expiresAt <= now) {
128
+ continue;
129
+ }
130
+ const missingOrExpired = !account.access || account.expires === undefined || account.expires <= now;
131
+ if (missingOrExpired) {
132
+ account.access = cached.accessToken;
133
+ if (typeof cached.expiresAt === "number") {
134
+ account.expires = cached.expiresAt;
135
+ }
136
+ changed = true;
137
+ }
138
+ if (!account.accountId &&
139
+ cached.accountId &&
140
+ shouldUpdateAccountIdFromToken(account.accountIdSource, account.accountId)) {
141
+ account.accountId = cached.accountId;
142
+ account.accountIdSource = account.accountIdSource ?? "token";
143
+ changed = true;
144
+ }
145
+ }
146
+ if (!changed)
147
+ return;
148
+ try {
149
+ await this.persistence.saveToDisk();
150
+ }
151
+ catch (error) {
152
+ log.debug("Failed to persist Codex CLI cache hydration", {
153
+ error: String(error),
154
+ });
155
+ }
156
+ }
157
+ /**
158
+ * Atomically increment the auth-failure counter for the account's refresh
159
+ * token and return the post-increment value.
160
+ *
161
+ * The read-modify-write is serialized through a per-refresh-token promise
162
+ * chain so that concurrent callers (for example, two org-variant accounts
163
+ * sharing a refresh token that fail auth simultaneously) cannot lose an
164
+ * increment. Without serialization both callers could read the same stale
165
+ * value, both compute `+1`, and both write the same result — masking a hard
166
+ * auth failure and causing the manager to keep hammering a dead token.
167
+ *
168
+ * Callers must `await` the returned promise before branching on the
169
+ * threshold (see `index.ts` auth-refresh failure path).
170
+ */
171
+ async incrementAuthFailures(account) {
172
+ const key = account.refreshToken;
173
+ const prev = this.state.incrementAuthFailuresChain.get(key) ?? Promise.resolve(0);
174
+ const next = prev.then(() => {
175
+ const currentFailures = this.state.authFailuresByRefreshToken.get(key) ?? 0;
176
+ const newFailures = currentFailures + 1;
177
+ this.state.authFailuresByRefreshToken.set(key, newFailures);
178
+ return newFailures;
179
+ });
180
+ this.state.incrementAuthFailuresChain.set(key, next);
181
+ try {
182
+ return await next;
183
+ }
184
+ finally {
185
+ // Drop the chain entry only if no later caller has already replaced it.
186
+ if (this.state.incrementAuthFailuresChain.get(key) === next) {
187
+ this.state.incrementAuthFailuresChain.delete(key);
188
+ }
189
+ }
190
+ }
191
+ /**
192
+ * Return the current auth-failure counter for the account's refresh token
193
+ * without mutating state. Intended for tests and diagnostics.
194
+ */
195
+ getAuthFailures(account) {
196
+ return this.state.authFailuresByRefreshToken.get(account.refreshToken) ?? 0;
197
+ }
198
+ /**
199
+ * Clear the authentication failure counter for the given account's refresh token.
200
+ *
201
+ * Notes:
202
+ * - Failure counts are tracked per refresh token (not per account), so this clears
203
+ * shared failure state for all org variants that reuse the same token.
204
+ * - Failure counts are in-memory only for the current AccountManager instance.
205
+ */
206
+ clearAuthFailures(account) {
207
+ this.state.authFailuresByRefreshToken.delete(account.refreshToken);
208
+ }
209
+ /**
210
+ * Remove all accounts that share the same refreshToken as the given account.
211
+ * This is used when auth refresh fails to remove all org variants together.
212
+ * @returns Number of accounts removed
213
+ */
214
+ removeAccountsWithSameRefreshToken(account) {
215
+ const refreshToken = account.refreshToken;
216
+ // Snapshot first because removeAccount mutates the accounts array.
217
+ const accountsToRemove = this.state.accounts.filter((acc) => acc.refreshToken === refreshToken);
218
+ let removedCount = 0;
219
+ for (const accountToRemove of accountsToRemove) {
220
+ if (this.state.removeAccount(accountToRemove)) {
221
+ removedCount++;
222
+ }
223
+ }
224
+ // Clear stale auth failure state for this refresh token
225
+ this.state.authFailuresByRefreshToken.delete(refreshToken);
226
+ return removedCount;
227
+ }
228
+ }
229
+ //# sourceMappingURL=recovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery.js","sourceRoot":"","sources":["../../../lib/accounts/recovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Rotation + rate-limit + cooldown surface for {@link AccountManager}.
3
+ *
4
+ * Pure logic module: all state mutations land on a shared {@link AccountState}
5
+ * reference. Integrates with the health and token-bucket trackers in
6
+ * `lib/rotation.ts` (note: that file is the hybrid selection algorithm; this
7
+ * module is the manager-facing wrapper that wires it to `AccountState`).
8
+ */
9
+ import type { ModelFamily } from "../prompts/codex.js";
10
+ import { type HybridSelectionOptions } from "../rotation.js";
11
+ import type { CooldownReason } from "../storage.js";
12
+ import { type RateLimitReason } from "./rate-limits.js";
13
+ import type { AccountState, ManagedAccount } from "./state.js";
14
+ export declare class AccountRotation {
15
+ private readonly state;
16
+ constructor(state: AccountState);
17
+ getCurrentOrNextForFamily(family: ModelFamily, model?: string | null): ManagedAccount | null;
18
+ getNextForFamily(family: ModelFamily, model?: string | null): ManagedAccount | null;
19
+ getCurrentOrNextForFamilyHybrid(family: ModelFamily, model?: string | null, options?: HybridSelectionOptions): ManagedAccount | null;
20
+ recordSuccess(account: ManagedAccount, family: ModelFamily, model?: string | null): void;
21
+ recordRateLimit(account: ManagedAccount, family: ModelFamily, model?: string | null): void;
22
+ recordFailure(account: ManagedAccount, family: ModelFamily, model?: string | null): void;
23
+ consumeToken(account: ManagedAccount, family: ModelFamily, model?: string | null): boolean;
24
+ /**
25
+ * Refund a token consumed within the refund window (30 seconds).
26
+ * Use this when a request fails due to network errors (not rate limits).
27
+ * @returns true if refund was successful, false if no valid consumption found
28
+ */
29
+ refundToken(account: ManagedAccount, family: ModelFamily, model?: string | null): boolean;
30
+ markRateLimited(account: ManagedAccount, retryAfterMs: number, family: ModelFamily, model?: string | null): void;
31
+ markRateLimitedWithReason(account: ManagedAccount, retryAfterMs: number, family: ModelFamily, reason: RateLimitReason, model?: string | null): void;
32
+ markAccountCoolingDown(account: ManagedAccount, cooldownMs: number, reason: CooldownReason): void;
33
+ /**
34
+ * Mark every in-memory account sharing a refresh token as cooling down.
35
+ * @returns Number of live accounts updated.
36
+ */
37
+ markAccountsWithRefreshTokenCoolingDown(refreshToken: string, cooldownMs: number, reason: CooldownReason): number;
38
+ getMinWaitTimeForFamily(family: ModelFamily, model?: string | null): number;
39
+ }
40
+ //# sourceMappingURL=rotation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rotation.d.ts","sourceRoot":"","sources":["../../../lib/accounts/rotation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAKN,KAAK,sBAAsB,EAC3B,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,EAIN,KAAK,eAAe,EACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE/D,qBAAa,eAAe;IACf,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,YAAY;IAEhD,yBAAyB,CACxB,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,cAAc,GAAG,IAAI;IA6BxB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,cAAc,GAAG,IAAI;IA4BnF,+BAA+B,CAC9B,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAC9B,cAAc,GAAG,IAAI;IA8DxB,aAAa,CACZ,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,IAAI;IAKP,eAAe,CACd,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,IAAI;IAMP,aAAa,CACZ,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,IAAI;IAKP,YAAY,CACX,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,OAAO;IAKV;;;;OAIG;IACH,WAAW,CACV,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,OAAO;IAKV,eAAe,CACd,OAAO,EAAE,cAAc,EACvB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,IAAI;IAIP,yBAAyB,CACxB,OAAO,EAAE,cAAc,EACvB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,eAAe,EACvB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,IAAI;IAeP,sBAAsB,CACrB,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,cAAc,GACpB,IAAI;IAMP;;;OAGG;IACH,uCAAuC,CACtC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,cAAc,GACpB,MAAM;IAUT,uBAAuB,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM;CAuC3E"}