workos 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (333) hide show
  1. package/README.md +8 -145
  2. package/dist/bin.js +129 -50
  3. package/dist/bin.js.map +1 -1
  4. package/dist/commands/api/index.js +18 -10
  5. package/dist/commands/api/index.js.map +1 -1
  6. package/dist/commands/api/interactive.js +11 -11
  7. package/dist/commands/api/interactive.js.map +1 -1
  8. package/dist/commands/claim.js +28 -16
  9. package/dist/commands/claim.js.map +1 -1
  10. package/dist/commands/connection.js +3 -3
  11. package/dist/commands/connection.js.map +1 -1
  12. package/dist/commands/debug.js +6 -6
  13. package/dist/commands/debug.js.map +1 -1
  14. package/dist/commands/dev.d.ts +7 -8
  15. package/dist/commands/dev.js +14 -14
  16. package/dist/commands/dev.js.map +1 -1
  17. package/dist/commands/directory.js +3 -3
  18. package/dist/commands/directory.js.map +1 -1
  19. package/dist/commands/doctor.js +2 -2
  20. package/dist/commands/doctor.js.map +1 -1
  21. package/dist/commands/emulate.d.ts +1 -0
  22. package/dist/commands/emulate.js +3 -2
  23. package/dist/commands/emulate.js.map +1 -1
  24. package/dist/commands/env.d.ts +10 -0
  25. package/dist/commands/env.js +94 -18
  26. package/dist/commands/env.js.map +1 -1
  27. package/dist/commands/install.js +8 -13
  28. package/dist/commands/install.js.map +1 -1
  29. package/dist/commands/login.d.ts +25 -15
  30. package/dist/commands/login.js +126 -71
  31. package/dist/commands/login.js.map +1 -1
  32. package/dist/commands/logout.js +4 -4
  33. package/dist/commands/logout.js.map +1 -1
  34. package/dist/commands/mcp.js +7 -16
  35. package/dist/commands/mcp.js.map +1 -1
  36. package/dist/commands/migrations.js +2 -1
  37. package/dist/commands/migrations.js.map +1 -1
  38. package/dist/commands/seed.js +5 -4
  39. package/dist/commands/seed.js.map +1 -1
  40. package/dist/commands/setup.d.ts +50 -0
  41. package/dist/commands/setup.js +237 -0
  42. package/dist/commands/setup.js.map +1 -0
  43. package/dist/commands/vault-run.js +3 -2
  44. package/dist/commands/vault-run.js.map +1 -1
  45. package/dist/commands/verify-login.d.ts +25 -0
  46. package/dist/commands/verify-login.js +158 -0
  47. package/dist/commands/verify-login.js.map +1 -0
  48. package/dist/doctor/issues.js +3 -2
  49. package/dist/doctor/issues.js.map +1 -1
  50. package/dist/doctor/output.js +2 -1
  51. package/dist/doctor/output.js.map +1 -1
  52. package/dist/integrations/dotnet/index.js +1 -1
  53. package/dist/integrations/dotnet/index.js.map +1 -1
  54. package/dist/integrations/elixir/index.js +1 -1
  55. package/dist/integrations/elixir/index.js.map +1 -1
  56. package/dist/integrations/go/index.js +1 -1
  57. package/dist/integrations/go/index.js.map +1 -1
  58. package/dist/integrations/nextjs/index.js +8 -5
  59. package/dist/integrations/nextjs/index.js.map +1 -1
  60. package/dist/integrations/nextjs/utils.d.ts +1 -1
  61. package/dist/integrations/nextjs/utils.js +21 -6
  62. package/dist/integrations/nextjs/utils.js.map +1 -1
  63. package/dist/integrations/react-router/index.js +5 -5
  64. package/dist/integrations/react-router/index.js.map +1 -1
  65. package/dist/integrations/react-router/utils.js +28 -12
  66. package/dist/integrations/react-router/utils.js.map +1 -1
  67. package/dist/integrations/ruby/index.js +1 -1
  68. package/dist/integrations/ruby/index.js.map +1 -1
  69. package/dist/lib/adapters/cli-adapter.d.ts +33 -4
  70. package/dist/lib/adapters/cli-adapter.js +251 -135
  71. package/dist/lib/adapters/cli-adapter.js.map +1 -1
  72. package/dist/lib/adapters/dashboard-adapter.js +3 -3
  73. package/dist/lib/adapters/dashboard-adapter.js.map +1 -1
  74. package/dist/lib/adapters/headless-adapter.d.ts +7 -0
  75. package/dist/lib/adapters/headless-adapter.js +42 -5
  76. package/dist/lib/adapters/headless-adapter.js.map +1 -1
  77. package/dist/lib/agent-interface.js +15 -1
  78. package/dist/lib/agent-interface.js.map +1 -1
  79. package/dist/lib/agent-runner.js +1 -1
  80. package/dist/lib/agent-runner.js.map +1 -1
  81. package/dist/lib/api-key.js +2 -1
  82. package/dist/lib/api-key.js.map +1 -1
  83. package/dist/lib/completion-data.d.ts +33 -0
  84. package/dist/lib/completion-data.js +33 -0
  85. package/dist/lib/completion-data.js.map +1 -0
  86. package/dist/lib/config-store.d.ts +13 -0
  87. package/dist/lib/config-store.js +24 -0
  88. package/dist/lib/config-store.js.map +1 -1
  89. package/dist/lib/config.d.ts +1 -1
  90. package/dist/lib/config.js +1 -1
  91. package/dist/lib/config.js.map +1 -1
  92. package/dist/lib/constants.d.ts +8 -0
  93. package/dist/lib/constants.js +8 -0
  94. package/dist/lib/constants.js.map +1 -1
  95. package/dist/lib/events.d.ts +34 -1
  96. package/dist/lib/events.js.map +1 -1
  97. package/dist/lib/framework-config.d.ts +6 -0
  98. package/dist/lib/framework-config.js.map +1 -1
  99. package/dist/lib/installer-core.d.ts +14 -1
  100. package/dist/lib/installer-core.js +24 -5
  101. package/dist/lib/installer-core.js.map +1 -1
  102. package/dist/lib/installer-core.types.d.ts +3 -1
  103. package/dist/lib/installer-core.types.js.map +1 -1
  104. package/dist/lib/mcp-clients.d.ts +6 -0
  105. package/dist/lib/mcp-clients.js +13 -0
  106. package/dist/lib/mcp-clients.js.map +1 -1
  107. package/dist/lib/port-detection.js +19 -13
  108. package/dist/lib/port-detection.js.map +1 -1
  109. package/dist/lib/preferences.d.ts +30 -2
  110. package/dist/lib/preferences.js +34 -8
  111. package/dist/lib/preferences.js.map +1 -1
  112. package/dist/lib/run-with-core.js +40 -3
  113. package/dist/lib/run-with-core.js.map +1 -1
  114. package/dist/lib/telemetry-notice.d.ts +5 -5
  115. package/dist/lib/telemetry-notice.js +7 -8
  116. package/dist/lib/telemetry-notice.js.map +1 -1
  117. package/dist/lib/unclaimed-env-provision.js +15 -12
  118. package/dist/lib/unclaimed-env-provision.js.map +1 -1
  119. package/dist/lib/unclaimed-warning.js +4 -3
  120. package/dist/lib/unclaimed-warning.js.map +1 -1
  121. package/dist/lib/validation/security-checks.js +2 -1
  122. package/dist/lib/validation/security-checks.js.map +1 -1
  123. package/dist/lib/validation/validator.js +30 -3
  124. package/dist/lib/validation/validator.js.map +1 -1
  125. package/dist/lib/workos-management.js +26 -19
  126. package/dist/lib/workos-management.js.map +1 -1
  127. package/dist/run.d.ts +1 -0
  128. package/dist/run.js +5 -1
  129. package/dist/run.js.map +1 -1
  130. package/dist/steps/add-or-update-environment-variables.js +10 -10
  131. package/dist/steps/add-or-update-environment-variables.js.map +1 -1
  132. package/dist/steps/run-prettier.js +3 -3
  133. package/dist/steps/run-prettier.js.map +1 -1
  134. package/dist/steps/upload-environment-variables/index.js +15 -3
  135. package/dist/steps/upload-environment-variables/index.js.map +1 -1
  136. package/dist/steps/upload-environment-variables/providers/vercel.js +2 -2
  137. package/dist/steps/upload-environment-variables/providers/vercel.js.map +1 -1
  138. package/dist/utils/box.d.ts +6 -30
  139. package/dist/utils/box.js +8 -95
  140. package/dist/utils/box.js.map +1 -1
  141. package/dist/utils/cli-symbols.d.ts +14 -2
  142. package/dist/utils/cli-symbols.js +12 -0
  143. package/dist/utils/cli-symbols.js.map +1 -1
  144. package/dist/utils/debug.js +3 -3
  145. package/dist/utils/debug.js.map +1 -1
  146. package/dist/utils/environment.js +1 -1
  147. package/dist/utils/environment.js.map +1 -1
  148. package/dist/utils/help-json.js +115 -4
  149. package/dist/utils/help-json.js.map +1 -1
  150. package/dist/utils/package-manager.js +1 -1
  151. package/dist/utils/package-manager.js.map +1 -1
  152. package/dist/utils/recovery-hints.d.ts +5 -0
  153. package/dist/utils/recovery-hints.js +12 -0
  154. package/dist/utils/recovery-hints.js.map +1 -1
  155. package/dist/utils/summary-box.d.ts +8 -1
  156. package/dist/utils/summary-box.js +67 -4
  157. package/dist/utils/summary-box.js.map +1 -1
  158. package/dist/utils/types.d.ts +10 -0
  159. package/dist/utils/types.js.map +1 -1
  160. package/dist/utils/{clack-utils.d.ts → ui-utils.d.ts} +1 -1
  161. package/dist/utils/{clack-utils.js → ui-utils.js} +64 -37
  162. package/dist/utils/ui-utils.js.map +1 -0
  163. package/dist/utils/ui.d.ts +148 -0
  164. package/dist/utils/ui.js +368 -0
  165. package/dist/utils/ui.js.map +1 -0
  166. package/package.json +5 -13
  167. package/dist/check-coverage.ts +0 -237
  168. package/dist/emulate/core/id.d.ts +0 -48
  169. package/dist/emulate/core/id.js +0 -73
  170. package/dist/emulate/core/id.js.map +0 -1
  171. package/dist/emulate/core/index.d.ts +0 -8
  172. package/dist/emulate/core/index.js +0 -8
  173. package/dist/emulate/core/index.js.map +0 -1
  174. package/dist/emulate/core/jwt.d.ts +0 -28
  175. package/dist/emulate/core/jwt.js +0 -78
  176. package/dist/emulate/core/jwt.js.map +0 -1
  177. package/dist/emulate/core/middleware/auth.d.ts +0 -15
  178. package/dist/emulate/core/middleware/auth.js +0 -17
  179. package/dist/emulate/core/middleware/auth.js.map +0 -1
  180. package/dist/emulate/core/middleware/error-handler.d.ts +0 -22
  181. package/dist/emulate/core/middleware/error-handler.js +0 -72
  182. package/dist/emulate/core/middleware/error-handler.js.map +0 -1
  183. package/dist/emulate/core/pagination.d.ts +0 -27
  184. package/dist/emulate/core/pagination.js +0 -43
  185. package/dist/emulate/core/pagination.js.map +0 -1
  186. package/dist/emulate/core/plugin.d.ts +0 -15
  187. package/dist/emulate/core/plugin.js +0 -2
  188. package/dist/emulate/core/plugin.js.map +0 -1
  189. package/dist/emulate/core/server.d.ts +0 -17
  190. package/dist/emulate/core/server.js +0 -90
  191. package/dist/emulate/core/server.js.map +0 -1
  192. package/dist/emulate/core/store.d.ts +0 -44
  193. package/dist/emulate/core/store.js +0 -169
  194. package/dist/emulate/core/store.js.map +0 -1
  195. package/dist/emulate/index.d.ts +0 -25
  196. package/dist/emulate/index.js +0 -47
  197. package/dist/emulate/index.js.map +0 -1
  198. package/dist/emulate/workos/constants.d.ts +0 -56
  199. package/dist/emulate/workos/constants.js +0 -56
  200. package/dist/emulate/workos/constants.js.map +0 -1
  201. package/dist/emulate/workos/entities.d.ts +0 -360
  202. package/dist/emulate/workos/entities.js +0 -2
  203. package/dist/emulate/workos/entities.js.map +0 -1
  204. package/dist/emulate/workos/event-bus.d.ts +0 -17
  205. package/dist/emulate/workos/event-bus.js +0 -70
  206. package/dist/emulate/workos/event-bus.js.map +0 -1
  207. package/dist/emulate/workos/helpers.d.ts +0 -72
  208. package/dist/emulate/workos/helpers.js +0 -211
  209. package/dist/emulate/workos/helpers.js.map +0 -1
  210. package/dist/emulate/workos/index.d.ts +0 -93
  211. package/dist/emulate/workos/index.js +0 -326
  212. package/dist/emulate/workos/index.js.map +0 -1
  213. package/dist/emulate/workos/role-helpers.d.ts +0 -21
  214. package/dist/emulate/workos/role-helpers.js +0 -130
  215. package/dist/emulate/workos/role-helpers.js.map +0 -1
  216. package/dist/emulate/workos/routes/api-keys.d.ts +0 -2
  217. package/dist/emulate/workos/routes/api-keys.js +0 -32
  218. package/dist/emulate/workos/routes/api-keys.js.map +0 -1
  219. package/dist/emulate/workos/routes/audit-logs.d.ts +0 -2
  220. package/dist/emulate/workos/routes/audit-logs.js +0 -104
  221. package/dist/emulate/workos/routes/audit-logs.js.map +0 -1
  222. package/dist/emulate/workos/routes/auth-challenges.d.ts +0 -2
  223. package/dist/emulate/workos/routes/auth-challenges.js +0 -51
  224. package/dist/emulate/workos/routes/auth-challenges.js.map +0 -1
  225. package/dist/emulate/workos/routes/auth-factors.d.ts +0 -2
  226. package/dist/emulate/workos/routes/auth-factors.js +0 -51
  227. package/dist/emulate/workos/routes/auth-factors.js.map +0 -1
  228. package/dist/emulate/workos/routes/auth.d.ts +0 -2
  229. package/dist/emulate/workos/routes/auth.js +0 -350
  230. package/dist/emulate/workos/routes/auth.js.map +0 -1
  231. package/dist/emulate/workos/routes/authorization-checks.d.ts +0 -10
  232. package/dist/emulate/workos/routes/authorization-checks.js +0 -123
  233. package/dist/emulate/workos/routes/authorization-checks.js.map +0 -1
  234. package/dist/emulate/workos/routes/authorization-org-roles.d.ts +0 -2
  235. package/dist/emulate/workos/routes/authorization-org-roles.js +0 -64
  236. package/dist/emulate/workos/routes/authorization-org-roles.js.map +0 -1
  237. package/dist/emulate/workos/routes/authorization-permissions.d.ts +0 -2
  238. package/dist/emulate/workos/routes/authorization-permissions.js +0 -67
  239. package/dist/emulate/workos/routes/authorization-permissions.js.map +0 -1
  240. package/dist/emulate/workos/routes/authorization-resources.d.ts +0 -2
  241. package/dist/emulate/workos/routes/authorization-resources.js +0 -117
  242. package/dist/emulate/workos/routes/authorization-resources.js.map +0 -1
  243. package/dist/emulate/workos/routes/authorization-roles.d.ts +0 -2
  244. package/dist/emulate/workos/routes/authorization-roles.js +0 -13
  245. package/dist/emulate/workos/routes/authorization-roles.js.map +0 -1
  246. package/dist/emulate/workos/routes/config.d.ts +0 -2
  247. package/dist/emulate/workos/routes/config.js +0 -57
  248. package/dist/emulate/workos/routes/config.js.map +0 -1
  249. package/dist/emulate/workos/routes/connect.d.ts +0 -2
  250. package/dist/emulate/workos/routes/connect.js +0 -65
  251. package/dist/emulate/workos/routes/connect.js.map +0 -1
  252. package/dist/emulate/workos/routes/connections.d.ts +0 -2
  253. package/dist/emulate/workos/routes/connections.js +0 -73
  254. package/dist/emulate/workos/routes/connections.js.map +0 -1
  255. package/dist/emulate/workos/routes/data-integrations.d.ts +0 -2
  256. package/dist/emulate/workos/routes/data-integrations.js +0 -55
  257. package/dist/emulate/workos/routes/data-integrations.js.map +0 -1
  258. package/dist/emulate/workos/routes/directories.d.ts +0 -2
  259. package/dist/emulate/workos/routes/directories.js +0 -90
  260. package/dist/emulate/workos/routes/directories.js.map +0 -1
  261. package/dist/emulate/workos/routes/email-verification.d.ts +0 -2
  262. package/dist/emulate/workos/routes/email-verification.js +0 -49
  263. package/dist/emulate/workos/routes/email-verification.js.map +0 -1
  264. package/dist/emulate/workos/routes/events.d.ts +0 -2
  265. package/dist/emulate/workos/routes/events.js +0 -18
  266. package/dist/emulate/workos/routes/events.js.map +0 -1
  267. package/dist/emulate/workos/routes/feature-flags.d.ts +0 -2
  268. package/dist/emulate/workos/routes/feature-flags.js +0 -103
  269. package/dist/emulate/workos/routes/feature-flags.js.map +0 -1
  270. package/dist/emulate/workos/routes/invitations.d.ts +0 -2
  271. package/dist/emulate/workos/routes/invitations.js +0 -122
  272. package/dist/emulate/workos/routes/invitations.js.map +0 -1
  273. package/dist/emulate/workos/routes/legacy-mfa.d.ts +0 -2
  274. package/dist/emulate/workos/routes/legacy-mfa.js +0 -75
  275. package/dist/emulate/workos/routes/legacy-mfa.js.map +0 -1
  276. package/dist/emulate/workos/routes/magic-auth.d.ts +0 -2
  277. package/dist/emulate/workos/routes/magic-auth.js +0 -32
  278. package/dist/emulate/workos/routes/magic-auth.js.map +0 -1
  279. package/dist/emulate/workos/routes/memberships.d.ts +0 -2
  280. package/dist/emulate/workos/routes/memberships.js +0 -114
  281. package/dist/emulate/workos/routes/memberships.js.map +0 -1
  282. package/dist/emulate/workos/routes/organization-domains.d.ts +0 -2
  283. package/dist/emulate/workos/routes/organization-domains.js +0 -58
  284. package/dist/emulate/workos/routes/organization-domains.js.map +0 -1
  285. package/dist/emulate/workos/routes/organizations.d.ts +0 -2
  286. package/dist/emulate/workos/routes/organizations.js +0 -131
  287. package/dist/emulate/workos/routes/organizations.js.map +0 -1
  288. package/dist/emulate/workos/routes/password-reset.d.ts +0 -2
  289. package/dist/emulate/workos/routes/password-reset.js +0 -61
  290. package/dist/emulate/workos/routes/password-reset.js.map +0 -1
  291. package/dist/emulate/workos/routes/pipes.d.ts +0 -2
  292. package/dist/emulate/workos/routes/pipes.js +0 -82
  293. package/dist/emulate/workos/routes/pipes.js.map +0 -1
  294. package/dist/emulate/workos/routes/portal.d.ts +0 -2
  295. package/dist/emulate/workos/routes/portal.js +0 -18
  296. package/dist/emulate/workos/routes/portal.js.map +0 -1
  297. package/dist/emulate/workos/routes/radar.d.ts +0 -2
  298. package/dist/emulate/workos/routes/radar.js +0 -41
  299. package/dist/emulate/workos/routes/radar.js.map +0 -1
  300. package/dist/emulate/workos/routes/sessions.d.ts +0 -2
  301. package/dist/emulate/workos/routes/sessions.js +0 -51
  302. package/dist/emulate/workos/routes/sessions.js.map +0 -1
  303. package/dist/emulate/workos/routes/sso.d.ts +0 -2
  304. package/dist/emulate/workos/routes/sso.js +0 -161
  305. package/dist/emulate/workos/routes/sso.js.map +0 -1
  306. package/dist/emulate/workos/routes/user-features.d.ts +0 -2
  307. package/dist/emulate/workos/routes/user-features.js +0 -50
  308. package/dist/emulate/workos/routes/user-features.js.map +0 -1
  309. package/dist/emulate/workos/routes/users.d.ts +0 -2
  310. package/dist/emulate/workos/routes/users.js +0 -129
  311. package/dist/emulate/workos/routes/users.js.map +0 -1
  312. package/dist/emulate/workos/routes/webhook-endpoints.d.ts +0 -2
  313. package/dist/emulate/workos/routes/webhook-endpoints.js +0 -67
  314. package/dist/emulate/workos/routes/webhook-endpoints.js.map +0 -1
  315. package/dist/emulate/workos/routes/widgets.d.ts +0 -2
  316. package/dist/emulate/workos/routes/widgets.js +0 -27
  317. package/dist/emulate/workos/routes/widgets.js.map +0 -1
  318. package/dist/emulate/workos/store.d.ts +0 -48
  319. package/dist/emulate/workos/store.js +0 -102
  320. package/dist/emulate/workos/store.js.map +0 -1
  321. package/dist/emulate/workos/webhook-signer.d.ts +0 -1
  322. package/dist/emulate/workos/webhook-signer.js +0 -8
  323. package/dist/emulate/workos/webhook-signer.js.map +0 -1
  324. package/dist/gen-routes-lib.spec.ts +0 -659
  325. package/dist/gen-routes-lib.ts +0 -647
  326. package/dist/gen-routes.ts +0 -96
  327. package/dist/lib/mcp-notice.d.ts +0 -72
  328. package/dist/lib/mcp-notice.js +0 -275
  329. package/dist/lib/mcp-notice.js.map +0 -1
  330. package/dist/utils/clack-utils.js.map +0 -1
  331. package/dist/utils/clack.d.ts +0 -5
  332. package/dist/utils/clack.js +0 -34
  333. package/dist/utils/clack.js.map +0 -1
package/README.md CHANGED
@@ -85,6 +85,9 @@ Resource Management:
85
85
  Migrations:
86
86
  migrations Migrate users and SSO connections into WorkOS
87
87
 
88
+ Local Development:
89
+ emulate Start a local WorkOS API emulator
90
+
88
91
  Workflows:
89
92
  seed Declarative resource provisioning from YAML
90
93
  setup-org One-shot organization onboarding
@@ -221,38 +224,9 @@ workos migrations import --csv users.csv
221
224
 
222
225
  Run `workos migrations --help` for all available subcommands.
223
226
 
224
- <!-- UNRELEASED: Local Development (emulator) — hidden until beta testing is complete.
225
- To restore, uncomment this section and re-enable the `emulate` and `dev` commands
226
- in src/bin.ts and src/utils/help-json.ts.
227
-
228
- ### Local Development
229
-
230
- Test your WorkOS integration locally without hitting the live API. The emulator provides a full in-memory WorkOS API replacement with all major endpoints.
231
-
232
- #### `workos dev` — One command to start everything
233
-
234
- The fastest way to develop locally. Starts the emulator and your app together, auto-detecting your framework and injecting the right environment variables.
235
-
236
- ```bash
237
- # Auto-detects framework (Next.js, Vite, Remix, SvelteKit, etc.) and dev command
238
- workos dev
239
-
240
- # Override the dev command
241
- workos dev -- npx vite --port 5173
242
-
243
- # Custom emulator port and seed data
244
- workos dev --port 8080 --seed workos-emulate.config.yaml
245
- ```
246
-
247
- Your app receives these environment variables automatically:
227
+ ### Local Emulation
248
228
 
249
- - `WORKOS_API_BASE_URL` points to the local emulator (e.g. `http://localhost:4100`)
250
- - `WORKOS_API_KEY` — `sk_test_default`
251
- - `WORKOS_CLIENT_ID` — `client_emulate`
252
-
253
- #### `workos emulate` — Standalone emulator
254
-
255
- Run the emulator on its own for CI, test suites, or when you want manual control.
229
+ Start a local WorkOS API emulator. The command is backed by [`@workos/emulate`](https://github.com/workos/emulate); the standalone package binary is `workos-emulate`.
256
230
 
257
231
  ```bash
258
232
  # Start with defaults (port 4100)
@@ -260,124 +234,13 @@ workos emulate
260
234
 
261
235
  # CI-friendly: JSON output, custom port
262
236
  workos emulate --port 9100 --json
263
- # → {"url":"http://localhost:9100","port":9100,"apiKey":"sk_test_default","health":"http://localhost:9100/health"}
264
237
 
265
238
  # Pre-load seed data
266
239
  workos emulate --seed workos-emulate.config.yaml
267
- ```
268
240
 
269
- The emulator supports `GET /health` for readiness polling and shuts down cleanly on Ctrl+C.
270
-
271
- #### Seed configuration
272
-
273
- Create a `workos-emulate.config.yaml` (auto-detected) or pass `--seed <path>`:
274
-
275
- ```yaml
276
- users:
277
- - email: alice@acme.com
278
- first_name: Alice
279
- password: test123
280
- email_verified: true
281
-
282
- organizations:
283
- - name: Acme Corp
284
- domains:
285
- - domain: acme.com
286
- state: verified
287
- memberships:
288
- - user_id: <user_id>
289
- role: admin
290
-
291
- connections:
292
- - name: Acme SSO
293
- organization: Acme Corp
294
- connection_type: GenericSAML
295
- domains: [acme.com]
296
-
297
- roles:
298
- - slug: admin
299
- name: Admin
300
- permissions: [posts:read, posts:write]
301
-
302
- permissions:
303
- - slug: posts:read
304
- name: Read Posts
305
- - slug: posts:write
306
- name: Write Posts
307
-
308
- webhookEndpoints:
309
- - url: http://localhost:3000/webhooks
310
- events: [user.created, organization.updated]
311
- ```
312
-
313
- #### Programmatic API
314
-
315
- Use the emulator directly in test suites without the CLI:
316
-
317
- ```typescript
318
- import { createEmulator } from 'workos/emulate';
319
-
320
- const emulator = await createEmulator({
321
- port: 0, // random available port
322
- seed: {
323
- users: [{ email: 'test@example.com', password: 'secret' }],
324
- },
325
- });
326
-
327
- // Use emulator.url as your WORKOS_API_BASE_URL
328
- const res = await fetch(`${emulator.url}/user_management/users`, {
329
- headers: { Authorization: 'Bearer sk_test_default' },
330
- });
331
-
332
- // Reset between tests (clears data, re-applies seed)
333
- emulator.reset();
334
-
335
- // Clean up
336
- await emulator.close();
337
- ```
338
-
339
- #### Emulated endpoints
340
-
341
- The emulator covers the full WorkOS API surface (~84% of OpenAPI spec endpoints). Run `pnpm check:coverage <openapi-spec>` to see exact coverage.
342
-
343
- | Endpoint Group | Routes |
344
- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
345
- | Organizations | CRUD, external_id lookup, domain management |
346
- | Users | CRUD, email uniqueness, password management |
347
- | Organization memberships | CRUD, role assignment, deactivate/reactivate |
348
- | Organization domains | CRUD, verification |
349
- | SSO connections | CRUD, domain-based lookup |
350
- | SSO flow | Authorize, token exchange, profile, JWKS, SSO logout |
351
- | AuthKit | OAuth authorize (login_hint, multi-user), authenticate (7 grant types incl. refresh_token, MFA TOTP, org selection, device code), PKCE, sealed sessions, impersonation |
352
- | Sessions | List, revoke, logout redirect, JWKS per client |
353
- | Email verification | Send code, confirm |
354
- | Password reset | Create token, confirm |
355
- | Magic auth | Create code |
356
- | Auth factors | TOTP enrollment, delete |
357
- | MFA challenges | Create challenge, verify code |
358
- | Invitations | CRUD, accept, revoke, resend, get by token |
359
- | Config | Redirect URIs, CORS origins, JWT template |
360
- | User features | Authorized apps, connected accounts, data providers |
361
- | Widgets | Token generation |
362
- | Authorization (RBAC) | Environment roles, org roles (priority ordering), permissions, role-permission management |
363
- | Authorization (FGA) | Resources CRUD, permission checks, role assignments |
364
- | Directory Sync | List/get/delete directories, users, groups |
365
- | Audit Logs | Actions, schemas, events, exports, org config/retention |
366
- | Feature Flags | List/get, enable/disable, targets, org/user evaluations |
367
- | Connect | Applications CRUD, client secrets |
368
- | Data Integrations | OAuth authorize + token exchange |
369
- | Radar | Attempts list/get, allow/deny lists |
370
- | API Keys | Validate, delete, list by org |
371
- | Portal | Generate admin portal links |
372
- | Legacy MFA | Enroll/get/delete factors, challenge/verify |
373
- | Webhook Endpoints | CRUD with auto-generated secrets, secret masking |
374
- | Events | Paginated event stream with type filtering |
375
- | Event Bus | Auto-emits events on entity CRUD via collection hooks, fire-and-forget webhook delivery with HMAC signatures |
376
- | Pipes | Connection CRUD, mock `getAccessToken()` |
377
-
378
- JWT tokens include `role` and `permissions` claims for org-scoped sessions. All list endpoints support cursor pagination (`before`, `after`, `limit`, `order`). Error responses match the WorkOS format (`{ message, code, errors }`).
379
-
380
- END UNRELEASED -->
241
+ # Show login pages for SSO/AuthKit browser testing
242
+ workos emulate --interactive
243
+ ```
381
244
 
382
245
  ### Environment Management
383
246
 
package/dist/bin.js CHANGED
@@ -14,7 +14,7 @@ import { hideBin } from 'yargs/helpers';
14
14
  import { ensureAuthenticated } from './lib/ensure-auth.js';
15
15
  import { checkForUpdates } from './lib/version-check.js';
16
16
  const NODE_VERSION_RANGE = getConfig().nodeVersion;
17
- // Have to run this above the other imports because they are importing clack that
17
+ // Have to run this above the other imports because they are importing the UI facade that
18
18
  // has the problematic imports.
19
19
  if (!satisfies(process.version, NODE_VERSION_RANGE)) {
20
20
  red(`WorkOS AuthKit installer requires Node.js ${NODE_VERSION_RANGE}. You are using Node.js ${process.version}. Please upgrade your Node.js version.`);
@@ -22,7 +22,7 @@ if (!satisfies(process.version, NODE_VERSION_RANGE)) {
22
22
  }
23
23
  import { InvalidInteractionModeError, isPromptAllowed, resolveInteractionMode, setInteractionMode, } from './utils/interaction-mode.js';
24
24
  import { resolveEffectiveOutputMode, resolveOutputMode, setOutputMode, isJsonMode, outputJson, outputError, exitWithError, } from './utils/output.js';
25
- import clack from './utils/clack.js';
25
+ import ui, { PromptUnavailableError } from './utils/ui.js';
26
26
  import { registerSubcommand } from './utils/register-subcommand.js';
27
27
  import { installCrashReporter, sanitizeMessage } from './utils/crash-reporter.js';
28
28
  import { installStoreForward, recoverPendingEvents } from './utils/telemetry-store-forward.js';
@@ -34,6 +34,8 @@ import { CliExit } from './utils/cli-exit.js';
34
34
  import { telemetryClient } from './utils/telemetry-client.js';
35
35
  import { ExitCode } from './utils/exit-codes.js';
36
36
  import { analytics } from './utils/analytics.js';
37
+ import { formatWorkOSCommand, getWorkOSCommand } from './utils/command-invocation.js';
38
+ import { MIGRATIONS_DESCRIPTION } from './lib/constants.js';
37
39
  // Enable debug logging for all commands via env var.
38
40
  // Subsumes the installer's --debug flag for non-installer commands.
39
41
  if (process.env.WORKOS_DEBUG === '1') {
@@ -208,6 +210,11 @@ const installerOptions = {
208
210
  choices: ['npm', 'pnpm', 'yarn', 'bun'],
209
211
  type: 'string',
210
212
  },
213
+ router: {
214
+ choices: ['app', 'pages'],
215
+ describe: 'Next.js router to target when detection is ambiguous (app or pages)',
216
+ type: 'string',
217
+ },
211
218
  };
212
219
  // Check for updates (blocks up to 500ms, skip in JSON/non-human modes to keep machine streams clean)
213
220
  if (!isJsonMode() && isPromptAllowed())
@@ -267,8 +274,9 @@ async function runCli() {
267
274
  })
268
275
  .middleware(async (argv) => {
269
276
  // Warn about unclaimed environments before management commands.
270
- // Excluded: auth/claim/install/dashboard handle their own credential flows;
271
- // skills/doctor/env/debug are utility commands where the warning is unnecessary.
277
+ // Excluded: auth/claim/install/setup/dashboard handle their own credential
278
+ // or onboarding flows; skills/doctor/env/debug are utility commands where
279
+ // the warning is unnecessary.
272
280
  const command = String(argv._?.[0] ?? '');
273
281
  if ([
274
282
  'auth',
@@ -277,6 +285,7 @@ async function runCli() {
277
285
  'env',
278
286
  'claim',
279
287
  'install',
288
+ 'setup',
280
289
  'debug',
281
290
  'dashboard',
282
291
  'emulate',
@@ -287,34 +296,6 @@ async function runCli() {
287
296
  return;
288
297
  await applyInsecureStorage(argv.insecureStorage);
289
298
  await maybeWarnUnclaimed();
290
- })
291
- .middleware(async (argv) => {
292
- // One-time MCP banner (lowest-priority startup notice — runs after the
293
- // telemetry notice + unclaimed warning so they win the one-per-run slot).
294
- // Skip commands that manage MCP/agents directly or where the nudge is
295
- // noise, mirroring + extending maybeWarnUnclaimed's list. Self-guarded and
296
- // never throws.
297
- const command = String(argv._?.[0] ?? '');
298
- if ([
299
- 'mcp',
300
- 'install',
301
- 'doctor',
302
- 'skills',
303
- 'auth',
304
- 'env',
305
- 'claim',
306
- 'debug',
307
- 'dashboard',
308
- 'emulate',
309
- 'dev',
310
- 'migrations',
311
- 'telemetry',
312
- 'completion',
313
- '',
314
- ].includes(command))
315
- return;
316
- const { maybeShowMcpNotice } = await import('./lib/mcp-notice.js');
317
- await maybeShowMcpNotice();
318
299
  })
319
300
  .command('auth', 'Manage authentication (login, logout, status)', (yargs) => {
320
301
  yargs.options(insecureStorageOption);
@@ -466,6 +447,38 @@ async function runCli() {
466
447
  }), async (argv) => {
467
448
  const { handleDoctor } = await import('./commands/doctor.js');
468
449
  await handleDoctor(argv);
450
+ })
451
+ .command('verify-login', 'Verify the AuthKit login loop end-to-end against the active environment (creates and deletes a throwaway user)', (yargs) => yargs.options({
452
+ ...insecureStorageOption,
453
+ 'api-key': {
454
+ type: 'string',
455
+ describe: 'WorkOS API key (overrides environment config). Format: sk_test_* (production keys are refused)',
456
+ },
457
+ 'client-id': {
458
+ type: 'string',
459
+ describe: 'WorkOS client ID (overrides the active environment)',
460
+ },
461
+ method: {
462
+ type: 'string',
463
+ choices: ['password'],
464
+ default: 'password',
465
+ describe: 'Authentication method to verify',
466
+ },
467
+ }), async (argv) => {
468
+ await applyInsecureStorage(argv.insecureStorage);
469
+ const { resolveApiKey, resolveApiBaseUrl } = await import('./lib/api-key.js');
470
+ const { getActiveEnvironment } = await import('./lib/config-store.js');
471
+ const { runVerifyLogin } = await import('./commands/verify-login.js');
472
+ const apiKey = resolveApiKey({ apiKey: argv.apiKey }); // exits 4 if none
473
+ const activeEnv = getActiveEnvironment();
474
+ await runVerifyLogin({
475
+ apiKey,
476
+ clientId: argv.clientId ?? activeEnv?.clientId,
477
+ baseUrl: resolveApiBaseUrl(),
478
+ envType: activeEnv?.type ?? null,
479
+ envName: activeEnv?.name,
480
+ method: argv.method,
481
+ });
469
482
  })
470
483
  // NOTE: When adding commands here, also update src/utils/help-json.ts
471
484
  .command('env', 'Manage environment configurations (API keys, endpoints, active environment)', (yargs) => {
@@ -484,7 +497,7 @@ async function runCli() {
484
497
  endpoint: argv.endpoint,
485
498
  });
486
499
  });
487
- registerSubcommand(yargs, 'remove <name>', 'Remove an environment configuration', (y) => y.positional('name', { type: 'string', demandOption: true, describe: 'Environment name' }), async (argv) => {
500
+ registerSubcommand(yargs, 'remove <name>', 'Remove an environment from local CLI config (does not delete or unclaim the environment in WorkOS)', (y) => y.positional('name', { type: 'string', demandOption: true, describe: 'Environment name' }), async (argv) => {
488
501
  await applyInsecureStorage(argv.insecureStorage);
489
502
  const { runEnvRemove } = await import('./commands/env.js');
490
503
  await runEnvRemove(argv.name);
@@ -493,7 +506,7 @@ async function runCli() {
493
506
  if (!argv.name && !isPromptAllowed()) {
494
507
  exitWithError({
495
508
  code: 'missing_args',
496
- message: 'Environment name required. Usage: workos env switch <name>',
509
+ message: `Environment name required. Usage: ${formatWorkOSCommand('env switch <name>')}`,
497
510
  });
498
511
  }
499
512
  await applyInsecureStorage(argv.insecureStorage);
@@ -505,11 +518,16 @@ async function runCli() {
505
518
  const { runEnvList } = await import('./commands/env.js');
506
519
  await runEnvList();
507
520
  });
508
- registerSubcommand(yargs, 'claim', 'Claim an unclaimed environment (link it to your account)', (y) => y, async (argv) => {
521
+ registerSubcommand(yargs, 'claim', 'Claim an unclaimed environment link it to your account (permanent — cannot be undone)', (y) => y, async (argv) => {
509
522
  await applyInsecureStorage(argv.insecureStorage);
510
523
  const { runClaim } = await import('./commands/claim.js');
511
524
  await runClaim();
512
525
  });
526
+ registerSubcommand(yargs, 'provision', 'Provision a new unclaimed WorkOS environment (credentials only, no code changes)', (y) => y, async (argv) => {
527
+ await applyInsecureStorage(argv.insecureStorage);
528
+ const { runEnvProvision } = await import('./commands/env.js');
529
+ await runEnvProvision();
530
+ });
513
531
  return yargs.demandCommand(1, 'Please specify an env subcommand').strict();
514
532
  })
515
533
  .command('api [endpoint] [filter]', 'Make authenticated requests to the WorkOS API', (yargs) => yargs
@@ -1449,6 +1467,30 @@ async function runCli() {
1449
1467
  const { resolveApiKey, resolveApiBaseUrl } = await import('./lib/api-key.js');
1450
1468
  const { runSeed } = await import('./commands/seed.js');
1451
1469
  await runSeed({ file: argv.file, clean: argv.clean, init: argv.init }, resolveApiKey({ apiKey: argv.apiKey }), resolveApiBaseUrl());
1470
+ })
1471
+ .command('setup', 'Set up your coding agent (install WorkOS skills + MCP server)', (yargs) => yargs.options({
1472
+ ...insecureStorageOption,
1473
+ agents: { type: 'string', describe: 'Comma-separated agent keys (claude-code, codex, cursor, goose)' },
1474
+ 'skills-only': { type: 'boolean', describe: 'Install skills only (skip the MCP server)' },
1475
+ 'mcp-only': { type: 'boolean', describe: 'Install the MCP server only (skip skills)' },
1476
+ yes: { type: 'boolean', alias: 'y', describe: 'Install without prompting' },
1477
+ reset: { type: 'boolean', describe: 'Re-enable automatic setup offers after a decline' },
1478
+ }), async (argv) => {
1479
+ await applyInsecureStorage(argv.insecureStorage);
1480
+ const { runSetup } = await import('./commands/setup.js');
1481
+ await runSetup({
1482
+ trigger: 'command',
1483
+ agents: argv.agents
1484
+ ? String(argv.agents)
1485
+ .split(',')
1486
+ .map((a) => a.trim())
1487
+ .filter(Boolean)
1488
+ : undefined,
1489
+ skillsOnly: argv.skillsOnly,
1490
+ mcpOnly: argv.mcpOnly,
1491
+ assumeYes: argv.yes,
1492
+ reset: argv.reset,
1493
+ });
1452
1494
  })
1453
1495
  .command('setup-org <name>', 'One-shot organization onboarding (create org, domain, roles, portal link)', (yargs) => yargs.positional('name', { type: 'string', demandOption: true, describe: 'Organization name' }).options({
1454
1496
  ...insecureStorageOption,
@@ -1492,7 +1534,7 @@ async function runCli() {
1492
1534
  await runDebugSync(argv.directoryId, resolveApiKey({ apiKey: argv.apiKey }), resolveApiBaseUrl());
1493
1535
  })
1494
1536
  // Alias — canonical command is `workos env claim`
1495
- .command('claim', 'Claim an unclaimed WorkOS environment (link it to your account)', (yargs) => yargs.options({
1537
+ .command('claim', 'Claim an unclaimed WorkOS environment link it to your account (permanent — cannot be undone)', (yargs) => yargs.options({
1496
1538
  ...insecureStorageOption,
1497
1539
  }), async (argv) => {
1498
1540
  await applyInsecureStorage(argv.insecureStorage);
@@ -1504,14 +1546,6 @@ async function runCli() {
1504
1546
  await resolveInstallCredentials(argv.apiKey, argv.installDir, argv.skipAuth, ensureAuthenticated);
1505
1547
  const { handleInstall } = await import('./commands/install.js');
1506
1548
  await handleInstall(argv);
1507
- })
1508
- .command('emulate', false, // Hidden: unreleased beta feature
1509
- (yargs) => yargs.options({
1510
- port: { type: 'number', default: 4100, describe: 'Port to listen on' },
1511
- seed: { type: 'string', describe: 'Path to seed config file (YAML or JSON)' },
1512
- }), async (argv) => {
1513
- const { runEmulate } = await import('./commands/emulate.js');
1514
- await runEmulate({ port: argv.port, seed: argv.seed, json: argv.json });
1515
1549
  })
1516
1550
  .command('dev', false, // Hidden: unreleased beta feature
1517
1551
  (yargs) => yargs.options({
@@ -1524,6 +1558,33 @@ async function runCli() {
1524
1558
  seed: argv.seed,
1525
1559
  '--': argv['--'],
1526
1560
  });
1561
+ })
1562
+ .command('emulate', 'Start a local WorkOS API emulator', (yargs) => yargs.options({
1563
+ port: {
1564
+ alias: 'p',
1565
+ type: 'number',
1566
+ default: 4100,
1567
+ describe: 'Port to listen on',
1568
+ },
1569
+ seed: {
1570
+ alias: 's',
1571
+ type: 'string',
1572
+ describe: 'Path to seed config file (YAML or JSON)',
1573
+ },
1574
+ interactive: {
1575
+ alias: 'i',
1576
+ type: 'boolean',
1577
+ default: false,
1578
+ describe: 'Show login pages for SSO/AuthKit',
1579
+ },
1580
+ }), async (argv) => {
1581
+ const { runEmulate } = await import('./commands/emulate.js');
1582
+ await runEmulate({
1583
+ port: argv.port,
1584
+ seed: argv.seed,
1585
+ json: argv.json,
1586
+ interactive: argv.interactive,
1587
+ });
1527
1588
  })
1528
1589
  .command('debug', false, (yargs) => {
1529
1590
  yargs.options(insecureStorageOption);
@@ -1605,9 +1666,9 @@ async function runCli() {
1605
1666
  const { runDebugToken } = await import('./commands/debug.js');
1606
1667
  await runDebugToken();
1607
1668
  });
1608
- return yargs.demandCommand(1, 'Run "workos debug <command>" for debug tools.').strict();
1669
+ return yargs.demandCommand(1, `Run "${getWorkOSCommand()} debug <command>" for debug tools.`).strict();
1609
1670
  })
1610
- .command('migrations', 'Migrate users from identity providers (Auth0, Cognito, Clerk, Firebase) to WorkOS', (yargs) => yargs
1671
+ .command('migrations', MIGRATIONS_DESCRIPTION, (yargs) => yargs
1611
1672
  .strictCommands(false)
1612
1673
  .strict(false)
1613
1674
  .help(false)
@@ -1632,16 +1693,23 @@ async function runCli() {
1632
1693
  await handleInstall({ ...argv, dashboard: true });
1633
1694
  })
1634
1695
  .command(['$0'], 'WorkOS AuthKit CLI', (yargs) => yargs.options(insecureStorageOption), async (argv) => {
1635
- // Non-human modes: show help instead of prompting
1696
+ // Non-human modes: emit machine-readable command tree (JSON) or the
1697
+ // fully-configured parser help (human non-TTY edge) instead of prompting.
1636
1698
  if (!isPromptAllowed()) {
1637
- yargs(rawArgs).showHelp();
1699
+ if (isJsonMode()) {
1700
+ const { buildCommandTree } = await import('./utils/help-json.js');
1701
+ outputJson(buildCommandTree());
1702
+ }
1703
+ else {
1704
+ parser.showHelp();
1705
+ }
1638
1706
  return;
1639
1707
  }
1640
1708
  // TTY: ask if user wants to run installer
1641
- const shouldInstall = await clack.confirm({
1709
+ const shouldInstall = await ui.confirm({
1642
1710
  message: 'Run the AuthKit installer?',
1643
1711
  });
1644
- if (clack.isCancel(shouldInstall) || !shouldInstall) {
1712
+ if (ui.isCancel(shouldInstall) || !shouldInstall) {
1645
1713
  return;
1646
1714
  }
1647
1715
  await applyInsecureStorage(argv.insecureStorage);
@@ -1681,6 +1749,17 @@ async function runCli() {
1681
1749
  },
1682
1750
  };
1683
1751
  }
1752
+ else if (error instanceof PromptUnavailableError) {
1753
+ // A prompt was attempted where the user can't answer (--json, or non-TTY
1754
+ // stdin) on a direct command. Not a crash — surface a clear, structured
1755
+ // error with its own code so scripts and telemetry can distinguish it.
1756
+ process.exitCode = 1;
1757
+ commandOutcome = {
1758
+ success: false,
1759
+ options: { flags, reason: 'validation_error', errorCode: 'prompt_unavailable' },
1760
+ };
1761
+ outputError({ code: 'prompt_unavailable', message: error.message });
1762
+ }
1684
1763
  else {
1685
1764
  // Unexpected error (crash)
1686
1765
  process.exitCode = 1;