@xopcai/xopc 0.0.101 → 0.0.103

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 (323) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  5. package/dist/extensions/feishu/src/transport/webhook/monitor.js +2 -2
  6. package/dist/extensions/feishu/src/transport/webhook/monitor.js.map +1 -1
  7. package/dist/extensions/feishu/src/workflow-progress.js +1 -1
  8. package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
  9. package/dist/extensions/telegram/src/inbound-processor.js +1 -1
  10. package/dist/extensions/telegram/src/plugin.js +1 -1
  11. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  12. package/dist/extensions/telegram/src/send-options.js +8 -5
  13. package/dist/extensions/telegram/src/send-options.js.map +1 -1
  14. package/dist/extensions/telegram/src/update-offset-store.js +1 -1
  15. package/dist/extensions/telegram/src/workflow-progress.js +1 -1
  16. package/dist/extensions/telegram/xopc.extension.json +1 -1
  17. package/dist/extensions/weixin/src/api/api.js +2 -2
  18. package/dist/extensions/weixin/src/auth/accounts.js +1 -1
  19. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  20. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  21. package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
  22. package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
  23. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  24. package/dist/extensions/weixin/src/plugin.js +1 -1
  25. package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
  26. package/dist/extensions/weixin/src/workflow-progress.js +1 -1
  27. package/dist/gateway/static/root/assets/{agents-u8cmUfGQ.js → agents-BwXkia_W.js} +1 -1
  28. package/dist/gateway/static/root/assets/{apps-page-DF8m9cUE.js → apps-page-C5RmwmTT.js} +1 -1
  29. package/dist/gateway/static/root/assets/{channels-settings-BM3doRvi.js → channels-settings-tlOTdaXw.js} +1 -1
  30. package/dist/gateway/static/root/assets/{channels-status-swr-ah4zWEIP.js → channels-status-swr-D4XjqwqC.js} +1 -1
  31. package/dist/gateway/static/root/assets/{cron-api-DgMuL_2b.js → cron-api-DcmfGuj0.js} +1 -1
  32. package/dist/gateway/static/root/assets/{cron-page-COfUPKfq.js → cron-page-CijJ4G6F.js} +1 -1
  33. package/dist/gateway/static/root/assets/{dist-Dzy3Q0ZH.js → dist-CWm8hTXZ.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-debug-page-kyxxefKh.js → extension-debug-page-BzYgTkS9.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-page-BVbCBHoI.js → extension-page-BmTZH6gL.js} +1 -1
  36. package/dist/gateway/static/root/assets/{extension-settings-page-t1lb2A7v.js → extension-settings-page-CyJk_G64.js} +1 -1
  37. package/dist/gateway/static/root/assets/{fetch-drJUxxKP.js → fetch-CMoWY2Si.js} +1 -1
  38. package/dist/gateway/static/root/assets/{field-primitives-6Vo1Yga4.js → field-primitives-C4GpxsDo.js} +1 -1
  39. package/dist/gateway/static/root/assets/{heartbeat-config-api-BF3psu4O.js → heartbeat-config-api-CLD0Gpi3.js} +1 -1
  40. package/dist/gateway/static/root/assets/index-0HmunJW9.js +4845 -0
  41. package/dist/gateway/static/root/assets/index-Bk75Phrd.css +1 -0
  42. package/dist/gateway/static/root/assets/{logs-page-BTVPXcHV.js → logs-page-BjdQjHwk.js} +1 -1
  43. package/dist/gateway/static/root/assets/{note-detail-page-DqSAg_5Z.js → note-detail-page-8Er4197b.js} +2 -2
  44. package/dist/gateway/static/root/assets/{note-time-FSOjchic.js → note-time-CF3vf1jm.js} +1 -1
  45. package/dist/gateway/static/root/assets/{notes-page-DkRX7BE2.js → notes-page-BBnTh0uI.js} +1 -1
  46. package/dist/gateway/static/root/assets/{sessions-page-Khdw35Zk.js → sessions-page-B0riYK7j.js} +1 -1
  47. package/dist/gateway/static/root/assets/{settings-advanced-gate-DspC8oEm.js → settings-advanced-gate-DiP_WHu_.js} +1 -1
  48. package/dist/gateway/static/root/assets/{settings-form-section-DuxvUuur.js → settings-form-section-C7qA7y0J.js} +1 -1
  49. package/dist/gateway/static/root/assets/{settings-page-DN8JBZ8F.js → settings-page-1ZPhcCZ9.js} +2 -2
  50. package/dist/gateway/static/root/assets/share-preview-page-Tvr5Mtq5.js +2 -0
  51. package/dist/gateway/static/root/assets/{skills-page-ByYT0fXZ.js → skills-page-BQ1hllKD.js} +1 -1
  52. package/dist/gateway/static/root/assets/{theme-store-B6KXPHgK.js → theme-store-HTvJlFLL.js} +1 -1
  53. package/dist/gateway/static/root/assets/url-F3_D_6zZ.js +3 -0
  54. package/dist/gateway/static/root/assets/{utils-DK_1H47k.js → utils-CPr3FBh2.js} +1 -1
  55. package/dist/gateway/static/root/assets/{voice-api-key-field-BYN2EIMs.js → voice-api-key-field-BkbDl6dH.js} +1 -1
  56. package/dist/gateway/static/root/assets/{workflow-page.utils-Bi19YNTr.js → workflow-page.utils-CeBkAjP7.js} +1 -1
  57. package/dist/gateway/static/root/assets/{workflows-page-DP57FEKW.js → workflows-page-D059ysoF.js} +1 -1
  58. package/dist/gateway/static/root/index.html +5 -5
  59. package/dist/package.js +1 -1
  60. package/dist/src/agent/agent-manager.js +7 -7
  61. package/dist/src/agent/agent-scope.js +1 -1
  62. package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
  63. package/dist/src/agent/context/workspace-seed.js +2 -2
  64. package/dist/src/agent/context/workspace-state.js +1 -1
  65. package/dist/src/agent/goals/goal-run-store.js +4 -4
  66. package/dist/src/agent/goals/persistent-goal-service.js +1 -1
  67. package/dist/src/agent/goals/post-turn.js +2 -2
  68. package/dist/src/agent/image/load-image-media.js +2 -2
  69. package/dist/src/agent/inbound/attachment-pipeline.js +2 -2
  70. package/dist/src/agent/inbound/attachment-pipeline.js.map +1 -1
  71. package/dist/src/agent/ipc/bus.js +1 -1
  72. package/dist/src/agent/ipc/inbox.js +2 -2
  73. package/dist/src/agent/ipc/socket.js +1 -1
  74. package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
  75. package/dist/src/agent/mcp/bundle-mcp-runtime.js +1 -1
  76. package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
  77. package/dist/src/agent/mcp/mcp-transport.js +1 -1
  78. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  79. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  80. package/dist/src/agent/memory/dreaming/events.js +1 -1
  81. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  82. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  83. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  84. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  85. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  86. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  87. package/dist/src/agent/memory/memory-flush.js +1 -1
  88. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  89. package/dist/src/agent/models/manager.js +1 -1
  90. package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
  91. package/dist/src/agent/reply/post-compaction-context.js +1 -1
  92. package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
  93. package/dist/src/agent/sandbox/path-policy.js +2 -2
  94. package/dist/src/agent/service.js +4 -4
  95. package/dist/src/agent/session/session-inspector.js +1 -1
  96. package/dist/src/agent/skills/config.js +1 -1
  97. package/dist/src/agent/skills/hub-hash.js +2 -2
  98. package/dist/src/agent/skills/hub-lock.js +1 -1
  99. package/dist/src/agent/skills/hub-pull.js +2 -2
  100. package/dist/src/agent/skills/index.js +1 -1
  101. package/dist/src/agent/skills/managed-store.js +1 -1
  102. package/dist/src/agent/skills/scanner.js +1 -1
  103. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  104. package/dist/src/agent/skills/skill-manager.js +1 -1
  105. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  106. package/dist/src/agent/tools/factory.js +1 -1
  107. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  108. package/dist/src/agent/tools/send-media.js +2 -3
  109. package/dist/src/agent/tools/send-media.js.map +1 -1
  110. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  111. package/dist/src/agent/tools/workflow-tool.js +1 -1
  112. package/dist/src/agent/tools/write.js +1 -1
  113. package/dist/src/agent/workflow/catalog.js +1 -1
  114. package/dist/src/auth/credentials.d.ts +7 -0
  115. package/dist/src/auth/credentials.js +37 -4
  116. package/dist/src/auth/credentials.js.map +1 -1
  117. package/dist/src/auth/index.d.ts +1 -1
  118. package/dist/src/auth/index.js.map +1 -1
  119. package/dist/src/auth/oauth/github-copilot.d.ts +1 -1
  120. package/dist/src/auth/oauth/google-antigravity.d.ts +1 -3
  121. package/dist/src/auth/oauth/google-antigravity.js +1 -1
  122. package/dist/src/auth/oauth/google-gemini-cli.d.ts +1 -3
  123. package/dist/src/auth/oauth/google-gemini-cli.js +1 -1
  124. package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/google-antigravity.js +3 -5
  125. package/dist/src/auth/oauth/google-oauth/google-antigravity.js.map +1 -0
  126. package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/google-gemini-cli.js +4 -5
  127. package/dist/src/auth/oauth/google-oauth/google-gemini-cli.js.map +1 -0
  128. package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/oauth-page.js +12 -4
  129. package/dist/src/auth/oauth/google-oauth/oauth-page.js.map +1 -0
  130. package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/pkce.d.ts +1 -1
  131. package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/pkce.js +2 -2
  132. package/dist/src/auth/oauth/google-oauth/pkce.js.map +1 -0
  133. package/dist/src/auth/oauth/index.js +2 -2
  134. package/dist/src/auth/oauth/kimi-coding.d.ts +1 -1
  135. package/dist/src/auth/oauth/kimi-coding.js +1 -1
  136. package/dist/src/auth/oauth/kimi-coding.js.map +1 -1
  137. package/dist/src/auth/oauth/minimax-cn.js +1 -1
  138. package/dist/src/auth/oauth/minimax-cn.js.map +1 -1
  139. package/dist/src/auth/oauth/minimax.js +1 -1
  140. package/dist/src/auth/oauth/minimax.js.map +1 -1
  141. package/dist/src/auth/oauth/openai-codex.d.ts +7 -2
  142. package/dist/src/auth/oauth/openai-codex.js +318 -1
  143. package/dist/src/auth/oauth/openai-codex.js.map +1 -0
  144. package/dist/src/auth/profiles/store.js +4 -3
  145. package/dist/src/auth/profiles/store.js.map +1 -1
  146. package/dist/src/auth/sync-provider-auth.js +1 -1
  147. package/dist/src/browser/cache-dir-policy.js +1 -1
  148. package/dist/src/browser/cdp-local-launcher.js +2 -2
  149. package/dist/src/browser/providers/browser-ext-install.js +3 -3
  150. package/dist/src/browser/providers/cloakbrowser.js +4 -4
  151. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  152. package/dist/src/browser/stealth.js +1 -1
  153. package/dist/src/channels/attachments/attachment-classifiers.d.ts +1 -0
  154. package/dist/src/channels/attachments/attachment-classifiers.js +13 -2
  155. package/dist/src/channels/attachments/attachment-classifiers.js.map +1 -1
  156. package/dist/src/channels/outbound/persist-store.js +1 -1
  157. package/dist/src/channels/pairing/allow-from-file.js +1 -1
  158. package/dist/src/channels/pairing/pairing-store.js +2 -2
  159. package/dist/src/chat-commands/agent-edit.js +2 -2
  160. package/dist/src/chat-commands/builtins/config.js +2 -2
  161. package/dist/src/chat-commands/builtins/model.js +2 -2
  162. package/dist/src/chat-commands/builtins/model.js.map +1 -1
  163. package/dist/src/chat-commands/context.js +1 -1
  164. package/dist/src/cli/command-manifest.js +1 -1
  165. package/dist/src/cli/command-manifest.js.map +1 -1
  166. package/dist/src/cli/commands/auth.js +39 -51
  167. package/dist/src/cli/commands/auth.js.map +1 -1
  168. package/dist/src/cli/commands/config.js +1 -1
  169. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  170. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  171. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  172. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  173. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
  174. package/dist/src/cli/commands/extension-dev.js +1 -1
  175. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  176. package/dist/src/cli/commands/extension-pack.js +1 -1
  177. package/dist/src/cli/commands/gateway/logs.js +1 -1
  178. package/dist/src/cli/commands/image.js +1 -1
  179. package/dist/src/cli/commands/init.js +3 -3
  180. package/dist/src/cli/commands/models.js +189 -54
  181. package/dist/src/cli/commands/models.js.map +1 -1
  182. package/dist/src/cli/commands/onboard/model.d.ts +1 -4
  183. package/dist/src/cli/commands/onboard/model.js +253 -183
  184. package/dist/src/cli/commands/onboard/model.js.map +1 -1
  185. package/dist/src/cli/utils/init-workspace-core.js +2 -2
  186. package/dist/src/cli/utils/oauth-login.d.ts +17 -0
  187. package/dist/src/cli/utils/oauth-login.js +93 -0
  188. package/dist/src/cli/utils/oauth-login.js.map +1 -0
  189. package/dist/src/cli/utils/oauth-providers.js +2 -2
  190. package/dist/src/commands/agents.config.js +1 -1
  191. package/dist/src/config/agent-profile.js +1 -1
  192. package/dist/src/config/gateway-bind.js +1 -1
  193. package/dist/src/config/index.js +5 -5
  194. package/dist/src/config/loader.js +2 -2
  195. package/dist/src/config/models-json.js +2 -2
  196. package/dist/src/config/paths-state.js +1 -1
  197. package/dist/src/config/profile.js +2 -2
  198. package/dist/src/config/workspace-path.js +1 -1
  199. package/dist/src/cron/executor.js +2 -2
  200. package/dist/src/cron/persistence.js +1 -1
  201. package/dist/src/daemon/constants.js +1 -1
  202. package/dist/src/daemon/install-plan.js +2 -2
  203. package/dist/src/daemon/launchd.js +2 -2
  204. package/dist/src/daemon/schtasks.js +2 -2
  205. package/dist/src/daemon/systemd.js +2 -2
  206. package/dist/src/extensions/bundle-mcp.js +1 -1
  207. package/dist/src/extensions/discover-extensions.js +1 -1
  208. package/dist/src/extensions/health.js +1 -1
  209. package/dist/src/extensions/loader.js +1 -1
  210. package/dist/src/extensions/lockfile.js +2 -2
  211. package/dist/src/extensions/update.js +1 -1
  212. package/dist/src/gateway/agents-admin.js +3 -3
  213. package/dist/src/gateway/file-path-classifier.js +2 -2
  214. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  215. package/dist/src/gateway/hono/lib/extension-store.js +2 -2
  216. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  217. package/dist/src/gateway/hono/oauth-async.js +3 -3
  218. package/dist/src/gateway/hono/oauth.js +3 -3
  219. package/dist/src/gateway/hono/routes/agents.js +1 -1
  220. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  221. package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
  222. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  223. package/dist/src/gateway/hono/routes/host-fs.js +2 -2
  224. package/dist/src/gateway/hono/routes/models.js +26 -6
  225. package/dist/src/gateway/hono/routes/models.js.map +1 -1
  226. package/dist/src/gateway/hono/routes/notes.js +9 -22
  227. package/dist/src/gateway/hono/routes/notes.js.map +1 -1
  228. package/dist/src/gateway/hono/routes/shares.js +1 -1
  229. package/dist/src/gateway/hono/routes/workspace.js +2 -2
  230. package/dist/src/gateway/lock.js +3 -3
  231. package/dist/src/gateway/ports.js +1 -1
  232. package/dist/src/gateway/service/agent-runner.js +2 -2
  233. package/dist/src/gateway/service/marketplace-service.js +2 -2
  234. package/dist/src/gateway/service.js +1 -1
  235. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  236. package/dist/src/infra/brew.js +1 -1
  237. package/dist/src/infra/package-json.js +1 -1
  238. package/dist/src/infra/package-update-steps.js +1 -1
  239. package/dist/src/infra/path-env.js +2 -2
  240. package/dist/src/infra/restart.js +2 -2
  241. package/dist/src/infra/stable-node-path.js +1 -1
  242. package/dist/src/infra/update-check.js +1 -1
  243. package/dist/src/infra/update-global.js +1 -1
  244. package/dist/src/infra/update-lock.js +3 -3
  245. package/dist/src/infra/update-runner.js +1 -1
  246. package/dist/src/infra/update-startup.js +2 -2
  247. package/dist/src/infra/write-file-atomic.js +2 -2
  248. package/dist/src/media/store.js +4 -1
  249. package/dist/src/media/store.js.map +1 -1
  250. package/dist/src/notes/note-attachment-sync.d.ts +2 -3
  251. package/dist/src/notes/note-attachment-sync.js +2 -27
  252. package/dist/src/notes/note-attachment-sync.js.map +1 -1
  253. package/dist/src/notes/note-index-meta.d.ts +6 -2
  254. package/dist/src/notes/note-index-meta.js +11 -16
  255. package/dist/src/notes/note-index-meta.js.map +1 -1
  256. package/dist/src/notes/note-markdown.d.ts +61 -0
  257. package/dist/src/notes/note-markdown.js +177 -0
  258. package/dist/src/notes/note-markdown.js.map +1 -0
  259. package/dist/src/notes/service.d.ts +9 -7
  260. package/dist/src/notes/service.js +163 -312
  261. package/dist/src/notes/service.js.map +1 -1
  262. package/dist/src/notes/store.js +4 -5
  263. package/dist/src/notes/store.js.map +1 -1
  264. package/dist/src/notes/types.d.ts +29 -58
  265. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  266. package/dist/src/providers/index.d.ts +3 -3
  267. package/dist/src/providers/index.js +25 -17
  268. package/dist/src/providers/index.js.map +1 -1
  269. package/dist/src/providers/model-registry.js +1 -1
  270. package/dist/src/providers/presentation.d.ts +34 -0
  271. package/dist/src/providers/presentation.js +162 -0
  272. package/dist/src/providers/presentation.js.map +1 -0
  273. package/dist/src/session/init-session-turn.js +2 -2
  274. package/dist/src/session/resolve-session.js +3 -3
  275. package/dist/src/session/session-title.js +2 -2
  276. package/dist/src/session/store.js +2 -2
  277. package/dist/src/share/share-auto.js +2 -2
  278. package/dist/src/share/share-store.js +3 -3
  279. package/dist/src/share/share-thumbnail.js +2 -2
  280. package/dist/src/share/share-zip.js +1 -1
  281. package/dist/src/share/site-share-store.js +3 -3
  282. package/dist/src/share/site-static-serve.js +1 -1
  283. package/dist/src/storage/sqlite/connection.js +2 -2
  284. package/dist/src/storage/sqlite/memory-index-repository.js +2 -2
  285. package/dist/src/storage/sqlite/migrations/003_add_note_markdown_meta.sql +4 -0
  286. package/dist/src/storage/sqlite/migrations/discover.js +1 -1
  287. package/dist/src/storage/sqlite/migrations/runner.d.ts +2 -2
  288. package/dist/src/storage/sqlite/migrations/runner.js +5 -5
  289. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  290. package/dist/src/storage/sqlite/migrations/runner.ts +2 -2
  291. package/dist/src/storage/sqlite/notes-repository.js +18 -6
  292. package/dist/src/storage/sqlite/notes-repository.js.map +1 -1
  293. package/dist/src/storage/sqlite/schema.js +4 -4
  294. package/dist/src/storage/sqlite/schema.sql +5 -1
  295. package/dist/src/tui/clipboard-image.js +3 -3
  296. package/dist/src/tui/theme-manager.js +1 -1
  297. package/dist/src/tui/tui-keybindings-file.js +1 -1
  298. package/dist/src/tui/tui-scoped-models.js +2 -2
  299. package/dist/src/tui/tui-settings.js +1 -1
  300. package/dist/src/tui/tui.js +3 -3
  301. package/dist/src/tunnel/frpc-binary.js +3 -3
  302. package/dist/src/tunnel/frpc-config.js +1 -1
  303. package/dist/src/tunnel/frpc-extract.js +1 -1
  304. package/dist/src/tunnel/tunnel-state.js +1 -1
  305. package/dist/src/utils/logger/audit.js +1 -1
  306. package/dist/src/utils/logger/log-store.js +1 -1
  307. package/dist/src/utils/logger/rotation.js +1 -1
  308. package/dist/src/voice/tts/audio.js +1 -1
  309. package/dist/src/voice/tts/providers/edge-speech.js +2 -2
  310. package/dist/src/workflows/store/event-store.js +1 -1
  311. package/dist/src/workflows/store/run-store.js +1 -1
  312. package/package.json +1 -1
  313. package/dist/gateway/static/root/assets/index-DjNDHzwG.css +0 -1
  314. package/dist/gateway/static/root/assets/index-WAyKAilR.js +0 -4840
  315. package/dist/gateway/static/root/assets/share-preview-page-UNAcbiMb.js +0 -2
  316. package/dist/gateway/static/root/assets/url-q28QhI7l.js +0 -3
  317. package/dist/src/auth/oauth/vendor-pi-google/google-antigravity.js.map +0 -1
  318. package/dist/src/auth/oauth/vendor-pi-google/google-gemini-cli.js.map +0 -1
  319. package/dist/src/auth/oauth/vendor-pi-google/oauth-page.js.map +0 -1
  320. package/dist/src/auth/oauth/vendor-pi-google/pkce.js.map +0 -1
  321. /package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/google-antigravity.d.ts +0 -0
  322. /package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/google-gemini-cli.d.ts +0 -0
  323. /package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/oauth-page.d.ts +0 -0
@@ -1,6 +1,6 @@
1
1
  import { oauthErrorHtml, oauthSuccessHtml } from "./oauth-page.js";
2
2
  import { generatePKCE } from "./pkce.js";
3
- //#region src/auth/oauth/vendor-pi-google/google-antigravity.ts
3
+ //#region src/auth/oauth/google-oauth/google-antigravity.ts
4
4
  let _createServer = null;
5
5
  let _httpImportPromise = null;
6
6
  if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) _httpImportPromise = import("node:http").then((m) => {
@@ -28,7 +28,6 @@ const SCOPES = [
28
28
  ];
29
29
  const AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
30
30
  const TOKEN_URL = "https://oauth2.googleapis.com/token";
31
- const DEFAULT_PROJECT_ID = "rising-fact-p41fc";
32
31
  /**
33
32
  * Start a local HTTP server to receive the OAuth callback
34
33
  */
@@ -80,7 +79,7 @@ async function startCallbackServer() {
80
79
  server.on("error", (err) => {
81
80
  reject(err);
82
81
  });
83
- server.listen(51121, "127.0.0.1", () => {
82
+ server.listen(51121, () => {
84
83
  resolve({
85
84
  server,
86
85
  cancelWait: () => {
@@ -140,8 +139,7 @@ async function discoverProject(accessToken, onProgress) {
140
139
  if (data.cloudaicompanionProject && typeof data.cloudaicompanionProject === "object" && data.cloudaicompanionProject.id) return data.cloudaicompanionProject.id;
141
140
  }
142
141
  } catch {}
143
- onProgress?.("Using default project...");
144
- return DEFAULT_PROJECT_ID;
142
+ throw new Error("Failed to discover Google Cloud companion project");
145
143
  }
146
144
  /**
147
145
  * Get user email from the access token
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-antigravity.js","names":[],"sources":["../../../../../src/auth/oauth/google-oauth/google-antigravity.ts"],"sourcesContent":["/**\n * Antigravity OAuth flow (Gemini 3, Claude, GPT-OSS via Google Cloud)\n * Uses different OAuth credentials than google-gemini-cli for access to additional models.\n *\n * NOTE: This module uses Node.js http.createServer for the OAuth callback.\n * It is only intended for CLI use, not browser environments.\n */\n\nimport type { Server } from \"node:http\";\nimport { oauthErrorHtml, oauthSuccessHtml } from \"./oauth-page.js\";\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"../types.js\";\n\ntype AntigravityCredentials = OAuthCredentials & {\n\tprojectId: string;\n};\n\nlet _createServer: typeof import(\"node:http\").createServer | null = null;\nlet _httpImportPromise: Promise<void> | null = null;\nif (typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun)) {\n\t_httpImportPromise = import(\"node:http\").then((m) => {\n\t\t_createServer = m.createServer;\n\t});\n}\n\nconst ANTIGRAVITY_CLIENT_ID_ENV = 'XOPC_GOOGLE_ANTIGRAVITY_OAUTH_CLIENT_ID';\nconst ANTIGRAVITY_CLIENT_SECRET_ENV = 'XOPC_GOOGLE_ANTIGRAVITY_OAUTH_CLIENT_SECRET';\n\n/** Desktop OAuth client for this flow — must be set locally (not committed; avoids GitHub push protection). */\nfunction getAntigravityOAuthClient(): { clientId: string; clientSecret: string } {\n\tconst clientId = process.env[ANTIGRAVITY_CLIENT_ID_ENV]?.trim();\n\tconst clientSecret = process.env[ANTIGRAVITY_CLIENT_SECRET_ENV]?.trim();\n\tif (!clientId || !clientSecret) {\n\t\tthrow new Error(\n\t\t\t`Google Antigravity OAuth requires ${ANTIGRAVITY_CLIENT_ID_ENV} and ${ANTIGRAVITY_CLIENT_SECRET_ENV}.`,\n\t\t);\n\t}\n\treturn { clientId, clientSecret };\n}\n\nconst REDIRECT_URI = \"http://localhost:51121/oauth-callback\";\n\n// Antigravity requires additional scopes\nconst SCOPES = [\n\t\"https://www.googleapis.com/auth/cloud-platform\",\n\t\"https://www.googleapis.com/auth/userinfo.email\",\n\t\"https://www.googleapis.com/auth/userinfo.profile\",\n\t\"https://www.googleapis.com/auth/cclog\",\n\t\"https://www.googleapis.com/auth/experimentsandconfigs\",\n];\n\nconst AUTH_URL = \"https://accounts.google.com/o/oauth2/v2/auth\";\nconst TOKEN_URL = \"https://oauth2.googleapis.com/token\";\n\n\ntype CallbackServerInfo = {\n\tserver: Server;\n\tcancelWait: () => void;\n\twaitForCode: () => Promise<{ code: string; state: string } | null>;\n};\n\n/**\n * Start a local HTTP server to receive the OAuth callback\n */\nasync function getNodeCreateServer(): Promise<typeof import(\"node:http\").createServer> {\n\tif (_createServer) return _createServer;\n\tif (_httpImportPromise) {\n\t\tawait _httpImportPromise;\n\t}\n\tif (_createServer) return _createServer;\n\tthrow new Error(\"Antigravity OAuth is only available in Node.js environments\");\n}\n\nasync function startCallbackServer(): Promise<CallbackServerInfo> {\n\tconst createServer = await getNodeCreateServer();\n\n\treturn new Promise((resolve, reject) => {\n\t\tlet settleWait: ((value: { code: string; state: string } | null) => void) | undefined;\n\t\tconst waitForCodePromise = new Promise<{ code: string; state: string } | null>((resolveWait) => {\n\t\t\tlet settled = false;\n\t\t\tsettleWait = (value) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tresolveWait(value);\n\t\t\t};\n\t\t});\n\n\t\tconst server = createServer((req, res) => {\n\t\t\tconst url = new URL(req.url || \"\", `http://localhost:51121`);\n\n\t\t\tif (url.pathname === \"/oauth-callback\") {\n\t\t\t\tconst code = url.searchParams.get(\"code\");\n\t\t\t\tconst state = url.searchParams.get(\"state\");\n\t\t\t\tconst error = url.searchParams.get(\"error\");\n\n\t\t\t\tif (error) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"Google authentication did not complete.\", `Error: ${error}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (code && state) {\n\t\t\t\t\tres.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthSuccessHtml(\"Google authentication completed. You can close this window.\"));\n\t\t\t\t\tsettleWait?.({ code, state });\n\t\t\t\t} else {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"Missing code or state parameter.\"));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tres.writeHead(404, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\tres.end(oauthErrorHtml(\"Callback route not found.\"));\n\t\t\t}\n\t\t});\n\n\t\tserver.on(\"error\", (err) => {\n\t\t\treject(err);\n\t\t});\n\n\t\tserver.listen(51121, () => {\n\t\t\tresolve({\n\t\t\t\tserver,\n\t\t\t\tcancelWait: () => {\n\t\t\t\t\tsettleWait?.(null);\n\t\t\t\t},\n\t\t\t\twaitForCode: () => waitForCodePromise,\n\t\t\t});\n\t\t});\n\t});\n}\n\n/**\n * Parse redirect URL to extract code and state\n */\nfunction parseRedirectUrl(input: string): { code?: string; state?: string } {\n\tconst value = input.trim();\n\tif (!value) return {};\n\n\ttry {\n\t\tconst url = new URL(value);\n\t\treturn {\n\t\t\tcode: url.searchParams.get(\"code\") ?? undefined,\n\t\t\tstate: url.searchParams.get(\"state\") ?? undefined,\n\t\t};\n\t} catch {\n\t\t// Not a URL, return empty\n\t\treturn {};\n\t}\n}\n\ninterface LoadCodeAssistPayload {\n\tcloudaicompanionProject?: string | { id?: string };\n\tcurrentTier?: { id?: string };\n\tallowedTiers?: Array<{ id?: string; isDefault?: boolean }>;\n}\n\n/**\n * Discover or provision a project for the user\n */\nasync function discoverProject(accessToken: string, onProgress?: (message: string) => void): Promise<string> {\n\tconst headers = {\n\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\"Content-Type\": \"application/json\",\n\t\t\"User-Agent\": \"google-api-nodejs-client/9.15.1\",\n\t\t\"X-Goog-Api-Client\": \"google-cloud-sdk vscode_cloudshelleditor/0.1\",\n\t\t\"Client-Metadata\": JSON.stringify({\n\t\t\tideType: \"IDE_UNSPECIFIED\",\n\t\t\tplatform: \"PLATFORM_UNSPECIFIED\",\n\t\t\tpluginType: \"GEMINI\",\n\t\t}),\n\t};\n\n\t// Try endpoints in order: prod first, then sandbox\n\tconst endpoints = [\"https://cloudcode-pa.googleapis.com\", \"https://daily-cloudcode-pa.sandbox.googleapis.com\"];\n\n\tonProgress?.(\"Checking for existing project...\");\n\n\tfor (const endpoint of endpoints) {\n\t\ttry {\n\t\t\tconst loadResponse = await fetch(`${endpoint}/v1internal:loadCodeAssist`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders,\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\tideType: \"IDE_UNSPECIFIED\",\n\t\t\t\t\t\tplatform: \"PLATFORM_UNSPECIFIED\",\n\t\t\t\t\t\tpluginType: \"GEMINI\",\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tif (loadResponse.ok) {\n\t\t\t\tconst data = (await loadResponse.json()) as LoadCodeAssistPayload;\n\n\t\t\t\t// Handle both string and object formats\n\t\t\t\tif (typeof data.cloudaicompanionProject === \"string\" && data.cloudaicompanionProject) {\n\t\t\t\t\treturn data.cloudaicompanionProject;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\tdata.cloudaicompanionProject &&\n\t\t\t\t\ttypeof data.cloudaicompanionProject === \"object\" &&\n\t\t\t\t\tdata.cloudaicompanionProject.id\n\t\t\t\t) {\n\t\t\t\t\treturn data.cloudaicompanionProject.id;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Try next endpoint\n\t\t}\n\t}\n\n\tthrow new Error(\"Failed to discover Google Cloud companion project\");\n}\n\n/**\n * Get user email from the access token\n */\nasync function getUserEmail(accessToken: string): Promise<string | undefined> {\n\ttry {\n\t\tconst response = await fetch(\"https://www.googleapis.com/oauth2/v1/userinfo?alt=json\", {\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\t},\n\t\t});\n\n\t\tif (response.ok) {\n\t\t\tconst data = (await response.json()) as { email?: string };\n\t\t\treturn data.email;\n\t\t}\n\t} catch {\n\t\t// Ignore errors, email is optional\n\t}\n\treturn undefined;\n}\n\n/**\n * Refresh Antigravity token\n */\nexport async function refreshAntigravityToken(refreshToken: string, projectId: string): Promise<OAuthCredentials> {\n\tconst { clientId, clientSecret } = getAntigravityOAuthClient();\n\tconst response = await fetch(TOKEN_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n\t\tbody: new URLSearchParams({\n\t\t\tclient_id: clientId,\n\t\t\tclient_secret: clientSecret,\n\t\t\trefresh_token: refreshToken,\n\t\t\tgrant_type: \"refresh_token\",\n\t\t}),\n\t});\n\n\tif (!response.ok) {\n\t\tconst error = await response.text();\n\t\tthrow new Error(`Antigravity token refresh failed: ${error}`);\n\t}\n\n\tconst data = (await response.json()) as {\n\t\taccess_token: string;\n\t\texpires_in: number;\n\t\trefresh_token?: string;\n\t};\n\n\treturn {\n\t\trefresh: data.refresh_token || refreshToken,\n\t\taccess: data.access_token,\n\t\texpires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n\t\tprojectId,\n\t};\n}\n\n/**\n * Login with Antigravity OAuth\n *\n * @param onAuth - Callback with URL and optional instructions\n * @param onProgress - Optional progress callback\n * @param onManualCodeInput - Optional promise that resolves with user-pasted redirect URL.\n * Races with browser callback - whichever completes first wins.\n */\nexport async function loginAntigravity(\n\tonAuth: (info: { url: string; instructions?: string }) => void,\n\tonProgress?: (message: string) => void,\n\tonManualCodeInput?: () => Promise<string>,\n): Promise<OAuthCredentials> {\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst { clientId, clientSecret } = getAntigravityOAuthClient();\n\n\t// Start local server for callback\n\tonProgress?.(\"Starting local server for OAuth callback...\");\n\tconst server = await startCallbackServer();\n\n\tlet code: string | undefined;\n\n\ttry {\n\t\t// Build authorization URL\n\t\tconst authParams = new URLSearchParams({\n\t\t\tclient_id: clientId,\n\t\t\tresponse_type: \"code\",\n\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\tscope: SCOPES.join(\" \"),\n\t\t\tcode_challenge: challenge,\n\t\t\tcode_challenge_method: \"S256\",\n\t\t\tstate: verifier,\n\t\t\taccess_type: \"offline\",\n\t\t\tprompt: \"consent\",\n\t\t});\n\n\t\tconst authUrl = `${AUTH_URL}?${authParams.toString()}`;\n\n\t\t// Notify caller with URL to open\n\t\tonAuth({\n\t\t\turl: authUrl,\n\t\t\tinstructions: \"Complete the sign-in in your browser.\",\n\t\t});\n\n\t\t// Wait for the callback, racing with manual input if provided\n\t\tonProgress?.(\"Waiting for OAuth callback...\");\n\n\t\tif (onManualCodeInput) {\n\t\t\t// Race between browser callback and manual input\n\t\t\tlet manualInput: string | undefined;\n\t\t\tlet manualError: Error | undefined;\n\t\t\tconst manualPromise = onManualCodeInput()\n\t\t\t\t.then((input) => {\n\t\t\t\t\tmanualInput = input;\n\t\t\t\t\tserver.cancelWait();\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tmanualError = err instanceof Error ? err : new Error(String(err));\n\t\t\t\t\tserver.cancelWait();\n\t\t\t\t});\n\n\t\t\tconst result = await server.waitForCode();\n\n\t\t\t// If manual input was cancelled, throw that error\n\t\t\tif (manualError) {\n\t\t\t\tthrow manualError;\n\t\t\t}\n\n\t\t\tif (result?.code) {\n\t\t\t\t// Browser callback won - verify state\n\t\t\t\tif (result.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch - possible CSRF attack\");\n\t\t\t\t}\n\t\t\t\tcode = result.code;\n\t\t\t} else if (manualInput) {\n\t\t\t\t// Manual input won\n\t\t\t\tconst parsed = parseRedirectUrl(manualInput);\n\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch - possible CSRF attack\");\n\t\t\t\t}\n\t\t\t\tcode = parsed.code;\n\t\t\t}\n\n\t\t\t// If still no code, wait for manual promise and try that\n\t\t\tif (!code) {\n\t\t\t\tawait manualPromise;\n\t\t\t\tif (manualError) {\n\t\t\t\t\tthrow manualError;\n\t\t\t\t}\n\t\t\t\tif (manualInput) {\n\t\t\t\t\tconst parsed = parseRedirectUrl(manualInput);\n\t\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\t\tthrow new Error(\"OAuth state mismatch - possible CSRF attack\");\n\t\t\t\t\t}\n\t\t\t\t\tcode = parsed.code;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Original flow: just wait for callback\n\t\t\tconst result = await server.waitForCode();\n\t\t\tif (result?.code) {\n\t\t\t\tif (result.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch - possible CSRF attack\");\n\t\t\t\t}\n\t\t\t\tcode = result.code;\n\t\t\t}\n\t\t}\n\n\t\tif (!code) {\n\t\t\tthrow new Error(\"No authorization code received\");\n\t\t}\n\n\t\t// Exchange code for tokens\n\t\tonProgress?.(\"Exchanging authorization code for tokens...\");\n\t\tconst tokenResponse = await fetch(TOKEN_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tclient_id: clientId,\n\t\t\t\tclient_secret: clientSecret,\n\t\t\t\tcode,\n\t\t\t\tgrant_type: \"authorization_code\",\n\t\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\t\tcode_verifier: verifier,\n\t\t\t}),\n\t\t});\n\n\t\tif (!tokenResponse.ok) {\n\t\t\tconst error = await tokenResponse.text();\n\t\t\tthrow new Error(`Token exchange failed: ${error}`);\n\t\t}\n\n\t\tconst tokenData = (await tokenResponse.json()) as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t};\n\n\t\tif (!tokenData.refresh_token) {\n\t\t\tthrow new Error(\"No refresh token received. Please try again.\");\n\t\t}\n\n\t\t// Get user email\n\t\tonProgress?.(\"Getting user info...\");\n\t\tconst email = await getUserEmail(tokenData.access_token);\n\n\t\t// Discover project\n\t\tconst projectId = await discoverProject(tokenData.access_token, onProgress);\n\n\t\t// Calculate expiry time (current time + expires_in seconds - 5 min buffer)\n\t\tconst expiresAt = Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000;\n\n\t\tconst credentials: OAuthCredentials = {\n\t\t\trefresh: tokenData.refresh_token,\n\t\t\taccess: tokenData.access_token,\n\t\t\texpires: expiresAt,\n\t\t\tprojectId,\n\t\t\temail,\n\t\t};\n\n\t\treturn credentials;\n\t} finally {\n\t\tserver.server.close();\n\t}\n}\n\nexport const antigravityOAuthProvider: OAuthProviderInterface = {\n\tid: \"google-antigravity\",\n\tname: \"Antigravity (Gemini 3, Claude, GPT-OSS)\",\n\tusesCallbackServer: true,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginAntigravity(callbacks.onAuth, callbacks.onProgress, callbacks.onManualCodeInput);\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\tconst creds = credentials as AntigravityCredentials;\n\t\tif (!creds.projectId) {\n\t\t\tthrow new Error(\"Antigravity credentials missing projectId\");\n\t\t}\n\t\treturn refreshAntigravityToken(creds.refresh, creds.projectId);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\tconst creds = credentials as AntigravityCredentials;\n\t\treturn JSON.stringify({ token: creds.access, projectId: creds.projectId });\n\t},\n};\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { oauthErrorHtml, oauthSuccessHtml } from "./oauth-page.js";
2
2
  import { generatePKCE } from "./pkce.js";
3
- //#region src/auth/oauth/vendor-pi-google/google-gemini-cli.ts
3
+ //#region src/auth/oauth/google-oauth/google-gemini-cli.ts
4
4
  let _createServer = null;
5
5
  let _httpImportPromise = null;
6
6
  if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) _httpImportPromise = import("node:http").then((m) => {
@@ -77,7 +77,7 @@ async function startCallbackServer() {
77
77
  server.on("error", (err) => {
78
78
  reject(err);
79
79
  });
80
- server.listen(8085, "127.0.0.1", () => {
80
+ server.listen(8085, () => {
81
81
  resolve({
82
82
  server,
83
83
  cancelWait: () => {
@@ -105,7 +105,6 @@ function parseRedirectUrl(input) {
105
105
  }
106
106
  }
107
107
  const TIER_FREE = "free-tier";
108
- const TIER_LEGACY = "legacy-tier";
109
108
  const TIER_STANDARD = "standard-tier";
110
109
  /**
111
110
  * Wait helper for onboarding retries
@@ -117,8 +116,8 @@ function wait(ms) {
117
116
  * Get default tier from allowed tiers
118
117
  */
119
118
  function getDefaultTier(allowedTiers) {
120
- if (!allowedTiers || allowedTiers.length === 0) return { id: TIER_LEGACY };
121
- return allowedTiers.find((t) => t.isDefault) ?? { id: TIER_LEGACY };
119
+ if (!allowedTiers || allowedTiers.length === 0) return { id: TIER_FREE };
120
+ return allowedTiers.find((t) => t.isDefault) ?? allowedTiers[0] ?? { id: TIER_FREE };
122
121
  }
123
122
  function isVpcScAffectedUser(payload) {
124
123
  if (!payload || typeof payload !== "object") return false;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-gemini-cli.js","names":[],"sources":["../../../../../src/auth/oauth/google-oauth/google-gemini-cli.ts"],"sourcesContent":["/**\n * Gemini CLI OAuth flow (Google Cloud Code Assist)\n * Standard Gemini models only (gemini-2.0-flash, gemini-2.5-*)\n *\n * NOTE: This module uses Node.js http.createServer for the OAuth callback.\n * It is only intended for CLI use, not browser environments.\n */\n\nimport type { Server } from \"node:http\";\nimport { oauthErrorHtml, oauthSuccessHtml } from \"./oauth-page.js\";\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"../types.js\";\n\ntype GeminiCredentials = OAuthCredentials & {\n\tprojectId: string;\n};\n\nlet _createServer: typeof import(\"node:http\").createServer | null = null;\nlet _httpImportPromise: Promise<void> | null = null;\nif (typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun)) {\n\t_httpImportPromise = import(\"node:http\").then((m) => {\n\t\t_createServer = m.createServer;\n\t});\n}\n\nconst GEMINI_CLI_CLIENT_ID_ENV = 'XOPC_GOOGLE_GEMINI_CLI_OAUTH_CLIENT_ID';\nconst GEMINI_CLI_CLIENT_SECRET_ENV = 'XOPC_GOOGLE_GEMINI_CLI_OAUTH_CLIENT_SECRET';\n\nfunction getGeminiCliOAuthClient(): { clientId: string; clientSecret: string } {\n\tconst clientId = process.env[GEMINI_CLI_CLIENT_ID_ENV]?.trim();\n\tconst clientSecret = process.env[GEMINI_CLI_CLIENT_SECRET_ENV]?.trim();\n\tif (!clientId || !clientSecret) {\n\t\tthrow new Error(\n\t\t\t`Google Gemini CLI OAuth requires ${GEMINI_CLI_CLIENT_ID_ENV} and ${GEMINI_CLI_CLIENT_SECRET_ENV}.`,\n\t\t);\n\t}\n\treturn { clientId, clientSecret };\n}\n\nconst REDIRECT_URI = \"http://localhost:8085/oauth2callback\";\nconst SCOPES = [\n\t\"https://www.googleapis.com/auth/cloud-platform\",\n\t\"https://www.googleapis.com/auth/userinfo.email\",\n\t\"https://www.googleapis.com/auth/userinfo.profile\",\n];\nconst AUTH_URL = \"https://accounts.google.com/o/oauth2/v2/auth\";\nconst TOKEN_URL = \"https://oauth2.googleapis.com/token\";\nconst CODE_ASSIST_ENDPOINT = \"https://cloudcode-pa.googleapis.com\";\n\ntype CallbackServerInfo = {\n\tserver: Server;\n\tcancelWait: () => void;\n\twaitForCode: () => Promise<{ code: string; state: string } | null>;\n};\n\n/**\n * Start a local HTTP server to receive the OAuth callback\n */\nasync function getNodeCreateServer(): Promise<typeof import(\"node:http\").createServer> {\n\tif (_createServer) return _createServer;\n\tif (_httpImportPromise) {\n\t\tawait _httpImportPromise;\n\t}\n\tif (_createServer) return _createServer;\n\tthrow new Error(\"Gemini CLI OAuth is only available in Node.js environments\");\n}\n\nasync function startCallbackServer(): Promise<CallbackServerInfo> {\n\tconst createServer = await getNodeCreateServer();\n\n\treturn new Promise((resolve, reject) => {\n\t\tlet settleWait: ((value: { code: string; state: string } | null) => void) | undefined;\n\t\tconst waitForCodePromise = new Promise<{ code: string; state: string } | null>((resolveWait) => {\n\t\t\tlet settled = false;\n\t\t\tsettleWait = (value) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tresolveWait(value);\n\t\t\t};\n\t\t});\n\n\t\tconst server = createServer((req, res) => {\n\t\t\tconst url = new URL(req.url || \"\", `http://localhost:8085`);\n\n\t\t\tif (url.pathname === \"/oauth2callback\") {\n\t\t\t\tconst code = url.searchParams.get(\"code\");\n\t\t\t\tconst state = url.searchParams.get(\"state\");\n\t\t\t\tconst error = url.searchParams.get(\"error\");\n\n\t\t\t\tif (error) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"Google authentication did not complete.\", `Error: ${error}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (code && state) {\n\t\t\t\t\tres.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthSuccessHtml(\"Google authentication completed. You can close this window.\"));\n\t\t\t\t\tsettleWait?.({ code, state });\n\t\t\t\t} else {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"Missing code or state parameter.\"));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tres.writeHead(404, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\tres.end(oauthErrorHtml(\"Callback route not found.\"));\n\t\t\t}\n\t\t});\n\n\t\tserver.on(\"error\", (err) => {\n\t\t\treject(err);\n\t\t});\n\n\t\tserver.listen(8085, () => {\n\t\t\tresolve({\n\t\t\t\tserver,\n\t\t\t\tcancelWait: () => {\n\t\t\t\t\tsettleWait?.(null);\n\t\t\t\t},\n\t\t\t\twaitForCode: () => waitForCodePromise,\n\t\t\t});\n\t\t});\n\t});\n}\n\n/**\n * Parse redirect URL to extract code and state\n */\nfunction parseRedirectUrl(input: string): { code?: string; state?: string } {\n\tconst value = input.trim();\n\tif (!value) return {};\n\n\ttry {\n\t\tconst url = new URL(value);\n\t\treturn {\n\t\t\tcode: url.searchParams.get(\"code\") ?? undefined,\n\t\t\tstate: url.searchParams.get(\"state\") ?? undefined,\n\t\t};\n\t} catch {\n\t\t// Not a URL, return empty\n\t\treturn {};\n\t}\n}\n\ninterface LoadCodeAssistPayload {\n\tcloudaicompanionProject?: string;\n\tcurrentTier?: { id?: string };\n\tallowedTiers?: Array<{ id?: string; isDefault?: boolean }>;\n}\n\n/**\n * Long-running operation response from onboardUser\n */\ninterface LongRunningOperationResponse {\n\tname?: string;\n\tdone?: boolean;\n\tresponse?: {\n\t\tcloudaicompanionProject?: { id?: string };\n\t};\n}\n\n// Tier IDs as used by the Cloud Code API\nconst TIER_FREE = \"free-tier\";\nconst TIER_STANDARD = \"standard-tier\";\n\ninterface GoogleRpcErrorResponse {\n\terror?: {\n\t\tdetails?: Array<{ reason?: string }>;\n\t};\n}\n\n/**\n * Wait helper for onboarding retries\n */\nfunction wait(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Get default tier from allowed tiers\n */\nfunction getDefaultTier(allowedTiers?: Array<{ id?: string; isDefault?: boolean }>): { id?: string } {\n\tif (!allowedTiers || allowedTiers.length === 0) return { id: TIER_FREE };\n\tconst defaultTier = allowedTiers.find((t) => t.isDefault);\n\treturn defaultTier ?? allowedTiers[0] ?? { id: TIER_FREE };\n}\n\nfunction isVpcScAffectedUser(payload: unknown): boolean {\n\tif (!payload || typeof payload !== \"object\") return false;\n\tif (!(\"error\" in payload)) return false;\n\tconst error = (payload as GoogleRpcErrorResponse).error;\n\tif (!error?.details || !Array.isArray(error.details)) return false;\n\treturn error.details.some((detail) => detail.reason === \"SECURITY_POLICY_VIOLATED\");\n}\n\n/**\n * Poll a long-running operation until completion\n */\nasync function pollOperation(\n\toperationName: string,\n\theaders: Record<string, string>,\n\tonProgress?: (message: string) => void,\n): Promise<LongRunningOperationResponse> {\n\tlet attempt = 0;\n\twhile (true) {\n\t\tif (attempt > 0) {\n\t\t\tonProgress?.(`Waiting for project provisioning (attempt ${attempt + 1})...`);\n\t\t\tawait wait(5000);\n\t\t}\n\n\t\tconst response = await fetch(`${CODE_ASSIST_ENDPOINT}/v1internal/${operationName}`, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders,\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Failed to poll operation: ${response.status} ${response.statusText}`);\n\t\t}\n\n\t\tconst data = (await response.json()) as LongRunningOperationResponse;\n\t\tif (data.done) {\n\t\t\treturn data;\n\t\t}\n\n\t\tattempt += 1;\n\t}\n}\n\n/**\n * Discover or provision a Google Cloud project for the user\n */\nasync function discoverProject(accessToken: string, onProgress?: (message: string) => void): Promise<string> {\n\t// Check for user-provided project ID via environment variable\n\tconst envProjectId = process.env.GOOGLE_CLOUD_PROJECT || process.env.GOOGLE_CLOUD_PROJECT_ID;\n\n\tconst headers = {\n\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\"Content-Type\": \"application/json\",\n\t\t\"User-Agent\": \"google-api-nodejs-client/9.15.1\",\n\t\t\"X-Goog-Api-Client\": \"gl-node/22.17.0\",\n\t};\n\n\t// Try to load existing project via loadCodeAssist\n\tonProgress?.(\"Checking for existing Cloud Code Assist project...\");\n\tconst loadResponse = await fetch(`${CODE_ASSIST_ENDPOINT}/v1internal:loadCodeAssist`, {\n\t\tmethod: \"POST\",\n\t\theaders,\n\t\tbody: JSON.stringify({\n\t\t\tcloudaicompanionProject: envProjectId,\n\t\t\tmetadata: {\n\t\t\t\tideType: \"IDE_UNSPECIFIED\",\n\t\t\t\tplatform: \"PLATFORM_UNSPECIFIED\",\n\t\t\t\tpluginType: \"GEMINI\",\n\t\t\t\tduetProject: envProjectId,\n\t\t\t},\n\t\t}),\n\t});\n\n\tlet data: LoadCodeAssistPayload;\n\n\tif (!loadResponse.ok) {\n\t\tlet errorPayload: unknown;\n\t\ttry {\n\t\t\terrorPayload = await loadResponse.clone().json();\n\t\t} catch {\n\t\t\terrorPayload = undefined;\n\t\t}\n\n\t\tif (isVpcScAffectedUser(errorPayload)) {\n\t\t\tdata = { currentTier: { id: TIER_STANDARD } };\n\t\t} else {\n\t\t\tconst errorText = await loadResponse.text();\n\t\t\tthrow new Error(`loadCodeAssist failed: ${loadResponse.status} ${loadResponse.statusText}: ${errorText}`);\n\t\t}\n\t} else {\n\t\tdata = (await loadResponse.json()) as LoadCodeAssistPayload;\n\t}\n\n\t// If user already has a current tier and project, use it\n\tif (data.currentTier) {\n\t\tif (data.cloudaicompanionProject) {\n\t\t\treturn data.cloudaicompanionProject;\n\t\t}\n\t\t// User has a tier but no managed project - they need to provide one via env var\n\t\tif (envProjectId) {\n\t\t\treturn envProjectId;\n\t\t}\n\t\tthrow new Error(\n\t\t\t\"This account requires setting the GOOGLE_CLOUD_PROJECT or GOOGLE_CLOUD_PROJECT_ID environment variable. \" +\n\t\t\t\t\"See https://goo.gle/gemini-cli-auth-docs#workspace-gca\",\n\t\t);\n\t}\n\n\t// User needs to be onboarded - get the default tier\n\tconst tier = getDefaultTier(data.allowedTiers);\n\tconst tierId = tier?.id ?? TIER_FREE;\n\n\tif (tierId !== TIER_FREE && !envProjectId) {\n\t\tthrow new Error(\n\t\t\t\"This account requires setting the GOOGLE_CLOUD_PROJECT or GOOGLE_CLOUD_PROJECT_ID environment variable. \" +\n\t\t\t\t\"See https://goo.gle/gemini-cli-auth-docs#workspace-gca\",\n\t\t);\n\t}\n\n\tonProgress?.(\"Provisioning Cloud Code Assist project (this may take a moment)...\");\n\n\t// Build onboard request - for free tier, don't include project ID (Google provisions one)\n\t// For other tiers, include the user's project ID if available\n\tconst onboardBody: Record<string, unknown> = {\n\t\ttierId,\n\t\tmetadata: {\n\t\t\tideType: \"IDE_UNSPECIFIED\",\n\t\t\tplatform: \"PLATFORM_UNSPECIFIED\",\n\t\t\tpluginType: \"GEMINI\",\n\t\t},\n\t};\n\n\tif (tierId !== TIER_FREE && envProjectId) {\n\t\tonboardBody.cloudaicompanionProject = envProjectId;\n\t\t(onboardBody.metadata as Record<string, unknown>).duetProject = envProjectId;\n\t}\n\n\t// Start onboarding - this returns a long-running operation\n\tconst onboardResponse = await fetch(`${CODE_ASSIST_ENDPOINT}/v1internal:onboardUser`, {\n\t\tmethod: \"POST\",\n\t\theaders,\n\t\tbody: JSON.stringify(onboardBody),\n\t});\n\n\tif (!onboardResponse.ok) {\n\t\tconst errorText = await onboardResponse.text();\n\t\tthrow new Error(`onboardUser failed: ${onboardResponse.status} ${onboardResponse.statusText}: ${errorText}`);\n\t}\n\n\tlet lroData = (await onboardResponse.json()) as LongRunningOperationResponse;\n\n\t// If the operation isn't done yet, poll until completion\n\tif (!lroData.done && lroData.name) {\n\t\tlroData = await pollOperation(lroData.name, headers, onProgress);\n\t}\n\n\t// Try to get project ID from the response\n\tconst projectId = lroData.response?.cloudaicompanionProject?.id;\n\tif (projectId) {\n\t\treturn projectId;\n\t}\n\n\t// If no project ID from onboarding, fall back to env var\n\tif (envProjectId) {\n\t\treturn envProjectId;\n\t}\n\n\tthrow new Error(\n\t\t\"Could not discover or provision a Google Cloud project. \" +\n\t\t\t\"Try setting the GOOGLE_CLOUD_PROJECT or GOOGLE_CLOUD_PROJECT_ID environment variable. \" +\n\t\t\t\"See https://goo.gle/gemini-cli-auth-docs#workspace-gca\",\n\t);\n}\n\n/**\n * Get user email from the access token\n */\nasync function getUserEmail(accessToken: string): Promise<string | undefined> {\n\ttry {\n\t\tconst response = await fetch(\"https://www.googleapis.com/oauth2/v1/userinfo?alt=json\", {\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\t},\n\t\t});\n\n\t\tif (response.ok) {\n\t\t\tconst data = (await response.json()) as { email?: string };\n\t\t\treturn data.email;\n\t\t}\n\t} catch {\n\t\t// Ignore errors, email is optional\n\t}\n\treturn undefined;\n}\n\n/**\n * Refresh Google Cloud Code Assist token\n */\nexport async function refreshGoogleCloudToken(refreshToken: string, projectId: string): Promise<OAuthCredentials> {\n\tconst { clientId, clientSecret } = getGeminiCliOAuthClient();\n\tconst response = await fetch(TOKEN_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n\t\tbody: new URLSearchParams({\n\t\t\tclient_id: clientId,\n\t\t\tclient_secret: clientSecret,\n\t\t\trefresh_token: refreshToken,\n\t\t\tgrant_type: \"refresh_token\",\n\t\t}),\n\t});\n\n\tif (!response.ok) {\n\t\tconst error = await response.text();\n\t\tthrow new Error(`Google Cloud token refresh failed: ${error}`);\n\t}\n\n\tconst data = (await response.json()) as {\n\t\taccess_token: string;\n\t\texpires_in: number;\n\t\trefresh_token?: string;\n\t};\n\n\treturn {\n\t\trefresh: data.refresh_token || refreshToken,\n\t\taccess: data.access_token,\n\t\texpires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n\t\tprojectId,\n\t};\n}\n\n/**\n * Login with Gemini CLI (Google Cloud Code Assist) OAuth\n *\n * @param onAuth - Callback with URL and optional instructions\n * @param onProgress - Optional progress callback\n * @param onManualCodeInput - Optional promise that resolves with user-pasted redirect URL.\n * Races with browser callback - whichever completes first wins.\n */\nexport async function loginGeminiCli(\n\tonAuth: (info: { url: string; instructions?: string }) => void,\n\tonProgress?: (message: string) => void,\n\tonManualCodeInput?: () => Promise<string>,\n): Promise<OAuthCredentials> {\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst { clientId, clientSecret } = getGeminiCliOAuthClient();\n\n\t// Start local server for callback\n\tonProgress?.(\"Starting local server for OAuth callback...\");\n\tconst server = await startCallbackServer();\n\n\tlet code: string | undefined;\n\n\ttry {\n\t\t// Build authorization URL\n\t\tconst authParams = new URLSearchParams({\n\t\t\tclient_id: clientId,\n\t\t\tresponse_type: \"code\",\n\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\tscope: SCOPES.join(\" \"),\n\t\t\tcode_challenge: challenge,\n\t\t\tcode_challenge_method: \"S256\",\n\t\t\tstate: verifier,\n\t\t\taccess_type: \"offline\",\n\t\t\tprompt: \"consent\",\n\t\t});\n\n\t\tconst authUrl = `${AUTH_URL}?${authParams.toString()}`;\n\n\t\t// Notify caller with URL to open\n\t\tonAuth({\n\t\t\turl: authUrl,\n\t\t\tinstructions: \"Complete the sign-in in your browser.\",\n\t\t});\n\n\t\t// Wait for the callback, racing with manual input if provided\n\t\tonProgress?.(\"Waiting for OAuth callback...\");\n\n\t\tif (onManualCodeInput) {\n\t\t\t// Race between browser callback and manual input\n\t\t\tlet manualInput: string | undefined;\n\t\t\tlet manualError: Error | undefined;\n\t\t\tconst manualPromise = onManualCodeInput()\n\t\t\t\t.then((input) => {\n\t\t\t\t\tmanualInput = input;\n\t\t\t\t\tserver.cancelWait();\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tmanualError = err instanceof Error ? err : new Error(String(err));\n\t\t\t\t\tserver.cancelWait();\n\t\t\t\t});\n\n\t\t\tconst result = await server.waitForCode();\n\n\t\t\t// If manual input was cancelled, throw that error\n\t\t\tif (manualError) {\n\t\t\t\tthrow manualError;\n\t\t\t}\n\n\t\t\tif (result?.code) {\n\t\t\t\t// Browser callback won - verify state\n\t\t\t\tif (result.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch - possible CSRF attack\");\n\t\t\t\t}\n\t\t\t\tcode = result.code;\n\t\t\t} else if (manualInput) {\n\t\t\t\t// Manual input won\n\t\t\t\tconst parsed = parseRedirectUrl(manualInput);\n\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch - possible CSRF attack\");\n\t\t\t\t}\n\t\t\t\tcode = parsed.code;\n\t\t\t}\n\n\t\t\t// If still no code, wait for manual promise and try that\n\t\t\tif (!code) {\n\t\t\t\tawait manualPromise;\n\t\t\t\tif (manualError) {\n\t\t\t\t\tthrow manualError;\n\t\t\t\t}\n\t\t\t\tif (manualInput) {\n\t\t\t\t\tconst parsed = parseRedirectUrl(manualInput);\n\t\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\t\tthrow new Error(\"OAuth state mismatch - possible CSRF attack\");\n\t\t\t\t\t}\n\t\t\t\t\tcode = parsed.code;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Original flow: just wait for callback\n\t\t\tconst result = await server.waitForCode();\n\t\t\tif (result?.code) {\n\t\t\t\tif (result.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch - possible CSRF attack\");\n\t\t\t\t}\n\t\t\t\tcode = result.code;\n\t\t\t}\n\t\t}\n\n\t\tif (!code) {\n\t\t\tthrow new Error(\"No authorization code received\");\n\t\t}\n\n\t\t// Exchange code for tokens\n\t\tonProgress?.(\"Exchanging authorization code for tokens...\");\n\t\tconst tokenResponse = await fetch(TOKEN_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tclient_id: clientId,\n\t\t\t\tclient_secret: clientSecret,\n\t\t\t\tcode,\n\t\t\t\tgrant_type: \"authorization_code\",\n\t\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\t\tcode_verifier: verifier,\n\t\t\t}),\n\t\t});\n\n\t\tif (!tokenResponse.ok) {\n\t\t\tconst error = await tokenResponse.text();\n\t\t\tthrow new Error(`Token exchange failed: ${error}`);\n\t\t}\n\n\t\tconst tokenData = (await tokenResponse.json()) as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t};\n\n\t\tif (!tokenData.refresh_token) {\n\t\t\tthrow new Error(\"No refresh token received. Please try again.\");\n\t\t}\n\n\t\t// Get user email\n\t\tonProgress?.(\"Getting user info...\");\n\t\tconst email = await getUserEmail(tokenData.access_token);\n\n\t\t// Discover project\n\t\tconst projectId = await discoverProject(tokenData.access_token, onProgress);\n\n\t\t// Calculate expiry time (current time + expires_in seconds - 5 min buffer)\n\t\tconst expiresAt = Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000;\n\n\t\tconst credentials: OAuthCredentials = {\n\t\t\trefresh: tokenData.refresh_token,\n\t\t\taccess: tokenData.access_token,\n\t\t\texpires: expiresAt,\n\t\t\tprojectId,\n\t\t\temail,\n\t\t};\n\n\t\treturn credentials;\n\t} finally {\n\t\tserver.server.close();\n\t}\n}\n\nexport const geminiCliOAuthProvider: OAuthProviderInterface = {\n\tid: \"google-gemini-cli\",\n\tname: \"Google Cloud Code Assist (Gemini CLI)\",\n\tusesCallbackServer: true,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginGeminiCli(callbacks.onAuth, callbacks.onProgress, callbacks.onManualCodeInput);\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\tconst creds = credentials as GeminiCredentials;\n\t\tif (!creds.projectId) {\n\t\t\tthrow new Error(\"Google Cloud credentials missing projectId\");\n\t\t}\n\t\treturn refreshGoogleCloudToken(creds.refresh, creds.projectId);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\tconst creds = credentials as GeminiCredentials;\n\t\treturn JSON.stringify({ token: creds.access, projectId: creds.projectId });\n\t},\n};\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- //#region src/auth/oauth/vendor-pi-google/oauth-page.ts
2
- const LOGO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800" aria-hidden="true"><path fill="#fff" fill-rule="evenodd" d="M165.29 165.29 H517.36 V400 H400 V517.36 H282.65 V634.72 H165.29 Z M282.65 282.65 V400 H400 V282.65 Z"/><path fill="#fff" d="M517.36 400 H634.72 V634.72 H517.36 Z"/></svg>`;
1
+ //#region src/auth/oauth/google-oauth/oauth-page.ts
2
+ const LOGO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72 72" aria-hidden="true"><rect width="72" height="72" rx="20" fill="#2563eb"/><path d="M22 22l28 28M50 22L22 50" stroke="#fff" stroke-width="8" stroke-linecap="round"/></svg>`;
3
3
  function escapeHtml(value) {
4
4
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&#39;");
5
5
  }
@@ -44,11 +44,19 @@ function renderPage(options) {
44
44
  align-items: center;
45
45
  justify-content: center;
46
46
  }
47
+ .brand {
48
+ display: flex;
49
+ flex-direction: column;
50
+ align-items: center;
51
+ gap: 10px;
52
+ margin-bottom: 24px;
53
+ font-weight: 700;
54
+ letter-spacing: -0.02em;
55
+ }
47
56
  .logo {
48
57
  width: 72px;
49
58
  height: 72px;
50
59
  display: block;
51
- margin-bottom: 24px;
52
60
  }
53
61
  h1 {
54
62
  margin: 0 0 10px;
@@ -75,7 +83,7 @@ function renderPage(options) {
75
83
  </head>
76
84
  <body>
77
85
  <main>
78
- <div class="logo">${LOGO_SVG}</div>
86
+ <div class="brand"><div class="logo">${LOGO_SVG}</div><div>xopc</div></div>
79
87
  <h1>${heading}</h1>
80
88
  <p>${message}</p>
81
89
  ${details ? `<div class="details">${details}</div>` : ""}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth-page.js","names":[],"sources":["../../../../../src/auth/oauth/google-oauth/oauth-page.ts"],"sourcesContent":["const LOGO_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 72 72\" aria-hidden=\"true\"><rect width=\"72\" height=\"72\" rx=\"20\" fill=\"#2563eb\"/><path d=\"M22 22l28 28M50 22L22 50\" stroke=\"#fff\" stroke-width=\"8\" stroke-linecap=\"round\"/></svg>`;\n\nfunction escapeHtml(value: string): string {\n\treturn value\n\t\t.replaceAll(\"&\", \"&amp;\")\n\t\t.replaceAll(\"<\", \"&lt;\")\n\t\t.replaceAll(\">\", \"&gt;\")\n\t\t.replaceAll('\"', \"&quot;\")\n\t\t.replaceAll(\"'\", \"&#39;\");\n}\n\nfunction renderPage(options: { title: string; heading: string; message: string; details?: string }): string {\n\tconst title = escapeHtml(options.title);\n\tconst heading = escapeHtml(options.heading);\n\tconst message = escapeHtml(options.message);\n\tconst details = options.details ? escapeHtml(options.details) : undefined;\n\n\treturn `<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>${title}</title>\n <style>\n :root {\n --text: #fafafa;\n --text-dim: #a1a1aa;\n --page-bg: #09090b;\n --font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n }\n * { box-sizing: border-box; }\n html { color-scheme: dark; }\n body {\n margin: 0;\n min-height: 100vh;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n background: var(--page-bg);\n color: var(--text);\n font-family: var(--font-sans);\n text-align: center;\n }\n main {\n width: 100%;\n max-width: 560px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n }\n .brand {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n margin-bottom: 24px;\n font-weight: 700;\n letter-spacing: -0.02em;\n }\n .logo {\n width: 72px;\n height: 72px;\n display: block;\n }\n h1 {\n margin: 0 0 10px;\n font-size: 28px;\n line-height: 1.15;\n font-weight: 650;\n color: var(--text);\n }\n p {\n margin: 0;\n line-height: 1.7;\n color: var(--text-dim);\n font-size: 15px;\n }\n .details {\n margin-top: 16px;\n font-family: var(--font-mono);\n font-size: 13px;\n color: var(--text-dim);\n white-space: pre-wrap;\n word-break: break-word;\n }\n </style>\n</head>\n<body>\n <main>\n <div class=\"brand\"><div class=\"logo\">${LOGO_SVG}</div><div>xopc</div></div>\n <h1>${heading}</h1>\n <p>${message}</p>\n ${details ? `<div class=\"details\">${details}</div>` : \"\"}\n </main>\n</body>\n</html>`;\n}\n\nexport function oauthSuccessHtml(message: string): string {\n\treturn renderPage({\n\t\ttitle: \"Authentication successful\",\n\t\theading: \"Authentication successful\",\n\t\tmessage,\n\t});\n}\n\nexport function oauthErrorHtml(message: string, details?: string): string {\n\treturn renderPage({\n\t\ttitle: \"Authentication failed\",\n\t\theading: \"Authentication failed\",\n\t\tmessage,\n\t\tdetails,\n\t});\n}\n"],"mappings":";AAAA,MAAM,WAAW;AAEjB,SAAS,WAAW,OAAuB;AAC1C,QAAO,MACL,WAAW,KAAK,QAAQ,CACxB,WAAW,KAAK,OAAO,CACvB,WAAW,KAAK,OAAO,CACvB,WAAW,MAAK,SAAS,CACzB,WAAW,KAAK,QAAQ;;AAG3B,SAAS,WAAW,SAAwF;CAC3G,MAAM,QAAQ,WAAW,QAAQ,MAAM;CACvC,MAAM,UAAU,WAAW,QAAQ,QAAQ;CAC3C,MAAM,UAAU,WAAW,QAAQ,QAAQ;CAC3C,MAAM,UAAU,QAAQ,UAAU,WAAW,QAAQ,QAAQ,GAAG,KAAA;AAEhE,QAAO;;;;;WAKG,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CAsE0B,SAAS;UAC1C,QAAQ;SACT,QAAQ;MACX,UAAU,wBAAwB,QAAQ,UAAU,GAAG;;;;;AAM7D,SAAgB,iBAAiB,SAAyB;AACzD,QAAO,WAAW;EACjB,OAAO;EACP,SAAS;EACT;EACA,CAAC;;AAGH,SAAgB,eAAe,SAAiB,SAA0B;AACzE,QAAO,WAAW;EACjB,OAAO;EACP,SAAS;EACT;EACA;EACA,CAAC"}
@@ -4,7 +4,7 @@
4
4
  */
5
5
  /**
6
6
  * Generate PKCE code verifier and challenge.
7
- * Uses Web Crypto API for cross-platform compatibility.
7
+ * Uses Web Crypto API.
8
8
  */
9
9
  export declare function generatePKCE(): Promise<{
10
10
  verifier: string;
@@ -1,4 +1,4 @@
1
- //#region src/auth/oauth/vendor-pi-google/pkce.ts
1
+ //#region src/auth/oauth/google-oauth/pkce.ts
2
2
  /**
3
3
  * PKCE utilities using Web Crypto API.
4
4
  * Works in both Node.js 20+ and browsers.
@@ -13,7 +13,7 @@ function base64urlEncode(bytes) {
13
13
  }
14
14
  /**
15
15
  * Generate PKCE code verifier and challenge.
16
- * Uses Web Crypto API for cross-platform compatibility.
16
+ * Uses Web Crypto API.
17
17
  */
18
18
  async function generatePKCE() {
19
19
  const verifierBytes = new Uint8Array(32);
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.js","names":[],"sources":["../../../../../src/auth/oauth/google-oauth/pkce.ts"],"sourcesContent":["/**\n * PKCE utilities using Web Crypto API.\n * Works in both Node.js 20+ and browsers.\n */\n\n/**\n * Encode bytes as base64url string.\n */\nfunction base64urlEncode(bytes: Uint8Array): string {\n\tlet binary = \"\";\n\tfor (const byte of bytes) {\n\t\tbinary += String.fromCharCode(byte);\n\t}\n\treturn btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=/g, \"\");\n}\n\n/**\n * Generate PKCE code verifier and challenge.\n * Uses Web Crypto API.\n */\nexport async function generatePKCE(): Promise<{ verifier: string; challenge: string }> {\n\t// Generate random verifier\n\tconst verifierBytes = new Uint8Array(32);\n\tcrypto.getRandomValues(verifierBytes);\n\tconst verifier = base64urlEncode(verifierBytes);\n\n\t// Compute SHA-256 challenge\n\tconst encoder = new TextEncoder();\n\tconst data = encoder.encode(verifier);\n\tconst hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n\tconst challenge = base64urlEncode(new Uint8Array(hashBuffer));\n\n\treturn { verifier, challenge };\n}\n"],"mappings":";;;;;;;;AAQA,SAAS,gBAAgB,OAA2B;CACnD,IAAI,SAAS;AACb,MAAK,MAAM,QAAQ,MAClB,WAAU,OAAO,aAAa,KAAK;AAEpC,QAAO,KAAK,OAAO,CAAC,QAAQ,OAAO,IAAI,CAAC,QAAQ,OAAO,IAAI,CAAC,QAAQ,MAAM,GAAG;;;;;;AAO9E,eAAsB,eAAiE;CAEtF,MAAM,gBAAgB,IAAI,WAAW,GAAG;AACxC,QAAO,gBAAgB,cAAc;CACrC,MAAM,WAAW,gBAAgB,cAAc;CAI/C,MAAM,OAAO,IADO,aACA,CAAC,OAAO,SAAS;CACrC,MAAM,aAAa,MAAM,OAAO,OAAO,OAAO,WAAW,KAAK;AAG9D,QAAO;EAAE;EAAU,WAFD,gBAAgB,IAAI,WAAW,WAAW,CAEhC;EAAE"}
@@ -3,9 +3,9 @@ import { minimaxOAuthProvider } from "./minimax.js";
3
3
  import { minimaxCnOAuthProvider } from "./minimax-cn.js";
4
4
  import { kimiCodingOAuthProvider } from "./kimi-coding.js";
5
5
  import { getGitHubCopilotBaseUrl, githubCopilotOAuthProvider, loginGitHubCopilot, normalizeDomain, refreshGitHubCopilotToken } from "./github-copilot.js";
6
- import { geminiCliOAuthProvider, loginGeminiCli, refreshGoogleCloudToken } from "./vendor-pi-google/google-gemini-cli.js";
6
+ import { geminiCliOAuthProvider, loginGeminiCli, refreshGoogleCloudToken } from "./google-oauth/google-gemini-cli.js";
7
7
  import "./google-gemini-cli.js";
8
- import { antigravityOAuthProvider, loginAntigravity, refreshAntigravityToken } from "./vendor-pi-google/google-antigravity.js";
8
+ import { antigravityOAuthProvider, loginAntigravity, refreshAntigravityToken } from "./google-oauth/google-antigravity.js";
9
9
  import "./google-antigravity.js";
10
10
  import { loginOpenAICodex, openaiCodexOAuthProvider, refreshOpenAICodexToken } from "./openai-codex.js";
11
11
  export { anthropicOAuthProvider, getGitHubCopilotBaseUrl, githubCopilotOAuthProvider, antigravityOAuthProvider as googleAntigravityOAuthProvider, geminiCliOAuthProvider as googleGeminiCliOAuthProvider, kimiCodingOAuthProvider, loginAnthropic, loginAntigravity, loginGeminiCli, loginGitHubCopilot, loginOpenAICodex, minimaxCnOAuthProvider, minimaxOAuthProvider, normalizeDomain, openaiCodexOAuthProvider, refreshAnthropicToken, refreshAntigravityToken, refreshGitHubCopilotToken, refreshGoogleCloudToken, refreshOpenAICodexToken };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Kimi Coding (Moonshot AI) OAuth device code flow for pi-ai `kimi-coding` provider.
2
+ * Kimi Coding (Moonshot AI) OAuth device code flow.
3
3
  * @see https://auth.kimi.com
4
4
  */
5
5
  import type { OAuthProviderInterface } from './types.js';
@@ -6,7 +6,7 @@ const KIMI_OAUTH_CLIENT_ID = "17e5f671-d194-4dfb-9706-5516cb48c098";
6
6
  const kimiCodingOAuthProvider = {
7
7
  id: "kimi-coding",
8
8
  name: "Kimi For Coding (月之暗面)",
9
- usesCallbackServer: true,
9
+ usesCallbackServer: false,
10
10
  async login(callbacks) {
11
11
  const deviceResponse = await fetch(KIMI_OAUTH_DEVICE_URL, {
12
12
  method: "POST",
@@ -1 +1 @@
1
- {"version":3,"file":"kimi-coding.js","names":[],"sources":["../../../../src/auth/oauth/kimi-coding.ts"],"sourcesContent":["/**\n * Kimi Coding (Moonshot AI) OAuth device code flow for pi-ai `kimi-coding` provider.\n * @see https://auth.kimi.com\n */\n\nimport type { OAuthCredentials, OAuthProviderInterface, OAuthLoginCallbacks } from './types.js';\n\nconst KIMI_OAUTH_BASE_URL = 'https://auth.kimi.com';\nconst KIMI_OAUTH_DEVICE_URL = `${KIMI_OAUTH_BASE_URL}/api/oauth/device_authorization`;\nconst KIMI_OAUTH_TOKEN_URL = `${KIMI_OAUTH_BASE_URL}/api/oauth/token`;\nconst KIMI_OAUTH_CLIENT_ID = '17e5f671-d194-4dfb-9706-5516cb48c098';\n\nexport const kimiCodingOAuthProvider: OAuthProviderInterface = {\n\tid: 'kimi-coding',\n\tname: 'Kimi For Coding (月之暗面)',\n\tusesCallbackServer: true,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\tconst deviceResponse = await fetch(KIMI_OAUTH_DEVICE_URL, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tclient_id: KIMI_OAUTH_CLIENT_ID,\n\t\t\t\tscope: 'kimi-code',\n\t\t\t}),\n\t\t});\n\n\t\tif (!deviceResponse.ok) {\n\t\t\tconst error = await deviceResponse.text();\n\t\t\tthrow new Error(`Device code request failed: ${error}`);\n\t\t}\n\n\t\tconst deviceData = (await deviceResponse.json()) as {\n\t\t\tdevice_code: string;\n\t\t\tuser_code: string;\n\t\t\tverification_uri: string;\n\t\t\tverification_uri_complete: string;\n\t\t\tinterval: number;\n\t\t\texpires_in: number;\n\t\t};\n\n\t\tcallbacks.onAuth({\n\t\t\turl: deviceData.verification_uri_complete || deviceData.verification_uri,\n\t\t\tinstructions: `Please visit ${deviceData.verification_uri} and enter code: ${deviceData.user_code}`,\n\t\t});\n\n\t\tconst expiresAt = Date.now() + deviceData.expires_in * 1000;\n\t\tconst pollInterval = (deviceData.interval || 5) * 1000;\n\n\t\twhile (Date.now() < expiresAt) {\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, pollInterval));\n\n\t\t\tconst tokenResponse = await fetch(KIMI_OAUTH_TOKEN_URL, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams({\n\t\t\t\t\tgrant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n\t\t\t\t\tclient_id: KIMI_OAUTH_CLIENT_ID,\n\t\t\t\t\tdevice_code: deviceData.device_code,\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tif (tokenResponse.ok) {\n\t\t\t\tconst tokenData = (await tokenResponse.json()) as {\n\t\t\t\t\taccess_token: string;\n\t\t\t\t\trefresh_token: string;\n\t\t\t\t\texpires_in: number;\n\t\t\t\t};\n\n\t\t\t\treturn {\n\t\t\t\t\taccess: tokenData.access_token,\n\t\t\t\t\trefresh: tokenData.refresh_token,\n\t\t\t\t\texpires: Date.now() + tokenData.expires_in * 1000,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst errorData = (await tokenResponse.json()) as { error?: string };\n\t\t\tif (errorData.error === 'expired_token') {\n\t\t\t\tthrow new Error('Device code expired. Please try again.');\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error('Device code expired. Please try again.');\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\tif (!credentials.refresh) {\n\t\t\tthrow new Error('Kimi OAuth refresh token missing. Re-authenticate.');\n\t\t}\n\n\t\tconst response = await fetch(KIMI_OAUTH_TOKEN_URL, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: 'refresh_token',\n\t\t\t\tclient_id: KIMI_OAUTH_CLIENT_ID,\n\t\t\t\trefresh_token: credentials.refresh,\n\t\t\t}),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst text = await response.text();\n\t\t\tthrow new Error(`Kimi OAuth refresh failed: ${text}`);\n\t\t}\n\n\t\tconst payload = (await response.json()) as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t};\n\n\t\treturn {\n\t\t\t...credentials,\n\t\t\taccess: payload.access_token,\n\t\t\trefresh: payload.refresh_token || credentials.refresh,\n\t\t\texpires: Date.now() + payload.expires_in * 1000,\n\t\t};\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n"],"mappings":";AAOA,MAAM,sBAAsB;AAC5B,MAAM,wBAAwB,GAAG,oBAAoB;AACrD,MAAM,uBAAuB,GAAG,oBAAoB;AACpD,MAAM,uBAAuB;AAE7B,MAAa,0BAAkD;CAC9D,IAAI;CACJ,MAAM;CACN,oBAAoB;CAEpB,MAAM,MAAM,WAA2D;EACtE,MAAM,iBAAiB,MAAM,MAAM,uBAAuB;GACzD,QAAQ;GACR,SAAS,EACR,gBAAgB,qCAChB;GACD,MAAM,IAAI,gBAAgB;IACzB,WAAW;IACX,OAAO;IACP,CAAC;GACF,CAAC;AAEF,MAAI,CAAC,eAAe,IAAI;GACvB,MAAM,QAAQ,MAAM,eAAe,MAAM;AACzC,SAAM,IAAI,MAAM,+BAA+B,QAAQ;;EAGxD,MAAM,aAAc,MAAM,eAAe,MAAM;AAS/C,YAAU,OAAO;GAChB,KAAK,WAAW,6BAA6B,WAAW;GACxD,cAAc,gBAAgB,WAAW,iBAAiB,mBAAmB,WAAW;GACxF,CAAC;EAEF,MAAM,YAAY,KAAK,KAAK,GAAG,WAAW,aAAa;EACvD,MAAM,gBAAgB,WAAW,YAAY,KAAK;AAElD,SAAO,KAAK,KAAK,GAAG,WAAW;AAC9B,SAAM,IAAI,SAAS,YAAY,WAAW,SAAS,aAAa,CAAC;GAEjE,MAAM,gBAAgB,MAAM,MAAM,sBAAsB;IACvD,QAAQ;IACR,SAAS,EACR,gBAAgB,qCAChB;IACD,MAAM,IAAI,gBAAgB;KACzB,YAAY;KACZ,WAAW;KACX,aAAa,WAAW;KACxB,CAAC;IACF,CAAC;AAEF,OAAI,cAAc,IAAI;IACrB,MAAM,YAAa,MAAM,cAAc,MAAM;AAM7C,WAAO;KACN,QAAQ,UAAU;KAClB,SAAS,UAAU;KACnB,SAAS,KAAK,KAAK,GAAG,UAAU,aAAa;KAC7C;;AAIF,QAAI,MADqB,cAAc,MAAM,EAC/B,UAAU,gBACvB,OAAM,IAAI,MAAM,yCAAyC;;AAI3D,QAAM,IAAI,MAAM,yCAAyC;;CAG1D,MAAM,aAAa,aAA0D;AAC5E,MAAI,CAAC,YAAY,QAChB,OAAM,IAAI,MAAM,qDAAqD;EAGtE,MAAM,WAAW,MAAM,MAAM,sBAAsB;GAClD,QAAQ;GACR,SAAS,EACR,gBAAgB,qCAChB;GACD,MAAM,IAAI,gBAAgB;IACzB,YAAY;IACZ,WAAW;IACX,eAAe,YAAY;IAC3B,CAAC;GACF,CAAC;AAEF,MAAI,CAAC,SAAS,IAAI;GACjB,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,SAAM,IAAI,MAAM,8BAA8B,OAAO;;EAGtD,MAAM,UAAW,MAAM,SAAS,MAAM;AAMtC,SAAO;GACN,GAAG;GACH,QAAQ,QAAQ;GAChB,SAAS,QAAQ,iBAAiB,YAAY;GAC9C,SAAS,KAAK,KAAK,GAAG,QAAQ,aAAa;GAC3C;;CAGF,UAAU,aAAuC;AAChD,SAAO,YAAY;;CAEpB"}
1
+ {"version":3,"file":"kimi-coding.js","names":[],"sources":["../../../../src/auth/oauth/kimi-coding.ts"],"sourcesContent":["/**\n * Kimi Coding (Moonshot AI) OAuth device code flow.\n * @see https://auth.kimi.com\n */\n\nimport type { OAuthCredentials, OAuthProviderInterface, OAuthLoginCallbacks } from './types.js';\n\nconst KIMI_OAUTH_BASE_URL = 'https://auth.kimi.com';\nconst KIMI_OAUTH_DEVICE_URL = `${KIMI_OAUTH_BASE_URL}/api/oauth/device_authorization`;\nconst KIMI_OAUTH_TOKEN_URL = `${KIMI_OAUTH_BASE_URL}/api/oauth/token`;\nconst KIMI_OAUTH_CLIENT_ID = '17e5f671-d194-4dfb-9706-5516cb48c098';\n\nexport const kimiCodingOAuthProvider: OAuthProviderInterface = {\n\tid: 'kimi-coding',\n\tname: 'Kimi For Coding (月之暗面)',\n\tusesCallbackServer: false,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\tconst deviceResponse = await fetch(KIMI_OAUTH_DEVICE_URL, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tclient_id: KIMI_OAUTH_CLIENT_ID,\n\t\t\t\tscope: 'kimi-code',\n\t\t\t}),\n\t\t});\n\n\t\tif (!deviceResponse.ok) {\n\t\t\tconst error = await deviceResponse.text();\n\t\t\tthrow new Error(`Device code request failed: ${error}`);\n\t\t}\n\n\t\tconst deviceData = (await deviceResponse.json()) as {\n\t\t\tdevice_code: string;\n\t\t\tuser_code: string;\n\t\t\tverification_uri: string;\n\t\t\tverification_uri_complete: string;\n\t\t\tinterval: number;\n\t\t\texpires_in: number;\n\t\t};\n\n\t\tcallbacks.onAuth({\n\t\t\turl: deviceData.verification_uri_complete || deviceData.verification_uri,\n\t\t\tinstructions: `Please visit ${deviceData.verification_uri} and enter code: ${deviceData.user_code}`,\n\t\t});\n\n\t\tconst expiresAt = Date.now() + deviceData.expires_in * 1000;\n\t\tconst pollInterval = (deviceData.interval || 5) * 1000;\n\n\t\twhile (Date.now() < expiresAt) {\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, pollInterval));\n\n\t\t\tconst tokenResponse = await fetch(KIMI_OAUTH_TOKEN_URL, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams({\n\t\t\t\t\tgrant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n\t\t\t\t\tclient_id: KIMI_OAUTH_CLIENT_ID,\n\t\t\t\t\tdevice_code: deviceData.device_code,\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tif (tokenResponse.ok) {\n\t\t\t\tconst tokenData = (await tokenResponse.json()) as {\n\t\t\t\t\taccess_token: string;\n\t\t\t\t\trefresh_token: string;\n\t\t\t\t\texpires_in: number;\n\t\t\t\t};\n\n\t\t\t\treturn {\n\t\t\t\t\taccess: tokenData.access_token,\n\t\t\t\t\trefresh: tokenData.refresh_token,\n\t\t\t\t\texpires: Date.now() + tokenData.expires_in * 1000,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst errorData = (await tokenResponse.json()) as { error?: string };\n\t\t\tif (errorData.error === 'expired_token') {\n\t\t\t\tthrow new Error('Device code expired. Please try again.');\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error('Device code expired. Please try again.');\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\tif (!credentials.refresh) {\n\t\t\tthrow new Error('Kimi OAuth refresh token missing. Re-authenticate.');\n\t\t}\n\n\t\tconst response = await fetch(KIMI_OAUTH_TOKEN_URL, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: 'refresh_token',\n\t\t\t\tclient_id: KIMI_OAUTH_CLIENT_ID,\n\t\t\t\trefresh_token: credentials.refresh,\n\t\t\t}),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst text = await response.text();\n\t\t\tthrow new Error(`Kimi OAuth refresh failed: ${text}`);\n\t\t}\n\n\t\tconst payload = (await response.json()) as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t};\n\n\t\treturn {\n\t\t\t...credentials,\n\t\t\taccess: payload.access_token,\n\t\t\trefresh: payload.refresh_token || credentials.refresh,\n\t\t\texpires: Date.now() + payload.expires_in * 1000,\n\t\t};\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n"],"mappings":";AAOA,MAAM,sBAAsB;AAC5B,MAAM,wBAAwB,GAAG,oBAAoB;AACrD,MAAM,uBAAuB,GAAG,oBAAoB;AACpD,MAAM,uBAAuB;AAE7B,MAAa,0BAAkD;CAC9D,IAAI;CACJ,MAAM;CACN,oBAAoB;CAEpB,MAAM,MAAM,WAA2D;EACtE,MAAM,iBAAiB,MAAM,MAAM,uBAAuB;GACzD,QAAQ;GACR,SAAS,EACR,gBAAgB,qCAChB;GACD,MAAM,IAAI,gBAAgB;IACzB,WAAW;IACX,OAAO;IACP,CAAC;GACF,CAAC;AAEF,MAAI,CAAC,eAAe,IAAI;GACvB,MAAM,QAAQ,MAAM,eAAe,MAAM;AACzC,SAAM,IAAI,MAAM,+BAA+B,QAAQ;;EAGxD,MAAM,aAAc,MAAM,eAAe,MAAM;AAS/C,YAAU,OAAO;GAChB,KAAK,WAAW,6BAA6B,WAAW;GACxD,cAAc,gBAAgB,WAAW,iBAAiB,mBAAmB,WAAW;GACxF,CAAC;EAEF,MAAM,YAAY,KAAK,KAAK,GAAG,WAAW,aAAa;EACvD,MAAM,gBAAgB,WAAW,YAAY,KAAK;AAElD,SAAO,KAAK,KAAK,GAAG,WAAW;AAC9B,SAAM,IAAI,SAAS,YAAY,WAAW,SAAS,aAAa,CAAC;GAEjE,MAAM,gBAAgB,MAAM,MAAM,sBAAsB;IACvD,QAAQ;IACR,SAAS,EACR,gBAAgB,qCAChB;IACD,MAAM,IAAI,gBAAgB;KACzB,YAAY;KACZ,WAAW;KACX,aAAa,WAAW;KACxB,CAAC;IACF,CAAC;AAEF,OAAI,cAAc,IAAI;IACrB,MAAM,YAAa,MAAM,cAAc,MAAM;AAM7C,WAAO;KACN,QAAQ,UAAU;KAClB,SAAS,UAAU;KACnB,SAAS,KAAK,KAAK,GAAG,UAAU,aAAa;KAC7C;;AAIF,QAAI,MADqB,cAAc,MAAM,EAC/B,UAAU,gBACvB,OAAM,IAAI,MAAM,yCAAyC;;AAI3D,QAAM,IAAI,MAAM,yCAAyC;;CAG1D,MAAM,aAAa,aAA0D;AAC5E,MAAI,CAAC,YAAY,QAChB,OAAM,IAAI,MAAM,qDAAqD;EAGtE,MAAM,WAAW,MAAM,MAAM,sBAAsB;GAClD,QAAQ;GACR,SAAS,EACR,gBAAgB,qCAChB;GACD,MAAM,IAAI,gBAAgB;IACzB,YAAY;IACZ,WAAW;IACX,eAAe,YAAY;IAC3B,CAAC;GACF,CAAC;AAEF,MAAI,CAAC,SAAS,IAAI;GACjB,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,SAAM,IAAI,MAAM,8BAA8B,OAAO;;EAGtD,MAAM,UAAW,MAAM,SAAS,MAAM;AAMtC,SAAO;GACN,GAAG;GACH,QAAQ,QAAQ;GAChB,SAAS,QAAQ,iBAAiB,YAAY;GAC9C,SAAS,KAAK,KAAK,GAAG,QAAQ,aAAa;GAC3C;;CAGF,UAAU,aAAuC;AAChD,SAAO,YAAY;;CAEpB"}
@@ -6,7 +6,7 @@ const MINIMAX_CN_OAUTH_CLIENT_ID = "your_client_id";
6
6
  const minimaxCnOAuthProvider = {
7
7
  id: "minimax-cn",
8
8
  name: "MiniMax 国内版",
9
- usesCallbackServer: true,
9
+ usesCallbackServer: false,
10
10
  async login(callbacks) {
11
11
  const codeVerifier = generateCodeVerifier();
12
12
  const codeChallenge = await generateCodeChallenge(codeVerifier);
@@ -1 +1 @@
1
- {"version":3,"file":"minimax-cn.js","names":[],"sources":["../../../../src/auth/oauth/minimax-cn.ts"],"sourcesContent":["/**\n * MiniMax CN (China region) OAuth provider\n *\n * OAuth 2.0 for the MiniMax China platform: https://platform.minimax.chat/\n *\n * Endpoints differ from the international product:\n * - International: platform.minimaxi.com\n * - China: platform.minimax.chat\n */\n\nimport type { OAuthCredentials, OAuthProviderInterface, OAuthLoginCallbacks } from './types.js';\n\nconst MINIMAX_CN_OAUTH_BASE_URL = 'https://platform.minimax.chat';\nconst MINIMAX_CN_OAUTH_AUTHORIZE_URL = `${MINIMAX_CN_OAUTH_BASE_URL}/oauth/authorize`;\nconst MINIMAX_CN_OAUTH_TOKEN_URL = `${MINIMAX_CN_OAUTH_BASE_URL}/oauth/token`;\nconst MINIMAX_CN_OAUTH_CLIENT_ID = 'your_client_id'; // Users need to register their own app\n\nexport const minimaxCnOAuthProvider: OAuthProviderInterface = {\n\tid: 'minimax-cn',\n\tname: 'MiniMax 国内版',\n\tusesCallbackServer: true,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\t// MiniMax CN uses authorization code flow\n\t\tconst codeVerifier = generateCodeVerifier();\n\t\tconst codeChallenge = await generateCodeChallenge(codeVerifier);\n\t\t\n\t\tconst authUrl = new URL(MINIMAX_CN_OAUTH_AUTHORIZE_URL);\n\t\tauthUrl.searchParams.set('client_id', MINIMAX_CN_OAUTH_CLIENT_ID);\n\t\tauthUrl.searchParams.set('redirect_uri', 'http://localhost:3000/callback');\n\t\tauthUrl.searchParams.set('response_type', 'code');\n\t\tauthUrl.searchParams.set('scope', 'api');\n\t\tauthUrl.searchParams.set('code_challenge', codeChallenge);\n\t\tauthUrl.searchParams.set('code_challenge_method', 'S256');\n\n\t\t// Show user the auth URL\n\t\tcallbacks.onAuth({\n\t\t\turl: authUrl.toString(),\n\t\t\tinstructions: '请在浏览器中授权应用,然后输入返回的授权码。',\n\t\t});\n\n\t\t// Prompt for the authorization code\n\t\tconst code = await callbacks.onPrompt({\n\t\t\tmessage: '请输入授权码:',\n\t\t});\n\n\t\t// Exchange code for token\n\t\tconst tokenResponse = await fetch(MINIMAX_CN_OAUTH_TOKEN_URL, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: 'authorization_code',\n\t\t\t\tclient_id: MINIMAX_CN_OAUTH_CLIENT_ID,\n\t\t\t\tcode,\n\t\t\t\tredirect_uri: 'http://localhost:3000/callback',\n\t\t\t\tcode_verifier: codeVerifier,\n\t\t\t}),\n\t\t});\n\n\t\tif (!tokenResponse.ok) {\n\t\t\tconst error = await tokenResponse.text();\n\t\t\tthrow new Error(`Token exchange failed: ${error}`);\n\t\t}\n\n\t\tconst tokenData = await tokenResponse.json() as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t};\n\n\t\treturn {\n\t\t\taccess: tokenData.access_token,\n\t\t\trefresh: tokenData.refresh_token,\n\t\t\texpires: Date.now() + tokenData.expires_in * 1000,\n\t\t};\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\tif (!credentials.refresh) {\n\t\t\tthrow new Error('MiniMax CN OAuth refresh token missing. Re-authenticate.');\n\t\t}\n\n\t\tconst response = await fetch(MINIMAX_CN_OAUTH_TOKEN_URL, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: 'refresh_token',\n\t\t\t\tclient_id: MINIMAX_CN_OAUTH_CLIENT_ID,\n\t\t\t\trefresh_token: credentials.refresh,\n\t\t\t}),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst text = await response.text();\n\t\t\tthrow new Error(`MiniMax CN OAuth refresh failed: ${text}`);\n\t\t}\n\n\t\tconst payload = await response.json() as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t};\n\n\t\treturn {\n\t\t\t...credentials,\n\t\t\taccess: payload.access_token,\n\t\t\trefresh: payload.refresh_token || credentials.refresh,\n\t\t\texpires: Date.now() + payload.expires_in * 1000,\n\t\t};\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n\nfunction generateCodeVerifier(): string {\n\tconst array = new Uint8Array(32);\n\tcrypto.getRandomValues(array);\n\treturn base64UrlEncode(array);\n}\n\nasync function generateCodeChallenge(verifier: string): Promise<string> {\n\tconst encoder = new TextEncoder();\n\tconst data = encoder.encode(verifier);\n\tconst digest = await crypto.subtle.digest('SHA-256', data);\n\treturn base64UrlEncode(new Uint8Array(digest));\n}\n\nfunction base64UrlEncode(buffer: Uint8Array): string {\n\tlet str = '';\n\tbuffer.forEach(b => str += String.fromCharCode(b));\n\treturn btoa(str).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n"],"mappings":";AAYA,MAAM,4BAA4B;AAClC,MAAM,iCAAiC,GAAG,0BAA0B;AACpE,MAAM,6BAA6B,GAAG,0BAA0B;AAChE,MAAM,6BAA6B;AAEnC,MAAa,yBAAiD;CAC7D,IAAI;CACJ,MAAM;CACN,oBAAoB;CAEpB,MAAM,MAAM,WAA2D;EAEtE,MAAM,eAAe,sBAAsB;EAC3C,MAAM,gBAAgB,MAAM,sBAAsB,aAAa;EAE/D,MAAM,UAAU,IAAI,IAAI,+BAA+B;AACvD,UAAQ,aAAa,IAAI,aAAa,2BAA2B;AACjE,UAAQ,aAAa,IAAI,gBAAgB,iCAAiC;AAC1E,UAAQ,aAAa,IAAI,iBAAiB,OAAO;AACjD,UAAQ,aAAa,IAAI,SAAS,MAAM;AACxC,UAAQ,aAAa,IAAI,kBAAkB,cAAc;AACzD,UAAQ,aAAa,IAAI,yBAAyB,OAAO;AAGzD,YAAU,OAAO;GAChB,KAAK,QAAQ,UAAU;GACvB,cAAc;GACd,CAAC;EAGF,MAAM,OAAO,MAAM,UAAU,SAAS,EACrC,SAAS,WACT,CAAC;EAGF,MAAM,gBAAgB,MAAM,MAAM,4BAA4B;GAC7D,QAAQ;GACR,SAAS,EACR,gBAAgB,qCAChB;GACD,MAAM,IAAI,gBAAgB;IACzB,YAAY;IACZ,WAAW;IACX;IACA,cAAc;IACd,eAAe;IACf,CAAC;GACF,CAAC;AAEF,MAAI,CAAC,cAAc,IAAI;GACtB,MAAM,QAAQ,MAAM,cAAc,MAAM;AACxC,SAAM,IAAI,MAAM,0BAA0B,QAAQ;;EAGnD,MAAM,YAAY,MAAM,cAAc,MAAM;AAM5C,SAAO;GACN,QAAQ,UAAU;GAClB,SAAS,UAAU;GACnB,SAAS,KAAK,KAAK,GAAG,UAAU,aAAa;GAC7C;;CAGF,MAAM,aAAa,aAA0D;AAC5E,MAAI,CAAC,YAAY,QAChB,OAAM,IAAI,MAAM,2DAA2D;EAG5E,MAAM,WAAW,MAAM,MAAM,4BAA4B;GACxD,QAAQ;GACR,SAAS,EACR,gBAAgB,qCAChB;GACD,MAAM,IAAI,gBAAgB;IACzB,YAAY;IACZ,WAAW;IACX,eAAe,YAAY;IAC3B,CAAC;GACF,CAAC;AAEF,MAAI,CAAC,SAAS,IAAI;GACjB,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,SAAM,IAAI,MAAM,oCAAoC,OAAO;;EAG5D,MAAM,UAAU,MAAM,SAAS,MAAM;AAMrC,SAAO;GACN,GAAG;GACH,QAAQ,QAAQ;GAChB,SAAS,QAAQ,iBAAiB,YAAY;GAC9C,SAAS,KAAK,KAAK,GAAG,QAAQ,aAAa;GAC3C;;CAGF,UAAU,aAAuC;AAChD,SAAO,YAAY;;CAEpB;AAED,SAAS,uBAA+B;CACvC,MAAM,QAAQ,IAAI,WAAW,GAAG;AAChC,QAAO,gBAAgB,MAAM;AAC7B,QAAO,gBAAgB,MAAM;;AAG9B,eAAe,sBAAsB,UAAmC;CAEvE,MAAM,OAAO,IADO,aACA,CAAC,OAAO,SAAS;CACrC,MAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,KAAK;AAC1D,QAAO,gBAAgB,IAAI,WAAW,OAAO,CAAC;;AAG/C,SAAS,gBAAgB,QAA4B;CACpD,IAAI,MAAM;AACV,QAAO,SAAQ,MAAK,OAAO,OAAO,aAAa,EAAE,CAAC;AAClD,QAAO,KAAK,IAAI,CAAC,QAAQ,OAAO,IAAI,CAAC,QAAQ,OAAO,IAAI,CAAC,QAAQ,MAAM,GAAG"}
1
+ {"version":3,"file":"minimax-cn.js","names":[],"sources":["../../../../src/auth/oauth/minimax-cn.ts"],"sourcesContent":["/**\n * MiniMax CN (China region) OAuth provider\n *\n * OAuth 2.0 for the MiniMax China platform: https://platform.minimax.chat/\n *\n * Endpoints differ from the international product:\n * - International: platform.minimaxi.com\n * - China: platform.minimax.chat\n */\n\nimport type { OAuthCredentials, OAuthProviderInterface, OAuthLoginCallbacks } from './types.js';\n\nconst MINIMAX_CN_OAUTH_BASE_URL = 'https://platform.minimax.chat';\nconst MINIMAX_CN_OAUTH_AUTHORIZE_URL = `${MINIMAX_CN_OAUTH_BASE_URL}/oauth/authorize`;\nconst MINIMAX_CN_OAUTH_TOKEN_URL = `${MINIMAX_CN_OAUTH_BASE_URL}/oauth/token`;\nconst MINIMAX_CN_OAUTH_CLIENT_ID = 'your_client_id'; // Users need to register their own app\n\nexport const minimaxCnOAuthProvider: OAuthProviderInterface = {\n\tid: 'minimax-cn',\n\tname: 'MiniMax 国内版',\n\tusesCallbackServer: false,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\t// MiniMax CN uses authorization code flow\n\t\tconst codeVerifier = generateCodeVerifier();\n\t\tconst codeChallenge = await generateCodeChallenge(codeVerifier);\n\t\t\n\t\tconst authUrl = new URL(MINIMAX_CN_OAUTH_AUTHORIZE_URL);\n\t\tauthUrl.searchParams.set('client_id', MINIMAX_CN_OAUTH_CLIENT_ID);\n\t\tauthUrl.searchParams.set('redirect_uri', 'http://localhost:3000/callback');\n\t\tauthUrl.searchParams.set('response_type', 'code');\n\t\tauthUrl.searchParams.set('scope', 'api');\n\t\tauthUrl.searchParams.set('code_challenge', codeChallenge);\n\t\tauthUrl.searchParams.set('code_challenge_method', 'S256');\n\n\t\t// Show user the auth URL\n\t\tcallbacks.onAuth({\n\t\t\turl: authUrl.toString(),\n\t\t\tinstructions: '请在浏览器中授权应用,然后输入返回的授权码。',\n\t\t});\n\n\t\t// Prompt for the authorization code\n\t\tconst code = await callbacks.onPrompt({\n\t\t\tmessage: '请输入授权码:',\n\t\t});\n\n\t\t// Exchange code for token\n\t\tconst tokenResponse = await fetch(MINIMAX_CN_OAUTH_TOKEN_URL, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: 'authorization_code',\n\t\t\t\tclient_id: MINIMAX_CN_OAUTH_CLIENT_ID,\n\t\t\t\tcode,\n\t\t\t\tredirect_uri: 'http://localhost:3000/callback',\n\t\t\t\tcode_verifier: codeVerifier,\n\t\t\t}),\n\t\t});\n\n\t\tif (!tokenResponse.ok) {\n\t\t\tconst error = await tokenResponse.text();\n\t\t\tthrow new Error(`Token exchange failed: ${error}`);\n\t\t}\n\n\t\tconst tokenData = await tokenResponse.json() as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t};\n\n\t\treturn {\n\t\t\taccess: tokenData.access_token,\n\t\t\trefresh: tokenData.refresh_token,\n\t\t\texpires: Date.now() + tokenData.expires_in * 1000,\n\t\t};\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\tif (!credentials.refresh) {\n\t\t\tthrow new Error('MiniMax CN OAuth refresh token missing. Re-authenticate.');\n\t\t}\n\n\t\tconst response = await fetch(MINIMAX_CN_OAUTH_TOKEN_URL, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: 'refresh_token',\n\t\t\t\tclient_id: MINIMAX_CN_OAUTH_CLIENT_ID,\n\t\t\t\trefresh_token: credentials.refresh,\n\t\t\t}),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst text = await response.text();\n\t\t\tthrow new Error(`MiniMax CN OAuth refresh failed: ${text}`);\n\t\t}\n\n\t\tconst payload = await response.json() as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t};\n\n\t\treturn {\n\t\t\t...credentials,\n\t\t\taccess: payload.access_token,\n\t\t\trefresh: payload.refresh_token || credentials.refresh,\n\t\t\texpires: Date.now() + payload.expires_in * 1000,\n\t\t};\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n\nfunction generateCodeVerifier(): string {\n\tconst array = new Uint8Array(32);\n\tcrypto.getRandomValues(array);\n\treturn base64UrlEncode(array);\n}\n\nasync function generateCodeChallenge(verifier: string): Promise<string> {\n\tconst encoder = new TextEncoder();\n\tconst data = encoder.encode(verifier);\n\tconst digest = await crypto.subtle.digest('SHA-256', data);\n\treturn base64UrlEncode(new Uint8Array(digest));\n}\n\nfunction base64UrlEncode(buffer: Uint8Array): string {\n\tlet str = '';\n\tbuffer.forEach(b => str += String.fromCharCode(b));\n\treturn btoa(str).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n"],"mappings":";AAYA,MAAM,4BAA4B;AAClC,MAAM,iCAAiC,GAAG,0BAA0B;AACpE,MAAM,6BAA6B,GAAG,0BAA0B;AAChE,MAAM,6BAA6B;AAEnC,MAAa,yBAAiD;CAC7D,IAAI;CACJ,MAAM;CACN,oBAAoB;CAEpB,MAAM,MAAM,WAA2D;EAEtE,MAAM,eAAe,sBAAsB;EAC3C,MAAM,gBAAgB,MAAM,sBAAsB,aAAa;EAE/D,MAAM,UAAU,IAAI,IAAI,+BAA+B;AACvD,UAAQ,aAAa,IAAI,aAAa,2BAA2B;AACjE,UAAQ,aAAa,IAAI,gBAAgB,iCAAiC;AAC1E,UAAQ,aAAa,IAAI,iBAAiB,OAAO;AACjD,UAAQ,aAAa,IAAI,SAAS,MAAM;AACxC,UAAQ,aAAa,IAAI,kBAAkB,cAAc;AACzD,UAAQ,aAAa,IAAI,yBAAyB,OAAO;AAGzD,YAAU,OAAO;GAChB,KAAK,QAAQ,UAAU;GACvB,cAAc;GACd,CAAC;EAGF,MAAM,OAAO,MAAM,UAAU,SAAS,EACrC,SAAS,WACT,CAAC;EAGF,MAAM,gBAAgB,MAAM,MAAM,4BAA4B;GAC7D,QAAQ;GACR,SAAS,EACR,gBAAgB,qCAChB;GACD,MAAM,IAAI,gBAAgB;IACzB,YAAY;IACZ,WAAW;IACX;IACA,cAAc;IACd,eAAe;IACf,CAAC;GACF,CAAC;AAEF,MAAI,CAAC,cAAc,IAAI;GACtB,MAAM,QAAQ,MAAM,cAAc,MAAM;AACxC,SAAM,IAAI,MAAM,0BAA0B,QAAQ;;EAGnD,MAAM,YAAY,MAAM,cAAc,MAAM;AAM5C,SAAO;GACN,QAAQ,UAAU;GAClB,SAAS,UAAU;GACnB,SAAS,KAAK,KAAK,GAAG,UAAU,aAAa;GAC7C;;CAGF,MAAM,aAAa,aAA0D;AAC5E,MAAI,CAAC,YAAY,QAChB,OAAM,IAAI,MAAM,2DAA2D;EAG5E,MAAM,WAAW,MAAM,MAAM,4BAA4B;GACxD,QAAQ;GACR,SAAS,EACR,gBAAgB,qCAChB;GACD,MAAM,IAAI,gBAAgB;IACzB,YAAY;IACZ,WAAW;IACX,eAAe,YAAY;IAC3B,CAAC;GACF,CAAC;AAEF,MAAI,CAAC,SAAS,IAAI;GACjB,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,SAAM,IAAI,MAAM,oCAAoC,OAAO;;EAG5D,MAAM,UAAU,MAAM,SAAS,MAAM;AAMrC,SAAO;GACN,GAAG;GACH,QAAQ,QAAQ;GAChB,SAAS,QAAQ,iBAAiB,YAAY;GAC9C,SAAS,KAAK,KAAK,GAAG,QAAQ,aAAa;GAC3C;;CAGF,UAAU,aAAuC;AAChD,SAAO,YAAY;;CAEpB;AAED,SAAS,uBAA+B;CACvC,MAAM,QAAQ,IAAI,WAAW,GAAG;AAChC,QAAO,gBAAgB,MAAM;AAC7B,QAAO,gBAAgB,MAAM;;AAG9B,eAAe,sBAAsB,UAAmC;CAEvE,MAAM,OAAO,IADO,aACA,CAAC,OAAO,SAAS;CACrC,MAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,KAAK;AAC1D,QAAO,gBAAgB,IAAI,WAAW,OAAO,CAAC;;AAG/C,SAAS,gBAAgB,QAA4B;CACpD,IAAI,MAAM;AACV,QAAO,SAAQ,MAAK,OAAO,OAAO,aAAa,EAAE,CAAC;AAClD,QAAO,KAAK,IAAI,CAAC,QAAQ,OAAO,IAAI,CAAC,QAAQ,OAAO,IAAI,CAAC,QAAQ,MAAM,GAAG"}
@@ -6,7 +6,7 @@ const MINIMAX_OAUTH_CLIENT_ID = "your_client_id";
6
6
  const minimaxOAuthProvider = {
7
7
  id: "minimax",
8
8
  name: "MiniMax",
9
- usesCallbackServer: true,
9
+ usesCallbackServer: false,
10
10
  async login(callbacks) {
11
11
  const codeVerifier = generateCodeVerifier();
12
12
  const codeChallenge = await generateCodeChallenge(codeVerifier);
@@ -1 +1 @@
1
- {"version":3,"file":"minimax.js","names":[],"sources":["../../../../src/auth/oauth/minimax.ts"],"sourcesContent":["/**\n * MiniMax OAuth Provider\n * \n * OAuth 2.0 authentication for MiniMax Platform.\n * https://platform.minimaxi.com/\n */\n\nimport type { OAuthCredentials, OAuthProviderInterface, OAuthLoginCallbacks } from './types.js';\n\nconst MINIMAX_OAUTH_BASE_URL = 'https://platform.minimaxi.com';\nconst MINIMAX_OAUTH_AUTHORIZE_URL = `${MINIMAX_OAUTH_BASE_URL}/oauth/authorize`;\nconst MINIMAX_OAUTH_TOKEN_URL = `${MINIMAX_OAUTH_BASE_URL}/oauth/token`;\nconst MINIMAX_OAUTH_CLIENT_ID = 'your_client_id'; // Users need to register their own app\n\nexport const minimaxOAuthProvider: OAuthProviderInterface = {\n\tid: 'minimax',\n\tname: 'MiniMax',\n\tusesCallbackServer: true,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\t// MiniMax uses authorization code flow\n\t\t// First, generate a device code or authorization URL\n\t\t\n\t\t// For simplicity, we'll use a manual code flow\n\t\tconst codeVerifier = generateCodeVerifier();\n\t\tconst codeChallenge = await generateCodeChallenge(codeVerifier);\n\t\t\n\t\tconst authUrl = new URL(MINIMAX_OAUTH_AUTHORIZE_URL);\n\t\tauthUrl.searchParams.set('client_id', MINIMAX_OAUTH_CLIENT_ID);\n\t\tauthUrl.searchParams.set('redirect_uri', 'http://localhost:3000/callback');\n\t\tauthUrl.searchParams.set('response_type', 'code');\n\t\tauthUrl.searchParams.set('scope', 'api');\n\t\tauthUrl.searchParams.set('code_challenge', codeChallenge);\n\t\tauthUrl.searchParams.set('code_challenge_method', 'S256');\n\n\t\t// Show user the auth URL\n\t\tcallbacks.onAuth({\n\t\t\turl: authUrl.toString(),\n\t\t\tinstructions: 'Please authorize the application and enter the code shown.',\n\t\t});\n\n\t\t// Prompt for the authorization code\n\t\tconst code = await callbacks.onPrompt({\n\t\t\tmessage: 'Enter the authorization code:',\n\t\t});\n\n\t\t// Exchange code for token\n\t\tconst tokenResponse = await fetch(MINIMAX_OAUTH_TOKEN_URL, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: 'authorization_code',\n\t\t\t\tclient_id: MINIMAX_OAUTH_CLIENT_ID,\n\t\t\t\tcode,\n\t\t\t\tredirect_uri: 'http://localhost:3000/callback',\n\t\t\t\tcode_verifier: codeVerifier,\n\t\t\t}),\n\t\t});\n\n\t\tif (!tokenResponse.ok) {\n\t\t\tconst error = await tokenResponse.text();\n\t\t\tthrow new Error(`Token exchange failed: ${error}`);\n\t\t}\n\n\t\tconst tokenData = await tokenResponse.json() as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t};\n\n\t\treturn {\n\t\t\taccess: tokenData.access_token,\n\t\t\trefresh: tokenData.refresh_token,\n\t\t\texpires: Date.now() + tokenData.expires_in * 1000,\n\t\t};\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\tif (!credentials.refresh) {\n\t\t\tthrow new Error('MiniMax OAuth refresh token missing. Re-authenticate.');\n\t\t}\n\n\t\tconst response = await fetch(MINIMAX_OAUTH_TOKEN_URL, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: 'refresh_token',\n\t\t\t\tclient_id: MINIMAX_OAUTH_CLIENT_ID,\n\t\t\t\trefresh_token: credentials.refresh,\n\t\t\t}),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst text = await response.text();\n\t\t\tthrow new Error(`MiniMax OAuth refresh failed: ${text}`);\n\t\t}\n\n\t\tconst payload = await response.json() as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t};\n\n\t\treturn {\n\t\t\t...credentials,\n\t\t\taccess: payload.access_token,\n\t\t\trefresh: payload.refresh_token || credentials.refresh,\n\t\t\texpires: Date.now() + payload.expires_in * 1000,\n\t\t};\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n\nfunction generateCodeVerifier(): string {\n\tconst array = new Uint8Array(32);\n\tcrypto.getRandomValues(array);\n\treturn base64UrlEncode(array);\n}\n\nasync function generateCodeChallenge(verifier: string): Promise<string> {\n\tconst encoder = new TextEncoder();\n\tconst data = encoder.encode(verifier);\n\tconst digest = await crypto.subtle.digest('SHA-256', data);\n\treturn base64UrlEncode(new Uint8Array(digest));\n}\n\nfunction base64UrlEncode(buffer: Uint8Array): string {\n\tlet str = '';\n\tbuffer.forEach(b => str += String.fromCharCode(b));\n\treturn btoa(str).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n"],"mappings":";AASA,MAAM,yBAAyB;AAC/B,MAAM,8BAA8B,GAAG,uBAAuB;AAC9D,MAAM,0BAA0B,GAAG,uBAAuB;AAC1D,MAAM,0BAA0B;AAEhC,MAAa,uBAA+C;CAC3D,IAAI;CACJ,MAAM;CACN,oBAAoB;CAEpB,MAAM,MAAM,WAA2D;EAKtE,MAAM,eAAe,sBAAsB;EAC3C,MAAM,gBAAgB,MAAM,sBAAsB,aAAa;EAE/D,MAAM,UAAU,IAAI,IAAI,4BAA4B;AACpD,UAAQ,aAAa,IAAI,aAAa,wBAAwB;AAC9D,UAAQ,aAAa,IAAI,gBAAgB,iCAAiC;AAC1E,UAAQ,aAAa,IAAI,iBAAiB,OAAO;AACjD,UAAQ,aAAa,IAAI,SAAS,MAAM;AACxC,UAAQ,aAAa,IAAI,kBAAkB,cAAc;AACzD,UAAQ,aAAa,IAAI,yBAAyB,OAAO;AAGzD,YAAU,OAAO;GAChB,KAAK,QAAQ,UAAU;GACvB,cAAc;GACd,CAAC;EAGF,MAAM,OAAO,MAAM,UAAU,SAAS,EACrC,SAAS,iCACT,CAAC;EAGF,MAAM,gBAAgB,MAAM,MAAM,yBAAyB;GAC1D,QAAQ;GACR,SAAS,EACR,gBAAgB,qCAChB;GACD,MAAM,IAAI,gBAAgB;IACzB,YAAY;IACZ,WAAW;IACX;IACA,cAAc;IACd,eAAe;IACf,CAAC;GACF,CAAC;AAEF,MAAI,CAAC,cAAc,IAAI;GACtB,MAAM,QAAQ,MAAM,cAAc,MAAM;AACxC,SAAM,IAAI,MAAM,0BAA0B,QAAQ;;EAGnD,MAAM,YAAY,MAAM,cAAc,MAAM;AAM5C,SAAO;GACN,QAAQ,UAAU;GAClB,SAAS,UAAU;GACnB,SAAS,KAAK,KAAK,GAAG,UAAU,aAAa;GAC7C;;CAGF,MAAM,aAAa,aAA0D;AAC5E,MAAI,CAAC,YAAY,QAChB,OAAM,IAAI,MAAM,wDAAwD;EAGzE,MAAM,WAAW,MAAM,MAAM,yBAAyB;GACrD,QAAQ;GACR,SAAS,EACR,gBAAgB,qCAChB;GACD,MAAM,IAAI,gBAAgB;IACzB,YAAY;IACZ,WAAW;IACX,eAAe,YAAY;IAC3B,CAAC;GACF,CAAC;AAEF,MAAI,CAAC,SAAS,IAAI;GACjB,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,SAAM,IAAI,MAAM,iCAAiC,OAAO;;EAGzD,MAAM,UAAU,MAAM,SAAS,MAAM;AAMrC,SAAO;GACN,GAAG;GACH,QAAQ,QAAQ;GAChB,SAAS,QAAQ,iBAAiB,YAAY;GAC9C,SAAS,KAAK,KAAK,GAAG,QAAQ,aAAa;GAC3C;;CAGF,UAAU,aAAuC;AAChD,SAAO,YAAY;;CAEpB;AAED,SAAS,uBAA+B;CACvC,MAAM,QAAQ,IAAI,WAAW,GAAG;AAChC,QAAO,gBAAgB,MAAM;AAC7B,QAAO,gBAAgB,MAAM;;AAG9B,eAAe,sBAAsB,UAAmC;CAEvE,MAAM,OAAO,IADO,aACA,CAAC,OAAO,SAAS;CACrC,MAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,KAAK;AAC1D,QAAO,gBAAgB,IAAI,WAAW,OAAO,CAAC;;AAG/C,SAAS,gBAAgB,QAA4B;CACpD,IAAI,MAAM;AACV,QAAO,SAAQ,MAAK,OAAO,OAAO,aAAa,EAAE,CAAC;AAClD,QAAO,KAAK,IAAI,CAAC,QAAQ,OAAO,IAAI,CAAC,QAAQ,OAAO,IAAI,CAAC,QAAQ,MAAM,GAAG"}
1
+ {"version":3,"file":"minimax.js","names":[],"sources":["../../../../src/auth/oauth/minimax.ts"],"sourcesContent":["/**\n * MiniMax OAuth Provider\n * \n * OAuth 2.0 authentication for MiniMax Platform.\n * https://platform.minimaxi.com/\n */\n\nimport type { OAuthCredentials, OAuthProviderInterface, OAuthLoginCallbacks } from './types.js';\n\nconst MINIMAX_OAUTH_BASE_URL = 'https://platform.minimaxi.com';\nconst MINIMAX_OAUTH_AUTHORIZE_URL = `${MINIMAX_OAUTH_BASE_URL}/oauth/authorize`;\nconst MINIMAX_OAUTH_TOKEN_URL = `${MINIMAX_OAUTH_BASE_URL}/oauth/token`;\nconst MINIMAX_OAUTH_CLIENT_ID = 'your_client_id'; // Users need to register their own app\n\nexport const minimaxOAuthProvider: OAuthProviderInterface = {\n\tid: 'minimax',\n\tname: 'MiniMax',\n\tusesCallbackServer: false,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\t// MiniMax uses authorization code flow\n\t\t// First, generate a device code or authorization URL\n\t\t\n\t\t// For simplicity, we'll use a manual code flow\n\t\tconst codeVerifier = generateCodeVerifier();\n\t\tconst codeChallenge = await generateCodeChallenge(codeVerifier);\n\t\t\n\t\tconst authUrl = new URL(MINIMAX_OAUTH_AUTHORIZE_URL);\n\t\tauthUrl.searchParams.set('client_id', MINIMAX_OAUTH_CLIENT_ID);\n\t\tauthUrl.searchParams.set('redirect_uri', 'http://localhost:3000/callback');\n\t\tauthUrl.searchParams.set('response_type', 'code');\n\t\tauthUrl.searchParams.set('scope', 'api');\n\t\tauthUrl.searchParams.set('code_challenge', codeChallenge);\n\t\tauthUrl.searchParams.set('code_challenge_method', 'S256');\n\n\t\t// Show user the auth URL\n\t\tcallbacks.onAuth({\n\t\t\turl: authUrl.toString(),\n\t\t\tinstructions: 'Please authorize the application and enter the code shown.',\n\t\t});\n\n\t\t// Prompt for the authorization code\n\t\tconst code = await callbacks.onPrompt({\n\t\t\tmessage: 'Enter the authorization code:',\n\t\t});\n\n\t\t// Exchange code for token\n\t\tconst tokenResponse = await fetch(MINIMAX_OAUTH_TOKEN_URL, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: 'authorization_code',\n\t\t\t\tclient_id: MINIMAX_OAUTH_CLIENT_ID,\n\t\t\t\tcode,\n\t\t\t\tredirect_uri: 'http://localhost:3000/callback',\n\t\t\t\tcode_verifier: codeVerifier,\n\t\t\t}),\n\t\t});\n\n\t\tif (!tokenResponse.ok) {\n\t\t\tconst error = await tokenResponse.text();\n\t\t\tthrow new Error(`Token exchange failed: ${error}`);\n\t\t}\n\n\t\tconst tokenData = await tokenResponse.json() as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t};\n\n\t\treturn {\n\t\t\taccess: tokenData.access_token,\n\t\t\trefresh: tokenData.refresh_token,\n\t\t\texpires: Date.now() + tokenData.expires_in * 1000,\n\t\t};\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\tif (!credentials.refresh) {\n\t\t\tthrow new Error('MiniMax OAuth refresh token missing. Re-authenticate.');\n\t\t}\n\n\t\tconst response = await fetch(MINIMAX_OAUTH_TOKEN_URL, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: 'refresh_token',\n\t\t\t\tclient_id: MINIMAX_OAUTH_CLIENT_ID,\n\t\t\t\trefresh_token: credentials.refresh,\n\t\t\t}),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst text = await response.text();\n\t\t\tthrow new Error(`MiniMax OAuth refresh failed: ${text}`);\n\t\t}\n\n\t\tconst payload = await response.json() as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t};\n\n\t\treturn {\n\t\t\t...credentials,\n\t\t\taccess: payload.access_token,\n\t\t\trefresh: payload.refresh_token || credentials.refresh,\n\t\t\texpires: Date.now() + payload.expires_in * 1000,\n\t\t};\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n\nfunction generateCodeVerifier(): string {\n\tconst array = new Uint8Array(32);\n\tcrypto.getRandomValues(array);\n\treturn base64UrlEncode(array);\n}\n\nasync function generateCodeChallenge(verifier: string): Promise<string> {\n\tconst encoder = new TextEncoder();\n\tconst data = encoder.encode(verifier);\n\tconst digest = await crypto.subtle.digest('SHA-256', data);\n\treturn base64UrlEncode(new Uint8Array(digest));\n}\n\nfunction base64UrlEncode(buffer: Uint8Array): string {\n\tlet str = '';\n\tbuffer.forEach(b => str += String.fromCharCode(b));\n\treturn btoa(str).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n"],"mappings":";AASA,MAAM,yBAAyB;AAC/B,MAAM,8BAA8B,GAAG,uBAAuB;AAC9D,MAAM,0BAA0B,GAAG,uBAAuB;AAC1D,MAAM,0BAA0B;AAEhC,MAAa,uBAA+C;CAC3D,IAAI;CACJ,MAAM;CACN,oBAAoB;CAEpB,MAAM,MAAM,WAA2D;EAKtE,MAAM,eAAe,sBAAsB;EAC3C,MAAM,gBAAgB,MAAM,sBAAsB,aAAa;EAE/D,MAAM,UAAU,IAAI,IAAI,4BAA4B;AACpD,UAAQ,aAAa,IAAI,aAAa,wBAAwB;AAC9D,UAAQ,aAAa,IAAI,gBAAgB,iCAAiC;AAC1E,UAAQ,aAAa,IAAI,iBAAiB,OAAO;AACjD,UAAQ,aAAa,IAAI,SAAS,MAAM;AACxC,UAAQ,aAAa,IAAI,kBAAkB,cAAc;AACzD,UAAQ,aAAa,IAAI,yBAAyB,OAAO;AAGzD,YAAU,OAAO;GAChB,KAAK,QAAQ,UAAU;GACvB,cAAc;GACd,CAAC;EAGF,MAAM,OAAO,MAAM,UAAU,SAAS,EACrC,SAAS,iCACT,CAAC;EAGF,MAAM,gBAAgB,MAAM,MAAM,yBAAyB;GAC1D,QAAQ;GACR,SAAS,EACR,gBAAgB,qCAChB;GACD,MAAM,IAAI,gBAAgB;IACzB,YAAY;IACZ,WAAW;IACX;IACA,cAAc;IACd,eAAe;IACf,CAAC;GACF,CAAC;AAEF,MAAI,CAAC,cAAc,IAAI;GACtB,MAAM,QAAQ,MAAM,cAAc,MAAM;AACxC,SAAM,IAAI,MAAM,0BAA0B,QAAQ;;EAGnD,MAAM,YAAY,MAAM,cAAc,MAAM;AAM5C,SAAO;GACN,QAAQ,UAAU;GAClB,SAAS,UAAU;GACnB,SAAS,KAAK,KAAK,GAAG,UAAU,aAAa;GAC7C;;CAGF,MAAM,aAAa,aAA0D;AAC5E,MAAI,CAAC,YAAY,QAChB,OAAM,IAAI,MAAM,wDAAwD;EAGzE,MAAM,WAAW,MAAM,MAAM,yBAAyB;GACrD,QAAQ;GACR,SAAS,EACR,gBAAgB,qCAChB;GACD,MAAM,IAAI,gBAAgB;IACzB,YAAY;IACZ,WAAW;IACX,eAAe,YAAY;IAC3B,CAAC;GACF,CAAC;AAEF,MAAI,CAAC,SAAS,IAAI;GACjB,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,SAAM,IAAI,MAAM,iCAAiC,OAAO;;EAGzD,MAAM,UAAU,MAAM,SAAS,MAAM;AAMrC,SAAO;GACN,GAAG;GACH,QAAQ,QAAQ;GAChB,SAAS,QAAQ,iBAAiB,YAAY;GAC9C,SAAS,KAAK,KAAK,GAAG,QAAQ,aAAa;GAC3C;;CAGF,UAAU,aAAuC;AAChD,SAAO,YAAY;;CAEpB;AAED,SAAS,uBAA+B;CACvC,MAAM,QAAQ,IAAI,WAAW,GAAG;AAChC,QAAO,gBAAgB,MAAM;AAC7B,QAAO,gBAAgB,MAAM;;AAG9B,eAAe,sBAAsB,UAAmC;CAEvE,MAAM,OAAO,IADO,aACA,CAAC,OAAO,SAAS;CACrC,MAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,KAAK;AAC1D,QAAO,gBAAgB,IAAI,WAAW,OAAO,CAAC;;AAG/C,SAAS,gBAAgB,QAA4B;CACpD,IAAI,MAAM;AACV,QAAO,SAAQ,MAAK,OAAO,OAAO,aAAa,EAAE,CAAC;AAClD,QAAO,KAAK,IAAI,CAAC,QAAQ,OAAO,IAAI,CAAC,QAAQ,OAAO,IAAI,CAAC,QAAQ,MAAM,GAAG"}
@@ -1,4 +1,9 @@
1
1
  /**
2
- * OpenAI Codex (ChatGPT) OAuth — delegated to @earendil-works/pi-ai.
2
+ * OpenAI Codex (ChatGPT) OAuth.
3
+ *
4
+ * Owns callback validation, manual prompt handling, and success/error pages.
3
5
  */
4
- export { loginOpenAICodex, openaiCodexOAuthProvider, refreshOpenAICodexToken } from '@earendil-works/pi-ai/oauth';
6
+ import type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from './types.js';
7
+ export declare function loginOpenAICodex(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;
8
+ export declare function refreshOpenAICodexToken(refreshToken: string): Promise<OAuthCredentials>;
9
+ export declare const openaiCodexOAuthProvider: OAuthProviderInterface;