@theokit/sdk 5.13.0 → 5.15.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 (241) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/{agent-DSMuwADp.d.ts → agent-B6C9i_qu.d.ts} +31 -213
  3. package/dist/{agent-iW5kPpfT.d.cts → agent-B6FQad6P.d.cts} +31 -213
  4. package/dist/{agent-5DSDDH7K.js → agent-DRDGUU6T.js} +21 -20
  5. package/dist/{agent-5DSDDH7K.js.map → agent-DRDGUU6T.js.map} +1 -1
  6. package/dist/{agent-WOMRT3KX.cjs → agent-VI2HITPT.cjs} +22 -21
  7. package/dist/{agent-WOMRT3KX.cjs.map → agent-VI2HITPT.cjs.map} +1 -1
  8. package/dist/agent.d.ts +2 -3
  9. package/dist/auth/index.cjs +17 -16
  10. package/dist/auth/index.cjs.map +1 -1
  11. package/dist/auth/index.js +5 -4
  12. package/dist/auth/index.js.map +1 -1
  13. package/dist/{batch-EP3FCL6D.js → batch-N2XDYZED.js} +4 -4
  14. package/dist/{batch-EP3FCL6D.js.map → batch-N2XDYZED.js.map} +1 -1
  15. package/dist/{batch-IZ5EDKJ5.cjs → batch-VFR2MAUE.cjs} +7 -7
  16. package/dist/{batch-IZ5EDKJ5.cjs.map → batch-VFR2MAUE.cjs.map} +1 -1
  17. package/dist/{chunk-XOYNB3YN.js → chunk-23SS4ID4.js} +3 -3
  18. package/dist/{chunk-XOYNB3YN.js.map → chunk-23SS4ID4.js.map} +1 -1
  19. package/dist/{chunk-NHOEXFZT.js → chunk-2HXTNVLM.js} +5 -2
  20. package/dist/chunk-2HXTNVLM.js.map +1 -0
  21. package/dist/{chunk-2C24NSNV.js → chunk-3BBTHFGJ.js} +3 -3
  22. package/dist/{chunk-2C24NSNV.js.map → chunk-3BBTHFGJ.js.map} +1 -1
  23. package/dist/{chunk-NP362THY.cjs → chunk-3F53FLQ7.cjs} +5 -7
  24. package/dist/chunk-3F53FLQ7.cjs.map +1 -0
  25. package/dist/{chunk-3FSBE4PS.js → chunk-3GTN4HOO.js} +10 -6
  26. package/dist/chunk-3GTN4HOO.js.map +1 -0
  27. package/dist/{chunk-7WARNHWW.cjs → chunk-3UMPP553.cjs} +5 -2
  28. package/dist/chunk-3UMPP553.cjs.map +1 -0
  29. package/dist/{chunk-SXH37C7X.cjs → chunk-55LLQFHW.cjs} +6 -6
  30. package/dist/{chunk-SXH37C7X.cjs.map → chunk-55LLQFHW.cjs.map} +1 -1
  31. package/dist/{chunk-QISSETTG.cjs → chunk-5645PMVU.cjs} +6 -4
  32. package/dist/chunk-5645PMVU.cjs.map +1 -0
  33. package/dist/{chunk-JX4LB6XO.js → chunk-5M5GQYBM.js} +617 -250
  34. package/dist/chunk-5M5GQYBM.js.map +1 -0
  35. package/dist/{chunk-KL7ZUMK3.cjs → chunk-64ECM3XM.cjs} +704 -337
  36. package/dist/chunk-64ECM3XM.cjs.map +1 -0
  37. package/dist/{chunk-ZJAYFSVI.js → chunk-7ACS6P5Z.js} +5 -7
  38. package/dist/chunk-7ACS6P5Z.js.map +1 -0
  39. package/dist/{chunk-5A4UFBHW.cjs → chunk-A77UMVMD.cjs} +15 -11
  40. package/dist/chunk-A77UMVMD.cjs.map +1 -0
  41. package/dist/{chunk-ZTP6ZACR.js → chunk-ARC2V7NY.js} +3 -3
  42. package/dist/{chunk-ZTP6ZACR.js.map → chunk-ARC2V7NY.js.map} +1 -1
  43. package/dist/{chunk-WDVG5R2Q.cjs → chunk-AUH2EVWY.cjs} +4 -3
  44. package/dist/chunk-AUH2EVWY.cjs.map +1 -0
  45. package/dist/chunk-BNEUB52I.cjs +55 -0
  46. package/dist/chunk-BNEUB52I.cjs.map +1 -0
  47. package/dist/chunk-BPL5CVZ5.js +53 -0
  48. package/dist/chunk-BPL5CVZ5.js.map +1 -0
  49. package/dist/{chunk-2SFLLOMN.js → chunk-CBBT42VX.js} +3 -3
  50. package/dist/{chunk-2SFLLOMN.js.map → chunk-CBBT42VX.js.map} +1 -1
  51. package/dist/chunk-CHKV2L2Y.cjs +416 -0
  52. package/dist/chunk-CHKV2L2Y.cjs.map +1 -0
  53. package/dist/{chunk-4UYHP6NF.cjs → chunk-DJKGDLYZ.cjs} +93 -63
  54. package/dist/chunk-DJKGDLYZ.cjs.map +1 -0
  55. package/dist/{chunk-354F3OF5.js → chunk-FGGVSHDW.js} +3 -3
  56. package/dist/{chunk-354F3OF5.js.map → chunk-FGGVSHDW.js.map} +1 -1
  57. package/dist/{chunk-6OCJWGVD.cjs → chunk-FTXY4D44.cjs} +4 -4
  58. package/dist/{chunk-6OCJWGVD.cjs.map → chunk-FTXY4D44.cjs.map} +1 -1
  59. package/dist/chunk-INVEGVGO.js +405 -0
  60. package/dist/chunk-INVEGVGO.js.map +1 -0
  61. package/dist/{chunk-2PRGRYEQ.js → chunk-IOBHFP2E.js} +50 -20
  62. package/dist/chunk-IOBHFP2E.js.map +1 -0
  63. package/dist/{chunk-47EACDOC.cjs → chunk-KMFBNKCT.cjs} +4 -4
  64. package/dist/{chunk-47EACDOC.cjs.map → chunk-KMFBNKCT.cjs.map} +1 -1
  65. package/dist/{chunk-DF77RBF4.js → chunk-LCCT5ZXJ.js} +6 -6
  66. package/dist/{chunk-DF77RBF4.js.map → chunk-LCCT5ZXJ.js.map} +1 -1
  67. package/dist/{chunk-G7XBVM3T.cjs → chunk-MHUOVS5I.cjs} +5 -5
  68. package/dist/{chunk-G7XBVM3T.cjs.map → chunk-MHUOVS5I.cjs.map} +1 -1
  69. package/dist/{chunk-CWQPQTUZ.cjs → chunk-NEH3BPFD.cjs} +15 -15
  70. package/dist/{chunk-CWQPQTUZ.cjs.map → chunk-NEH3BPFD.cjs.map} +1 -1
  71. package/dist/{chunk-5AR6O7GW.js → chunk-NK5EOTDY.js} +3 -3
  72. package/dist/{chunk-5AR6O7GW.js.map → chunk-NK5EOTDY.js.map} +1 -1
  73. package/dist/{chunk-S46WJTDL.cjs → chunk-P7QYG4RZ.cjs} +27 -19
  74. package/dist/chunk-P7QYG4RZ.cjs.map +1 -0
  75. package/dist/chunk-PPU2D4FZ.js +19 -0
  76. package/dist/chunk-PPU2D4FZ.js.map +1 -0
  77. package/dist/{chunk-MS3TQSXU.js → chunk-QD6B6W6I.js} +6 -4
  78. package/dist/chunk-QD6B6W6I.js.map +1 -0
  79. package/dist/{chunk-AB4OPJLD.js → chunk-RGVMJU57.js} +3 -3
  80. package/dist/{chunk-AB4OPJLD.js.map → chunk-RGVMJU57.js.map} +1 -1
  81. package/dist/{chunk-NWWTYBD3.cjs → chunk-RTDVSHJR.cjs} +5 -5
  82. package/dist/{chunk-NWWTYBD3.cjs.map → chunk-RTDVSHJR.cjs.map} +1 -1
  83. package/dist/{chunk-5HSMH2ZZ.js → chunk-RZL2W4C3.js} +25 -17
  84. package/dist/chunk-RZL2W4C3.js.map +1 -0
  85. package/dist/chunk-SPEN7RJU.cjs +18 -0
  86. package/dist/{chunk-LO6LIUZ6.cjs.map → chunk-SPEN7RJU.cjs.map} +1 -1
  87. package/dist/{chunk-ZF2LDKQQ.cjs → chunk-U3DW3WDE.cjs} +9 -8
  88. package/dist/chunk-U3DW3WDE.cjs.map +1 -0
  89. package/dist/{chunk-DVP3YMDA.cjs → chunk-U7PRI3XM.cjs} +3 -3
  90. package/dist/{chunk-DVP3YMDA.cjs.map → chunk-U7PRI3XM.cjs.map} +1 -1
  91. package/dist/{chunk-H7G65PNI.js → chunk-VCQ37TC5.js} +3 -3
  92. package/dist/{chunk-H7G65PNI.js.map → chunk-VCQ37TC5.js.map} +1 -1
  93. package/dist/{chunk-SDZ4XDWS.cjs → chunk-VWYFGE27.cjs} +9 -9
  94. package/dist/{chunk-SDZ4XDWS.cjs.map → chunk-VWYFGE27.cjs.map} +1 -1
  95. package/dist/{chunk-RN3XDZGS.js → chunk-WM646HEN.js} +4 -3
  96. package/dist/chunk-WM646HEN.js.map +1 -0
  97. package/dist/chunk-X7CE7Y5W.js +305 -0
  98. package/dist/chunk-X7CE7Y5W.js.map +1 -0
  99. package/dist/{chunk-CGH4BCIY.cjs → chunk-XE3CAY6Z.cjs} +5 -5
  100. package/dist/{chunk-CGH4BCIY.cjs.map → chunk-XE3CAY6Z.cjs.map} +1 -1
  101. package/dist/chunk-XOU3CL7S.cjs +312 -0
  102. package/dist/chunk-XOU3CL7S.cjs.map +1 -0
  103. package/dist/{chunk-NKQVLWDF.js → chunk-YKNBTHMD.js} +3 -3
  104. package/dist/{chunk-NKQVLWDF.js.map → chunk-YKNBTHMD.js.map} +1 -1
  105. package/dist/{compact-session-B7P6EU3Z.cjs → compact-session-NX7HUNTB.cjs} +18 -18
  106. package/dist/{compact-session-B7P6EU3Z.cjs.map → compact-session-NX7HUNTB.cjs.map} +1 -1
  107. package/dist/{compact-session-5HMX6KYT.js → compact-session-Q5IGNFPW.js} +9 -9
  108. package/dist/{compact-session-5HMX6KYT.js.map → compact-session-Q5IGNFPW.js.map} +1 -1
  109. package/dist/{cron-BvxrLW5J.d.cts → cron-Bh3aWgQ2.d.cts} +2 -2
  110. package/dist/{cron-DdKzwJqK.d.ts → cron-CCDxeeFZ.d.ts} +2 -2
  111. package/dist/cron.cjs +21 -20
  112. package/dist/cron.d.cts +4 -3
  113. package/dist/cron.d.ts +4 -3
  114. package/dist/cron.js +20 -19
  115. package/dist/eval.cjs +20 -19
  116. package/dist/eval.cjs.map +1 -1
  117. package/dist/eval.js +19 -18
  118. package/dist/eval.js.map +1 -1
  119. package/dist/fs-session-store-CYNTEPJZ.cjs +20 -0
  120. package/dist/{fs-session-store-S2AXVJIX.cjs.map → fs-session-store-CYNTEPJZ.cjs.map} +1 -1
  121. package/dist/fs-session-store-MYQEVUFL.js +11 -0
  122. package/dist/{fs-session-store-6ZCCJX3K.js.map → fs-session-store-MYQEVUFL.js.map} +1 -1
  123. package/dist/{index-manager-HO456AVW.cjs → index-manager-2KH75BRW.cjs} +7 -7
  124. package/dist/{index-manager-HO456AVW.cjs.map → index-manager-2KH75BRW.cjs.map} +1 -1
  125. package/dist/{index-manager-QDH56FER.js → index-manager-NF2WRLOU.js} +6 -6
  126. package/dist/{index-manager-QDH56FER.js.map → index-manager-NF2WRLOU.js.map} +1 -1
  127. package/dist/index.cjs +93 -273
  128. package/dist/index.cjs.map +1 -1
  129. package/dist/index.d.cts +13 -46
  130. package/dist/index.d.ts +13 -46
  131. package/dist/index.js +52 -236
  132. package/dist/index.js.map +1 -1
  133. package/dist/{inject-session-75L3NCNL.js → inject-session-4ROYLZHY.js} +3 -3
  134. package/dist/{inject-session-75L3NCNL.js.map → inject-session-4ROYLZHY.js.map} +1 -1
  135. package/dist/{inject-session-WOH7TPDX.cjs → inject-session-AWKDCGHV.cjs} +4 -4
  136. package/dist/{inject-session-WOH7TPDX.cjs.map → inject-session-AWKDCGHV.cjs.map} +1 -1
  137. package/dist/internal/agent-loop/doom-loop-tracker.d.ts +3 -0
  138. package/dist/internal/agent-loop/prune-tool-results.d.ts +37 -0
  139. package/dist/internal/agent-loop/types.d.ts +6 -0
  140. package/dist/internal/auth/credential-store.d.ts +1 -1
  141. package/dist/internal/auth/types.d.ts +4 -0
  142. package/dist/internal/error-mappers/anthropic.d.ts +3 -0
  143. package/dist/internal/error-mappers/openai-compatible.d.ts +2 -3
  144. package/dist/internal/local-agent/local-agent-dispatch.d.ts +3 -1
  145. package/dist/internal/local-agent/send-queue.d.ts +31 -0
  146. package/dist/internal/mcp/client.d.ts +2 -0
  147. package/dist/internal/mcp/oauth-bearer.d.ts +2 -0
  148. package/dist/internal/memory/adapters/index.cjs +3 -3
  149. package/dist/internal/memory/adapters/index.js +2 -2
  150. package/dist/internal/memory/dreaming/phases.d.ts +15 -0
  151. package/dist/internal/memory/dreaming/run.d.ts +29 -0
  152. package/dist/internal/memory/sdk-memory-peer-loader.d.ts +2 -0
  153. package/dist/internal/memory/storage/index.cjs +51 -35
  154. package/dist/internal/memory/storage/index.d.cts +2 -0
  155. package/dist/internal/memory/storage/index.d.ts +2 -0
  156. package/dist/internal/memory/storage/index.js +4 -4
  157. package/dist/internal/persistence/cwd-mutex.d.cts +4 -2
  158. package/dist/internal/persistence/cwd-mutex.d.ts +4 -2
  159. package/dist/internal/persistence/index.cjs +4 -4
  160. package/dist/internal/persistence/index.js +2 -2
  161. package/dist/internal/persistence/sqlite-session-store.d.cts +25 -0
  162. package/dist/internal/persistence/sqlite-session-store.d.ts +25 -0
  163. package/dist/internal/providers/registry.d.ts +5 -1
  164. package/dist/internal/runtime/skills/binary-on-path.d.ts +1 -0
  165. package/dist/internal/runtime/skills/discover-skills.d.ts +2 -0
  166. package/dist/mcp-auth.cjs +25 -307
  167. package/dist/mcp-auth.cjs.map +1 -1
  168. package/dist/mcp-auth.js +5 -305
  169. package/dist/mcp-auth.js.map +1 -1
  170. package/dist/models.cjs +11 -11
  171. package/dist/models.js +4 -4
  172. package/dist/persistence.cjs +9 -4
  173. package/dist/persistence.cjs.map +1 -1
  174. package/dist/persistence.d.cts +744 -40
  175. package/dist/persistence.d.ts +744 -40
  176. package/dist/persistence.js +3 -2
  177. package/dist/persistence.js.map +1 -1
  178. package/dist/providers.cjs +6 -6
  179. package/dist/providers.js +4 -4
  180. package/dist/sandbox/docker-sandbox.d.cts +58 -0
  181. package/dist/sandbox/docker-sandbox.d.ts +58 -0
  182. package/dist/sandbox/index.cjs +129 -1
  183. package/dist/sandbox/index.cjs.map +1 -1
  184. package/dist/sandbox/index.d.cts +1 -0
  185. package/dist/sandbox/index.d.ts +1 -0
  186. package/dist/sandbox/index.js +132 -5
  187. package/dist/sandbox/index.js.map +1 -1
  188. package/dist/{sdk-agent-4-dXI2GS.d.cts → sdk-agent-BA_6_wtc.d.cts} +57 -4
  189. package/dist/{sdk-agent-CTOJlWA_.d.ts → sdk-agent-CnwPODYH.d.ts} +57 -4
  190. package/dist/session-store-Dh07jr9N.d.cts +209 -0
  191. package/dist/session-store-Dh07jr9N.d.ts +209 -0
  192. package/dist/skills.cjs +4 -4
  193. package/dist/skills.js +1 -1
  194. package/dist/sqlite-session-store-BbcpKY1L.d.ts +64 -0
  195. package/dist/sqlite-session-store-TKXtT4ON.d.cts +64 -0
  196. package/dist/subagents-loader-KLWF4QPD.cjs +16 -0
  197. package/dist/{subagents-loader-TXOA5EJJ.cjs.map → subagents-loader-KLWF4QPD.cjs.map} +1 -1
  198. package/dist/subagents-loader-SXETS2F2.js +7 -0
  199. package/dist/{subagents-loader-Z744TAKD.js.map → subagents-loader-SXETS2F2.js.map} +1 -1
  200. package/dist/subagents-loader.cjs +2 -2
  201. package/dist/subagents-loader.d.cts +3 -2
  202. package/dist/subagents-loader.d.ts +3 -2
  203. package/dist/subagents-loader.js +1 -1
  204. package/dist/types/agent.d.ts +20 -1
  205. package/dist/types/budget-tracker.d.ts +6 -2
  206. package/dist/types/mcp.d.ts +14 -0
  207. package/dist/types/run.d.ts +42 -3
  208. package/dist/workflow.d.cts +1 -1
  209. package/dist/workflow.d.ts +1 -1
  210. package/docs/adr/mutation-testing-scope.md +66 -0
  211. package/docs/error-codes.md +48 -45
  212. package/docs/harness-capability-map.md +60 -6
  213. package/package.json +1 -1
  214. package/dist/chunk-2PRGRYEQ.js.map +0 -1
  215. package/dist/chunk-3FSBE4PS.js.map +0 -1
  216. package/dist/chunk-4UYHP6NF.cjs.map +0 -1
  217. package/dist/chunk-5A4UFBHW.cjs.map +0 -1
  218. package/dist/chunk-5HSMH2ZZ.js.map +0 -1
  219. package/dist/chunk-6CXRYPG7.cjs +0 -211
  220. package/dist/chunk-6CXRYPG7.cjs.map +0 -1
  221. package/dist/chunk-7WARNHWW.cjs.map +0 -1
  222. package/dist/chunk-JX4LB6XO.js.map +0 -1
  223. package/dist/chunk-KL7ZUMK3.cjs.map +0 -1
  224. package/dist/chunk-LO6LIUZ6.cjs +0 -18
  225. package/dist/chunk-MS3TQSXU.js.map +0 -1
  226. package/dist/chunk-MSEL5E5P.js +0 -204
  227. package/dist/chunk-MSEL5E5P.js.map +0 -1
  228. package/dist/chunk-NHOEXFZT.js.map +0 -1
  229. package/dist/chunk-NP362THY.cjs.map +0 -1
  230. package/dist/chunk-Q5EWJPRY.js +0 -18
  231. package/dist/chunk-Q5EWJPRY.js.map +0 -1
  232. package/dist/chunk-QISSETTG.cjs.map +0 -1
  233. package/dist/chunk-RN3XDZGS.js.map +0 -1
  234. package/dist/chunk-S46WJTDL.cjs.map +0 -1
  235. package/dist/chunk-WDVG5R2Q.cjs.map +0 -1
  236. package/dist/chunk-ZF2LDKQQ.cjs.map +0 -1
  237. package/dist/chunk-ZJAYFSVI.js.map +0 -1
  238. package/dist/fs-session-store-6ZCCJX3K.js +0 -11
  239. package/dist/fs-session-store-S2AXVJIX.cjs +0 -20
  240. package/dist/subagents-loader-TXOA5EJJ.cjs +0 -16
  241. package/dist/subagents-loader-Z744TAKD.js +0 -7
@@ -1,25 +1,26 @@
1
- export { Agent } from './chunk-JX4LB6XO.js';
1
+ export { Agent } from './chunk-5M5GQYBM.js';
2
2
  import './chunk-HWMGR3HA.js';
3
- import './chunk-XOYNB3YN.js';
3
+ import './chunk-23SS4ID4.js';
4
4
  import './chunk-K2BQQ445.js';
5
- import './chunk-2C24NSNV.js';
5
+ import './chunk-3BBTHFGJ.js';
6
6
  import './chunk-HJ2LV464.js';
7
7
  import './chunk-2SFBB54R.js';
8
- import './chunk-H7G65PNI.js';
8
+ import './chunk-VCQ37TC5.js';
9
9
  import './chunk-H73MEMQB.js';
10
10
  import './chunk-QK2ERTO3.js';
11
- import './chunk-DF77RBF4.js';
12
- import './chunk-AB4OPJLD.js';
13
- import './chunk-2PRGRYEQ.js';
14
- import './chunk-5AR6O7GW.js';
11
+ import './chunk-LCCT5ZXJ.js';
12
+ import './chunk-RGVMJU57.js';
13
+ import './chunk-IOBHFP2E.js';
14
+ import './chunk-NK5EOTDY.js';
15
15
  import './chunk-2XC6KDJM.js';
16
- import './chunk-ZJAYFSVI.js';
16
+ import './chunk-7ACS6P5Z.js';
17
17
  import './chunk-24MGQDK3.js';
18
18
  import './chunk-AGO5S5WD.js';
19
19
  import './chunk-HKCKOAIO.js';
20
20
  import './chunk-KCM3RMKR.js';
21
21
  import './chunk-XJ3WU5CZ.js';
22
22
  import './chunk-KVNWIAO4.js';
23
+ import './chunk-X7CE7Y5W.js';
23
24
  import './chunk-OLJOI4LK.js';
24
25
  import './chunk-FD2UT76F.js';
25
26
  import './chunk-7I5Z3UBJ.js';
@@ -27,7 +28,7 @@ import './chunk-FJWQP6EE.js';
27
28
  import './chunk-NAF4L3T6.js';
28
29
  import './chunk-VZGE7NAI.js';
29
30
  import './chunk-6X6ID4MO.js';
30
- import './chunk-NHOEXFZT.js';
31
+ import './chunk-2HXTNVLM.js';
31
32
  import './chunk-4QCJAJAG.js';
32
33
  import './chunk-SAGRF4IB.js';
33
34
  import './chunk-PKRPV3R7.js';
@@ -39,24 +40,24 @@ import './chunk-XESYJ4JC.js';
39
40
  import './chunk-WE22OXQA.js';
40
41
  import './chunk-MLJDW2YK.js';
41
42
  import './chunk-KU5O7WPK.js';
42
- import './chunk-354F3OF5.js';
43
- import './chunk-Q5EWJPRY.js';
43
+ import './chunk-FGGVSHDW.js';
44
+ import './chunk-PPU2D4FZ.js';
44
45
  import './chunk-MLGETTYX.js';
45
46
  import './chunk-M4U24U6G.js';
46
- import './chunk-RN3XDZGS.js';
47
+ import './chunk-WM646HEN.js';
47
48
  import './chunk-YMVTUV5K.js';
48
49
  import './chunk-Q7UG242V.js';
49
50
  import './chunk-SZQFCHU6.js';
50
- import './chunk-2SFLLOMN.js';
51
+ import './chunk-CBBT42VX.js';
51
52
  import './chunk-R7WIIPUR.js';
52
- import './chunk-NKQVLWDF.js';
53
- import './chunk-5HSMH2ZZ.js';
53
+ import './chunk-YKNBTHMD.js';
54
+ import './chunk-RZL2W4C3.js';
54
55
  import './chunk-AGACYRJ2.js';
55
- import './chunk-3FSBE4PS.js';
56
- import './chunk-MS3TQSXU.js';
56
+ import './chunk-3GTN4HOO.js';
57
+ import './chunk-QD6B6W6I.js';
57
58
  import './chunk-5IUDICRK.js';
58
59
  import './chunk-Q7GYMXVC.js';
59
60
  import './chunk-TNFOU6SB.js';
60
61
  import './chunk-3OY6H3I7.js';
61
- //# sourceMappingURL=agent-5DSDDH7K.js.map
62
- //# sourceMappingURL=agent-5DSDDH7K.js.map
62
+ //# sourceMappingURL=agent-DRDGUU6T.js.map
63
+ //# sourceMappingURL=agent-DRDGUU6T.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"agent-5DSDDH7K.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"agent-DRDGUU6T.js"}
@@ -1,27 +1,28 @@
1
1
  'use strict';
2
2
 
3
- var chunkKL7ZUMK3_cjs = require('./chunk-KL7ZUMK3.cjs');
3
+ var chunk64ECM3XM_cjs = require('./chunk-64ECM3XM.cjs');
4
4
  require('./chunk-L7JPXZ2C.cjs');
5
- require('./chunk-DVP3YMDA.cjs');
5
+ require('./chunk-U7PRI3XM.cjs');
6
6
  require('./chunk-BUUUWQMB.cjs');
7
- require('./chunk-CWQPQTUZ.cjs');
7
+ require('./chunk-NEH3BPFD.cjs');
8
8
  require('./chunk-7YUPSBDV.cjs');
9
9
  require('./chunk-BV2MWEMV.cjs');
10
- require('./chunk-CGH4BCIY.cjs');
10
+ require('./chunk-XE3CAY6Z.cjs');
11
11
  require('./chunk-GHX4P3V2.cjs');
12
12
  require('./chunk-RS7YQR4X.cjs');
13
- require('./chunk-SDZ4XDWS.cjs');
14
- require('./chunk-6OCJWGVD.cjs');
15
- require('./chunk-4UYHP6NF.cjs');
16
- require('./chunk-SXH37C7X.cjs');
13
+ require('./chunk-VWYFGE27.cjs');
14
+ require('./chunk-FTXY4D44.cjs');
15
+ require('./chunk-DJKGDLYZ.cjs');
16
+ require('./chunk-55LLQFHW.cjs');
17
17
  require('./chunk-YJNYDJ2T.cjs');
18
- require('./chunk-NP362THY.cjs');
18
+ require('./chunk-3F53FLQ7.cjs');
19
19
  require('./chunk-QOGNZMHD.cjs');
20
20
  require('./chunk-MSW7LB2V.cjs');
21
21
  require('./chunk-2ZPEDVLM.cjs');
22
22
  require('./chunk-QG4SXZ2A.cjs');
23
23
  require('./chunk-UDAKAE4Z.cjs');
24
24
  require('./chunk-KRD3GQAA.cjs');
25
+ require('./chunk-XOU3CL7S.cjs');
25
26
  require('./chunk-3HA7N2BB.cjs');
26
27
  require('./chunk-MUUQ2WFJ.cjs');
27
28
  require('./chunk-AA27GEYS.cjs');
@@ -29,7 +30,7 @@ require('./chunk-YSTXFWQE.cjs');
29
30
  require('./chunk-FRITRLZQ.cjs');
30
31
  require('./chunk-H7HD6RXO.cjs');
31
32
  require('./chunk-NINIJCHU.cjs');
32
- require('./chunk-7WARNHWW.cjs');
33
+ require('./chunk-3UMPP553.cjs');
33
34
  require('./chunk-SWALPLFQ.cjs');
34
35
  require('./chunk-IJ7M6GOG.cjs');
35
36
  require('./chunk-3KIUY67P.cjs');
@@ -41,21 +42,21 @@ require('./chunk-3WKWBYPO.cjs');
41
42
  require('./chunk-A4RAL2ER.cjs');
42
43
  require('./chunk-AT2PESXB.cjs');
43
44
  require('./chunk-POBZXULR.cjs');
44
- require('./chunk-G7XBVM3T.cjs');
45
- require('./chunk-ZF2LDKQQ.cjs');
45
+ require('./chunk-MHUOVS5I.cjs');
46
+ require('./chunk-U3DW3WDE.cjs');
46
47
  require('./chunk-BWYC7RZG.cjs');
47
48
  require('./chunk-ZOFRNNZD.cjs');
48
- require('./chunk-WDVG5R2Q.cjs');
49
+ require('./chunk-AUH2EVWY.cjs');
49
50
  require('./chunk-YQ3XC6C2.cjs');
50
51
  require('./chunk-6XQLTQB6.cjs');
51
52
  require('./chunk-KX5QXLBS.cjs');
52
- require('./chunk-NWWTYBD3.cjs');
53
+ require('./chunk-RTDVSHJR.cjs');
53
54
  require('./chunk-3EE6LVWT.cjs');
54
- require('./chunk-LO6LIUZ6.cjs');
55
- require('./chunk-S46WJTDL.cjs');
55
+ require('./chunk-SPEN7RJU.cjs');
56
+ require('./chunk-P7QYG4RZ.cjs');
56
57
  require('./chunk-NVXXWAU7.cjs');
57
- require('./chunk-5A4UFBHW.cjs');
58
- require('./chunk-QISSETTG.cjs');
58
+ require('./chunk-A77UMVMD.cjs');
59
+ require('./chunk-5645PMVU.cjs');
59
60
  require('./chunk-IOFMRS6T.cjs');
60
61
  require('./chunk-EHD25JBZ.cjs');
61
62
  require('./chunk-CEGU5AVD.cjs');
@@ -65,7 +66,7 @@ require('./chunk-RNXXYF22.cjs');
65
66
 
66
67
  Object.defineProperty(exports, "Agent", {
67
68
  enumerable: true,
68
- get: function () { return chunkKL7ZUMK3_cjs.Agent; }
69
+ get: function () { return chunk64ECM3XM_cjs.Agent; }
69
70
  });
70
- //# sourceMappingURL=agent-WOMRT3KX.cjs.map
71
- //# sourceMappingURL=agent-WOMRT3KX.cjs.map
71
+ //# sourceMappingURL=agent-VI2HITPT.cjs.map
72
+ //# sourceMappingURL=agent-VI2HITPT.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"agent-WOMRT3KX.cjs"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"agent-VI2HITPT.cjs"}
package/dist/agent.d.ts CHANGED
@@ -152,9 +152,8 @@ export declare class Agent {
152
152
  * The agent-builder's M85 interrupt rotates the session id to work around a
153
153
  * constraint that does not exist.
154
154
  *
155
- * - `close()` marks the handle disposed WITHOUT evicting the cache entry. It is
156
- * internal and unused today; if it becomes reachable, this bullet stops being true
157
- * for that path.
155
+ * - `close()` marks the handle disposed AND drops its cache entry, so the next call
156
+ * builds a fresh handle.
158
157
  *
159
158
  * @public
160
159
  */
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkFRITRLZQ_cjs = require('../chunk-FRITRLZQ.cjs');
4
- var chunk5A4UFBHW_cjs = require('../chunk-5A4UFBHW.cjs');
5
- var chunkQISSETTG_cjs = require('../chunk-QISSETTG.cjs');
4
+ var chunkA77UMVMD_cjs = require('../chunk-A77UMVMD.cjs');
5
+ var chunk5645PMVU_cjs = require('../chunk-5645PMVU.cjs');
6
6
  var chunkIOFMRS6T_cjs = require('../chunk-IOFMRS6T.cjs');
7
7
  require('../chunk-EHD25JBZ.cjs');
8
8
  require('../chunk-CEGU5AVD.cjs');
@@ -104,7 +104,8 @@ async function pollDeviceToken(config, grant, deps) {
104
104
  // token as the refresh handle.
105
105
  refresh: data.refresh_token ?? data.access_token,
106
106
  expires: deps.now() + expiresIn * 1e3,
107
- ...accountId !== void 0 ? { accountId } : {}
107
+ ...accountId !== void 0 ? { accountId } : {},
108
+ ...typeof data.id_token === "string" && data.id_token.length > 0 ? { idToken: data.id_token } : {}
108
109
  };
109
110
  }
110
111
  if (data.error === "authorization_pending") {
@@ -202,7 +203,7 @@ async function openaiDeviceLogin(config, deps, hooks) {
202
203
  "device poll returned no authorization_code"
203
204
  );
204
205
  }
205
- const tokens = await chunk5A4UFBHW_cjs.exchangeCode(
206
+ const tokens = await chunkA77UMVMD_cjs.exchangeCode(
206
207
  config,
207
208
  { code: data.authorization_code, verifier: data.code_verifier },
208
209
  deps
@@ -250,51 +251,51 @@ Object.defineProperty(exports, "providerFromApiKeyPrefix", {
250
251
  });
251
252
  Object.defineProperty(exports, "ensureFreshCredential", {
252
253
  enumerable: true,
253
- get: function () { return chunk5A4UFBHW_cjs.ensureFreshCredential; }
254
+ get: function () { return chunkA77UMVMD_cjs.ensureFreshCredential; }
254
255
  });
255
256
  Object.defineProperty(exports, "exchangeCode", {
256
257
  enumerable: true,
257
- get: function () { return chunk5A4UFBHW_cjs.exchangeCode; }
258
+ get: function () { return chunkA77UMVMD_cjs.exchangeCode; }
258
259
  });
259
260
  Object.defineProperty(exports, "persistOAuthTokens", {
260
261
  enumerable: true,
261
- get: function () { return chunk5A4UFBHW_cjs.persistOAuthTokens; }
262
+ get: function () { return chunkA77UMVMD_cjs.persistOAuthTokens; }
262
263
  });
263
264
  Object.defineProperty(exports, "refreshOAuthTokens", {
264
265
  enumerable: true,
265
- get: function () { return chunk5A4UFBHW_cjs.refreshOAuthTokens; }
266
+ get: function () { return chunkA77UMVMD_cjs.refreshOAuthTokens; }
266
267
  });
267
268
  Object.defineProperty(exports, "resolveCredential", {
268
269
  enumerable: true,
269
- get: function () { return chunk5A4UFBHW_cjs.resolveCredential; }
270
+ get: function () { return chunkA77UMVMD_cjs.resolveCredential; }
270
271
  });
271
272
  Object.defineProperty(exports, "CredentialError", {
272
273
  enumerable: true,
273
- get: function () { return chunkQISSETTG_cjs.CredentialError; }
274
+ get: function () { return chunk5645PMVU_cjs.CredentialError; }
274
275
  });
275
276
  Object.defineProperty(exports, "assertSecureModes", {
276
277
  enumerable: true,
277
- get: function () { return chunkQISSETTG_cjs.assertSecureModes; }
278
+ get: function () { return chunk5645PMVU_cjs.assertSecureModes; }
278
279
  });
279
280
  Object.defineProperty(exports, "authFilePath", {
280
281
  enumerable: true,
281
- get: function () { return chunkQISSETTG_cjs.authFilePath; }
282
+ get: function () { return chunk5645PMVU_cjs.authFilePath; }
282
283
  });
283
284
  Object.defineProperty(exports, "credentialHome", {
284
285
  enumerable: true,
285
- get: function () { return chunkQISSETTG_cjs.credentialHome; }
286
+ get: function () { return chunk5645PMVU_cjs.credentialHome; }
286
287
  });
287
288
  Object.defineProperty(exports, "readAuthFile", {
288
289
  enumerable: true,
289
- get: function () { return chunkQISSETTG_cjs.readAuthFile; }
290
+ get: function () { return chunk5645PMVU_cjs.readAuthFile; }
290
291
  });
291
292
  Object.defineProperty(exports, "readStoredOAuth", {
292
293
  enumerable: true,
293
- get: function () { return chunkQISSETTG_cjs.readStoredOAuth; }
294
+ get: function () { return chunk5645PMVU_cjs.readStoredOAuth; }
294
295
  });
295
296
  Object.defineProperty(exports, "writeCredential", {
296
297
  enumerable: true,
297
- get: function () { return chunkQISSETTG_cjs.writeCredential; }
298
+ get: function () { return chunk5645PMVU_cjs.writeCredential; }
298
299
  });
299
300
  exports.deviceLogin = deviceLogin;
300
301
  exports.extractAccountId = extractAccountId;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/internal/auth/oauth-device.ts"],"names":["AuthCallbackError","exchangeCode"],"mappings":";;;;;;;;;;;AA0BA,IAAM,wBAAA,GAA2B,GAAA;AAejC,eAAe,eAAA,CAAgB,GAAA,EAAe,IAAA,EAAc,IAAA,EAAgC;AAC1F,EAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,EACxB,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAIA,mCAAA,CAAkB,IAAA,EAAM,CAAA,EAAG,IAAI,CAAA,2BAAA,EAA8B,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,GAAG,CAAC,CAAA,CAAE,CAAA;AAAA,EAC7F;AACF;AAIA,eAAsB,iBAAA,CACpB,QACA,IAAA,EAC0B;AAC1B,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,kBAAA,EAAoB;AAAA,MAChD,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,mCAAA,EAAqC,QAAQ,kBAAA,EAAmB;AAAA,MAC3F,IAAA,EAAM,IAAI,eAAA,CAAgB;AAAA,QACxB,WAAW,MAAA,CAAO,QAAA;AAAA,QAClB,KAAA,EAAO,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,GAAG;AAAA,OAC9B,EAAE,QAAA;AAAS,KACb,CAAA;AAAA,EACH,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,IAAIA,mCAAA;AAAA,MACR,mCAAA;AAAA,MACA,CAAA,uBAAA,EAA2B,IAAc,OAAO,CAAA;AAAA,KAClD;AAAA,EACF;AACA,EAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,IAAA,MAAM,IAAIA,mCAAA;AAAA,MACR,mCAAA;AAAA,MACA,CAAA,8BAAA,EAAiC,IAAI,MAAM,CAAA;AAAA,KAC7C;AAAA,EACF;AACA,EAAA,MAAM,OAAQ,MAAM,eAAA;AAAA,IAClB,GAAA;AAAA,IACA,mCAAA;AAAA,IACA;AAAA,GACF;AAQA,EAAA,IAAI,OAAO,IAAA,CAAK,WAAA,KAAgB,YAAY,OAAO,IAAA,CAAK,cAAc,QAAA,EAAU;AAC9E,IAAA,MAAM,IAAIA,mCAAA;AAAA,MACR,mCAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AACA,EAAA,MAAM,YAAA,GACJ,OAAO,IAAA,CAAK,gBAAA,KAAqB,QAAA,GAC7B,IAAA,CAAK,gBAAA,GACL,OAAO,IAAA,CAAK,yBAAA,KAA8B,QAAA,GACxC,IAAA,CAAK,yBAAA,GACL,EAAA;AACR,EAAA,OAAO;AAAA,IACL,YAAY,IAAA,CAAK,WAAA;AAAA,IACjB,UAAU,IAAA,CAAK,SAAA;AAAA,IACf,eAAA,EAAiB,YAAA;AAAA,IACjB,QAAA,EAAU,OAAO,IAAA,CAAK,QAAA,KAAa,YAAY,IAAA,CAAK,QAAA,GAAW,CAAA,GAAI,IAAA,CAAK,QAAA,GAAW,CAAA;AAAA,IACnF,SAAA,EAAW,OAAO,IAAA,CAAK,UAAA,KAAe,YAAY,IAAA,CAAK,UAAA,GAAa,CAAA,GAAI,IAAA,CAAK,UAAA,GAAa;AAAA,GAC5F;AACF;AAQA,eAAsB,eAAA,CACpB,MAAA,EACA,KAAA,EACA,IAAA,EACsB;AACtB,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI,GAAI,MAAM,SAAA,GAAY,GAAA;AAChD,EAAA,IAAI,UAAA,GAAa,MAAM,QAAA,GAAW,GAAA;AAElC,EAAA,OAAO,IAAA,CAAK,GAAA,EAAI,GAAI,QAAA,EAAU;AAC5B,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACF,MAAA,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,aAAA,EAAe;AAAA,QAC3C,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS;AAAA,UACP,cAAA,EAAgB,mCAAA;AAAA,UAChB,MAAA,EAAQ;AAAA,SACV;AAAA,QACA,IAAA,EAAM,IAAI,eAAA,CAAgB;AAAA,UACxB,WAAW,MAAA,CAAO,QAAA;AAAA,UAClB,aAAa,KAAA,CAAM,UAAA;AAAA,UACnB,UAAA,EAAY;AAAA,SACb,EAAE,QAAA;AAAS,OACb,CAAA;AAAA,IACH,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,IAAIA,mCAAA;AAAA,QACR,6BAAA;AAAA,QACA,CAAA,0BAAA,EAA8B,IAAc,OAAO,CAAA;AAAA,OACrD;AAAA,IACF;AAGA,IAAA,MAAM,IAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,GAAO,KAAA,CAAM,OAAO,EAAC,CAAE,CAAA;AAQ/C,IAAA,IAAI,CAAC,GAAA,CAAI,EAAA,IAAM,OAAO,IAAA,CAAK,UAAU,QAAA,EAAU;AAC7C,MAAA,MAAM,IAAIA,mCAAA;AAAA,QACR,6BAAA;AAAA,QACA,CAAA,oCAAA,EAAuC,IAAI,MAAM,CAAA;AAAA,OACnD;AAAA,IACF;AAEA,IAAA,IAAI,OAAO,IAAA,CAAK,YAAA,KAAiB,YAAY,IAAA,CAAK,YAAA,CAAa,SAAS,CAAA,EAAG;AACzE,MAAA,MAAM,YAAY,OAAO,IAAA,CAAK,UAAA,KAAe,QAAA,GAAW,KAAK,UAAA,GAAa,CAAA;AAC1E,MAAA,MAAM,YAAY,gBAAA,CAAiB;AAAA,QACjC,cAAc,IAAA,CAAK,YAAA;AAAA,QACnB,UAAU,IAAA,CAAK;AAAA,OAChB,CAAA;AACD,MAAA,OAAO;AAAA,QACL,QAAQ,IAAA,CAAK,YAAA;AAAA;AAAA;AAAA,QAGb,OAAA,EAAS,IAAA,CAAK,aAAA,IAAiB,IAAA,CAAK,YAAA;AAAA,QACpC,OAAA,EAAS,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA,GAAY,GAAA;AAAA,QAClC,GAAI,SAAA,KAAc,MAAA,GAAY,EAAE,SAAA,KAAc;AAAC,OACjD;AAAA,IACF;AAEA,IAAA,IAAI,IAAA,CAAK,UAAU,uBAAA,EAAyB;AAC1C,MAAA,MAAM,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,wBAAwB,CAAA;AACtD,MAAA;AAAA,IACF;AACA,IAAA,IAAI,IAAA,CAAK,UAAU,WAAA,EAAa;AAE9B,MAAA,UAAA,GAAA,CACG,OAAO,IAAA,CAAK,QAAA,KAAa,QAAA,IAAY,IAAA,CAAK,QAAA,GAAW,CAAA,GAClD,IAAA,CAAK,QAAA,GACL,KAAA,CAAM,QAAA,GAAW,CAAA,IAAK,GAAA;AAC5B,MAAA,MAAM,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,wBAAwB,CAAA;AACtD,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAO,IAAA,CAAK,KAAA,KAAU,QAAA,EAAU;AAClC,MAAA,MAAM,IAAIA,mCAAA;AAAA,QACR,6BAAA;AAAA,QACA,CAAA,+BAAA,EAAkC,KAAK,KAAK,CAAA;AAAA,OAC9C;AAAA,IACF;AACA,IAAA,MAAM,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,wBAAwB,CAAA;AAAA,EACxD;AACA,EAAA,MAAM,IAAIA,mCAAA;AAAA,IACR,2BAAA;AAAA,IACA;AAAA,GACF;AACF;AAMA,eAAsB,WAAA,CACpB,MAAA,EACA,IAAA,EACA,KAAA,EAGsB;AACtB,EAAA,MAAM,KAAA,GAAQ,MAAM,iBAAA,CAAkB,MAAA,EAAQ,IAAI,CAAA;AAClD,EAAA,KAAA,CAAM,QAAA,CAAS;AAAA,IACb,UAAU,KAAA,CAAM,QAAA;AAAA,IAChB,iBAAiB,KAAA,CAAM,eAAA;AAAA,IACvB,WAAW,KAAA,CAAM;AAAA,GAClB,CAAA;AACD,EAAA,OAAO,eAAA,CAAgB,MAAA,EAAQ,KAAA,EAAO,IAAI,CAAA;AAC5C;AAKA,eAAsB,qBAAA,CACpB,QACA,IAAA,EACuE;AACvE,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,sBAAA,EAAwB;AAAA,MACpD,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,QAAQ,kBAAA,EAAmB;AAAA,MAC1E,MAAM,IAAA,CAAK,SAAA,CAAU,EAAE,SAAA,EAAW,MAAA,CAAO,UAAU;AAAA,KACpD,CAAA;AAAA,EACH,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,IAAIA,mCAAA;AAAA,MACR,mCAAA;AAAA,MACA,CAAA,yBAAA,EAA6B,IAAc,OAAO,CAAA;AAAA,KACpD;AAAA,EACF;AACA,EAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,IAAA,MAAM,IAAIA,mCAAA;AAAA,MACR,mCAAA;AAAA,MACA,CAAA,gCAAA,EAAmC,IAAI,MAAM,CAAA;AAAA,KAC/C;AAAA,EACF;AACA,EAAA,MAAM,OAAQ,MAAM,eAAA;AAAA,IAClB,GAAA;AAAA,IACA,mCAAA;AAAA,IACA;AAAA,GACF;AAKA,EAAA,IAAI,OAAO,IAAA,CAAK,cAAA,KAAmB,YAAY,OAAO,IAAA,CAAK,cAAc,QAAA,EAAU;AACjF,IAAA,MAAM,IAAIA,mCAAA;AAAA,MACR,mCAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AACA,EAAA,MAAM,WAAW,IAAA,CAAK,GAAA;AAAA,IACpB,OAAO,KAAK,QAAA,KAAa,QAAA,GAAW,SAAS,IAAA,CAAK,QAAA,EAAU,EAAE,CAAA,IAAK,CAAA,GAAI,CAAA;AAAA,IACvE;AAAA,GACF;AACA,EAAA,OAAO,EAAE,YAAA,EAAc,IAAA,CAAK,gBAAgB,QAAA,EAAU,IAAA,CAAK,WAAW,QAAA,EAAS;AACjF;AAOA,eAAsB,iBAAA,CACpB,MAAA,EACA,IAAA,EACA,KAAA,EACsB;AACtB,EAAA,MAAM,EAAE,cAAc,QAAA,EAAU,QAAA,KAAa,MAAM,qBAAA,CAAsB,QAAQ,IAAI,CAAA;AACrF,EAAA,KAAA,CAAM,SAAS,EAAE,QAAA,EAAU,eAAA,EAAiB,MAAA,CAAO,iBAAiB,CAAA;AAEpE,EAAA,MAAM,aAAa,QAAA,GAAW,GAAA;AAE9B,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI,GAAI,KAAK,EAAA,GAAK,GAAA;AACxC,EAAA,OAAO,IAAA,CAAK,GAAA,EAAI,GAAI,QAAA,EAAU;AAC5B,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACF,MAAA,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,kBAAA,EAAoB;AAAA,QAChD,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,QAAQ,kBAAA,EAAmB;AAAA,QAC1E,IAAA,EAAM,KAAK,SAAA,CAAU,EAAE,gBAAgB,YAAA,EAAc,SAAA,EAAW,UAAU;AAAA,OAC3E,CAAA;AAAA,IACH,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,IAAIA,mCAAA;AAAA,QACR,6BAAA;AAAA,QACA,CAAA,oBAAA,EAAwB,IAAc,OAAO,CAAA;AAAA,OAC/C;AAAA,IACF;AACA,IAAA,IAAI,IAAI,EAAA,EAAI;AACV,MAAA,MAAM,IAAA,GAAQ,MAAM,eAAA,CAAgB,GAAA,EAAK,+BAA+B,aAAa,CAAA;AAIrF,MAAA,IAAI,OAAO,IAAA,CAAK,kBAAA,KAAuB,YAAY,OAAO,IAAA,CAAK,kBAAkB,QAAA,EAAU;AACzF,QAAA,MAAM,IAAIA,mCAAA;AAAA,UACR,6BAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AACA,MAAA,MAAM,SAAS,MAAMC,8BAAA;AAAA,QACnB,MAAA;AAAA,QACA,EAAE,IAAA,EAAM,IAAA,CAAK,kBAAA,EAAoB,QAAA,EAAU,KAAK,aAAA,EAAc;AAAA,QAC9D;AAAA,OACF;AAIA,MAAA,OAAO;AAAA,QACL,GAAG,MAAA;AAAA,QACH,SAAA,EAAW,OAAO,SAAA,IAAa,gBAAA,CAAiB,EAAE,YAAA,EAAc,MAAA,CAAO,QAAQ;AAAA,OACjF;AAAA,IACF;AAEA,IAAA,IAAI,GAAA,CAAI,MAAA,KAAW,GAAA,IAAO,GAAA,CAAI,WAAW,GAAA,EAAK;AAC5C,MAAA,MAAM,IAAID,mCAAA;AAAA,QACR,6BAAA;AAAA,QACA,CAAA,0BAAA,EAA6B,IAAI,MAAM,CAAA;AAAA,OACzC;AAAA,IACF;AACA,IAAA,MAAM,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,wBAAwB,CAAA;AAAA,EACxD;AACA,EAAA,MAAM,IAAIA,mCAAA;AAAA,IACR,2BAAA;AAAA,IACA;AAAA,GACF;AACF;AAUO,SAAS,eAAe,KAAA,EAA0C;AACvE,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA;AAC7B,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AAC/B,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,EAAa,WAAW,CAAA,CAAE,QAAA,EAAU,CAAA;AAAA,EAC3E,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAGO,SAAS,iBAAiB,MAAA,EAGV;AACrB,EAAA,KAAA,MAAW,SAAS,CAAC,MAAA,CAAO,QAAA,EAAU,MAAA,CAAO,YAAY,CAAA,EAAG;AAC1D,IAAA,IAAI,UAAU,MAAA,EAAW;AACzB,IAAA,MAAM,MAAA,GAAS,eAAe,KAAK,CAAA;AACnC,IAAA,MAAM,EAAA,GACJ,MAAA,EAAQ,kBAAA,IACR,MAAA,GAAS,6BAA6B,GAAG,kBAAA,IACzC,MAAA,EAAQ,aAAA,GAAgB,CAAC,CAAA,EAAG,EAAA;AAC9B,IAAA,IAAI,EAAA,KAAO,QAAW,OAAO,EAAA;AAAA,EAC/B;AACA,EAAA,OAAO,MAAA;AACT","file":"index.cjs","sourcesContent":["/**\n * M42 — the SDK OAuth device-authorization flows (RFC 8628 + OpenAI two-step headless). Split out of\n * oauth-engine.ts to respect the 500-line file budget; a sibling of the core engine. Promoted DOWN from\n * agent-builder's hardened `agents/lib/oauth-device.ts` (M37).\n *\n * Implements two device flows against their published specs: the RFC 8628 device-grant poll loop\n * (device_code → authorization_pending / slow_down) and OpenAI's two-step headless flow, including the\n * JWT-claim / account-id extraction used to attribute an account.\n * Design choices: network I/O + clock + sleep are INJECTED (deterministic tests), failures raise the SDK's\n * typed `AuthCallbackError`, and a device-code expiry DEADLINE guards each poll loop.\n *\n * @internal\n */\nimport { AuthCallbackError } from \"../../server/auth/errors.js\";\nimport { exchangeCode } from \"./oauth-engine.js\";\nimport type {\n DeviceCodeGrant,\n DeviceDeps,\n DeviceOAuthConfig,\n OAuthTokens,\n OpenAIDeviceConfig,\n} from \"./types.js\";\n\n// ─── OAuth 2.0 Device Authorization Grant (RFC 8628) — terminal-first / headless login ───\n\n/** Buffer added to every poll interval to avoid hitting the server a hair early. */\nconst POLLING_SAFETY_MARGIN_MS = 3000;\n\n/**\n * Parse a JSON body, or fail with this module's typed error instead of a raw `SyntaxError`.\n *\n * Every failure in this file is supposed to reach the caller as an `AuthCallbackError` carrying a code\n * the CLI can branch on. `res.json()` breaks that contract: a device endpoint that answers with HTML —\n * a captive portal, a corporate proxy's sign-in page, a load balancer's error page — makes it reject\n * with a `SyntaxError` that no `catch` here handles, so it escapes untyped past a caller prepared only\n * for `AuthCallbackError`.\n *\n * The body is quoted, truncated, because \"not JSON\" and \"not JSON, and it looks like a proxy login\n * page\" are different diagnoses for whoever is holding the terminal — and routing them to the provider\n * when the fault is their network is the expensive kind of wrong.\n */\nasync function parseJsonOrFail(res: Response, code: string, what: string): Promise<unknown> {\n const text = await res.text().catch(() => \"\");\n try {\n return JSON.parse(text);\n } catch {\n throw new AuthCallbackError(code, `${what} returned a non-JSON body: ${text.slice(0, 120)}`);\n }\n}\n\n/** Step 1 — request a device code. POSTs `{client_id, scope}` to the device endpoint. */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: RFC 8628 device-code request — cohesive network response parser ported verbatim (ADR D3).\nexport async function requestDeviceCode(\n config: DeviceOAuthConfig,\n deps: Pick<DeviceDeps, \"fetch\">,\n): Promise<DeviceCodeGrant> {\n let res: Response;\n try {\n res = await deps.fetch(config.deviceCodeEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\", accept: \"application/json\" },\n body: new URLSearchParams({\n client_id: config.clientId,\n scope: config.scopes.join(\" \"),\n }).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `device request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `device endpoint returned HTTP ${res.status}`,\n );\n }\n const data = (await parseJsonOrFail(\n res,\n \"oauth_device_authorization_failed\",\n \"device endpoint\",\n )) as {\n device_code?: unknown;\n user_code?: unknown;\n verification_uri?: unknown;\n verification_uri_complete?: unknown;\n interval?: unknown;\n expires_in?: unknown;\n };\n if (typeof data.device_code !== \"string\" || typeof data.user_code !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n \"device response missing device_code/user_code\",\n );\n }\n const verification =\n typeof data.verification_uri === \"string\"\n ? data.verification_uri\n : typeof data.verification_uri_complete === \"string\"\n ? data.verification_uri_complete\n : \"\";\n return {\n deviceCode: data.device_code,\n userCode: data.user_code,\n verificationUri: verification,\n interval: typeof data.interval === \"number\" && data.interval > 0 ? data.interval : 5,\n expiresIn: typeof data.expires_in === \"number\" && data.expires_in > 0 ? data.expires_in : 900,\n };\n}\n\n/**\n * Step 2 — poll the token endpoint until the user approves (or the code expires). Handles RFC 8628\n * `authorization_pending` (keep waiting) and `slow_down` (back off), with an expiry deadline so it cannot\n * spin forever.\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: RFC 8628 poll state machine (authorization_pending / slow_down / success / expiry) — a cohesive loop ported verbatim (ADR D3); fragmenting it would obscure the protocol.\nexport async function pollDeviceToken(\n config: DeviceOAuthConfig,\n grant: DeviceCodeGrant,\n deps: DeviceDeps,\n): Promise<OAuthTokens> {\n const deadline = deps.now() + grant.expiresIn * 1000;\n let intervalMs = grant.interval * 1000;\n\n while (deps.now() < deadline) {\n let res: Response;\n try {\n res = await deps.fetch(config.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n accept: \"application/json\",\n },\n body: new URLSearchParams({\n client_id: config.clientId,\n device_code: grant.deviceCode,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device token poll failed: ${(err as Error).message}`,\n );\n }\n // RFC 8628 §3.5: `authorization_pending` / `slow_down` arrive as a 400 with an `error` body — so the\n // body MUST be read before deciding failure. Parse first; only a non-OAuth-shaped body on a non-2xx fails.\n const data = (await res.json().catch(() => ({}))) as {\n access_token?: string;\n refresh_token?: string;\n expires_in?: number;\n id_token?: string;\n error?: string;\n interval?: number;\n };\n if (!res.ok && typeof data.error !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device token endpoint returned HTTP ${res.status}`,\n );\n }\n\n if (typeof data.access_token === \"string\" && data.access_token.length > 0) {\n const expiresIn = typeof data.expires_in === \"number\" ? data.expires_in : 0;\n const accountId = extractAccountId({\n access_token: data.access_token,\n id_token: data.id_token,\n });\n return {\n access: data.access_token,\n // Some device-grant providers (e.g. GitHub) issue no separate refresh token — reuse the access\n // token as the refresh handle.\n refresh: data.refresh_token ?? data.access_token,\n expires: deps.now() + expiresIn * 1000,\n ...(accountId !== undefined ? { accountId } : {}),\n };\n }\n\n if (data.error === \"authorization_pending\") {\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n continue;\n }\n if (data.error === \"slow_down\") {\n // RFC 8628 §3.5: add 5s to the interval, or honor a server-provided one.\n intervalMs =\n (typeof data.interval === \"number\" && data.interval > 0\n ? data.interval\n : grant.interval + 5) * 1000;\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n continue;\n }\n if (typeof data.error === \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device authorization rejected: ${data.error}`,\n );\n }\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n }\n throw new AuthCallbackError(\n \"oauth_device_code_expired\",\n \"the device code expired before it was approved\",\n );\n}\n\n/**\n * The full device login: request a code, hand the user the verification URL + user code via `onPrompt`\n * (never printed here — the caller renders it, keeping this module output-free), then poll to completion.\n */\nexport async function deviceLogin(\n config: DeviceOAuthConfig,\n deps: DeviceDeps,\n hooks: {\n onPrompt: (p: { userCode: string; verificationUri: string; expiresIn: number }) => void;\n },\n): Promise<OAuthTokens> {\n const grant = await requestDeviceCode(config, deps);\n hooks.onPrompt({\n userCode: grant.userCode,\n verificationUri: grant.verificationUri,\n expiresIn: grant.expiresIn,\n });\n return pollDeviceToken(config, grant, deps);\n}\n\n// ─── OpenAI / ChatGPT \"headless\" device flow (two-step) ───\n\n/** Step 1 (OpenAI) — request the user code. */\nexport async function requestOpenAIUsercode(\n config: OpenAIDeviceConfig,\n deps: Pick<DeviceDeps, \"fetch\">,\n): Promise<{ deviceAuthId: string; userCode: string; interval: number }> {\n let res: Response;\n try {\n res = await deps.fetch(config.deviceUsercodeEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({ client_id: config.clientId }),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `usercode request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `usercode endpoint returned HTTP ${res.status}`,\n );\n }\n const data = (await parseJsonOrFail(\n res,\n \"oauth_device_authorization_failed\",\n \"usercode endpoint\",\n )) as {\n device_auth_id?: unknown;\n user_code?: unknown;\n interval?: unknown;\n };\n if (typeof data.device_auth_id !== \"string\" || typeof data.user_code !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n \"usercode response missing device_auth_id/user_code\",\n );\n }\n const interval = Math.max(\n typeof data.interval === \"string\" ? parseInt(data.interval, 10) || 5 : 5,\n 1,\n );\n return { deviceAuthId: data.device_auth_id, userCode: data.user_code, interval };\n}\n\n/**\n * Step 2+3 (OpenAI) — poll for the authorization code (200 = ready; 403/404 = pending; else fail), then\n * exchange it for tokens at the standard `/oauth/token` endpoint (reuses `exchangeCode`).\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: OpenAI two-step headless poll loop (200 ready / 403,404 pending / else fail) — cohesive network state machine ported verbatim (ADR D3).\nexport async function openaiDeviceLogin(\n config: OpenAIDeviceConfig,\n deps: DeviceDeps,\n hooks: { onPrompt: (p: { userCode: string; verificationUri: string }) => void },\n): Promise<OAuthTokens> {\n const { deviceAuthId, userCode, interval } = await requestOpenAIUsercode(config, deps);\n hooks.onPrompt({ userCode, verificationUri: config.verificationUri });\n\n const intervalMs = interval * 1000;\n // Bound the loop so it cannot spin forever if the provider never resolves (upstream loops unbounded).\n const deadline = deps.now() + 15 * 60 * 1000;\n while (deps.now() < deadline) {\n let res: Response;\n try {\n res = await deps.fetch(config.devicePollEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({ device_auth_id: deviceAuthId, user_code: userCode }),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device poll failed: ${(err as Error).message}`,\n );\n }\n if (res.ok) {\n const data = (await parseJsonOrFail(res, \"oauth_token_exchange_failed\", \"device poll\")) as {\n authorization_code?: unknown;\n code_verifier?: unknown;\n };\n if (typeof data.authorization_code !== \"string\" || typeof data.code_verifier !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n \"device poll returned no authorization_code\",\n );\n }\n const tokens = await exchangeCode(\n config,\n { code: data.authorization_code, verifier: data.code_verifier },\n deps,\n );\n // M43 D4 fix #2 — the two-step exchange returns a JWT access token but `parseTokenResponse` only reads a\n // top-level `account_id`. JWT-extract the `chatgpt_account_id` (as the generic device poll already does)\n // so the login persists a non-empty account_id for the Codex `ChatGPT-Account-Id` header.\n return {\n ...tokens,\n accountId: tokens.accountId ?? extractAccountId({ access_token: tokens.access }),\n };\n }\n // 403/404 = still pending (user has not approved yet); anything else is a hard failure.\n if (res.status !== 403 && res.status !== 404) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device poll returned HTTP ${res.status}`,\n );\n }\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n }\n throw new AuthCallbackError(\n \"oauth_device_code_expired\",\n \"the device authorization expired before approval\",\n );\n}\n\n/** JWT id/access-token claims we read to attribute an account. */\ninterface IdTokenClaims {\n chatgpt_account_id?: string;\n organizations?: Array<{ id: string }>;\n \"https://api.openai.com/auth\"?: { chatgpt_account_id?: string };\n}\n\n/** Decode a JWT's claim set (no signature verification — used only to read a self-reported account id). */\nexport function parseJwtClaims(token: string): IdTokenClaims | undefined {\n const parts = token.split(\".\");\n if (parts.length !== 3) return undefined;\n try {\n return JSON.parse(Buffer.from(parts[1] as string, \"base64url\").toString()) as IdTokenClaims;\n } catch {\n return undefined;\n }\n}\n\n/** Best-effort account id from an id/access token's claims (OpenAI/ChatGPT shape). */\nexport function extractAccountId(tokens: {\n id_token?: string;\n access_token?: string;\n}): string | undefined {\n for (const token of [tokens.id_token, tokens.access_token]) {\n if (token === undefined) continue;\n const claims = parseJwtClaims(token);\n const id =\n claims?.chatgpt_account_id ??\n claims?.[\"https://api.openai.com/auth\"]?.chatgpt_account_id ??\n claims?.organizations?.[0]?.id;\n if (id !== undefined) return id;\n }\n return undefined;\n}\n"]}
1
+ {"version":3,"sources":["../../src/internal/auth/oauth-device.ts"],"names":["AuthCallbackError","exchangeCode"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * M42 — the SDK OAuth device-authorization flows (RFC 8628 + OpenAI two-step headless). Split out of\n * oauth-engine.ts to respect the 500-line file budget; a sibling of the core engine. Promoted DOWN from\n * agent-builder's hardened `agents/lib/oauth-device.ts` (M37).\n *\n * Implements two device flows against their published specs: the RFC 8628 device-grant poll loop\n * (device_code → authorization_pending / slow_down) and OpenAI's two-step headless flow, including the\n * JWT-claim / account-id extraction used to attribute an account.\n * Design choices: network I/O + clock + sleep are INJECTED (deterministic tests), failures raise the SDK's\n * typed `AuthCallbackError`, and a device-code expiry DEADLINE guards each poll loop.\n *\n * @internal\n */\nimport { AuthCallbackError } from \"../../server/auth/errors.js\";\nimport { exchangeCode } from \"./oauth-engine.js\";\nimport type {\n DeviceCodeGrant,\n DeviceDeps,\n DeviceOAuthConfig,\n OAuthTokens,\n OpenAIDeviceConfig,\n} from \"./types.js\";\n\n// ─── OAuth 2.0 Device Authorization Grant (RFC 8628) — terminal-first / headless login ───\n\n/** Buffer added to every poll interval to avoid hitting the server a hair early. */\nconst POLLING_SAFETY_MARGIN_MS = 3000;\n\n/**\n * Parse a JSON body, or fail with this module's typed error instead of a raw `SyntaxError`.\n *\n * Every failure in this file is supposed to reach the caller as an `AuthCallbackError` carrying a code\n * the CLI can branch on. `res.json()` breaks that contract: a device endpoint that answers with HTML —\n * a captive portal, a corporate proxy's sign-in page, a load balancer's error page — makes it reject\n * with a `SyntaxError` that no `catch` here handles, so it escapes untyped past a caller prepared only\n * for `AuthCallbackError`.\n *\n * The body is quoted, truncated, because \"not JSON\" and \"not JSON, and it looks like a proxy login\n * page\" are different diagnoses for whoever is holding the terminal — and routing them to the provider\n * when the fault is their network is the expensive kind of wrong.\n */\nasync function parseJsonOrFail(res: Response, code: string, what: string): Promise<unknown> {\n const text = await res.text().catch(() => \"\");\n try {\n return JSON.parse(text);\n } catch {\n throw new AuthCallbackError(code, `${what} returned a non-JSON body: ${text.slice(0, 120)}`);\n }\n}\n\n/** Step 1 — request a device code. POSTs `{client_id, scope}` to the device endpoint. */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: RFC 8628 device-code request — cohesive network response parser ported verbatim (ADR D3).\nexport async function requestDeviceCode(\n config: DeviceOAuthConfig,\n deps: Pick<DeviceDeps, \"fetch\">,\n): Promise<DeviceCodeGrant> {\n let res: Response;\n try {\n res = await deps.fetch(config.deviceCodeEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\", accept: \"application/json\" },\n body: new URLSearchParams({\n client_id: config.clientId,\n scope: config.scopes.join(\" \"),\n }).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `device request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `device endpoint returned HTTP ${res.status}`,\n );\n }\n const data = (await parseJsonOrFail(\n res,\n \"oauth_device_authorization_failed\",\n \"device endpoint\",\n )) as {\n device_code?: unknown;\n user_code?: unknown;\n verification_uri?: unknown;\n verification_uri_complete?: unknown;\n interval?: unknown;\n expires_in?: unknown;\n };\n if (typeof data.device_code !== \"string\" || typeof data.user_code !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n \"device response missing device_code/user_code\",\n );\n }\n const verification =\n typeof data.verification_uri === \"string\"\n ? data.verification_uri\n : typeof data.verification_uri_complete === \"string\"\n ? data.verification_uri_complete\n : \"\";\n return {\n deviceCode: data.device_code,\n userCode: data.user_code,\n verificationUri: verification,\n interval: typeof data.interval === \"number\" && data.interval > 0 ? data.interval : 5,\n expiresIn: typeof data.expires_in === \"number\" && data.expires_in > 0 ? data.expires_in : 900,\n };\n}\n\n/**\n * Step 2 — poll the token endpoint until the user approves (or the code expires). Handles RFC 8628\n * `authorization_pending` (keep waiting) and `slow_down` (back off), with an expiry deadline so it cannot\n * spin forever.\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: RFC 8628 poll state machine (authorization_pending / slow_down / success / expiry) — a cohesive loop ported verbatim (ADR D3); fragmenting it would obscure the protocol.\nexport async function pollDeviceToken(\n config: DeviceOAuthConfig,\n grant: DeviceCodeGrant,\n deps: DeviceDeps,\n): Promise<OAuthTokens> {\n const deadline = deps.now() + grant.expiresIn * 1000;\n let intervalMs = grant.interval * 1000;\n\n while (deps.now() < deadline) {\n let res: Response;\n try {\n res = await deps.fetch(config.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n accept: \"application/json\",\n },\n body: new URLSearchParams({\n client_id: config.clientId,\n device_code: grant.deviceCode,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device token poll failed: ${(err as Error).message}`,\n );\n }\n // RFC 8628 §3.5: `authorization_pending` / `slow_down` arrive as a 400 with an `error` body — so the\n // body MUST be read before deciding failure. Parse first; only a non-OAuth-shaped body on a non-2xx fails.\n const data = (await res.json().catch(() => ({}))) as {\n access_token?: string;\n refresh_token?: string;\n expires_in?: number;\n id_token?: string;\n error?: string;\n interval?: number;\n };\n if (!res.ok && typeof data.error !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device token endpoint returned HTTP ${res.status}`,\n );\n }\n\n if (typeof data.access_token === \"string\" && data.access_token.length > 0) {\n const expiresIn = typeof data.expires_in === \"number\" ? data.expires_in : 0;\n const accountId = extractAccountId({\n access_token: data.access_token,\n id_token: data.id_token,\n });\n return {\n access: data.access_token,\n // Some device-grant providers (e.g. GitHub) issue no separate refresh token — reuse the access\n // token as the refresh handle.\n refresh: data.refresh_token ?? data.access_token,\n expires: deps.now() + expiresIn * 1000,\n ...(accountId !== undefined ? { accountId } : {}),\n ...(typeof data.id_token === \"string\" && data.id_token.length > 0\n ? { idToken: data.id_token }\n : {}),\n };\n }\n\n if (data.error === \"authorization_pending\") {\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n continue;\n }\n if (data.error === \"slow_down\") {\n // RFC 8628 §3.5: add 5s to the interval, or honor a server-provided one.\n intervalMs =\n (typeof data.interval === \"number\" && data.interval > 0\n ? data.interval\n : grant.interval + 5) * 1000;\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n continue;\n }\n if (typeof data.error === \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device authorization rejected: ${data.error}`,\n );\n }\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n }\n throw new AuthCallbackError(\n \"oauth_device_code_expired\",\n \"the device code expired before it was approved\",\n );\n}\n\n/**\n * The full device login: request a code, hand the user the verification URL + user code via `onPrompt`\n * (never printed here — the caller renders it, keeping this module output-free), then poll to completion.\n */\nexport async function deviceLogin(\n config: DeviceOAuthConfig,\n deps: DeviceDeps,\n hooks: {\n onPrompt: (p: { userCode: string; verificationUri: string; expiresIn: number }) => void;\n },\n): Promise<OAuthTokens> {\n const grant = await requestDeviceCode(config, deps);\n hooks.onPrompt({\n userCode: grant.userCode,\n verificationUri: grant.verificationUri,\n expiresIn: grant.expiresIn,\n });\n return pollDeviceToken(config, grant, deps);\n}\n\n// ─── OpenAI / ChatGPT \"headless\" device flow (two-step) ───\n\n/** Step 1 (OpenAI) — request the user code. */\nexport async function requestOpenAIUsercode(\n config: OpenAIDeviceConfig,\n deps: Pick<DeviceDeps, \"fetch\">,\n): Promise<{ deviceAuthId: string; userCode: string; interval: number }> {\n let res: Response;\n try {\n res = await deps.fetch(config.deviceUsercodeEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({ client_id: config.clientId }),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `usercode request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `usercode endpoint returned HTTP ${res.status}`,\n );\n }\n const data = (await parseJsonOrFail(\n res,\n \"oauth_device_authorization_failed\",\n \"usercode endpoint\",\n )) as {\n device_auth_id?: unknown;\n user_code?: unknown;\n interval?: unknown;\n };\n if (typeof data.device_auth_id !== \"string\" || typeof data.user_code !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n \"usercode response missing device_auth_id/user_code\",\n );\n }\n const interval = Math.max(\n typeof data.interval === \"string\" ? parseInt(data.interval, 10) || 5 : 5,\n 1,\n );\n return { deviceAuthId: data.device_auth_id, userCode: data.user_code, interval };\n}\n\n/**\n * Step 2+3 (OpenAI) — poll for the authorization code (200 = ready; 403/404 = pending; else fail), then\n * exchange it for tokens at the standard `/oauth/token` endpoint (reuses `exchangeCode`).\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: OpenAI two-step headless poll loop (200 ready / 403,404 pending / else fail) — cohesive network state machine ported verbatim (ADR D3).\nexport async function openaiDeviceLogin(\n config: OpenAIDeviceConfig,\n deps: DeviceDeps,\n hooks: { onPrompt: (p: { userCode: string; verificationUri: string }) => void },\n): Promise<OAuthTokens> {\n const { deviceAuthId, userCode, interval } = await requestOpenAIUsercode(config, deps);\n hooks.onPrompt({ userCode, verificationUri: config.verificationUri });\n\n const intervalMs = interval * 1000;\n // Bound the loop so it cannot spin forever if the provider never resolves (upstream loops unbounded).\n const deadline = deps.now() + 15 * 60 * 1000;\n while (deps.now() < deadline) {\n let res: Response;\n try {\n res = await deps.fetch(config.devicePollEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({ device_auth_id: deviceAuthId, user_code: userCode }),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device poll failed: ${(err as Error).message}`,\n );\n }\n if (res.ok) {\n const data = (await parseJsonOrFail(res, \"oauth_token_exchange_failed\", \"device poll\")) as {\n authorization_code?: unknown;\n code_verifier?: unknown;\n };\n if (typeof data.authorization_code !== \"string\" || typeof data.code_verifier !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n \"device poll returned no authorization_code\",\n );\n }\n const tokens = await exchangeCode(\n config,\n { code: data.authorization_code, verifier: data.code_verifier },\n deps,\n );\n // M43 D4 fix #2 — the two-step exchange returns a JWT access token but `parseTokenResponse` only reads a\n // top-level `account_id`. JWT-extract the `chatgpt_account_id` (as the generic device poll already does)\n // so the login persists a non-empty account_id for the Codex `ChatGPT-Account-Id` header.\n return {\n ...tokens,\n accountId: tokens.accountId ?? extractAccountId({ access_token: tokens.access }),\n };\n }\n // 403/404 = still pending (user has not approved yet); anything else is a hard failure.\n if (res.status !== 403 && res.status !== 404) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device poll returned HTTP ${res.status}`,\n );\n }\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n }\n throw new AuthCallbackError(\n \"oauth_device_code_expired\",\n \"the device authorization expired before approval\",\n );\n}\n\n/** JWT id/access-token claims we read to attribute an account. */\ninterface IdTokenClaims {\n chatgpt_account_id?: string;\n organizations?: Array<{ id: string }>;\n \"https://api.openai.com/auth\"?: { chatgpt_account_id?: string };\n}\n\n/** Decode a JWT's claim set (no signature verification — used only to read a self-reported account id). */\nexport function parseJwtClaims(token: string): IdTokenClaims | undefined {\n const parts = token.split(\".\");\n if (parts.length !== 3) return undefined;\n try {\n return JSON.parse(Buffer.from(parts[1] as string, \"base64url\").toString()) as IdTokenClaims;\n } catch {\n return undefined;\n }\n}\n\n/** Best-effort account id from an id/access token's claims (OpenAI/ChatGPT shape). */\nexport function extractAccountId(tokens: {\n id_token?: string;\n access_token?: string;\n}): string | undefined {\n for (const token of [tokens.id_token, tokens.access_token]) {\n if (token === undefined) continue;\n const claims = parseJwtClaims(token);\n const id =\n claims?.chatgpt_account_id ??\n claims?.[\"https://api.openai.com/auth\"]?.chatgpt_account_id ??\n claims?.organizations?.[0]?.id;\n if (id !== undefined) return id;\n }\n return undefined;\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  export { providerFromApiKeyPrefix } from '../chunk-NAF4L3T6.js';
2
- import { exchangeCode } from '../chunk-3FSBE4PS.js';
3
- export { ensureFreshCredential, exchangeCode, persistOAuthTokens, refreshOAuthTokens, resolveCredential } from '../chunk-3FSBE4PS.js';
4
- export { CredentialError, assertSecureModes, authFilePath, credentialHome, readAuthFile, readStoredOAuth, writeCredential } from '../chunk-MS3TQSXU.js';
2
+ import { exchangeCode } from '../chunk-3GTN4HOO.js';
3
+ export { ensureFreshCredential, exchangeCode, persistOAuthTokens, refreshOAuthTokens, resolveCredential } from '../chunk-3GTN4HOO.js';
4
+ export { CredentialError, assertSecureModes, authFilePath, credentialHome, readAuthFile, readStoredOAuth, writeCredential } from '../chunk-QD6B6W6I.js';
5
5
  import { AuthCallbackError } from '../chunk-5IUDICRK.js';
6
6
  import '../chunk-Q7GYMXVC.js';
7
7
  import '../chunk-TNFOU6SB.js';
@@ -103,7 +103,8 @@ async function pollDeviceToken(config, grant, deps) {
103
103
  // token as the refresh handle.
104
104
  refresh: data.refresh_token ?? data.access_token,
105
105
  expires: deps.now() + expiresIn * 1e3,
106
- ...accountId !== void 0 ? { accountId } : {}
106
+ ...accountId !== void 0 ? { accountId } : {},
107
+ ...typeof data.id_token === "string" && data.id_token.length > 0 ? { idToken: data.id_token } : {}
107
108
  };
108
109
  }
109
110
  if (data.error === "authorization_pending") {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/internal/auth/oauth-device.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * M42 — the SDK OAuth device-authorization flows (RFC 8628 + OpenAI two-step headless). Split out of\n * oauth-engine.ts to respect the 500-line file budget; a sibling of the core engine. Promoted DOWN from\n * agent-builder's hardened `agents/lib/oauth-device.ts` (M37).\n *\n * Implements two device flows against their published specs: the RFC 8628 device-grant poll loop\n * (device_code → authorization_pending / slow_down) and OpenAI's two-step headless flow, including the\n * JWT-claim / account-id extraction used to attribute an account.\n * Design choices: network I/O + clock + sleep are INJECTED (deterministic tests), failures raise the SDK's\n * typed `AuthCallbackError`, and a device-code expiry DEADLINE guards each poll loop.\n *\n * @internal\n */\nimport { AuthCallbackError } from \"../../server/auth/errors.js\";\nimport { exchangeCode } from \"./oauth-engine.js\";\nimport type {\n DeviceCodeGrant,\n DeviceDeps,\n DeviceOAuthConfig,\n OAuthTokens,\n OpenAIDeviceConfig,\n} from \"./types.js\";\n\n// ─── OAuth 2.0 Device Authorization Grant (RFC 8628) — terminal-first / headless login ───\n\n/** Buffer added to every poll interval to avoid hitting the server a hair early. */\nconst POLLING_SAFETY_MARGIN_MS = 3000;\n\n/**\n * Parse a JSON body, or fail with this module's typed error instead of a raw `SyntaxError`.\n *\n * Every failure in this file is supposed to reach the caller as an `AuthCallbackError` carrying a code\n * the CLI can branch on. `res.json()` breaks that contract: a device endpoint that answers with HTML —\n * a captive portal, a corporate proxy's sign-in page, a load balancer's error page — makes it reject\n * with a `SyntaxError` that no `catch` here handles, so it escapes untyped past a caller prepared only\n * for `AuthCallbackError`.\n *\n * The body is quoted, truncated, because \"not JSON\" and \"not JSON, and it looks like a proxy login\n * page\" are different diagnoses for whoever is holding the terminal — and routing them to the provider\n * when the fault is their network is the expensive kind of wrong.\n */\nasync function parseJsonOrFail(res: Response, code: string, what: string): Promise<unknown> {\n const text = await res.text().catch(() => \"\");\n try {\n return JSON.parse(text);\n } catch {\n throw new AuthCallbackError(code, `${what} returned a non-JSON body: ${text.slice(0, 120)}`);\n }\n}\n\n/** Step 1 — request a device code. POSTs `{client_id, scope}` to the device endpoint. */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: RFC 8628 device-code request — cohesive network response parser ported verbatim (ADR D3).\nexport async function requestDeviceCode(\n config: DeviceOAuthConfig,\n deps: Pick<DeviceDeps, \"fetch\">,\n): Promise<DeviceCodeGrant> {\n let res: Response;\n try {\n res = await deps.fetch(config.deviceCodeEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\", accept: \"application/json\" },\n body: new URLSearchParams({\n client_id: config.clientId,\n scope: config.scopes.join(\" \"),\n }).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `device request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `device endpoint returned HTTP ${res.status}`,\n );\n }\n const data = (await parseJsonOrFail(\n res,\n \"oauth_device_authorization_failed\",\n \"device endpoint\",\n )) as {\n device_code?: unknown;\n user_code?: unknown;\n verification_uri?: unknown;\n verification_uri_complete?: unknown;\n interval?: unknown;\n expires_in?: unknown;\n };\n if (typeof data.device_code !== \"string\" || typeof data.user_code !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n \"device response missing device_code/user_code\",\n );\n }\n const verification =\n typeof data.verification_uri === \"string\"\n ? data.verification_uri\n : typeof data.verification_uri_complete === \"string\"\n ? data.verification_uri_complete\n : \"\";\n return {\n deviceCode: data.device_code,\n userCode: data.user_code,\n verificationUri: verification,\n interval: typeof data.interval === \"number\" && data.interval > 0 ? data.interval : 5,\n expiresIn: typeof data.expires_in === \"number\" && data.expires_in > 0 ? data.expires_in : 900,\n };\n}\n\n/**\n * Step 2 — poll the token endpoint until the user approves (or the code expires). Handles RFC 8628\n * `authorization_pending` (keep waiting) and `slow_down` (back off), with an expiry deadline so it cannot\n * spin forever.\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: RFC 8628 poll state machine (authorization_pending / slow_down / success / expiry) — a cohesive loop ported verbatim (ADR D3); fragmenting it would obscure the protocol.\nexport async function pollDeviceToken(\n config: DeviceOAuthConfig,\n grant: DeviceCodeGrant,\n deps: DeviceDeps,\n): Promise<OAuthTokens> {\n const deadline = deps.now() + grant.expiresIn * 1000;\n let intervalMs = grant.interval * 1000;\n\n while (deps.now() < deadline) {\n let res: Response;\n try {\n res = await deps.fetch(config.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n accept: \"application/json\",\n },\n body: new URLSearchParams({\n client_id: config.clientId,\n device_code: grant.deviceCode,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device token poll failed: ${(err as Error).message}`,\n );\n }\n // RFC 8628 §3.5: `authorization_pending` / `slow_down` arrive as a 400 with an `error` body — so the\n // body MUST be read before deciding failure. Parse first; only a non-OAuth-shaped body on a non-2xx fails.\n const data = (await res.json().catch(() => ({}))) as {\n access_token?: string;\n refresh_token?: string;\n expires_in?: number;\n id_token?: string;\n error?: string;\n interval?: number;\n };\n if (!res.ok && typeof data.error !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device token endpoint returned HTTP ${res.status}`,\n );\n }\n\n if (typeof data.access_token === \"string\" && data.access_token.length > 0) {\n const expiresIn = typeof data.expires_in === \"number\" ? data.expires_in : 0;\n const accountId = extractAccountId({\n access_token: data.access_token,\n id_token: data.id_token,\n });\n return {\n access: data.access_token,\n // Some device-grant providers (e.g. GitHub) issue no separate refresh token — reuse the access\n // token as the refresh handle.\n refresh: data.refresh_token ?? data.access_token,\n expires: deps.now() + expiresIn * 1000,\n ...(accountId !== undefined ? { accountId } : {}),\n };\n }\n\n if (data.error === \"authorization_pending\") {\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n continue;\n }\n if (data.error === \"slow_down\") {\n // RFC 8628 §3.5: add 5s to the interval, or honor a server-provided one.\n intervalMs =\n (typeof data.interval === \"number\" && data.interval > 0\n ? data.interval\n : grant.interval + 5) * 1000;\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n continue;\n }\n if (typeof data.error === \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device authorization rejected: ${data.error}`,\n );\n }\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n }\n throw new AuthCallbackError(\n \"oauth_device_code_expired\",\n \"the device code expired before it was approved\",\n );\n}\n\n/**\n * The full device login: request a code, hand the user the verification URL + user code via `onPrompt`\n * (never printed here — the caller renders it, keeping this module output-free), then poll to completion.\n */\nexport async function deviceLogin(\n config: DeviceOAuthConfig,\n deps: DeviceDeps,\n hooks: {\n onPrompt: (p: { userCode: string; verificationUri: string; expiresIn: number }) => void;\n },\n): Promise<OAuthTokens> {\n const grant = await requestDeviceCode(config, deps);\n hooks.onPrompt({\n userCode: grant.userCode,\n verificationUri: grant.verificationUri,\n expiresIn: grant.expiresIn,\n });\n return pollDeviceToken(config, grant, deps);\n}\n\n// ─── OpenAI / ChatGPT \"headless\" device flow (two-step) ───\n\n/** Step 1 (OpenAI) — request the user code. */\nexport async function requestOpenAIUsercode(\n config: OpenAIDeviceConfig,\n deps: Pick<DeviceDeps, \"fetch\">,\n): Promise<{ deviceAuthId: string; userCode: string; interval: number }> {\n let res: Response;\n try {\n res = await deps.fetch(config.deviceUsercodeEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({ client_id: config.clientId }),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `usercode request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `usercode endpoint returned HTTP ${res.status}`,\n );\n }\n const data = (await parseJsonOrFail(\n res,\n \"oauth_device_authorization_failed\",\n \"usercode endpoint\",\n )) as {\n device_auth_id?: unknown;\n user_code?: unknown;\n interval?: unknown;\n };\n if (typeof data.device_auth_id !== \"string\" || typeof data.user_code !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n \"usercode response missing device_auth_id/user_code\",\n );\n }\n const interval = Math.max(\n typeof data.interval === \"string\" ? parseInt(data.interval, 10) || 5 : 5,\n 1,\n );\n return { deviceAuthId: data.device_auth_id, userCode: data.user_code, interval };\n}\n\n/**\n * Step 2+3 (OpenAI) — poll for the authorization code (200 = ready; 403/404 = pending; else fail), then\n * exchange it for tokens at the standard `/oauth/token` endpoint (reuses `exchangeCode`).\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: OpenAI two-step headless poll loop (200 ready / 403,404 pending / else fail) — cohesive network state machine ported verbatim (ADR D3).\nexport async function openaiDeviceLogin(\n config: OpenAIDeviceConfig,\n deps: DeviceDeps,\n hooks: { onPrompt: (p: { userCode: string; verificationUri: string }) => void },\n): Promise<OAuthTokens> {\n const { deviceAuthId, userCode, interval } = await requestOpenAIUsercode(config, deps);\n hooks.onPrompt({ userCode, verificationUri: config.verificationUri });\n\n const intervalMs = interval * 1000;\n // Bound the loop so it cannot spin forever if the provider never resolves (upstream loops unbounded).\n const deadline = deps.now() + 15 * 60 * 1000;\n while (deps.now() < deadline) {\n let res: Response;\n try {\n res = await deps.fetch(config.devicePollEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({ device_auth_id: deviceAuthId, user_code: userCode }),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device poll failed: ${(err as Error).message}`,\n );\n }\n if (res.ok) {\n const data = (await parseJsonOrFail(res, \"oauth_token_exchange_failed\", \"device poll\")) as {\n authorization_code?: unknown;\n code_verifier?: unknown;\n };\n if (typeof data.authorization_code !== \"string\" || typeof data.code_verifier !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n \"device poll returned no authorization_code\",\n );\n }\n const tokens = await exchangeCode(\n config,\n { code: data.authorization_code, verifier: data.code_verifier },\n deps,\n );\n // M43 D4 fix #2 — the two-step exchange returns a JWT access token but `parseTokenResponse` only reads a\n // top-level `account_id`. JWT-extract the `chatgpt_account_id` (as the generic device poll already does)\n // so the login persists a non-empty account_id for the Codex `ChatGPT-Account-Id` header.\n return {\n ...tokens,\n accountId: tokens.accountId ?? extractAccountId({ access_token: tokens.access }),\n };\n }\n // 403/404 = still pending (user has not approved yet); anything else is a hard failure.\n if (res.status !== 403 && res.status !== 404) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device poll returned HTTP ${res.status}`,\n );\n }\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n }\n throw new AuthCallbackError(\n \"oauth_device_code_expired\",\n \"the device authorization expired before approval\",\n );\n}\n\n/** JWT id/access-token claims we read to attribute an account. */\ninterface IdTokenClaims {\n chatgpt_account_id?: string;\n organizations?: Array<{ id: string }>;\n \"https://api.openai.com/auth\"?: { chatgpt_account_id?: string };\n}\n\n/** Decode a JWT's claim set (no signature verification — used only to read a self-reported account id). */\nexport function parseJwtClaims(token: string): IdTokenClaims | undefined {\n const parts = token.split(\".\");\n if (parts.length !== 3) return undefined;\n try {\n return JSON.parse(Buffer.from(parts[1] as string, \"base64url\").toString()) as IdTokenClaims;\n } catch {\n return undefined;\n }\n}\n\n/** Best-effort account id from an id/access token's claims (OpenAI/ChatGPT shape). */\nexport function extractAccountId(tokens: {\n id_token?: string;\n access_token?: string;\n}): string | undefined {\n for (const token of [tokens.id_token, tokens.access_token]) {\n if (token === undefined) continue;\n const claims = parseJwtClaims(token);\n const id =\n claims?.chatgpt_account_id ??\n claims?.[\"https://api.openai.com/auth\"]?.chatgpt_account_id ??\n claims?.organizations?.[0]?.id;\n if (id !== undefined) return id;\n }\n return undefined;\n}\n"]}
1
+ {"version":3,"sources":["../../src/internal/auth/oauth-device.ts"],"names":[],"mappings":";;;;;;;;;;AA0BA,IAAM,wBAAA,GAA2B,GAAA;AAejC,eAAe,eAAA,CAAgB,GAAA,EAAe,IAAA,EAAc,IAAA,EAAgC;AAC1F,EAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,EACxB,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,iBAAA,CAAkB,IAAA,EAAM,CAAA,EAAG,IAAI,CAAA,2BAAA,EAA8B,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,GAAG,CAAC,CAAA,CAAE,CAAA;AAAA,EAC7F;AACF;AAIA,eAAsB,iBAAA,CACpB,QACA,IAAA,EAC0B;AAC1B,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,kBAAA,EAAoB;AAAA,MAChD,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,mCAAA,EAAqC,QAAQ,kBAAA,EAAmB;AAAA,MAC3F,IAAA,EAAM,IAAI,eAAA,CAAgB;AAAA,QACxB,WAAW,MAAA,CAAO,QAAA;AAAA,QAClB,KAAA,EAAO,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,GAAG;AAAA,OAC9B,EAAE,QAAA;AAAS,KACb,CAAA;AAAA,EACH,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,mCAAA;AAAA,MACA,CAAA,uBAAA,EAA2B,IAAc,OAAO,CAAA;AAAA,KAClD;AAAA,EACF;AACA,EAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,mCAAA;AAAA,MACA,CAAA,8BAAA,EAAiC,IAAI,MAAM,CAAA;AAAA,KAC7C;AAAA,EACF;AACA,EAAA,MAAM,OAAQ,MAAM,eAAA;AAAA,IAClB,GAAA;AAAA,IACA,mCAAA;AAAA,IACA;AAAA,GACF;AAQA,EAAA,IAAI,OAAO,IAAA,CAAK,WAAA,KAAgB,YAAY,OAAO,IAAA,CAAK,cAAc,QAAA,EAAU;AAC9E,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,mCAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AACA,EAAA,MAAM,YAAA,GACJ,OAAO,IAAA,CAAK,gBAAA,KAAqB,QAAA,GAC7B,IAAA,CAAK,gBAAA,GACL,OAAO,IAAA,CAAK,yBAAA,KAA8B,QAAA,GACxC,IAAA,CAAK,yBAAA,GACL,EAAA;AACR,EAAA,OAAO;AAAA,IACL,YAAY,IAAA,CAAK,WAAA;AAAA,IACjB,UAAU,IAAA,CAAK,SAAA;AAAA,IACf,eAAA,EAAiB,YAAA;AAAA,IACjB,QAAA,EAAU,OAAO,IAAA,CAAK,QAAA,KAAa,YAAY,IAAA,CAAK,QAAA,GAAW,CAAA,GAAI,IAAA,CAAK,QAAA,GAAW,CAAA;AAAA,IACnF,SAAA,EAAW,OAAO,IAAA,CAAK,UAAA,KAAe,YAAY,IAAA,CAAK,UAAA,GAAa,CAAA,GAAI,IAAA,CAAK,UAAA,GAAa;AAAA,GAC5F;AACF;AAQA,eAAsB,eAAA,CACpB,MAAA,EACA,KAAA,EACA,IAAA,EACsB;AACtB,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI,GAAI,MAAM,SAAA,GAAY,GAAA;AAChD,EAAA,IAAI,UAAA,GAAa,MAAM,QAAA,GAAW,GAAA;AAElC,EAAA,OAAO,IAAA,CAAK,GAAA,EAAI,GAAI,QAAA,EAAU;AAC5B,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACF,MAAA,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,aAAA,EAAe;AAAA,QAC3C,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS;AAAA,UACP,cAAA,EAAgB,mCAAA;AAAA,UAChB,MAAA,EAAQ;AAAA,SACV;AAAA,QACA,IAAA,EAAM,IAAI,eAAA,CAAgB;AAAA,UACxB,WAAW,MAAA,CAAO,QAAA;AAAA,UAClB,aAAa,KAAA,CAAM,UAAA;AAAA,UACnB,UAAA,EAAY;AAAA,SACb,EAAE,QAAA;AAAS,OACb,CAAA;AAAA,IACH,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,IAAI,iBAAA;AAAA,QACR,6BAAA;AAAA,QACA,CAAA,0BAAA,EAA8B,IAAc,OAAO,CAAA;AAAA,OACrD;AAAA,IACF;AAGA,IAAA,MAAM,IAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,GAAO,KAAA,CAAM,OAAO,EAAC,CAAE,CAAA;AAQ/C,IAAA,IAAI,CAAC,GAAA,CAAI,EAAA,IAAM,OAAO,IAAA,CAAK,UAAU,QAAA,EAAU;AAC7C,MAAA,MAAM,IAAI,iBAAA;AAAA,QACR,6BAAA;AAAA,QACA,CAAA,oCAAA,EAAuC,IAAI,MAAM,CAAA;AAAA,OACnD;AAAA,IACF;AAEA,IAAA,IAAI,OAAO,IAAA,CAAK,YAAA,KAAiB,YAAY,IAAA,CAAK,YAAA,CAAa,SAAS,CAAA,EAAG;AACzE,MAAA,MAAM,YAAY,OAAO,IAAA,CAAK,UAAA,KAAe,QAAA,GAAW,KAAK,UAAA,GAAa,CAAA;AAC1E,MAAA,MAAM,YAAY,gBAAA,CAAiB;AAAA,QACjC,cAAc,IAAA,CAAK,YAAA;AAAA,QACnB,UAAU,IAAA,CAAK;AAAA,OAChB,CAAA;AACD,MAAA,OAAO;AAAA,QACL,QAAQ,IAAA,CAAK,YAAA;AAAA;AAAA;AAAA,QAGb,OAAA,EAAS,IAAA,CAAK,aAAA,IAAiB,IAAA,CAAK,YAAA;AAAA,QACpC,OAAA,EAAS,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA,GAAY,GAAA;AAAA,QAClC,GAAI,SAAA,KAAc,MAAA,GAAY,EAAE,SAAA,KAAc,EAAC;AAAA,QAC/C,GAAI,OAAO,IAAA,CAAK,QAAA,KAAa,YAAY,IAAA,CAAK,QAAA,CAAS,MAAA,GAAS,CAAA,GAC5D,EAAE,OAAA,EAAS,IAAA,CAAK,QAAA,KAChB;AAAC,OACP;AAAA,IACF;AAEA,IAAA,IAAI,IAAA,CAAK,UAAU,uBAAA,EAAyB;AAC1C,MAAA,MAAM,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,wBAAwB,CAAA;AACtD,MAAA;AAAA,IACF;AACA,IAAA,IAAI,IAAA,CAAK,UAAU,WAAA,EAAa;AAE9B,MAAA,UAAA,GAAA,CACG,OAAO,IAAA,CAAK,QAAA,KAAa,QAAA,IAAY,IAAA,CAAK,QAAA,GAAW,CAAA,GAClD,IAAA,CAAK,QAAA,GACL,KAAA,CAAM,QAAA,GAAW,CAAA,IAAK,GAAA;AAC5B,MAAA,MAAM,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,wBAAwB,CAAA;AACtD,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAO,IAAA,CAAK,KAAA,KAAU,QAAA,EAAU;AAClC,MAAA,MAAM,IAAI,iBAAA;AAAA,QACR,6BAAA;AAAA,QACA,CAAA,+BAAA,EAAkC,KAAK,KAAK,CAAA;AAAA,OAC9C;AAAA,IACF;AACA,IAAA,MAAM,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,wBAAwB,CAAA;AAAA,EACxD;AACA,EAAA,MAAM,IAAI,iBAAA;AAAA,IACR,2BAAA;AAAA,IACA;AAAA,GACF;AACF;AAMA,eAAsB,WAAA,CACpB,MAAA,EACA,IAAA,EACA,KAAA,EAGsB;AACtB,EAAA,MAAM,KAAA,GAAQ,MAAM,iBAAA,CAAkB,MAAA,EAAQ,IAAI,CAAA;AAClD,EAAA,KAAA,CAAM,QAAA,CAAS;AAAA,IACb,UAAU,KAAA,CAAM,QAAA;AAAA,IAChB,iBAAiB,KAAA,CAAM,eAAA;AAAA,IACvB,WAAW,KAAA,CAAM;AAAA,GAClB,CAAA;AACD,EAAA,OAAO,eAAA,CAAgB,MAAA,EAAQ,KAAA,EAAO,IAAI,CAAA;AAC5C;AAKA,eAAsB,qBAAA,CACpB,QACA,IAAA,EACuE;AACvE,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,sBAAA,EAAwB;AAAA,MACpD,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,QAAQ,kBAAA,EAAmB;AAAA,MAC1E,MAAM,IAAA,CAAK,SAAA,CAAU,EAAE,SAAA,EAAW,MAAA,CAAO,UAAU;AAAA,KACpD,CAAA;AAAA,EACH,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,mCAAA;AAAA,MACA,CAAA,yBAAA,EAA6B,IAAc,OAAO,CAAA;AAAA,KACpD;AAAA,EACF;AACA,EAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,mCAAA;AAAA,MACA,CAAA,gCAAA,EAAmC,IAAI,MAAM,CAAA;AAAA,KAC/C;AAAA,EACF;AACA,EAAA,MAAM,OAAQ,MAAM,eAAA;AAAA,IAClB,GAAA;AAAA,IACA,mCAAA;AAAA,IACA;AAAA,GACF;AAKA,EAAA,IAAI,OAAO,IAAA,CAAK,cAAA,KAAmB,YAAY,OAAO,IAAA,CAAK,cAAc,QAAA,EAAU;AACjF,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,mCAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AACA,EAAA,MAAM,WAAW,IAAA,CAAK,GAAA;AAAA,IACpB,OAAO,KAAK,QAAA,KAAa,QAAA,GAAW,SAAS,IAAA,CAAK,QAAA,EAAU,EAAE,CAAA,IAAK,CAAA,GAAI,CAAA;AAAA,IACvE;AAAA,GACF;AACA,EAAA,OAAO,EAAE,YAAA,EAAc,IAAA,CAAK,gBAAgB,QAAA,EAAU,IAAA,CAAK,WAAW,QAAA,EAAS;AACjF;AAOA,eAAsB,iBAAA,CACpB,MAAA,EACA,IAAA,EACA,KAAA,EACsB;AACtB,EAAA,MAAM,EAAE,cAAc,QAAA,EAAU,QAAA,KAAa,MAAM,qBAAA,CAAsB,QAAQ,IAAI,CAAA;AACrF,EAAA,KAAA,CAAM,SAAS,EAAE,QAAA,EAAU,eAAA,EAAiB,MAAA,CAAO,iBAAiB,CAAA;AAEpE,EAAA,MAAM,aAAa,QAAA,GAAW,GAAA;AAE9B,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI,GAAI,KAAK,EAAA,GAAK,GAAA;AACxC,EAAA,OAAO,IAAA,CAAK,GAAA,EAAI,GAAI,QAAA,EAAU;AAC5B,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACF,MAAA,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,kBAAA,EAAoB;AAAA,QAChD,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,QAAQ,kBAAA,EAAmB;AAAA,QAC1E,IAAA,EAAM,KAAK,SAAA,CAAU,EAAE,gBAAgB,YAAA,EAAc,SAAA,EAAW,UAAU;AAAA,OAC3E,CAAA;AAAA,IACH,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,IAAI,iBAAA;AAAA,QACR,6BAAA;AAAA,QACA,CAAA,oBAAA,EAAwB,IAAc,OAAO,CAAA;AAAA,OAC/C;AAAA,IACF;AACA,IAAA,IAAI,IAAI,EAAA,EAAI;AACV,MAAA,MAAM,IAAA,GAAQ,MAAM,eAAA,CAAgB,GAAA,EAAK,+BAA+B,aAAa,CAAA;AAIrF,MAAA,IAAI,OAAO,IAAA,CAAK,kBAAA,KAAuB,YAAY,OAAO,IAAA,CAAK,kBAAkB,QAAA,EAAU;AACzF,QAAA,MAAM,IAAI,iBAAA;AAAA,UACR,6BAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AACA,MAAA,MAAM,SAAS,MAAM,YAAA;AAAA,QACnB,MAAA;AAAA,QACA,EAAE,IAAA,EAAM,IAAA,CAAK,kBAAA,EAAoB,QAAA,EAAU,KAAK,aAAA,EAAc;AAAA,QAC9D;AAAA,OACF;AAIA,MAAA,OAAO;AAAA,QACL,GAAG,MAAA;AAAA,QACH,SAAA,EAAW,OAAO,SAAA,IAAa,gBAAA,CAAiB,EAAE,YAAA,EAAc,MAAA,CAAO,QAAQ;AAAA,OACjF;AAAA,IACF;AAEA,IAAA,IAAI,GAAA,CAAI,MAAA,KAAW,GAAA,IAAO,GAAA,CAAI,WAAW,GAAA,EAAK;AAC5C,MAAA,MAAM,IAAI,iBAAA;AAAA,QACR,6BAAA;AAAA,QACA,CAAA,0BAAA,EAA6B,IAAI,MAAM,CAAA;AAAA,OACzC;AAAA,IACF;AACA,IAAA,MAAM,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,wBAAwB,CAAA;AAAA,EACxD;AACA,EAAA,MAAM,IAAI,iBAAA;AAAA,IACR,2BAAA;AAAA,IACA;AAAA,GACF;AACF;AAUO,SAAS,eAAe,KAAA,EAA0C;AACvE,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA;AAC7B,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AAC/B,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,EAAa,WAAW,CAAA,CAAE,QAAA,EAAU,CAAA;AAAA,EAC3E,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAGO,SAAS,iBAAiB,MAAA,EAGV;AACrB,EAAA,KAAA,MAAW,SAAS,CAAC,MAAA,CAAO,QAAA,EAAU,MAAA,CAAO,YAAY,CAAA,EAAG;AAC1D,IAAA,IAAI,UAAU,MAAA,EAAW;AACzB,IAAA,MAAM,MAAA,GAAS,eAAe,KAAK,CAAA;AACnC,IAAA,MAAM,EAAA,GACJ,MAAA,EAAQ,kBAAA,IACR,MAAA,GAAS,6BAA6B,GAAG,kBAAA,IACzC,MAAA,EAAQ,aAAA,GAAgB,CAAC,CAAA,EAAG,EAAA;AAC9B,IAAA,IAAI,EAAA,KAAO,QAAW,OAAO,EAAA;AAAA,EAC/B;AACA,EAAA,OAAO,MAAA;AACT","file":"index.js","sourcesContent":["/**\n * M42 — the SDK OAuth device-authorization flows (RFC 8628 + OpenAI two-step headless). Split out of\n * oauth-engine.ts to respect the 500-line file budget; a sibling of the core engine. Promoted DOWN from\n * agent-builder's hardened `agents/lib/oauth-device.ts` (M37).\n *\n * Implements two device flows against their published specs: the RFC 8628 device-grant poll loop\n * (device_code → authorization_pending / slow_down) and OpenAI's two-step headless flow, including the\n * JWT-claim / account-id extraction used to attribute an account.\n * Design choices: network I/O + clock + sleep are INJECTED (deterministic tests), failures raise the SDK's\n * typed `AuthCallbackError`, and a device-code expiry DEADLINE guards each poll loop.\n *\n * @internal\n */\nimport { AuthCallbackError } from \"../../server/auth/errors.js\";\nimport { exchangeCode } from \"./oauth-engine.js\";\nimport type {\n DeviceCodeGrant,\n DeviceDeps,\n DeviceOAuthConfig,\n OAuthTokens,\n OpenAIDeviceConfig,\n} from \"./types.js\";\n\n// ─── OAuth 2.0 Device Authorization Grant (RFC 8628) — terminal-first / headless login ───\n\n/** Buffer added to every poll interval to avoid hitting the server a hair early. */\nconst POLLING_SAFETY_MARGIN_MS = 3000;\n\n/**\n * Parse a JSON body, or fail with this module's typed error instead of a raw `SyntaxError`.\n *\n * Every failure in this file is supposed to reach the caller as an `AuthCallbackError` carrying a code\n * the CLI can branch on. `res.json()` breaks that contract: a device endpoint that answers with HTML —\n * a captive portal, a corporate proxy's sign-in page, a load balancer's error page — makes it reject\n * with a `SyntaxError` that no `catch` here handles, so it escapes untyped past a caller prepared only\n * for `AuthCallbackError`.\n *\n * The body is quoted, truncated, because \"not JSON\" and \"not JSON, and it looks like a proxy login\n * page\" are different diagnoses for whoever is holding the terminal — and routing them to the provider\n * when the fault is their network is the expensive kind of wrong.\n */\nasync function parseJsonOrFail(res: Response, code: string, what: string): Promise<unknown> {\n const text = await res.text().catch(() => \"\");\n try {\n return JSON.parse(text);\n } catch {\n throw new AuthCallbackError(code, `${what} returned a non-JSON body: ${text.slice(0, 120)}`);\n }\n}\n\n/** Step 1 — request a device code. POSTs `{client_id, scope}` to the device endpoint. */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: RFC 8628 device-code request — cohesive network response parser ported verbatim (ADR D3).\nexport async function requestDeviceCode(\n config: DeviceOAuthConfig,\n deps: Pick<DeviceDeps, \"fetch\">,\n): Promise<DeviceCodeGrant> {\n let res: Response;\n try {\n res = await deps.fetch(config.deviceCodeEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\", accept: \"application/json\" },\n body: new URLSearchParams({\n client_id: config.clientId,\n scope: config.scopes.join(\" \"),\n }).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `device request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `device endpoint returned HTTP ${res.status}`,\n );\n }\n const data = (await parseJsonOrFail(\n res,\n \"oauth_device_authorization_failed\",\n \"device endpoint\",\n )) as {\n device_code?: unknown;\n user_code?: unknown;\n verification_uri?: unknown;\n verification_uri_complete?: unknown;\n interval?: unknown;\n expires_in?: unknown;\n };\n if (typeof data.device_code !== \"string\" || typeof data.user_code !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n \"device response missing device_code/user_code\",\n );\n }\n const verification =\n typeof data.verification_uri === \"string\"\n ? data.verification_uri\n : typeof data.verification_uri_complete === \"string\"\n ? data.verification_uri_complete\n : \"\";\n return {\n deviceCode: data.device_code,\n userCode: data.user_code,\n verificationUri: verification,\n interval: typeof data.interval === \"number\" && data.interval > 0 ? data.interval : 5,\n expiresIn: typeof data.expires_in === \"number\" && data.expires_in > 0 ? data.expires_in : 900,\n };\n}\n\n/**\n * Step 2 — poll the token endpoint until the user approves (or the code expires). Handles RFC 8628\n * `authorization_pending` (keep waiting) and `slow_down` (back off), with an expiry deadline so it cannot\n * spin forever.\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: RFC 8628 poll state machine (authorization_pending / slow_down / success / expiry) — a cohesive loop ported verbatim (ADR D3); fragmenting it would obscure the protocol.\nexport async function pollDeviceToken(\n config: DeviceOAuthConfig,\n grant: DeviceCodeGrant,\n deps: DeviceDeps,\n): Promise<OAuthTokens> {\n const deadline = deps.now() + grant.expiresIn * 1000;\n let intervalMs = grant.interval * 1000;\n\n while (deps.now() < deadline) {\n let res: Response;\n try {\n res = await deps.fetch(config.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n accept: \"application/json\",\n },\n body: new URLSearchParams({\n client_id: config.clientId,\n device_code: grant.deviceCode,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device token poll failed: ${(err as Error).message}`,\n );\n }\n // RFC 8628 §3.5: `authorization_pending` / `slow_down` arrive as a 400 with an `error` body — so the\n // body MUST be read before deciding failure. Parse first; only a non-OAuth-shaped body on a non-2xx fails.\n const data = (await res.json().catch(() => ({}))) as {\n access_token?: string;\n refresh_token?: string;\n expires_in?: number;\n id_token?: string;\n error?: string;\n interval?: number;\n };\n if (!res.ok && typeof data.error !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device token endpoint returned HTTP ${res.status}`,\n );\n }\n\n if (typeof data.access_token === \"string\" && data.access_token.length > 0) {\n const expiresIn = typeof data.expires_in === \"number\" ? data.expires_in : 0;\n const accountId = extractAccountId({\n access_token: data.access_token,\n id_token: data.id_token,\n });\n return {\n access: data.access_token,\n // Some device-grant providers (e.g. GitHub) issue no separate refresh token — reuse the access\n // token as the refresh handle.\n refresh: data.refresh_token ?? data.access_token,\n expires: deps.now() + expiresIn * 1000,\n ...(accountId !== undefined ? { accountId } : {}),\n ...(typeof data.id_token === \"string\" && data.id_token.length > 0\n ? { idToken: data.id_token }\n : {}),\n };\n }\n\n if (data.error === \"authorization_pending\") {\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n continue;\n }\n if (data.error === \"slow_down\") {\n // RFC 8628 §3.5: add 5s to the interval, or honor a server-provided one.\n intervalMs =\n (typeof data.interval === \"number\" && data.interval > 0\n ? data.interval\n : grant.interval + 5) * 1000;\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n continue;\n }\n if (typeof data.error === \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device authorization rejected: ${data.error}`,\n );\n }\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n }\n throw new AuthCallbackError(\n \"oauth_device_code_expired\",\n \"the device code expired before it was approved\",\n );\n}\n\n/**\n * The full device login: request a code, hand the user the verification URL + user code via `onPrompt`\n * (never printed here — the caller renders it, keeping this module output-free), then poll to completion.\n */\nexport async function deviceLogin(\n config: DeviceOAuthConfig,\n deps: DeviceDeps,\n hooks: {\n onPrompt: (p: { userCode: string; verificationUri: string; expiresIn: number }) => void;\n },\n): Promise<OAuthTokens> {\n const grant = await requestDeviceCode(config, deps);\n hooks.onPrompt({\n userCode: grant.userCode,\n verificationUri: grant.verificationUri,\n expiresIn: grant.expiresIn,\n });\n return pollDeviceToken(config, grant, deps);\n}\n\n// ─── OpenAI / ChatGPT \"headless\" device flow (two-step) ───\n\n/** Step 1 (OpenAI) — request the user code. */\nexport async function requestOpenAIUsercode(\n config: OpenAIDeviceConfig,\n deps: Pick<DeviceDeps, \"fetch\">,\n): Promise<{ deviceAuthId: string; userCode: string; interval: number }> {\n let res: Response;\n try {\n res = await deps.fetch(config.deviceUsercodeEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({ client_id: config.clientId }),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `usercode request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `usercode endpoint returned HTTP ${res.status}`,\n );\n }\n const data = (await parseJsonOrFail(\n res,\n \"oauth_device_authorization_failed\",\n \"usercode endpoint\",\n )) as {\n device_auth_id?: unknown;\n user_code?: unknown;\n interval?: unknown;\n };\n if (typeof data.device_auth_id !== \"string\" || typeof data.user_code !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n \"usercode response missing device_auth_id/user_code\",\n );\n }\n const interval = Math.max(\n typeof data.interval === \"string\" ? parseInt(data.interval, 10) || 5 : 5,\n 1,\n );\n return { deviceAuthId: data.device_auth_id, userCode: data.user_code, interval };\n}\n\n/**\n * Step 2+3 (OpenAI) — poll for the authorization code (200 = ready; 403/404 = pending; else fail), then\n * exchange it for tokens at the standard `/oauth/token` endpoint (reuses `exchangeCode`).\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: OpenAI two-step headless poll loop (200 ready / 403,404 pending / else fail) — cohesive network state machine ported verbatim (ADR D3).\nexport async function openaiDeviceLogin(\n config: OpenAIDeviceConfig,\n deps: DeviceDeps,\n hooks: { onPrompt: (p: { userCode: string; verificationUri: string }) => void },\n): Promise<OAuthTokens> {\n const { deviceAuthId, userCode, interval } = await requestOpenAIUsercode(config, deps);\n hooks.onPrompt({ userCode, verificationUri: config.verificationUri });\n\n const intervalMs = interval * 1000;\n // Bound the loop so it cannot spin forever if the provider never resolves (upstream loops unbounded).\n const deadline = deps.now() + 15 * 60 * 1000;\n while (deps.now() < deadline) {\n let res: Response;\n try {\n res = await deps.fetch(config.devicePollEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({ device_auth_id: deviceAuthId, user_code: userCode }),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device poll failed: ${(err as Error).message}`,\n );\n }\n if (res.ok) {\n const data = (await parseJsonOrFail(res, \"oauth_token_exchange_failed\", \"device poll\")) as {\n authorization_code?: unknown;\n code_verifier?: unknown;\n };\n if (typeof data.authorization_code !== \"string\" || typeof data.code_verifier !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n \"device poll returned no authorization_code\",\n );\n }\n const tokens = await exchangeCode(\n config,\n { code: data.authorization_code, verifier: data.code_verifier },\n deps,\n );\n // M43 D4 fix #2 — the two-step exchange returns a JWT access token but `parseTokenResponse` only reads a\n // top-level `account_id`. JWT-extract the `chatgpt_account_id` (as the generic device poll already does)\n // so the login persists a non-empty account_id for the Codex `ChatGPT-Account-Id` header.\n return {\n ...tokens,\n accountId: tokens.accountId ?? extractAccountId({ access_token: tokens.access }),\n };\n }\n // 403/404 = still pending (user has not approved yet); anything else is a hard failure.\n if (res.status !== 403 && res.status !== 404) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device poll returned HTTP ${res.status}`,\n );\n }\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n }\n throw new AuthCallbackError(\n \"oauth_device_code_expired\",\n \"the device authorization expired before approval\",\n );\n}\n\n/** JWT id/access-token claims we read to attribute an account. */\ninterface IdTokenClaims {\n chatgpt_account_id?: string;\n organizations?: Array<{ id: string }>;\n \"https://api.openai.com/auth\"?: { chatgpt_account_id?: string };\n}\n\n/** Decode a JWT's claim set (no signature verification — used only to read a self-reported account id). */\nexport function parseJwtClaims(token: string): IdTokenClaims | undefined {\n const parts = token.split(\".\");\n if (parts.length !== 3) return undefined;\n try {\n return JSON.parse(Buffer.from(parts[1] as string, \"base64url\").toString()) as IdTokenClaims;\n } catch {\n return undefined;\n }\n}\n\n/** Best-effort account id from an id/access token's claims (OpenAI/ChatGPT shape). */\nexport function extractAccountId(tokens: {\n id_token?: string;\n access_token?: string;\n}): string | undefined {\n for (const token of [tokens.id_token, tokens.access_token]) {\n if (token === undefined) continue;\n const claims = parseJwtClaims(token);\n const id =\n claims?.chatgpt_account_id ??\n claims?.[\"https://api.openai.com/auth\"]?.chatgpt_account_id ??\n claims?.organizations?.[0]?.id;\n if (id !== undefined) return id;\n }\n return undefined;\n}\n"]}
@@ -1,9 +1,9 @@
1
1
  import { submit, subscribe } from './chunk-HWMGR3HA.js';
2
2
  import './chunk-K2BQQ445.js';
3
- import { newPooledCredential, CredentialPool, withCredentialPool } from './chunk-5AR6O7GW.js';
3
+ import { newPooledCredential, CredentialPool, withCredentialPool } from './chunk-NK5EOTDY.js';
4
4
  import './chunk-24MGQDK3.js';
5
5
  import { createSemaphore } from './chunk-AHKS3DKI.js';
6
- import './chunk-Q5EWJPRY.js';
6
+ import './chunk-PPU2D4FZ.js';
7
7
  import './chunk-MLGETTYX.js';
8
8
  import './chunk-M4U24U6G.js';
9
9
  import { ConfigurationError, TheokitAgentError } from './chunk-TNFOU6SB.js';
@@ -256,5 +256,5 @@ function buildPoolsFromApiKeys(apiKeys, strategy) {
256
256
  }
257
257
 
258
258
  export { batchImpl, validateBatchInput };
259
- //# sourceMappingURL=batch-EP3FCL6D.js.map
260
- //# sourceMappingURL=batch-EP3FCL6D.js.map
259
+ //# sourceMappingURL=batch-N2XDYZED.js.map
260
+ //# sourceMappingURL=batch-N2XDYZED.js.map