workos 0.2.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (401) hide show
  1. package/.claude-plugin/plugin.json +3 -3
  2. package/README.md +3 -2
  3. package/dist/bin.js +42 -20
  4. package/dist/bin.js.map +1 -1
  5. package/dist/cli.config.d.ts +6 -2
  6. package/dist/cli.config.js +8 -2
  7. package/dist/cli.config.js.map +1 -1
  8. package/dist/commands/install-skill.js.map +1 -0
  9. package/dist/{src/commands → commands}/install.js +8 -12
  10. package/dist/commands/install.js.map +1 -0
  11. package/dist/{src/commands → commands}/login.js +3 -2
  12. package/dist/commands/login.js.map +1 -0
  13. package/dist/commands/logout.js.map +1 -0
  14. package/dist/craft-pre-release.sh +10 -0
  15. package/dist/dashboard/components/AnimatedLogo.js.map +1 -0
  16. package/dist/dashboard/components/CompletionView.js.map +1 -0
  17. package/dist/dashboard/components/ConfirmPrompt.js.map +1 -0
  18. package/dist/dashboard/components/CredentialsForm.js.map +1 -0
  19. package/dist/dashboard/components/Dashboard.js.map +1 -0
  20. package/dist/{src/dashboard → dashboard}/components/DashboardLayout.d.ts +2 -2
  21. package/dist/dashboard/components/DashboardLayout.js.map +1 -0
  22. package/dist/{src/dashboard → dashboard}/components/DiffPanel.d.ts +2 -2
  23. package/dist/dashboard/components/DiffPanel.js.map +1 -0
  24. package/dist/dashboard/components/InlinePrompt.js.map +1 -0
  25. package/dist/{src/dashboard → dashboard}/components/OutputPanel.d.ts +2 -2
  26. package/dist/dashboard/components/OutputPanel.js.map +1 -0
  27. package/dist/dashboard/components/Panel.js.map +1 -0
  28. package/dist/dashboard/components/TextInput.js.map +1 -0
  29. package/dist/dashboard/components/WelcomeArt.js.map +1 -0
  30. package/dist/dashboard/hooks/useAnimation.js.map +1 -0
  31. package/dist/dashboard/hooks/useKeyboard.js.map +1 -0
  32. package/dist/dashboard/hooks/useTerminalSize.js.map +1 -0
  33. package/dist/{src/dashboard → dashboard}/index.d.ts +2 -2
  34. package/dist/dashboard/index.js.map +1 -0
  35. package/dist/dashboard/lib/diff-utils.js.map +1 -0
  36. package/dist/dashboard/lib/logo-frames.js.map +1 -0
  37. package/dist/dashboard/lib/welcome-art.js.map +1 -0
  38. package/dist/dashboard/types.d.ts +5 -0
  39. package/dist/dashboard/types.js.map +1 -0
  40. package/dist/{src/lib → lib}/adapters/cli-adapter.d.ts +5 -5
  41. package/dist/{src/lib → lib}/adapters/cli-adapter.js +5 -5
  42. package/dist/lib/adapters/cli-adapter.js.map +1 -0
  43. package/dist/{src/lib → lib}/adapters/dashboard-adapter.d.ts +4 -4
  44. package/dist/lib/adapters/dashboard-adapter.js.map +1 -0
  45. package/dist/{src/lib → lib}/adapters/index.d.ts +1 -1
  46. package/dist/lib/adapters/index.js.map +1 -0
  47. package/dist/{src/lib → lib}/adapters/types.d.ts +4 -4
  48. package/dist/lib/adapters/types.js.map +1 -0
  49. package/dist/{src/lib → lib}/agent-interface.d.ts +15 -9
  50. package/dist/{src/lib → lib}/agent-interface.js +146 -61
  51. package/dist/lib/agent-interface.js.map +1 -0
  52. package/dist/{src/lib → lib}/agent-runner.d.ts +2 -2
  53. package/dist/{src/lib → lib}/agent-runner.js +4 -4
  54. package/dist/lib/agent-runner.js.map +1 -0
  55. package/dist/{src/lib → lib}/ai-content.d.ts +6 -2
  56. package/dist/lib/ai-content.js +130 -0
  57. package/dist/lib/ai-content.js.map +1 -0
  58. package/dist/lib/api.js.map +1 -0
  59. package/dist/lib/background-refresh.d.ts +29 -0
  60. package/dist/lib/background-refresh.js +95 -0
  61. package/dist/lib/background-refresh.js.map +1 -0
  62. package/dist/{src/lib → lib}/config.d.ts +6 -6
  63. package/dist/lib/config.js.map +1 -0
  64. package/dist/{src/lib → lib}/constants.d.ts +1 -1
  65. package/dist/{src/lib → lib}/constants.js +1 -1
  66. package/dist/lib/constants.js.map +1 -0
  67. package/dist/lib/credential-discovery.js.map +1 -0
  68. package/dist/lib/credential-proxy.d.ts +36 -0
  69. package/dist/lib/credential-proxy.js +298 -0
  70. package/dist/lib/credential-proxy.js.map +1 -0
  71. package/dist/{src/lib → lib}/credentials.d.ts +6 -0
  72. package/dist/{src/lib → lib}/credentials.js +33 -0
  73. package/dist/lib/credentials.js.map +1 -0
  74. package/dist/{src/lib → lib}/device-auth.d.ts +1 -0
  75. package/dist/{src/lib → lib}/device-auth.js +2 -1
  76. package/dist/lib/device-auth.js.map +1 -0
  77. package/dist/lib/ensure-auth.d.ts +22 -0
  78. package/dist/lib/ensure-auth.js +83 -0
  79. package/dist/lib/ensure-auth.js.map +1 -0
  80. package/dist/lib/env-writer.js.map +1 -0
  81. package/dist/{src/lib → lib}/events.d.ts +8 -8
  82. package/dist/{src/lib → lib}/events.js +3 -3
  83. package/dist/{src/lib → lib}/events.js.map +1 -1
  84. package/dist/{src/lib → lib}/framework-config.d.ts +2 -2
  85. package/dist/{src/lib → lib}/framework-config.js +1 -1
  86. package/dist/lib/framework-config.js.map +1 -0
  87. package/dist/lib/helper-functions.js.map +1 -0
  88. package/dist/{src/lib/wizard-core.d.ts → lib/installer-core.d.ts} +21 -17
  89. package/dist/{src/lib/wizard-core.js → lib/installer-core.js} +19 -17
  90. package/dist/lib/installer-core.js.map +1 -0
  91. package/dist/{src/lib/wizard-core.types.d.ts → lib/installer-core.types.d.ts} +9 -9
  92. package/dist/lib/installer-core.types.js +2 -0
  93. package/dist/lib/installer-core.types.js.map +1 -0
  94. package/dist/lib/port-detection.js.map +1 -0
  95. package/dist/lib/post-install.js.map +1 -0
  96. package/dist/lib/progress-tracker.js.map +1 -0
  97. package/dist/lib/run-with-core.d.ts +2 -0
  98. package/dist/{src/lib → lib}/run-with-core.js +38 -48
  99. package/dist/lib/run-with-core.js.map +1 -0
  100. package/dist/lib/safe-tools.js.map +1 -0
  101. package/dist/{src/lib → lib}/settings.d.ts +3 -0
  102. package/dist/{src/lib → lib}/settings.js +2 -3
  103. package/dist/lib/settings.js.map +1 -0
  104. package/dist/lib/staging-api.js.map +1 -0
  105. package/dist/lib/token-refresh-client.d.ts +23 -0
  106. package/dist/lib/token-refresh-client.js +88 -0
  107. package/dist/lib/token-refresh-client.js.map +1 -0
  108. package/dist/{src/lib → lib}/token-refresh.js +1 -1
  109. package/dist/lib/token-refresh.js.map +1 -0
  110. package/dist/lib/validation/build-validator.js.map +1 -0
  111. package/dist/lib/validation/index.js.map +1 -0
  112. package/dist/lib/validation/types.js.map +1 -0
  113. package/dist/lib/validation/validator.js.map +1 -0
  114. package/dist/{src/lib → lib}/workos-management.js +3 -3
  115. package/dist/lib/workos-management.js.map +1 -0
  116. package/dist/nextjs/nextjs-installer-agent.d.ts +6 -0
  117. package/dist/{src/nextjs/nextjs-wizard-agent.js → nextjs/nextjs-installer-agent.js} +6 -6
  118. package/dist/nextjs/nextjs-installer-agent.js.map +1 -0
  119. package/dist/{src/nextjs → nextjs}/utils.d.ts +2 -2
  120. package/dist/nextjs/utils.js.map +1 -0
  121. package/dist/react/react-installer-agent.d.ts +2 -0
  122. package/dist/{src/react/react-wizard-agent.js → react/react-installer-agent.js} +4 -4
  123. package/dist/react/react-installer-agent.js.map +1 -0
  124. package/dist/react-router/react-router-installer-agent.d.ts +6 -0
  125. package/dist/{src/react-router/react-router-wizard-agent.js → react-router/react-router-installer-agent.js} +6 -6
  126. package/dist/react-router/react-router-installer-agent.js.map +1 -0
  127. package/dist/{src/react-router → react-router}/utils.d.ts +2 -2
  128. package/dist/react-router/utils.js.map +1 -0
  129. package/dist/{src/run.d.ts → run.d.ts} +2 -1
  130. package/dist/{src/run.js → run.js} +5 -4
  131. package/dist/run.js.map +1 -0
  132. package/dist/{src/steps → steps}/add-or-update-environment-variables.js +5 -5
  133. package/dist/steps/add-or-update-environment-variables.js.map +1 -0
  134. package/dist/steps/index.js.map +1 -0
  135. package/dist/{src/steps → steps}/run-prettier.d.ts +2 -2
  136. package/dist/{src/steps → steps}/run-prettier.js +1 -1
  137. package/dist/steps/run-prettier.js.map +1 -0
  138. package/dist/{src/steps → steps}/upload-environment-variables/EnvironmentProvider.d.ts +3 -3
  139. package/dist/steps/upload-environment-variables/EnvironmentProvider.js.map +1 -0
  140. package/dist/{src/steps → steps}/upload-environment-variables/index.d.ts +2 -2
  141. package/dist/{src/steps → steps}/upload-environment-variables/index.js +3 -3
  142. package/dist/steps/upload-environment-variables/index.js.map +1 -0
  143. package/dist/{src/steps → steps}/upload-environment-variables/providers/vercel.d.ts +2 -2
  144. package/dist/steps/upload-environment-variables/providers/vercel.js.map +1 -0
  145. package/dist/tanstack-start/tanstack-start-installer-agent.d.ts +2 -0
  146. package/dist/{src/tanstack-start/tanstack-start-wizard-agent.js → tanstack-start/tanstack-start-installer-agent.js} +4 -4
  147. package/dist/tanstack-start/tanstack-start-installer-agent.js.map +1 -0
  148. package/dist/telemetry.js.map +1 -0
  149. package/dist/{src/utils → utils}/analytics.js +8 -8
  150. package/dist/utils/analytics.js.map +1 -0
  151. package/dist/utils/bash.js.map +1 -0
  152. package/dist/{src/utils → utils}/clack-utils.d.ts +9 -9
  153. package/dist/{src/utils → utils}/clack-utils.js +8 -8
  154. package/dist/utils/clack-utils.js.map +1 -0
  155. package/dist/utils/clack.js.map +1 -0
  156. package/dist/utils/cli-symbols.js.map +1 -0
  157. package/dist/{src/utils → utils}/debug.js +1 -1
  158. package/dist/utils/debug.js.map +1 -0
  159. package/dist/utils/env-parser.js.map +1 -0
  160. package/dist/utils/environment.d.ts +4 -0
  161. package/dist/{src/utils → utils}/environment.js +1 -1
  162. package/dist/utils/environment.js.map +1 -0
  163. package/dist/{src/utils → utils}/errors.js +1 -1
  164. package/dist/utils/errors.js.map +1 -0
  165. package/dist/utils/git-utils.js.map +1 -0
  166. package/dist/utils/logging.js.map +1 -0
  167. package/dist/utils/package-json.js.map +1 -0
  168. package/dist/{src/utils → utils}/package-manager.d.ts +4 -4
  169. package/dist/utils/package-manager.js.map +1 -0
  170. package/dist/utils/redact.js.map +1 -0
  171. package/dist/utils/semver.js.map +1 -0
  172. package/dist/utils/string.js.map +1 -0
  173. package/dist/{src/utils → utils}/telemetry-client.js +6 -2
  174. package/dist/utils/telemetry-client.js.map +1 -0
  175. package/dist/{src/utils → utils}/telemetry-types.d.ts +5 -5
  176. package/dist/utils/telemetry-types.js +6 -0
  177. package/dist/utils/telemetry-types.js.map +1 -0
  178. package/dist/{src/utils → utils}/types.d.ts +7 -2
  179. package/dist/{src/utils → utils}/types.js.map +1 -1
  180. package/dist/utils/urls.js.map +1 -0
  181. package/dist/utils/vendor/is-unicorn-supported.js.map +1 -0
  182. package/dist/vanilla-js/vanilla-js-installer-agent.d.ts +2 -0
  183. package/dist/{src/vanilla-js/vanilla-js-wizard-agent.js → vanilla-js/vanilla-js-installer-agent.js} +4 -4
  184. package/dist/vanilla-js/vanilla-js-installer-agent.js.map +1 -0
  185. package/package.json +10 -6
  186. package/dist/src/commands/install-skill.js.map +0 -1
  187. package/dist/src/commands/install.js.map +0 -1
  188. package/dist/src/commands/login.js.map +0 -1
  189. package/dist/src/commands/logout.js.map +0 -1
  190. package/dist/src/dashboard/components/AnimatedLogo.js.map +0 -1
  191. package/dist/src/dashboard/components/CompletionView.js.map +0 -1
  192. package/dist/src/dashboard/components/ConfirmPrompt.js.map +0 -1
  193. package/dist/src/dashboard/components/CredentialsForm.js.map +0 -1
  194. package/dist/src/dashboard/components/Dashboard.js.map +0 -1
  195. package/dist/src/dashboard/components/DashboardLayout.js.map +0 -1
  196. package/dist/src/dashboard/components/DiffPanel.js.map +0 -1
  197. package/dist/src/dashboard/components/InlinePrompt.js.map +0 -1
  198. package/dist/src/dashboard/components/OutputPanel.js.map +0 -1
  199. package/dist/src/dashboard/components/Panel.js.map +0 -1
  200. package/dist/src/dashboard/components/TextInput.js.map +0 -1
  201. package/dist/src/dashboard/components/WelcomeArt.js.map +0 -1
  202. package/dist/src/dashboard/hooks/useAnimation.js.map +0 -1
  203. package/dist/src/dashboard/hooks/useKeyboard.js.map +0 -1
  204. package/dist/src/dashboard/hooks/useTerminalSize.js.map +0 -1
  205. package/dist/src/dashboard/index.js.map +0 -1
  206. package/dist/src/dashboard/lib/diff-utils.js.map +0 -1
  207. package/dist/src/dashboard/lib/logo-frames.js.map +0 -1
  208. package/dist/src/dashboard/lib/welcome-art.js.map +0 -1
  209. package/dist/src/dashboard/types.d.ts +0 -5
  210. package/dist/src/dashboard/types.js.map +0 -1
  211. package/dist/src/lib/__tests__/test-utils.d.ts +0 -40
  212. package/dist/src/lib/__tests__/test-utils.js +0 -108
  213. package/dist/src/lib/__tests__/test-utils.js.map +0 -1
  214. package/dist/src/lib/adapters/cli-adapter.js.map +0 -1
  215. package/dist/src/lib/adapters/dashboard-adapter.js.map +0 -1
  216. package/dist/src/lib/adapters/index.js.map +0 -1
  217. package/dist/src/lib/adapters/types.js.map +0 -1
  218. package/dist/src/lib/agent-interface.js.map +0 -1
  219. package/dist/src/lib/agent-runner.js.map +0 -1
  220. package/dist/src/lib/ai-content.js +0 -68
  221. package/dist/src/lib/ai-content.js.map +0 -1
  222. package/dist/src/lib/api.js.map +0 -1
  223. package/dist/src/lib/config.js.map +0 -1
  224. package/dist/src/lib/constants.js.map +0 -1
  225. package/dist/src/lib/credential-discovery.js.map +0 -1
  226. package/dist/src/lib/credentials.js.map +0 -1
  227. package/dist/src/lib/device-auth.js.map +0 -1
  228. package/dist/src/lib/env-writer.js.map +0 -1
  229. package/dist/src/lib/framework-config.js.map +0 -1
  230. package/dist/src/lib/helper-functions.js.map +0 -1
  231. package/dist/src/lib/port-detection.js.map +0 -1
  232. package/dist/src/lib/post-install.js.map +0 -1
  233. package/dist/src/lib/progress-tracker.js.map +0 -1
  234. package/dist/src/lib/run-with-core.d.ts +0 -2
  235. package/dist/src/lib/run-with-core.js.map +0 -1
  236. package/dist/src/lib/safe-tools.js.map +0 -1
  237. package/dist/src/lib/settings.js.map +0 -1
  238. package/dist/src/lib/staging-api.js.map +0 -1
  239. package/dist/src/lib/token-refresh.js.map +0 -1
  240. package/dist/src/lib/validation/build-validator.js.map +0 -1
  241. package/dist/src/lib/validation/index.js.map +0 -1
  242. package/dist/src/lib/validation/types.js.map +0 -1
  243. package/dist/src/lib/validation/validator.js.map +0 -1
  244. package/dist/src/lib/wizard-core.js.map +0 -1
  245. package/dist/src/lib/wizard-core.types.js +0 -2
  246. package/dist/src/lib/wizard-core.types.js.map +0 -1
  247. package/dist/src/lib/workos-management.js.map +0 -1
  248. package/dist/src/nextjs/nextjs-wizard-agent.d.ts +0 -6
  249. package/dist/src/nextjs/nextjs-wizard-agent.js.map +0 -1
  250. package/dist/src/nextjs/utils.js.map +0 -1
  251. package/dist/src/react/react-wizard-agent.d.ts +0 -2
  252. package/dist/src/react/react-wizard-agent.js.map +0 -1
  253. package/dist/src/react-router/react-router-wizard-agent.d.ts +0 -6
  254. package/dist/src/react-router/react-router-wizard-agent.js.map +0 -1
  255. package/dist/src/react-router/utils.js.map +0 -1
  256. package/dist/src/run.js.map +0 -1
  257. package/dist/src/steps/add-or-update-environment-variables.js.map +0 -1
  258. package/dist/src/steps/index.js.map +0 -1
  259. package/dist/src/steps/run-prettier.js.map +0 -1
  260. package/dist/src/steps/upload-environment-variables/EnvironmentProvider.js.map +0 -1
  261. package/dist/src/steps/upload-environment-variables/index.js.map +0 -1
  262. package/dist/src/steps/upload-environment-variables/providers/vercel.js.map +0 -1
  263. package/dist/src/tanstack-start/tanstack-start-wizard-agent.d.ts +0 -2
  264. package/dist/src/tanstack-start/tanstack-start-wizard-agent.js.map +0 -1
  265. package/dist/src/telemetry.js.map +0 -1
  266. package/dist/src/utils/analytics.js.map +0 -1
  267. package/dist/src/utils/bash.js.map +0 -1
  268. package/dist/src/utils/clack-utils.js.map +0 -1
  269. package/dist/src/utils/clack.js.map +0 -1
  270. package/dist/src/utils/cli-symbols.js.map +0 -1
  271. package/dist/src/utils/debug.js.map +0 -1
  272. package/dist/src/utils/env-parser.js.map +0 -1
  273. package/dist/src/utils/environment.d.ts +0 -4
  274. package/dist/src/utils/environment.js.map +0 -1
  275. package/dist/src/utils/errors.js.map +0 -1
  276. package/dist/src/utils/git-utils.js.map +0 -1
  277. package/dist/src/utils/logging.js.map +0 -1
  278. package/dist/src/utils/package-json.js.map +0 -1
  279. package/dist/src/utils/package-manager.js.map +0 -1
  280. package/dist/src/utils/redact.js.map +0 -1
  281. package/dist/src/utils/semver.js.map +0 -1
  282. package/dist/src/utils/string.js.map +0 -1
  283. package/dist/src/utils/telemetry-client.js.map +0 -1
  284. package/dist/src/utils/telemetry-types.js +0 -6
  285. package/dist/src/utils/telemetry-types.js.map +0 -1
  286. package/dist/src/utils/urls.js.map +0 -1
  287. package/dist/src/utils/vendor/is-unicorn-supported.js.map +0 -1
  288. package/dist/src/vanilla-js/vanilla-js-wizard-agent.d.ts +0 -2
  289. package/dist/src/vanilla-js/vanilla-js-wizard-agent.js.map +0 -1
  290. /package/dist/{src/commands → commands}/install-skill.d.ts +0 -0
  291. /package/dist/{src/commands → commands}/install-skill.js +0 -0
  292. /package/dist/{src/commands → commands}/install.d.ts +0 -0
  293. /package/dist/{src/commands → commands}/login.d.ts +0 -0
  294. /package/dist/{src/commands → commands}/logout.d.ts +0 -0
  295. /package/dist/{src/commands → commands}/logout.js +0 -0
  296. /package/dist/{src/dashboard → dashboard}/components/AnimatedLogo.d.ts +0 -0
  297. /package/dist/{src/dashboard → dashboard}/components/AnimatedLogo.js +0 -0
  298. /package/dist/{src/dashboard → dashboard}/components/CompletionView.d.ts +0 -0
  299. /package/dist/{src/dashboard → dashboard}/components/CompletionView.js +0 -0
  300. /package/dist/{src/dashboard → dashboard}/components/ConfirmPrompt.d.ts +0 -0
  301. /package/dist/{src/dashboard → dashboard}/components/ConfirmPrompt.js +0 -0
  302. /package/dist/{src/dashboard → dashboard}/components/CredentialsForm.d.ts +0 -0
  303. /package/dist/{src/dashboard → dashboard}/components/CredentialsForm.js +0 -0
  304. /package/dist/{src/dashboard → dashboard}/components/Dashboard.d.ts +0 -0
  305. /package/dist/{src/dashboard → dashboard}/components/Dashboard.js +0 -0
  306. /package/dist/{src/dashboard → dashboard}/components/DashboardLayout.js +0 -0
  307. /package/dist/{src/dashboard → dashboard}/components/DiffPanel.js +0 -0
  308. /package/dist/{src/dashboard → dashboard}/components/InlinePrompt.d.ts +0 -0
  309. /package/dist/{src/dashboard → dashboard}/components/InlinePrompt.js +0 -0
  310. /package/dist/{src/dashboard → dashboard}/components/OutputPanel.js +0 -0
  311. /package/dist/{src/dashboard → dashboard}/components/Panel.d.ts +0 -0
  312. /package/dist/{src/dashboard → dashboard}/components/Panel.js +0 -0
  313. /package/dist/{src/dashboard → dashboard}/components/TextInput.d.ts +0 -0
  314. /package/dist/{src/dashboard → dashboard}/components/TextInput.js +0 -0
  315. /package/dist/{src/dashboard → dashboard}/components/WelcomeArt.d.ts +0 -0
  316. /package/dist/{src/dashboard → dashboard}/components/WelcomeArt.js +0 -0
  317. /package/dist/{src/dashboard → dashboard}/hooks/useAnimation.d.ts +0 -0
  318. /package/dist/{src/dashboard → dashboard}/hooks/useAnimation.js +0 -0
  319. /package/dist/{src/dashboard → dashboard}/hooks/useKeyboard.d.ts +0 -0
  320. /package/dist/{src/dashboard → dashboard}/hooks/useKeyboard.js +0 -0
  321. /package/dist/{src/dashboard → dashboard}/hooks/useTerminalSize.d.ts +0 -0
  322. /package/dist/{src/dashboard → dashboard}/hooks/useTerminalSize.js +0 -0
  323. /package/dist/{src/dashboard → dashboard}/index.js +0 -0
  324. /package/dist/{src/dashboard → dashboard}/lib/diff-utils.d.ts +0 -0
  325. /package/dist/{src/dashboard → dashboard}/lib/diff-utils.js +0 -0
  326. /package/dist/{src/dashboard → dashboard}/lib/logo-frames.d.ts +0 -0
  327. /package/dist/{src/dashboard → dashboard}/lib/logo-frames.js +0 -0
  328. /package/dist/{src/dashboard → dashboard}/lib/welcome-art.d.ts +0 -0
  329. /package/dist/{src/dashboard → dashboard}/lib/welcome-art.js +0 -0
  330. /package/dist/{src/dashboard → dashboard}/types.js +0 -0
  331. /package/dist/{src/lib → lib}/adapters/dashboard-adapter.js +0 -0
  332. /package/dist/{src/lib → lib}/adapters/index.js +0 -0
  333. /package/dist/{src/lib → lib}/adapters/types.js +0 -0
  334. /package/dist/{src/lib → lib}/api.d.ts +0 -0
  335. /package/dist/{src/lib → lib}/api.js +0 -0
  336. /package/dist/{src/lib → lib}/config.js +0 -0
  337. /package/dist/{src/lib → lib}/credential-discovery.d.ts +0 -0
  338. /package/dist/{src/lib → lib}/credential-discovery.js +0 -0
  339. /package/dist/{src/lib → lib}/env-writer.d.ts +0 -0
  340. /package/dist/{src/lib → lib}/env-writer.js +0 -0
  341. /package/dist/{src/lib → lib}/helper-functions.d.ts +0 -0
  342. /package/dist/{src/lib → lib}/helper-functions.js +0 -0
  343. /package/dist/{src/lib → lib}/port-detection.d.ts +0 -0
  344. /package/dist/{src/lib → lib}/port-detection.js +0 -0
  345. /package/dist/{src/lib → lib}/post-install.d.ts +0 -0
  346. /package/dist/{src/lib → lib}/post-install.js +0 -0
  347. /package/dist/{src/lib → lib}/progress-tracker.d.ts +0 -0
  348. /package/dist/{src/lib → lib}/progress-tracker.js +0 -0
  349. /package/dist/{src/lib → lib}/safe-tools.d.ts +0 -0
  350. /package/dist/{src/lib → lib}/safe-tools.js +0 -0
  351. /package/dist/{src/lib → lib}/staging-api.d.ts +0 -0
  352. /package/dist/{src/lib → lib}/staging-api.js +0 -0
  353. /package/dist/{src/lib → lib}/token-refresh.d.ts +0 -0
  354. /package/dist/{src/lib → lib}/validation/build-validator.d.ts +0 -0
  355. /package/dist/{src/lib → lib}/validation/build-validator.js +0 -0
  356. /package/dist/{src/lib → lib}/validation/index.d.ts +0 -0
  357. /package/dist/{src/lib → lib}/validation/index.js +0 -0
  358. /package/dist/{src/lib → lib}/validation/types.d.ts +0 -0
  359. /package/dist/{src/lib → lib}/validation/types.js +0 -0
  360. /package/dist/{src/lib → lib}/validation/validator.d.ts +0 -0
  361. /package/dist/{src/lib → lib}/validation/validator.js +0 -0
  362. /package/dist/{src/lib → lib}/workos-management.d.ts +0 -0
  363. /package/dist/{src/nextjs → nextjs}/utils.js +0 -0
  364. /package/dist/{src/react-router → react-router}/utils.js +0 -0
  365. /package/dist/{src/steps → steps}/add-or-update-environment-variables.d.ts +0 -0
  366. /package/dist/{src/steps → steps}/index.d.ts +0 -0
  367. /package/dist/{src/steps → steps}/index.js +0 -0
  368. /package/dist/{src/steps → steps}/upload-environment-variables/EnvironmentProvider.js +0 -0
  369. /package/dist/{src/steps → steps}/upload-environment-variables/providers/vercel.js +0 -0
  370. /package/dist/{src/telemetry.d.ts → telemetry.d.ts} +0 -0
  371. /package/dist/{src/telemetry.js → telemetry.js} +0 -0
  372. /package/dist/{src/utils → utils}/analytics.d.ts +0 -0
  373. /package/dist/{src/utils → utils}/bash.d.ts +0 -0
  374. /package/dist/{src/utils → utils}/bash.js +0 -0
  375. /package/dist/{src/utils → utils}/clack.d.ts +0 -0
  376. /package/dist/{src/utils → utils}/clack.js +0 -0
  377. /package/dist/{src/utils → utils}/cli-symbols.d.ts +0 -0
  378. /package/dist/{src/utils → utils}/cli-symbols.js +0 -0
  379. /package/dist/{src/utils → utils}/debug.d.ts +0 -0
  380. /package/dist/{src/utils → utils}/env-parser.d.ts +0 -0
  381. /package/dist/{src/utils → utils}/env-parser.js +0 -0
  382. /package/dist/{src/utils → utils}/errors.d.ts +0 -0
  383. /package/dist/{src/utils → utils}/git-utils.d.ts +0 -0
  384. /package/dist/{src/utils → utils}/git-utils.js +0 -0
  385. /package/dist/{src/utils → utils}/logging.d.ts +0 -0
  386. /package/dist/{src/utils → utils}/logging.js +0 -0
  387. /package/dist/{src/utils → utils}/package-json.d.ts +0 -0
  388. /package/dist/{src/utils → utils}/package-json.js +0 -0
  389. /package/dist/{src/utils → utils}/package-manager.js +0 -0
  390. /package/dist/{src/utils → utils}/redact.d.ts +0 -0
  391. /package/dist/{src/utils → utils}/redact.js +0 -0
  392. /package/dist/{src/utils → utils}/semver.d.ts +0 -0
  393. /package/dist/{src/utils → utils}/semver.js +0 -0
  394. /package/dist/{src/utils → utils}/string.d.ts +0 -0
  395. /package/dist/{src/utils → utils}/string.js +0 -0
  396. /package/dist/{src/utils → utils}/telemetry-client.d.ts +0 -0
  397. /package/dist/{src/utils → utils}/types.js +0 -0
  398. /package/dist/{src/utils → utils}/urls.d.ts +0 -0
  399. /package/dist/{src/utils → utils}/urls.js +0 -0
  400. /package/dist/{src/utils → utils}/vendor/is-unicorn-supported.d.ts +0 -0
  401. /package/dist/{src/utils → utils}/vendor/is-unicorn-supported.js +0 -0
@@ -0,0 +1,298 @@
1
+ /**
2
+ * Lightweight HTTP proxy that injects credentials from file into requests.
3
+ * Includes lazy token refresh - refreshes proactively when token is expiring soon.
4
+ */
5
+ import http from 'node:http';
6
+ import https from 'node:https';
7
+ import { URL } from 'node:url';
8
+ import { logInfo, logError, logWarn } from '../utils/debug.js';
9
+ import { getCredentials, updateTokens } from './credentials.js';
10
+ import { analytics } from '../utils/analytics.js';
11
+ import { refreshAccessToken } from './token-refresh-client.js';
12
+ // Module-level state for lazy refresh
13
+ let refreshPromise = null;
14
+ let refreshConfig = null;
15
+ let consecutiveFailures = 0;
16
+ const MAX_CONSECUTIVE_FAILURES = 3;
17
+ /**
18
+ * Check if token needs refresh (expires within threshold).
19
+ */
20
+ function tokenNeedsRefresh(expiresAt, thresholdMs) {
21
+ return Date.now() + thresholdMs >= expiresAt;
22
+ }
23
+ /**
24
+ * Perform token refresh, updating credentials file.
25
+ * Returns true if refresh succeeded.
26
+ */
27
+ async function doRefresh() {
28
+ if (!refreshConfig) {
29
+ logError('[credential-proxy] No refresh config available');
30
+ return false;
31
+ }
32
+ const { authkitDomain, clientId, onRefreshSuccess, onRefreshExpired } = refreshConfig;
33
+ const startTime = Date.now();
34
+ logInfo('[credential-proxy] Starting token refresh...');
35
+ analytics.capture('installer.token.refresh', {
36
+ action: 'refresh_attempt',
37
+ trigger: 'lazy',
38
+ });
39
+ const result = await refreshAccessToken(authkitDomain, clientId);
40
+ if (result.success && result.accessToken && result.expiresAt) {
41
+ // Update credentials file atomically
42
+ updateTokens(result.accessToken, result.expiresAt, result.refreshToken);
43
+ consecutiveFailures = 0;
44
+ const durationMs = Date.now() - startTime;
45
+ logInfo(`[credential-proxy] Token refreshed in ${durationMs}ms, expires: ${new Date(result.expiresAt).toISOString()}`);
46
+ analytics.capture('installer.token.refresh', {
47
+ action: 'refresh_success',
48
+ duration_ms: durationMs,
49
+ token_rotated: !!result.refreshToken,
50
+ });
51
+ onRefreshSuccess?.();
52
+ return true;
53
+ }
54
+ consecutiveFailures++;
55
+ logError(`[credential-proxy] Refresh failed: ${result.error}`);
56
+ analytics.capture('installer.token.refresh', {
57
+ action: 'refresh_failure',
58
+ error_type: result.errorType || 'unknown',
59
+ error_message: result.error || 'Unknown error',
60
+ consecutive_failures: consecutiveFailures,
61
+ });
62
+ // Handle permanent failure
63
+ if (result.errorType === 'invalid_grant' || consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
64
+ logError('[credential-proxy] Refresh token expired or too many failures');
65
+ onRefreshExpired?.();
66
+ }
67
+ return false;
68
+ }
69
+ /**
70
+ * Ensure we have valid credentials, refreshing if needed.
71
+ * Uses a promise-based lock to prevent concurrent refreshes.
72
+ *
73
+ * @returns Credentials to use for request, or null if unavailable
74
+ */
75
+ async function ensureValidCredentials(thresholdMs) {
76
+ const creds = getCredentials();
77
+ if (!creds?.accessToken) {
78
+ return null;
79
+ }
80
+ // No refresh token = can't refresh, just use what we have
81
+ if (!creds.refreshToken || !refreshConfig) {
82
+ return creds;
83
+ }
84
+ const timeUntilExpiry = creds.expiresAt - Date.now();
85
+ if (timeUntilExpiry <= 0) {
86
+ // Token expired - must wait for refresh
87
+ logWarn('[credential-proxy] Token expired, waiting for refresh...');
88
+ if (!refreshPromise) {
89
+ refreshPromise = doRefresh()
90
+ .then(() => { })
91
+ .finally(() => {
92
+ refreshPromise = null;
93
+ });
94
+ }
95
+ await refreshPromise;
96
+ return getCredentials(); // Return fresh credentials
97
+ }
98
+ if (timeUntilExpiry < thresholdMs) {
99
+ // Token expiring soon - trigger background refresh, but use current token
100
+ logInfo(`[credential-proxy] Token expires in ${Math.round(timeUntilExpiry / 1000)}s, triggering refresh`);
101
+ if (!refreshPromise) {
102
+ refreshPromise = doRefresh()
103
+ .then(() => { })
104
+ .finally(() => {
105
+ refreshPromise = null;
106
+ });
107
+ }
108
+ // Don't await - fire and forget, use current (still valid) token
109
+ }
110
+ return creds;
111
+ }
112
+ /**
113
+ * Start the credential injector proxy with optional lazy refresh.
114
+ */
115
+ export async function startCredentialProxy(options) {
116
+ const upstream = new URL(options.upstreamUrl);
117
+ const useHttps = upstream.protocol === 'https:';
118
+ const thresholdMs = options.refresh?.refreshThresholdMs ?? 60_000;
119
+ // Store refresh config for lazy refresh
120
+ refreshConfig = options.refresh ?? null;
121
+ consecutiveFailures = 0;
122
+ const server = http.createServer(async (req, res) => {
123
+ await handleRequest(req, res, upstream, useHttps, thresholdMs);
124
+ });
125
+ // Find available port
126
+ const port = await new Promise((resolve, reject) => {
127
+ const tryPort = options.port ?? 0; // 0 = random available port
128
+ let attempts = 0;
129
+ const maxAttempts = 10;
130
+ const tryListen = (p) => {
131
+ server.once('error', (err) => {
132
+ if (err.code === 'EADDRINUSE' && attempts < maxAttempts) {
133
+ attempts++;
134
+ tryListen(0); // Try random port
135
+ }
136
+ else {
137
+ reject(err);
138
+ }
139
+ });
140
+ server.listen(p, '127.0.0.1', () => {
141
+ const addr = server.address();
142
+ if (addr && typeof addr === 'object') {
143
+ resolve(addr.port);
144
+ }
145
+ else {
146
+ reject(new Error('Failed to get server address'));
147
+ }
148
+ });
149
+ };
150
+ tryListen(tryPort);
151
+ });
152
+ const url = `http://127.0.0.1:${port}`;
153
+ logInfo(`[credential-proxy] Started on ${url}, forwarding to ${options.upstreamUrl}`);
154
+ if (refreshConfig) {
155
+ logInfo(`[credential-proxy] Lazy refresh enabled, threshold: ${thresholdMs}ms`);
156
+ }
157
+ // Telemetry for proxy start
158
+ analytics.capture('installer.proxy', {
159
+ action: 'start',
160
+ port,
161
+ refresh_enabled: !!refreshConfig,
162
+ });
163
+ return {
164
+ port,
165
+ url,
166
+ stop: async () => {
167
+ // Clear refresh state
168
+ refreshConfig = null;
169
+ refreshPromise = null;
170
+ consecutiveFailures = 0;
171
+ await stopServer(server);
172
+ },
173
+ };
174
+ }
175
+ async function handleRequest(req, res, upstream, useHttps, thresholdMs) {
176
+ // Get valid credentials, potentially triggering refresh
177
+ const creds = await ensureValidCredentials(thresholdMs);
178
+ if (!creds?.accessToken) {
179
+ logError('[credential-proxy] No credentials available');
180
+ res.writeHead(401, { 'Content-Type': 'application/json' });
181
+ res.end(JSON.stringify({
182
+ error: 'credentials_unavailable',
183
+ message: 'Not authenticated. Run `workos login` first.',
184
+ }));
185
+ return;
186
+ }
187
+ // Build upstream request options
188
+ // Concatenate paths properly - URL() would replace the base path with absolute paths
189
+ const requestPath = req.url || '/';
190
+ const basePath = upstream.pathname.replace(/\/$/, ''); // Remove trailing slash
191
+ const fullPath = basePath + requestPath;
192
+ const upstreamUrl = new URL(fullPath, upstream.origin);
193
+ const headers = {};
194
+ // Copy headers, excluding hop-by-hop headers
195
+ const hopByHop = new Set([
196
+ 'connection',
197
+ 'keep-alive',
198
+ 'proxy-authenticate',
199
+ 'proxy-authorization',
200
+ 'te',
201
+ 'trailer',
202
+ 'transfer-encoding',
203
+ 'upgrade',
204
+ ]);
205
+ for (const [key, value] of Object.entries(req.headers)) {
206
+ if (!hopByHop.has(key.toLowerCase()) && value !== undefined) {
207
+ headers[key] = value;
208
+ }
209
+ }
210
+ // Inject credentials
211
+ headers['authorization'] = `Bearer ${creds.accessToken}`;
212
+ headers['host'] = upstream.host;
213
+ // Strip beta=true query param - WorkOS LLM gateway doesn't support it
214
+ const searchParams = new URLSearchParams(upstreamUrl.search);
215
+ searchParams.delete('beta');
216
+ const queryString = searchParams.toString();
217
+ const finalPath = upstreamUrl.pathname + (queryString ? `?${queryString}` : '');
218
+ const requestOptions = {
219
+ hostname: upstream.hostname,
220
+ port: upstream.port || (useHttps ? 443 : 80),
221
+ path: finalPath,
222
+ method: req.method,
223
+ headers,
224
+ timeout: 120_000, // 2 minute timeout
225
+ };
226
+ const transport = useHttps ? https : http;
227
+ const proxyReq = transport.request(requestOptions, (proxyRes) => {
228
+ // Copy response headers
229
+ const responseHeaders = {};
230
+ for (const [key, value] of Object.entries(proxyRes.headers)) {
231
+ if (!hopByHop.has(key.toLowerCase()) && value !== undefined) {
232
+ responseHeaders[key] = value;
233
+ }
234
+ }
235
+ res.writeHead(proxyRes.statusCode || 500, responseHeaders);
236
+ proxyRes.pipe(res);
237
+ });
238
+ proxyReq.on('error', (err) => {
239
+ logError('[credential-proxy] Upstream error:', err.message);
240
+ if (!res.headersSent) {
241
+ if (err.code === 'ECONNREFUSED') {
242
+ res.writeHead(502, { 'Content-Type': 'application/json' });
243
+ res.end(JSON.stringify({
244
+ error: 'upstream_unavailable',
245
+ message: 'Could not connect to upstream server',
246
+ }));
247
+ }
248
+ else if (err.code === 'ETIMEDOUT') {
249
+ res.writeHead(504, { 'Content-Type': 'application/json' });
250
+ res.end(JSON.stringify({
251
+ error: 'upstream_timeout',
252
+ message: 'Upstream server timed out',
253
+ }));
254
+ }
255
+ else {
256
+ res.writeHead(502, { 'Content-Type': 'application/json' });
257
+ res.end(JSON.stringify({
258
+ error: 'proxy_error',
259
+ message: err.message,
260
+ }));
261
+ }
262
+ }
263
+ });
264
+ proxyReq.on('timeout', () => {
265
+ proxyReq.destroy();
266
+ if (!res.headersSent) {
267
+ res.writeHead(504, { 'Content-Type': 'application/json' });
268
+ res.end(JSON.stringify({
269
+ error: 'upstream_timeout',
270
+ message: 'Upstream server timed out',
271
+ }));
272
+ }
273
+ });
274
+ // Stream request body
275
+ req.pipe(proxyReq);
276
+ }
277
+ function stopServer(server) {
278
+ return new Promise((resolve, reject) => {
279
+ // Set a timeout for graceful shutdown
280
+ const timeout = setTimeout(() => {
281
+ logInfo('[credential-proxy] Force closing after timeout');
282
+ server.closeAllConnections?.();
283
+ resolve();
284
+ }, 5000);
285
+ server.close((err) => {
286
+ clearTimeout(timeout);
287
+ if (err) {
288
+ logError('[credential-proxy] Error stopping server:', err);
289
+ reject(err);
290
+ }
291
+ else {
292
+ logInfo('[credential-proxy] Stopped');
293
+ resolve();
294
+ }
295
+ });
296
+ });
297
+ }
298
+ //# sourceMappingURL=credential-proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-proxy.js","sourceRoot":"","sources":["../../src/lib/credential-proxy.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Lightweight HTTP proxy that injects credentials from file into requests.\n * Includes lazy token refresh - refreshes proactively when token is expiring soon.\n */\n\nimport http from 'node:http';\nimport https from 'node:https';\nimport { URL } from 'node:url';\nimport { logInfo, logError, logWarn } from '../utils/debug.js';\nimport { getCredentials, updateTokens, type Credentials } from './credentials.js';\nimport { analytics } from '../utils/analytics.js';\nimport { refreshAccessToken } from './token-refresh-client.js';\n\nexport interface RefreshConfig {\n /** AuthKit domain for refresh endpoint */\n authkitDomain: string;\n /** OAuth client ID */\n clientId: string;\n /** Threshold in ms - refresh when token expires within this window (default: 60000 = 1 min) */\n refreshThresholdMs?: number;\n /** Callback when refresh succeeds */\n onRefreshSuccess?: () => void;\n /** Callback when refresh fails permanently (token expired, invalid_grant) */\n onRefreshExpired?: () => void;\n}\n\nexport interface CredentialProxyOptions {\n /** Upstream URL to forward requests to */\n upstreamUrl: string;\n /** Optional: specific port to bind (default: random) */\n port?: number;\n /** Optional: refresh configuration for lazy token refresh */\n refresh?: RefreshConfig;\n}\n\nexport interface CredentialProxyHandle {\n /** Port the proxy is listening on */\n port: number;\n /** Full URL for the proxy (e.g., http://localhost:54321) */\n url: string;\n /** Stop the proxy server */\n stop: () => Promise<void>;\n}\n\n// Module-level state for lazy refresh\nlet refreshPromise: Promise<void> | null = null;\nlet refreshConfig: RefreshConfig | null = null;\nlet consecutiveFailures = 0;\nconst MAX_CONSECUTIVE_FAILURES = 3;\n\n/**\n * Check if token needs refresh (expires within threshold).\n */\nfunction tokenNeedsRefresh(expiresAt: number, thresholdMs: number): boolean {\n return Date.now() + thresholdMs >= expiresAt;\n}\n\n/**\n * Perform token refresh, updating credentials file.\n * Returns true if refresh succeeded.\n */\nasync function doRefresh(): Promise<boolean> {\n if (!refreshConfig) {\n logError('[credential-proxy] No refresh config available');\n return false;\n }\n\n const { authkitDomain, clientId, onRefreshSuccess, onRefreshExpired } = refreshConfig;\n const startTime = Date.now();\n\n logInfo('[credential-proxy] Starting token refresh...');\n\n analytics.capture('installer.token.refresh', {\n action: 'refresh_attempt',\n trigger: 'lazy',\n });\n\n const result = await refreshAccessToken(authkitDomain, clientId);\n\n if (result.success && result.accessToken && result.expiresAt) {\n // Update credentials file atomically\n updateTokens(result.accessToken, result.expiresAt, result.refreshToken);\n\n consecutiveFailures = 0;\n const durationMs = Date.now() - startTime;\n\n logInfo(\n `[credential-proxy] Token refreshed in ${durationMs}ms, expires: ${new Date(result.expiresAt).toISOString()}`,\n );\n\n analytics.capture('installer.token.refresh', {\n action: 'refresh_success',\n duration_ms: durationMs,\n token_rotated: !!result.refreshToken,\n });\n\n onRefreshSuccess?.();\n return true;\n }\n\n consecutiveFailures++;\n\n logError(`[credential-proxy] Refresh failed: ${result.error}`);\n\n analytics.capture('installer.token.refresh', {\n action: 'refresh_failure',\n error_type: result.errorType || 'unknown',\n error_message: result.error || 'Unknown error',\n consecutive_failures: consecutiveFailures,\n });\n\n // Handle permanent failure\n if (result.errorType === 'invalid_grant' || consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {\n logError('[credential-proxy] Refresh token expired or too many failures');\n onRefreshExpired?.();\n }\n\n return false;\n}\n\n/**\n * Ensure we have valid credentials, refreshing if needed.\n * Uses a promise-based lock to prevent concurrent refreshes.\n *\n * @returns Credentials to use for request, or null if unavailable\n */\nasync function ensureValidCredentials(thresholdMs: number): Promise<Credentials | null> {\n const creds = getCredentials();\n\n if (!creds?.accessToken) {\n return null;\n }\n\n // No refresh token = can't refresh, just use what we have\n if (!creds.refreshToken || !refreshConfig) {\n return creds;\n }\n\n const timeUntilExpiry = creds.expiresAt - Date.now();\n\n if (timeUntilExpiry <= 0) {\n // Token expired - must wait for refresh\n logWarn('[credential-proxy] Token expired, waiting for refresh...');\n\n if (!refreshPromise) {\n refreshPromise = doRefresh()\n .then(() => {})\n .finally(() => {\n refreshPromise = null;\n });\n }\n\n await refreshPromise;\n return getCredentials(); // Return fresh credentials\n }\n\n if (timeUntilExpiry < thresholdMs) {\n // Token expiring soon - trigger background refresh, but use current token\n logInfo(`[credential-proxy] Token expires in ${Math.round(timeUntilExpiry / 1000)}s, triggering refresh`);\n\n if (!refreshPromise) {\n refreshPromise = doRefresh()\n .then(() => {})\n .finally(() => {\n refreshPromise = null;\n });\n }\n // Don't await - fire and forget, use current (still valid) token\n }\n\n return creds;\n}\n\n/**\n * Start the credential injector proxy with optional lazy refresh.\n */\nexport async function startCredentialProxy(options: CredentialProxyOptions): Promise<CredentialProxyHandle> {\n const upstream = new URL(options.upstreamUrl);\n const useHttps = upstream.protocol === 'https:';\n const thresholdMs = options.refresh?.refreshThresholdMs ?? 60_000;\n\n // Store refresh config for lazy refresh\n refreshConfig = options.refresh ?? null;\n consecutiveFailures = 0;\n\n const server = http.createServer(async (req, res) => {\n await handleRequest(req, res, upstream, useHttps, thresholdMs);\n });\n\n // Find available port\n const port = await new Promise<number>((resolve, reject) => {\n const tryPort = options.port ?? 0; // 0 = random available port\n let attempts = 0;\n const maxAttempts = 10;\n\n const tryListen = (p: number) => {\n server.once('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE' && attempts < maxAttempts) {\n attempts++;\n tryListen(0); // Try random port\n } else {\n reject(err);\n }\n });\n\n server.listen(p, '127.0.0.1', () => {\n const addr = server.address();\n if (addr && typeof addr === 'object') {\n resolve(addr.port);\n } else {\n reject(new Error('Failed to get server address'));\n }\n });\n };\n\n tryListen(tryPort);\n });\n\n const url = `http://127.0.0.1:${port}`;\n logInfo(`[credential-proxy] Started on ${url}, forwarding to ${options.upstreamUrl}`);\n if (refreshConfig) {\n logInfo(`[credential-proxy] Lazy refresh enabled, threshold: ${thresholdMs}ms`);\n }\n\n // Telemetry for proxy start\n analytics.capture('installer.proxy', {\n action: 'start',\n port,\n refresh_enabled: !!refreshConfig,\n });\n\n return {\n port,\n url,\n stop: async () => {\n // Clear refresh state\n refreshConfig = null;\n refreshPromise = null;\n consecutiveFailures = 0;\n await stopServer(server);\n },\n };\n}\n\nasync function handleRequest(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n upstream: URL,\n useHttps: boolean,\n thresholdMs: number,\n): Promise<void> {\n // Get valid credentials, potentially triggering refresh\n const creds = await ensureValidCredentials(thresholdMs);\n\n if (!creds?.accessToken) {\n logError('[credential-proxy] No credentials available');\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: 'credentials_unavailable',\n message: 'Not authenticated. Run `workos login` first.',\n }),\n );\n return;\n }\n\n // Build upstream request options\n // Concatenate paths properly - URL() would replace the base path with absolute paths\n const requestPath = req.url || '/';\n const basePath = upstream.pathname.replace(/\\/$/, ''); // Remove trailing slash\n const fullPath = basePath + requestPath;\n const upstreamUrl = new URL(fullPath, upstream.origin);\n\n const headers: http.OutgoingHttpHeaders = {};\n\n // Copy headers, excluding hop-by-hop headers\n const hopByHop = new Set([\n 'connection',\n 'keep-alive',\n 'proxy-authenticate',\n 'proxy-authorization',\n 'te',\n 'trailer',\n 'transfer-encoding',\n 'upgrade',\n ]);\n\n for (const [key, value] of Object.entries(req.headers)) {\n if (!hopByHop.has(key.toLowerCase()) && value !== undefined) {\n headers[key] = value;\n }\n }\n\n // Inject credentials\n headers['authorization'] = `Bearer ${creds.accessToken}`;\n headers['host'] = upstream.host;\n\n // Strip beta=true query param - WorkOS LLM gateway doesn't support it\n const searchParams = new URLSearchParams(upstreamUrl.search);\n searchParams.delete('beta');\n const queryString = searchParams.toString();\n const finalPath = upstreamUrl.pathname + (queryString ? `?${queryString}` : '');\n\n const requestOptions: http.RequestOptions = {\n hostname: upstream.hostname,\n port: upstream.port || (useHttps ? 443 : 80),\n path: finalPath,\n method: req.method,\n headers,\n timeout: 120_000, // 2 minute timeout\n };\n\n const transport = useHttps ? https : http;\n\n const proxyReq = transport.request(requestOptions, (proxyRes) => {\n // Copy response headers\n const responseHeaders: http.OutgoingHttpHeaders = {};\n for (const [key, value] of Object.entries(proxyRes.headers)) {\n if (!hopByHop.has(key.toLowerCase()) && value !== undefined) {\n responseHeaders[key] = value;\n }\n }\n\n res.writeHead(proxyRes.statusCode || 500, responseHeaders);\n proxyRes.pipe(res);\n });\n\n proxyReq.on('error', (err) => {\n logError('[credential-proxy] Upstream error:', err.message);\n\n if (!res.headersSent) {\n if ((err as NodeJS.ErrnoException).code === 'ECONNREFUSED') {\n res.writeHead(502, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: 'upstream_unavailable',\n message: 'Could not connect to upstream server',\n }),\n );\n } else if ((err as NodeJS.ErrnoException).code === 'ETIMEDOUT') {\n res.writeHead(504, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: 'upstream_timeout',\n message: 'Upstream server timed out',\n }),\n );\n } else {\n res.writeHead(502, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: 'proxy_error',\n message: err.message,\n }),\n );\n }\n }\n });\n\n proxyReq.on('timeout', () => {\n proxyReq.destroy();\n if (!res.headersSent) {\n res.writeHead(504, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: 'upstream_timeout',\n message: 'Upstream server timed out',\n }),\n );\n }\n });\n\n // Stream request body\n req.pipe(proxyReq);\n}\n\nfunction stopServer(server: http.Server): Promise<void> {\n return new Promise((resolve, reject) => {\n // Set a timeout for graceful shutdown\n const timeout = setTimeout(() => {\n logInfo('[credential-proxy] Force closing after timeout');\n server.closeAllConnections?.();\n resolve();\n }, 5000);\n\n server.close((err) => {\n clearTimeout(timeout);\n if (err) {\n logError('[credential-proxy] Error stopping server:', err);\n reject(err);\n } else {\n logInfo('[credential-proxy] Stopped');\n resolve();\n }\n });\n });\n}\n"]}
@@ -9,6 +9,7 @@ export interface Credentials {
9
9
  userId: string;
10
10
  email?: string;
11
11
  staging?: StagingCache;
12
+ refreshToken?: string;
12
13
  }
13
14
  export declare function getCredentialsPath(): string;
14
15
  export declare function hasCredentials(): boolean;
@@ -39,3 +40,8 @@ export declare function getStagingCredentials(): {
39
40
  clientId: string;
40
41
  apiKey: string;
41
42
  } | null;
43
+ /**
44
+ * Atomically update tokens in credentials file.
45
+ * Uses write-to-temp + rename pattern for atomic updates.
46
+ */
47
+ export declare function updateTokens(accessToken: string, expiresAt: number, refreshToken?: string): void;
@@ -81,4 +81,37 @@ export function getStagingCredentials() {
81
81
  return null;
82
82
  return { clientId: creds.staging.clientId, apiKey: creds.staging.apiKey };
83
83
  }
84
+ /**
85
+ * Atomically update tokens in credentials file.
86
+ * Uses write-to-temp + rename pattern for atomic updates.
87
+ */
88
+ export function updateTokens(accessToken, expiresAt, refreshToken) {
89
+ const creds = getCredentials();
90
+ if (!creds) {
91
+ throw new Error('No existing credentials to update');
92
+ }
93
+ const updated = {
94
+ ...creds,
95
+ accessToken,
96
+ expiresAt,
97
+ ...(refreshToken && { refreshToken }),
98
+ };
99
+ // Atomic write: temp file + rename
100
+ const credPath = getCredentialsPath();
101
+ const tempPath = `${credPath}.${crypto.randomUUID()}.tmp`;
102
+ try {
103
+ fs.writeFileSync(tempPath, JSON.stringify(updated, null, 2), { mode: 0o600 });
104
+ fs.renameSync(tempPath, credPath);
105
+ }
106
+ catch (error) {
107
+ // Clean up temp file if rename failed
108
+ try {
109
+ fs.unlinkSync(tempPath);
110
+ }
111
+ catch {
112
+ // Ignore cleanup errors
113
+ }
114
+ throw error;
115
+ }
116
+ }
84
117
  //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/lib/credentials.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\n\nexport interface StagingCache {\n clientId: string;\n apiKey: string;\n fetchedAt: number;\n}\n\nexport interface Credentials {\n accessToken: string;\n expiresAt: number;\n userId: string;\n email?: string;\n staging?: StagingCache;\n refreshToken?: string;\n}\n\nfunction getCredentialsDir(): string {\n return path.join(os.homedir(), '.workos');\n}\n\nexport function getCredentialsPath(): string {\n return path.join(getCredentialsDir(), 'credentials.json');\n}\n\nexport function hasCredentials(): boolean {\n return fs.existsSync(getCredentialsPath());\n}\n\nexport function getCredentials(): Credentials | null {\n if (!hasCredentials()) return null;\n try {\n const content = fs.readFileSync(getCredentialsPath(), 'utf-8');\n return JSON.parse(content);\n } catch {\n return null;\n }\n}\n\nexport function saveCredentials(creds: Credentials): void {\n const dir = getCredentialsDir();\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n fs.writeFileSync(getCredentialsPath(), JSON.stringify(creds, null, 2), {\n mode: 0o600,\n });\n}\n\nexport function clearCredentials(): void {\n if (hasCredentials()) {\n fs.unlinkSync(getCredentialsPath());\n }\n}\n\n/**\n * Check if token is actually expired (hard expiry check).\n */\nexport function isTokenExpired(creds: Credentials): boolean {\n return Date.now() >= creds.expiresAt;\n}\n\n/**\n * Get access token if available and not expired.\n */\nexport function getAccessToken(): string | null {\n const creds = getCredentials();\n if (!creds) return null;\n if (isTokenExpired(creds)) return null;\n return creds.accessToken;\n}\n\n/**\n * Save staging credentials to the credential cache.\n * Staging credentials are tied to the access token lifecycle.\n */\nexport function saveStagingCredentials(staging: { clientId: string; apiKey: string }): void {\n const creds = getCredentials();\n if (!creds) return;\n\n saveCredentials({\n ...creds,\n staging: {\n ...staging,\n fetchedAt: Date.now(),\n },\n });\n}\n\n/**\n * Get cached staging credentials if available and access token is still valid.\n * Returns null if no cached credentials or if access token has expired.\n */\nexport function getStagingCredentials(): { clientId: string; apiKey: string } | null {\n const creds = getCredentials();\n if (!creds?.staging) return null;\n // Invalidate staging credentials when access token expires\n if (isTokenExpired(creds)) return null;\n return { clientId: creds.staging.clientId, apiKey: creds.staging.apiKey };\n}\n\n/**\n * Atomically update tokens in credentials file.\n * Uses write-to-temp + rename pattern for atomic updates.\n */\nexport function updateTokens(accessToken: string, expiresAt: number, refreshToken?: string): void {\n const creds = getCredentials();\n if (!creds) {\n throw new Error('No existing credentials to update');\n }\n\n const updated: Credentials = {\n ...creds,\n accessToken,\n expiresAt,\n ...(refreshToken && { refreshToken }),\n };\n\n // Atomic write: temp file + rename\n const credPath = getCredentialsPath();\n const tempPath = `${credPath}.${crypto.randomUUID()}.tmp`;\n\n try {\n fs.writeFileSync(tempPath, JSON.stringify(updated, null, 2), { mode: 0o600 });\n fs.renameSync(tempPath, credPath);\n } catch (error) {\n // Clean up temp file if rename failed\n try {\n fs.unlinkSync(tempPath);\n } catch {\n // Ignore cleanup errors\n }\n throw error;\n }\n}\n"]}
@@ -26,6 +26,7 @@ export interface DeviceAuthResult {
26
26
  expiresAt: number;
27
27
  userId: string;
28
28
  email?: string;
29
+ refreshToken?: string;
29
30
  }
30
31
  export declare class DeviceAuthError extends Error {
31
32
  constructor(message: string);
@@ -12,7 +12,7 @@ export class DeviceAuthError extends Error {
12
12
  }
13
13
  }
14
14
  const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
15
- const DEFAULT_SCOPES = ['openid', 'email', 'staging-environment:credentials:read'];
15
+ const DEFAULT_SCOPES = ['openid', 'email', 'staging-environment:credentials:read', 'offline_access'];
16
16
  function sleep(ms) {
17
17
  return new Promise((resolve) => setTimeout(resolve, ms));
18
18
  }
@@ -132,6 +132,7 @@ function parseTokenResponse(data) {
132
132
  expiresAt: jwtExpiry ?? (data.expires_in ? Date.now() + data.expires_in * 1000 : Date.now() + 15 * 60 * 1000),
133
133
  userId: String(idPayload?.sub ?? 'unknown'),
134
134
  email: idPayload?.email,
135
+ refreshToken: data.refresh_token,
135
136
  };
136
137
  }
137
138
  //# sourceMappingURL=device-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-auth.js","sourceRoot":"","sources":["../../src/lib/device-auth.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Device Authorization Flow\n *\n * Implements OAuth 2.0 Device Authorization Grant (RFC 8628) for CLI authentication.\n * Extracted from login.ts for reuse in wizard credential gathering.\n */\n\nimport { logInfo, logError } from '../utils/debug.js';\n\nexport interface DeviceAuthResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n expires_in: number;\n interval: number;\n}\n\nexport interface DeviceAuthOptions {\n clientId: string;\n authkitDomain: string;\n scopes?: string[];\n timeoutMs?: number;\n onPoll?: () => void;\n onSlowDown?: (newIntervalMs: number) => void;\n}\n\nexport interface DeviceAuthResult {\n accessToken: string;\n idToken: string;\n expiresAt: number;\n userId: string;\n email?: string;\n refreshToken?: string;\n}\n\ninterface TokenResponse {\n access_token: string;\n id_token: string;\n token_type: string;\n expires_in: number;\n refresh_token?: string;\n}\n\ninterface AuthErrorResponse {\n error: string;\n}\n\nexport class DeviceAuthError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'DeviceAuthError';\n }\n}\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\nconst DEFAULT_SCOPES = ['openid', 'email', 'staging-environment:credentials:read', 'offline_access'];\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Parse JWT payload\n */\nfunction parseJwt(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n return JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf-8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Extract expiry time from JWT token\n */\nfunction getJwtExpiry(token: string): number | null {\n const payload = parseJwt(token);\n if (!payload || typeof payload.exp !== 'number') return null;\n return payload.exp * 1000;\n}\n\n/**\n * Request a device code from the OAuth authorization server.\n * Returns the device code, user code, and verification URIs.\n */\nexport async function requestDeviceCode(options: DeviceAuthOptions): Promise<DeviceAuthResponse> {\n const scopes = options.scopes ?? DEFAULT_SCOPES;\n const url = `${options.authkitDomain}/oauth2/device_authorization`;\n\n logInfo('[device-auth] Requesting device code from:', url);\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n client_id: options.clientId,\n scope: scopes.join(' '),\n }),\n });\n\n logInfo('[device-auth] Device code response status:', res.status);\n if (!res.ok) {\n const text = await res.text();\n logError('[device-auth] Device authorization failed:', res.status, text);\n throw new DeviceAuthError(`Device authorization failed: ${res.status} ${text}`);\n }\n\n const data = (await res.json()) as DeviceAuthResponse;\n logInfo('[device-auth] Device code received, user_code:', data.user_code);\n return data;\n}\n\n/**\n * Poll for token after user has authorized in the browser.\n * Handles authorization_pending and slow_down responses per RFC 8628.\n */\nexport async function pollForToken(\n deviceCode: string,\n options: DeviceAuthOptions & { interval: number },\n): Promise<DeviceAuthResult> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const startTime = Date.now();\n let pollInterval = options.interval * 1000;\n const tokenUrl = `${options.authkitDomain}/oauth2/token`;\n\n logInfo('[device-auth] Starting token polling, timeout:', timeoutMs);\n while (Date.now() - startTime < timeoutMs) {\n await sleep(pollInterval);\n options.onPoll?.();\n\n let res: Response;\n try {\n res = await fetch(tokenUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceCode,\n client_id: options.clientId,\n }),\n });\n } catch (err) {\n logInfo('[device-auth] Token poll network error, retrying');\n continue;\n }\n\n let data;\n try {\n data = await res.json();\n } catch {\n logError('[device-auth] Invalid JSON response from auth server');\n throw new DeviceAuthError('Invalid response from auth server');\n }\n\n logInfo('[device-auth] Token poll response:', res.status, (data as AuthErrorResponse)?.error ?? 'success');\n if (res.ok) {\n logInfo('[device-auth] Token received successfully');\n return parseTokenResponse(data as TokenResponse);\n }\n\n const errorData = data as AuthErrorResponse;\n\n if (errorData.error === 'authorization_pending') {\n continue;\n }\n\n if (errorData.error === 'slow_down') {\n pollInterval += 5000;\n logInfo('[device-auth] Slowing down, new interval:', pollInterval);\n options.onSlowDown?.(pollInterval);\n continue;\n }\n\n logError('[device-auth] Token error:', errorData.error);\n throw new DeviceAuthError(`Token error: ${errorData.error}`);\n }\n\n logError('[device-auth] Authentication timed out');\n throw new DeviceAuthError('Authentication timed out after 5 minutes');\n}\n\nfunction parseTokenResponse(data: TokenResponse): DeviceAuthResult {\n const idPayload = parseJwt(data.id_token);\n const jwtExpiry = getJwtExpiry(data.access_token);\n\n return {\n accessToken: data.access_token,\n idToken: data.id_token,\n expiresAt: jwtExpiry ?? (data.expires_in ? Date.now() + data.expires_in * 1000 : Date.now() + 15 * 60 * 1000),\n userId: String(idPayload?.sub ?? 'unknown'),\n email: idPayload?.email as string | undefined,\n refreshToken: data.refresh_token,\n };\n}\n"]}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Startup auth guard - ensures valid authentication before command execution.
3
+ */
4
+ export interface EnsureAuthResult {
5
+ /** Whether auth is now valid */
6
+ authenticated: boolean;
7
+ /** Whether login flow was triggered */
8
+ loginTriggered: boolean;
9
+ /** Whether token was refreshed */
10
+ tokenRefreshed: boolean;
11
+ }
12
+ /**
13
+ * Ensure valid authentication before command execution.
14
+ *
15
+ * - No credentials: triggers login flow
16
+ * - Expired access token (valid refresh): silently refreshes
17
+ * - Expired refresh token: triggers login flow
18
+ *
19
+ * @returns Result indicating what actions were taken
20
+ * @throws Error if login fails or refresh fails unexpectedly
21
+ */
22
+ export declare function ensureAuthenticated(): Promise<EnsureAuthResult>;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Startup auth guard - ensures valid authentication before command execution.
3
+ */
4
+ import { getCredentials, updateTokens, hasCredentials, isTokenExpired } from './credentials.js';
5
+ import { refreshAccessToken } from './token-refresh-client.js';
6
+ import { getCliAuthClientId, getAuthkitDomain } from './settings.js';
7
+ import { runLogin } from '../commands/login.js';
8
+ import { logInfo } from '../utils/debug.js';
9
+ /**
10
+ * Ensure valid authentication before command execution.
11
+ *
12
+ * - No credentials: triggers login flow
13
+ * - Expired access token (valid refresh): silently refreshes
14
+ * - Expired refresh token: triggers login flow
15
+ *
16
+ * @returns Result indicating what actions were taken
17
+ * @throws Error if login fails or refresh fails unexpectedly
18
+ */
19
+ export async function ensureAuthenticated() {
20
+ const result = {
21
+ authenticated: false,
22
+ loginTriggered: false,
23
+ tokenRefreshed: false,
24
+ };
25
+ // Case 1: No credentials at all
26
+ if (!hasCredentials()) {
27
+ logInfo('[ensure-auth] No credentials found, triggering login');
28
+ await runLogin();
29
+ result.loginTriggered = true;
30
+ result.authenticated = hasCredentials();
31
+ return result;
32
+ }
33
+ const creds = getCredentials();
34
+ if (!creds) {
35
+ // Credentials file exists but is invalid/empty
36
+ logInfo('[ensure-auth] Invalid credentials file, triggering login');
37
+ await runLogin();
38
+ result.loginTriggered = true;
39
+ result.authenticated = hasCredentials();
40
+ return result;
41
+ }
42
+ // Case 2: Access token still valid
43
+ if (!isTokenExpired(creds)) {
44
+ result.authenticated = true;
45
+ return result;
46
+ }
47
+ // Case 3: Access token expired, try refresh
48
+ if (creds.refreshToken) {
49
+ logInfo('[ensure-auth] Access token expired, attempting refresh');
50
+ const clientId = getCliAuthClientId();
51
+ const authkitDomain = getAuthkitDomain();
52
+ if (clientId && authkitDomain) {
53
+ const refreshResult = await refreshAccessToken(authkitDomain, clientId);
54
+ if (refreshResult.success && refreshResult.accessToken && refreshResult.expiresAt) {
55
+ updateTokens(refreshResult.accessToken, refreshResult.expiresAt, refreshResult.refreshToken);
56
+ result.tokenRefreshed = true;
57
+ result.authenticated = true;
58
+ return result;
59
+ }
60
+ // Refresh failed - check if it's recoverable
61
+ if (refreshResult.errorType === 'invalid_grant') {
62
+ logInfo('[ensure-auth] Refresh token expired, triggering login');
63
+ await runLogin();
64
+ result.loginTriggered = true;
65
+ result.authenticated = hasCredentials();
66
+ return result;
67
+ }
68
+ // Network or server error - try login as fallback
69
+ logInfo(`[ensure-auth] Refresh failed (${refreshResult.errorType}), triggering login`);
70
+ await runLogin();
71
+ result.loginTriggered = true;
72
+ result.authenticated = hasCredentials();
73
+ return result;
74
+ }
75
+ }
76
+ // Case 4: No refresh token available, must login
77
+ logInfo('[ensure-auth] No refresh token, triggering login');
78
+ await runLogin();
79
+ result.loginTriggered = true;
80
+ result.authenticated = hasCredentials();
81
+ return result;
82
+ }
83
+ //# sourceMappingURL=ensure-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensure-auth.js","sourceRoot":"","sources":["../../src/lib/ensure-auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAChG,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAW5C;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,MAAM,GAAqB;QAC/B,aAAa,EAAE,KAAK;QACpB,cAAc,EAAE,KAAK;QACrB,cAAc,EAAE,KAAK;KACtB,CAAC;IAEF,gCAAgC;IAChC,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;QACtB,OAAO,CAAC,sDAAsD,CAAC,CAAC;QAChE,MAAM,QAAQ,EAAE,CAAC;QACjB,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC;QAC7B,MAAM,CAAC,aAAa,GAAG,cAAc,EAAE,CAAC;QACxC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;IAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,+CAA+C;QAC/C,OAAO,CAAC,0DAA0D,CAAC,CAAC;QACpE,MAAM,QAAQ,EAAE,CAAC;QACjB,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC;QAC7B,MAAM,CAAC,aAAa,GAAG,cAAc,EAAE,CAAC;QACxC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,mCAAmC;IACnC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,CAAC,aAAa,GAAG,IAAI,CAAC;QAC5B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,4CAA4C;IAC5C,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;QACvB,OAAO,CAAC,wDAAwD,CAAC,CAAC;QAElE,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAC;QACtC,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAC;QAEzC,IAAI,QAAQ,IAAI,aAAa,EAAE,CAAC;YAC9B,MAAM,aAAa,GAAG,MAAM,kBAAkB,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;YAExE,IAAI,aAAa,CAAC,OAAO,IAAI,aAAa,CAAC,WAAW,IAAI,aAAa,CAAC,SAAS,EAAE,CAAC;gBAClF,YAAY,CAAC,aAAa,CAAC,WAAW,EAAE,aAAa,CAAC,SAAS,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;gBAC7F,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC;gBAC7B,MAAM,CAAC,aAAa,GAAG,IAAI,CAAC;gBAC5B,OAAO,MAAM,CAAC;YAChB,CAAC;YAED,6CAA6C;YAC7C,IAAI,aAAa,CAAC,SAAS,KAAK,eAAe,EAAE,CAAC;gBAChD,OAAO,CAAC,uDAAuD,CAAC,CAAC;gBACjE,MAAM,QAAQ,EAAE,CAAC;gBACjB,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC;gBAC7B,MAAM,CAAC,aAAa,GAAG,cAAc,EAAE,CAAC;gBACxC,OAAO,MAAM,CAAC;YAChB,CAAC;YAED,kDAAkD;YAClD,OAAO,CAAC,iCAAiC,aAAa,CAAC,SAAS,qBAAqB,CAAC,CAAC;YACvF,MAAM,QAAQ,EAAE,CAAC;YACjB,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC;YAC7B,MAAM,CAAC,aAAa,GAAG,cAAc,EAAE,CAAC;YACxC,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,OAAO,CAAC,kDAAkD,CAAC,CAAC;IAC5D,MAAM,QAAQ,EAAE,CAAC;IACjB,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC;IAC7B,MAAM,CAAC,aAAa,GAAG,cAAc,EAAE,CAAC;IACxC,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["/**\n * Startup auth guard - ensures valid authentication before command execution.\n */\n\nimport { getCredentials, updateTokens, hasCredentials, isTokenExpired } from './credentials.js';\nimport { refreshAccessToken } from './token-refresh-client.js';\nimport { getCliAuthClientId, getAuthkitDomain } from './settings.js';\nimport { runLogin } from '../commands/login.js';\nimport { logInfo } from '../utils/debug.js';\n\nexport interface EnsureAuthResult {\n /** Whether auth is now valid */\n authenticated: boolean;\n /** Whether login flow was triggered */\n loginTriggered: boolean;\n /** Whether token was refreshed */\n tokenRefreshed: boolean;\n}\n\n/**\n * Ensure valid authentication before command execution.\n *\n * - No credentials: triggers login flow\n * - Expired access token (valid refresh): silently refreshes\n * - Expired refresh token: triggers login flow\n *\n * @returns Result indicating what actions were taken\n * @throws Error if login fails or refresh fails unexpectedly\n */\nexport async function ensureAuthenticated(): Promise<EnsureAuthResult> {\n const result: EnsureAuthResult = {\n authenticated: false,\n loginTriggered: false,\n tokenRefreshed: false,\n };\n\n // Case 1: No credentials at all\n if (!hasCredentials()) {\n logInfo('[ensure-auth] No credentials found, triggering login');\n await runLogin();\n result.loginTriggered = true;\n result.authenticated = hasCredentials();\n return result;\n }\n\n const creds = getCredentials();\n if (!creds) {\n // Credentials file exists but is invalid/empty\n logInfo('[ensure-auth] Invalid credentials file, triggering login');\n await runLogin();\n result.loginTriggered = true;\n result.authenticated = hasCredentials();\n return result;\n }\n\n // Case 2: Access token still valid\n if (!isTokenExpired(creds)) {\n result.authenticated = true;\n return result;\n }\n\n // Case 3: Access token expired, try refresh\n if (creds.refreshToken) {\n logInfo('[ensure-auth] Access token expired, attempting refresh');\n\n const clientId = getCliAuthClientId();\n const authkitDomain = getAuthkitDomain();\n\n if (clientId && authkitDomain) {\n const refreshResult = await refreshAccessToken(authkitDomain, clientId);\n\n if (refreshResult.success && refreshResult.accessToken && refreshResult.expiresAt) {\n updateTokens(refreshResult.accessToken, refreshResult.expiresAt, refreshResult.refreshToken);\n result.tokenRefreshed = true;\n result.authenticated = true;\n return result;\n }\n\n // Refresh failed - check if it's recoverable\n if (refreshResult.errorType === 'invalid_grant') {\n logInfo('[ensure-auth] Refresh token expired, triggering login');\n await runLogin();\n result.loginTriggered = true;\n result.authenticated = hasCredentials();\n return result;\n }\n\n // Network or server error - try login as fallback\n logInfo(`[ensure-auth] Refresh failed (${refreshResult.errorType}), triggering login`);\n await runLogin();\n result.loginTriggered = true;\n result.authenticated = hasCredentials();\n return result;\n }\n }\n\n // Case 4: No refresh token available, must login\n logInfo('[ensure-auth] No refresh token, triggering login');\n await runLogin();\n result.loginTriggered = true;\n result.authenticated = hasCredentials();\n return result;\n}\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-writer.js","sourceRoot":"","sources":["../../src/lib/env-writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAC7D,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAUtD;;;;GAIG;AACH,SAAS,sBAAsB;IAC7B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IACjC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAC9B,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAClF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,UAAkB,EAAE,OAAyB;IACzE,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAE/C,+BAA+B;IAC/B,IAAI,WAAW,GAA2B,EAAE,CAAC;IAC7C,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC/C,WAAW,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAED,iDAAiD;IACjD,MAAM,MAAM,GAAG,EAAE,GAAG,WAAW,EAAE,GAAG,OAAO,EAAE,CAAC;IAE9C,2CAA2C;IAC3C,IAAI,CAAC,MAAM,CAAC,sBAAsB,EAAE,CAAC;QACnC,MAAM,CAAC,sBAAsB,GAAG,sBAAsB,EAAE,CAAC;IAC3D,CAAC;IAED,aAAa;IACb,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;SACnC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC;SACxC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC,CAAC;AACzC,CAAC","sourcesContent":["import { existsSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { parseEnvFile } from '../utils/env-parser.js';\n\ninterface EnvVars {\n WORKOS_API_KEY?: string;\n WORKOS_CLIENT_ID: string;\n WORKOS_REDIRECT_URI?: string;\n NEXT_PUBLIC_WORKOS_REDIRECT_URI?: string;\n WORKOS_COOKIE_PASSWORD?: string;\n}\n\n/**\n * Generate a cryptographically secure cookie password.\n * Returns 32-char hex string (16 random bytes).\n * Uses Web Crypto API available in Node.js 20+\n */\nfunction generateCookiePassword(): string {\n const array = new Uint8Array(16);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => byte.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Write environment variables to .env.local before agent runs.\n * Merges with existing .env.local if present (new vars take precedence).\n * Auto-generates WORKOS_COOKIE_PASSWORD if not provided.\n */\nexport function writeEnvLocal(installDir: string, envVars: Partial<EnvVars>): void {\n const envPath = join(installDir, '.env.local');\n\n // Read existing env if present\n let existingEnv: Record<string, string> = {};\n if (existsSync(envPath)) {\n const content = readFileSync(envPath, 'utf-8');\n existingEnv = parseEnvFile(content);\n }\n\n // Merge with new vars (new vars take precedence)\n const merged = { ...existingEnv, ...envVars };\n\n // Generate cookie password if not provided\n if (!merged.WORKOS_COOKIE_PASSWORD) {\n merged.WORKOS_COOKIE_PASSWORD = generateCookiePassword();\n }\n\n // Write back\n const content = Object.entries(merged)\n .map(([key, value]) => `${key}=${value}`)\n .join('\\n');\n\n writeFileSync(envPath, content + '\\n');\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { EventEmitter } from 'events';
2
- export interface WizardEvents {
2
+ export interface InstallerEvents {
3
3
  status: {
4
4
  message: string;
5
5
  };
@@ -179,11 +179,11 @@ export interface WizardEvents {
179
179
  instructions: string;
180
180
  };
181
181
  }
182
- export type WizardEventName = keyof WizardEvents;
183
- export declare class WizardEventEmitter extends EventEmitter {
184
- emit<K extends WizardEventName>(event: K, payload: WizardEvents[K]): boolean;
185
- on<K extends WizardEventName>(event: K, listener: (payload: WizardEvents[K]) => void): this;
186
- off<K extends WizardEventName>(event: K, listener: (payload: WizardEvents[K]) => void): this;
187
- once<K extends WizardEventName>(event: K, listener: (payload: WizardEvents[K]) => void): this;
182
+ export type InstallerEventName = keyof InstallerEvents;
183
+ export declare class InstallerEventEmitter extends EventEmitter {
184
+ emit<K extends InstallerEventName>(event: K, payload: InstallerEvents[K]): boolean;
185
+ on<K extends InstallerEventName>(event: K, listener: (payload: InstallerEvents[K]) => void): this;
186
+ off<K extends InstallerEventName>(event: K, listener: (payload: InstallerEvents[K]) => void): this;
187
+ once<K extends InstallerEventName>(event: K, listener: (payload: InstallerEvents[K]) => void): this;
188
188
  }
189
- export declare function createWizardEventEmitter(): WizardEventEmitter;
189
+ export declare function createInstallerEventEmitter(): InstallerEventEmitter;
@@ -1,5 +1,5 @@
1
1
  import { EventEmitter } from 'events';
2
- export class WizardEventEmitter extends EventEmitter {
2
+ export class InstallerEventEmitter extends EventEmitter {
3
3
  emit(event, payload) {
4
4
  return super.emit(event, payload);
5
5
  }
@@ -13,7 +13,7 @@ export class WizardEventEmitter extends EventEmitter {
13
13
  return super.once(event, listener);
14
14
  }
15
15
  }
16
- export function createWizardEventEmitter() {
17
- return new WizardEventEmitter();
16
+ export function createInstallerEventEmitter() {
17
+ return new InstallerEventEmitter();
18
18
  }
19
19
  //# sourceMappingURL=events.js.map