workos 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +51 -15
  2. package/dist/bin.js +151 -0
  3. package/dist/bin.js.map +1 -1
  4. package/dist/cli.config.d.ts +1 -0
  5. package/dist/cli.config.js +1 -0
  6. package/dist/cli.config.js.map +1 -1
  7. package/dist/commands/doctor.d.ts +1 -0
  8. package/dist/commands/doctor.js +1 -0
  9. package/dist/commands/doctor.js.map +1 -1
  10. package/dist/commands/env.d.ts +9 -0
  11. package/dist/commands/env.js +188 -0
  12. package/dist/commands/env.js.map +1 -0
  13. package/dist/commands/organization.d.ts +18 -0
  14. package/dist/commands/organization.js +142 -0
  15. package/dist/commands/organization.js.map +1 -0
  16. package/dist/commands/user.d.ts +19 -0
  17. package/dist/commands/user.js +128 -0
  18. package/dist/commands/user.js.map +1 -0
  19. package/dist/dashboard/components/CompletionView.js +5 -1
  20. package/dist/dashboard/components/CompletionView.js.map +1 -1
  21. package/dist/doctor/agent-prompt.d.ts +10 -0
  22. package/dist/doctor/agent-prompt.js +190 -0
  23. package/dist/doctor/agent-prompt.js.map +1 -0
  24. package/dist/doctor/checks/ai-analysis.d.ts +9 -0
  25. package/dist/doctor/checks/ai-analysis.js +122 -0
  26. package/dist/doctor/checks/ai-analysis.js.map +1 -0
  27. package/dist/doctor/checks/auth-patterns.d.ts +2 -0
  28. package/dist/doctor/checks/auth-patterns.js +530 -0
  29. package/dist/doctor/checks/auth-patterns.js.map +1 -0
  30. package/dist/doctor/checks/environment.js +22 -4
  31. package/dist/doctor/checks/environment.js.map +1 -1
  32. package/dist/doctor/checks/framework.js +27 -8
  33. package/dist/doctor/checks/framework.js.map +1 -1
  34. package/dist/doctor/checks/language.d.ts +6 -0
  35. package/dist/doctor/checks/language.js +104 -0
  36. package/dist/doctor/checks/language.js.map +1 -0
  37. package/dist/doctor/checks/sdk.js +113 -22
  38. package/dist/doctor/checks/sdk.js.map +1 -1
  39. package/dist/doctor/index.js +26 -3
  40. package/dist/doctor/index.js.map +1 -1
  41. package/dist/doctor/issues.js +22 -1
  42. package/dist/doctor/issues.js.map +1 -1
  43. package/dist/doctor/output.js +85 -18
  44. package/dist/doctor/output.js.map +1 -1
  45. package/dist/doctor/types.d.ts +38 -0
  46. package/dist/doctor/types.js.map +1 -1
  47. package/dist/lib/adapters/cli-adapter.js +4 -14
  48. package/dist/lib/adapters/cli-adapter.js.map +1 -1
  49. package/dist/lib/adapters/dashboard-adapter.js +3 -16
  50. package/dist/lib/adapters/dashboard-adapter.js.map +1 -1
  51. package/dist/lib/api-key.d.ts +13 -0
  52. package/dist/lib/api-key.js +26 -0
  53. package/dist/lib/api-key.js.map +1 -0
  54. package/dist/lib/config-store.d.ts +27 -0
  55. package/dist/lib/config-store.js +142 -0
  56. package/dist/lib/config-store.js.map +1 -0
  57. package/dist/lib/credential-store.d.ts +4 -0
  58. package/dist/lib/credential-store.js +47 -11
  59. package/dist/lib/credential-store.js.map +1 -1
  60. package/dist/lib/credentials.d.ts +1 -1
  61. package/dist/lib/credentials.js +1 -1
  62. package/dist/lib/credentials.js.map +1 -1
  63. package/dist/lib/run-with-core.js +23 -2
  64. package/dist/lib/run-with-core.js.map +1 -1
  65. package/dist/lib/settings.d.ts +1 -0
  66. package/dist/lib/settings.js.map +1 -1
  67. package/dist/lib/validation/build-validator.js +0 -1
  68. package/dist/lib/validation/build-validator.js.map +1 -1
  69. package/dist/lib/validation/quick-checks.js +0 -1
  70. package/dist/lib/validation/quick-checks.js.map +1 -1
  71. package/dist/lib/workos-api.d.ts +30 -0
  72. package/dist/lib/workos-api.js +69 -0
  73. package/dist/lib/workos-api.js.map +1 -0
  74. package/dist/utils/cli-symbols.d.ts +1 -1
  75. package/dist/utils/lock-art.d.ts +4 -0
  76. package/dist/utils/lock-art.js +73 -0
  77. package/dist/utils/lock-art.js.map +1 -0
  78. package/dist/utils/package-json.d.ts +1 -0
  79. package/dist/utils/package-json.js +11 -0
  80. package/dist/utils/package-json.js.map +1 -1
  81. package/dist/utils/summary-box.d.ts +18 -0
  82. package/dist/utils/summary-box.js +148 -0
  83. package/dist/utils/summary-box.js.map +1 -0
  84. package/dist/utils/table.d.ts +5 -0
  85. package/dist/utils/table.js +18 -0
  86. package/dist/utils/table.js.map +1 -0
  87. package/package.json +1 -1
  88. package/skills/workos-authkit-nextjs/SKILL.md +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-adapter.js","sourceRoot":"","sources":["../../../src/lib/adapters/dashboard-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;;GAKG;AACH,MAAM,OAAO,gBAAgB;IAClB,OAAO,CAAwB;IAChC,SAAS,CAA6B;IACtC,OAAO,GAAwB,IAAI,CAAC;IACpC,SAAS,GAAG,KAAK,CAAC;IAClB,cAAc,GAAkD,IAAI,CAAC;IAE7E,YAAY,MAAqB;QAC/B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAC9B,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QAEtB,uDAAuD;QACvD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;QAChD,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,yCAAyC,CAAC,CAAC;QAE9E,6CAA6C;QAC7C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,yBAAyB;QAC9D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,sBAAsB;QACvD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,sBAAsB;QACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc;QAEjD,8CAA8C;QAC9C,MAAM,QAAQ,GAAG,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAE7E,yBAAyB;QACzB,IAAI,CAAC,OAAO,GAAG,GAAG,EAAE;YAClB,QAAQ,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc;YACjD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,wBAAwB;QAC/D,CAAC,CAAC;QAEF,kDAAkD;QAClD,0DAA0D;QAC1D,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,kBAAkB,EAAE,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAChE,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,sBAAsB,EAAE,IAAI,CAAC,yBAAyB,CAAC,CAAC;QAExE,yCAAyC;QACzC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;IACnD,CAAC;IAED;;OAEG;IACK,cAAc,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAA+B,EAAQ,EAAE;QACnF,IAAI,CAAC,cAAc,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAC7C,CAAC,CAAC;IAEF,KAAK,CAAC,IAAI;QACR,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAE5B,0BAA0B;QAC1B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,CAAC,qBAAqB,CAAC,CAAC;QACjE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACzE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QAElD,6CAA6C;QAC7C,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QAEpB,sEAAsE;QACtE,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,aAAa;YAC5B,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC;gBACpD,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;oBAChC,OAAO,CAAC,GAAG,EAAE,CAAC;oBACd,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;gBAC3C,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC;gBAChD,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;oBAChC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;gBACtD,CAAC;YACH,CAAC;YACD,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC;QAED,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAED;;OAEG;IACK,qBAAqB,GAAG,CAAC,EAAE,EAAE,EAAE,SAAS,EAAsC,EAAQ,EAAE;QAC9F,IAAI,EAAE,KAAK,YAAY,EAAE,CAAC;YACxB,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;QAC1E,CAAC;aAAM,IAAI,EAAE,KAAK,UAAU,EAAE,CAAC;YAC7B,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC;QAClF,CAAC;aAAM,IAAI,EAAE,KAAK,cAAc,EAAE,CAAC;YACjC,qFAAqF;YACrF,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC;QAC5E,CAAC;aAAM,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;YAC3B,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC;QAC9E,CAAC;aAAM,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC;QACtE,CAAC;IACH,CAAC,CAAC;IAEF;;OAEG;IACK,yBAAyB,GAAG,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAwC,EAAQ,EAAE;QACvG,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,uBAAuB,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtE,CAAC,CAAC;CACH","sourcesContent":["import type { InstallerAdapter, AdapterConfig } from './types.js';\nimport type { InstallerEventEmitter, InstallerEvents } from '../events.js';\nimport chalk from 'chalk';\n\n/**\n * Dashboard adapter that renders wizard events via Ink/React TUI.\n *\n * Wraps the existing Dashboard component and passes the emitter to it.\n * The Dashboard component already handles most event rendering internally.\n */\nexport class DashboardAdapter implements InstallerAdapter {\n readonly emitter: InstallerEventEmitter;\n private sendEvent: AdapterConfig['sendEvent'];\n private cleanup: (() => void) | null = null;\n private isStarted = false;\n private completionData: { success: boolean; summary?: string } | null = null;\n\n constructor(config: AdapterConfig) {\n this.emitter = config.emitter;\n this.sendEvent = config.sendEvent;\n }\n\n async start(): Promise<void> {\n if (this.isStarted) return;\n this.isStarted = true;\n\n // Dynamic imports to avoid loading Ink when not needed\n const { render } = await import('ink');\n const { createElement } = await import('react');\n const { Dashboard } = await import('../../dashboard/components/Dashboard.js');\n\n // Enter fullscreen (alternate screen buffer)\n process.stdout.write('\\x1b[?1049h'); // Enter alternate screen\n process.stdout.write('\\x1b[2J'); // Clear entire screen\n process.stdout.write('\\x1b[H'); // Move cursor to home\n process.stdout.write('\\x1b[?25l'); // Hide cursor\n\n // Render the Dashboard component with emitter\n const instance = render(createElement(Dashboard, { emitter: this.emitter }));\n\n // Setup cleanup function\n this.cleanup = () => {\n instance.unmount();\n process.stdout.write('\\x1b[?25h'); // Show cursor\n process.stdout.write('\\x1b[?1049l'); // Exit alternate screen\n };\n\n // Wire up Dashboard responses back to the machine\n // The Dashboard component emits these when user interacts\n this.emitter.on('confirm:response', this.handleConfirmResponse);\n this.emitter.on('credentials:response', this.handleCredentialsResponse);\n\n // Track completion for post-exit summary\n this.emitter.on('complete', this.handleComplete);\n }\n\n /**\n * Capture completion data for display after exit.\n */\n private handleComplete = ({ success, summary }: InstallerEvents['complete']): void => {\n this.completionData = { success, summary };\n };\n\n async stop(): Promise<void> {\n if (!this.isStarted) return;\n\n // Unsubscribe from events\n this.emitter.off('confirm:response', this.handleConfirmResponse);\n this.emitter.off('credentials:response', this.handleCredentialsResponse);\n this.emitter.off('complete', this.handleComplete);\n\n // Run cleanup (unmount Ink, exit fullscreen)\n this.cleanup?.();\n this.cleanup = null;\n\n // Print completion summary to terminal after exiting alternate screen\n if (this.completionData) {\n console.log(); // blank line\n if (this.completionData.success) {\n console.log(chalk.green('✓ Installation Complete'));\n if (this.completionData.summary) {\n console.log();\n console.log(this.completionData.summary);\n }\n } else {\n console.log(chalk.red('✗ Installation Failed'));\n if (this.completionData.summary) {\n console.log(chalk.dim(this.completionData.summary));\n }\n }\n console.log();\n }\n\n this.isStarted = false;\n }\n\n /**\n * Handle confirm dialog responses from Dashboard.\n */\n private handleConfirmResponse = ({ id, confirmed }: { id: string; confirmed: boolean }): void => {\n if (id === 'git-status') {\n this.sendEvent({ type: confirmed ? 'GIT_CONFIRMED' : 'GIT_CANCELLED' });\n } else if (id === 'env-scan') {\n this.sendEvent({ type: confirmed ? 'ENV_SCAN_APPROVED' : 'ENV_SCAN_DECLINED' });\n } else if (id === 'branch-check') {\n // For dashboard, confirmed=true means create branch, false means continue on current\n this.sendEvent({ type: confirmed ? 'BRANCH_CREATE' : 'BRANCH_CONTINUE' });\n } else if (id === 'commit') {\n this.sendEvent({ type: confirmed ? 'COMMIT_APPROVED' : 'COMMIT_DECLINED' });\n } else if (id === 'pr') {\n this.sendEvent({ type: confirmed ? 'PR_APPROVED' : 'PR_DECLINED' });\n }\n };\n\n /**\n * Handle credentials form submission from Dashboard.\n */\n private handleCredentialsResponse = ({ apiKey, clientId }: { apiKey: string; clientId: string }): void => {\n this.sendEvent({ type: 'CREDENTIALS_SUBMITTED', apiKey, clientId });\n };\n}\n"]}
1
+ {"version":3,"file":"dashboard-adapter.js","sourceRoot":"","sources":["../../../src/lib/adapters/dashboard-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InstallerAdapter, AdapterConfig } from './types.js';\nimport type { InstallerEventEmitter, InstallerEvents } from '../events.js';\nimport { renderCompletionSummary } from '../../utils/summary-box.js';\n\n/**\n * Dashboard adapter that renders wizard events via Ink/React TUI.\n *\n * Wraps the existing Dashboard component and passes the emitter to it.\n * The Dashboard component already handles most event rendering internally.\n */\nexport class DashboardAdapter implements InstallerAdapter {\n readonly emitter: InstallerEventEmitter;\n private sendEvent: AdapterConfig['sendEvent'];\n private cleanup: (() => void) | null = null;\n private isStarted = false;\n private completionData: { success: boolean; summary?: string } | null = null;\n\n constructor(config: AdapterConfig) {\n this.emitter = config.emitter;\n this.sendEvent = config.sendEvent;\n }\n\n async start(): Promise<void> {\n if (this.isStarted) return;\n this.isStarted = true;\n\n // Dynamic imports to avoid loading Ink when not needed\n const { render } = await import('ink');\n const { createElement } = await import('react');\n const { Dashboard } = await import('../../dashboard/components/Dashboard.js');\n\n // Enter fullscreen (alternate screen buffer)\n process.stdout.write('\\x1b[?1049h'); // Enter alternate screen\n process.stdout.write('\\x1b[2J'); // Clear entire screen\n process.stdout.write('\\x1b[H'); // Move cursor to home\n process.stdout.write('\\x1b[?25l'); // Hide cursor\n\n // Render the Dashboard component with emitter\n const instance = render(createElement(Dashboard, { emitter: this.emitter }));\n\n // Setup cleanup function\n this.cleanup = () => {\n instance.unmount();\n process.stdout.write('\\x1b[?25h'); // Show cursor\n process.stdout.write('\\x1b[?1049l'); // Exit alternate screen\n };\n\n // Wire up Dashboard responses back to the machine\n // The Dashboard component emits these when user interacts\n this.emitter.on('confirm:response', this.handleConfirmResponse);\n this.emitter.on('credentials:response', this.handleCredentialsResponse);\n\n // Track completion for post-exit summary\n this.emitter.on('complete', this.handleComplete);\n }\n\n /**\n * Capture completion data for display after exit.\n */\n private handleComplete = ({ success, summary }: InstallerEvents['complete']): void => {\n this.completionData = { success, summary };\n };\n\n async stop(): Promise<void> {\n if (!this.isStarted) return;\n\n // Unsubscribe from events\n this.emitter.off('confirm:response', this.handleConfirmResponse);\n this.emitter.off('credentials:response', this.handleCredentialsResponse);\n this.emitter.off('complete', this.handleComplete);\n\n // Run cleanup (unmount Ink, exit fullscreen)\n this.cleanup?.();\n this.cleanup = null;\n\n if (this.completionData) {\n console.log();\n console.log(renderCompletionSummary(this.completionData.success, this.completionData.summary));\n console.log();\n }\n\n this.isStarted = false;\n }\n\n /**\n * Handle confirm dialog responses from Dashboard.\n */\n private handleConfirmResponse = ({ id, confirmed }: { id: string; confirmed: boolean }): void => {\n if (id === 'git-status') {\n this.sendEvent({ type: confirmed ? 'GIT_CONFIRMED' : 'GIT_CANCELLED' });\n } else if (id === 'env-scan') {\n this.sendEvent({ type: confirmed ? 'ENV_SCAN_APPROVED' : 'ENV_SCAN_DECLINED' });\n } else if (id === 'branch-check') {\n // For dashboard, confirmed=true means create branch, false means continue on current\n this.sendEvent({ type: confirmed ? 'BRANCH_CREATE' : 'BRANCH_CONTINUE' });\n } else if (id === 'commit') {\n this.sendEvent({ type: confirmed ? 'COMMIT_APPROVED' : 'COMMIT_DECLINED' });\n } else if (id === 'pr') {\n this.sendEvent({ type: confirmed ? 'PR_APPROVED' : 'PR_DECLINED' });\n }\n };\n\n /**\n * Handle credentials form submission from Dashboard.\n */\n private handleCredentialsResponse = ({ apiKey, clientId }: { apiKey: string; clientId: string }): void => {\n this.sendEvent({ type: 'CREDENTIALS_SUBMITTED', apiKey, clientId });\n };\n}\n"]}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * API key resolution for management commands.
3
+ *
4
+ * Priority chain:
5
+ * 1. WORKOS_API_KEY environment variable
6
+ * 2. --api-key flag
7
+ * 3. Active environment's stored API key
8
+ */
9
+ export interface ApiKeyOptions {
10
+ apiKey?: string;
11
+ }
12
+ export declare function resolveApiKey(options?: ApiKeyOptions): string;
13
+ export declare function resolveApiBaseUrl(): string;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * API key resolution for management commands.
3
+ *
4
+ * Priority chain:
5
+ * 1. WORKOS_API_KEY environment variable
6
+ * 2. --api-key flag
7
+ * 3. Active environment's stored API key
8
+ */
9
+ import { getActiveEnvironment } from './config-store.js';
10
+ const DEFAULT_BASE_URL = 'https://api.workos.com';
11
+ export function resolveApiKey(options) {
12
+ const envVar = process.env.WORKOS_API_KEY;
13
+ if (envVar)
14
+ return envVar;
15
+ if (options?.apiKey)
16
+ return options.apiKey;
17
+ const activeEnv = getActiveEnvironment();
18
+ if (activeEnv?.apiKey)
19
+ return activeEnv.apiKey;
20
+ throw new Error('No API key configured. Run `workos env add` to configure an environment, or set WORKOS_API_KEY.');
21
+ }
22
+ export function resolveApiBaseUrl() {
23
+ const activeEnv = getActiveEnvironment();
24
+ return activeEnv?.endpoint || DEFAULT_BASE_URL;
25
+ }
26
+ //# sourceMappingURL=api-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-key.js","sourceRoot":"","sources":["../../src/lib/api-key.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,gBAAgB,GAAG,wBAAwB,CAAC;AAMlD,MAAM,UAAU,aAAa,CAAC,OAAuB;IACnD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC1C,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,IAAI,OAAO,EAAE,MAAM;QAAE,OAAO,OAAO,CAAC,MAAM,CAAC;IAE3C,MAAM,SAAS,GAAG,oBAAoB,EAAE,CAAC;IACzC,IAAI,SAAS,EAAE,MAAM;QAAE,OAAO,SAAS,CAAC,MAAM,CAAC;IAE/C,MAAM,IAAI,KAAK,CAAC,iGAAiG,CAAC,CAAC;AACrH,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,MAAM,SAAS,GAAG,oBAAoB,EAAE,CAAC;IACzC,OAAO,SAAS,EAAE,QAAQ,IAAI,gBAAgB,CAAC;AACjD,CAAC","sourcesContent":["/**\n * API key resolution for management commands.\n *\n * Priority chain:\n * 1. WORKOS_API_KEY environment variable\n * 2. --api-key flag\n * 3. Active environment's stored API key\n */\n\nimport { getActiveEnvironment } from './config-store.js';\n\nconst DEFAULT_BASE_URL = 'https://api.workos.com';\n\nexport interface ApiKeyOptions {\n apiKey?: string;\n}\n\nexport function resolveApiKey(options?: ApiKeyOptions): string {\n const envVar = process.env.WORKOS_API_KEY;\n if (envVar) return envVar;\n\n if (options?.apiKey) return options.apiKey;\n\n const activeEnv = getActiveEnvironment();\n if (activeEnv?.apiKey) return activeEnv.apiKey;\n\n throw new Error('No API key configured. Run `workos env add` to configure an environment, or set WORKOS_API_KEY.');\n}\n\nexport function resolveApiBaseUrl(): string {\n const activeEnv = getActiveEnvironment();\n return activeEnv?.endpoint || DEFAULT_BASE_URL;\n}\n"]}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * CLI config storage abstraction with keyring support and file fallback.
3
+ *
4
+ * Stores environment configurations (names, API keys, endpoints) separately
5
+ * from OAuth credentials. Uses a second keyring entry under the same service.
6
+ *
7
+ * Storage priority:
8
+ * 1. If insecure storage forced: use file only
9
+ * 2. Try keyring, fall back to file with warning if unavailable
10
+ */
11
+ export interface EnvironmentConfig {
12
+ name: string;
13
+ type: 'production' | 'sandbox';
14
+ apiKey: string;
15
+ clientId?: string;
16
+ endpoint?: string;
17
+ }
18
+ export interface CliConfig {
19
+ activeEnvironment?: string;
20
+ environments: Record<string, EnvironmentConfig>;
21
+ }
22
+ export declare function setInsecureConfigStorage(value: boolean): void;
23
+ export declare function getConfig(): CliConfig | null;
24
+ export declare function saveConfig(config: CliConfig): void;
25
+ export declare function clearConfig(): void;
26
+ export declare function getActiveEnvironment(): EnvironmentConfig | null;
27
+ export declare function getConfigPath(): string;
@@ -0,0 +1,142 @@
1
+ /**
2
+ * CLI config storage abstraction with keyring support and file fallback.
3
+ *
4
+ * Stores environment configurations (names, API keys, endpoints) separately
5
+ * from OAuth credentials. Uses a second keyring entry under the same service.
6
+ *
7
+ * Storage priority:
8
+ * 1. If insecure storage forced: use file only
9
+ * 2. Try keyring, fall back to file with warning if unavailable
10
+ */
11
+ import { Entry } from '@napi-rs/keyring';
12
+ import fs from 'node:fs';
13
+ import path from 'node:path';
14
+ import os from 'node:os';
15
+ import { logWarn } from '../utils/debug.js';
16
+ const SERVICE_NAME = 'workos-cli';
17
+ const ACCOUNT_NAME = 'config';
18
+ let fallbackWarningShown = false;
19
+ let forceInsecureStorage = false;
20
+ export function setInsecureConfigStorage(value) {
21
+ forceInsecureStorage = value;
22
+ }
23
+ function getConfigDir() {
24
+ return path.join(os.homedir(), '.workos');
25
+ }
26
+ function getConfigFilePath() {
27
+ return path.join(getConfigDir(), 'config.json');
28
+ }
29
+ function fileExists() {
30
+ return fs.existsSync(getConfigFilePath());
31
+ }
32
+ function readFromFile() {
33
+ if (!fileExists())
34
+ return null;
35
+ try {
36
+ const content = fs.readFileSync(getConfigFilePath(), 'utf-8');
37
+ return JSON.parse(content);
38
+ }
39
+ catch (error) {
40
+ logWarn('Failed to read config file:', error);
41
+ return null;
42
+ }
43
+ }
44
+ function writeToFile(config) {
45
+ const dir = getConfigDir();
46
+ if (!fs.existsSync(dir)) {
47
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
48
+ }
49
+ fs.writeFileSync(getConfigFilePath(), JSON.stringify(config, null, 2), {
50
+ mode: 0o600,
51
+ });
52
+ }
53
+ function deleteFile() {
54
+ if (fileExists()) {
55
+ fs.unlinkSync(getConfigFilePath());
56
+ }
57
+ }
58
+ function getKeyringEntry() {
59
+ return new Entry(SERVICE_NAME, ACCOUNT_NAME);
60
+ }
61
+ function readFromKeyring() {
62
+ try {
63
+ const entry = getKeyringEntry();
64
+ const data = entry.getPassword();
65
+ if (!data)
66
+ return null;
67
+ return JSON.parse(data);
68
+ }
69
+ catch (error) {
70
+ logWarn('Failed to read config from keyring:', error);
71
+ return null;
72
+ }
73
+ }
74
+ function writeToKeyring(config) {
75
+ try {
76
+ const entry = getKeyringEntry();
77
+ entry.setPassword(JSON.stringify(config));
78
+ return true;
79
+ }
80
+ catch (error) {
81
+ logWarn('Failed to write config to keyring:', error);
82
+ return false;
83
+ }
84
+ }
85
+ function deleteFromKeyring() {
86
+ try {
87
+ const entry = getKeyringEntry();
88
+ entry.deletePassword();
89
+ }
90
+ catch (error) {
91
+ const msg = error instanceof Error ? error.message : String(error);
92
+ if (!msg.includes('not found') && !msg.includes('No such')) {
93
+ logWarn('Failed to delete config from keyring:', error);
94
+ }
95
+ }
96
+ }
97
+ function showFallbackWarning() {
98
+ if (fallbackWarningShown || forceInsecureStorage)
99
+ return;
100
+ fallbackWarningShown = true;
101
+ logWarn('Unable to store config in system keyring. Using file storage.', 'Config saved to ~/.workos/config.json', 'Use --insecure-storage to suppress this warning.');
102
+ }
103
+ export function getConfig() {
104
+ if (forceInsecureStorage)
105
+ return readFromFile();
106
+ const keyringConfig = readFromKeyring();
107
+ if (keyringConfig)
108
+ return keyringConfig;
109
+ const fileConfig = readFromFile();
110
+ if (fileConfig) {
111
+ // Migrate file config to keyring if possible
112
+ if (writeToKeyring(fileConfig))
113
+ deleteFile();
114
+ return fileConfig;
115
+ }
116
+ return null;
117
+ }
118
+ export function saveConfig(config) {
119
+ if (forceInsecureStorage)
120
+ return writeToFile(config);
121
+ if (writeToKeyring(config)) {
122
+ deleteFile();
123
+ }
124
+ else {
125
+ showFallbackWarning();
126
+ writeToFile(config);
127
+ }
128
+ }
129
+ export function clearConfig() {
130
+ deleteFromKeyring();
131
+ deleteFile();
132
+ }
133
+ export function getActiveEnvironment() {
134
+ const config = getConfig();
135
+ if (!config?.activeEnvironment)
136
+ return null;
137
+ return config.environments[config.activeEnvironment] ?? null;
138
+ }
139
+ export function getConfigPath() {
140
+ return getConfigFilePath();
141
+ }
142
+ //# sourceMappingURL=config-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-store.js","sourceRoot":"","sources":["../../src/lib/config-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * CLI config storage abstraction with keyring support and file fallback.\n *\n * Stores environment configurations (names, API keys, endpoints) separately\n * from OAuth credentials. Uses a second keyring entry under the same service.\n *\n * Storage priority:\n * 1. If insecure storage forced: use file only\n * 2. Try keyring, fall back to file with warning if unavailable\n */\n\nimport { Entry } from '@napi-rs/keyring';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { logWarn } from '../utils/debug.js';\n\nexport interface EnvironmentConfig {\n name: string;\n type: 'production' | 'sandbox';\n apiKey: string;\n clientId?: string;\n endpoint?: string;\n}\n\nexport interface CliConfig {\n activeEnvironment?: string;\n environments: Record<string, EnvironmentConfig>;\n}\n\nconst SERVICE_NAME = 'workos-cli';\nconst ACCOUNT_NAME = 'config';\n\nlet fallbackWarningShown = false;\nlet forceInsecureStorage = false;\n\nexport function setInsecureConfigStorage(value: boolean): void {\n forceInsecureStorage = value;\n}\n\nfunction getConfigDir(): string {\n return path.join(os.homedir(), '.workos');\n}\n\nfunction getConfigFilePath(): string {\n return path.join(getConfigDir(), 'config.json');\n}\n\nfunction fileExists(): boolean {\n return fs.existsSync(getConfigFilePath());\n}\n\nfunction readFromFile(): CliConfig | null {\n if (!fileExists()) return null;\n try {\n const content = fs.readFileSync(getConfigFilePath(), 'utf-8');\n return JSON.parse(content);\n } catch (error) {\n logWarn('Failed to read config file:', error);\n return null;\n }\n}\n\nfunction writeToFile(config: CliConfig): void {\n const dir = getConfigDir();\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n fs.writeFileSync(getConfigFilePath(), JSON.stringify(config, null, 2), {\n mode: 0o600,\n });\n}\n\nfunction deleteFile(): void {\n if (fileExists()) {\n fs.unlinkSync(getConfigFilePath());\n }\n}\n\nfunction getKeyringEntry(): Entry {\n return new Entry(SERVICE_NAME, ACCOUNT_NAME);\n}\n\nfunction readFromKeyring(): CliConfig | null {\n try {\n const entry = getKeyringEntry();\n const data = entry.getPassword();\n if (!data) return null;\n return JSON.parse(data);\n } catch (error) {\n logWarn('Failed to read config from keyring:', error);\n return null;\n }\n}\n\nfunction writeToKeyring(config: CliConfig): boolean {\n try {\n const entry = getKeyringEntry();\n entry.setPassword(JSON.stringify(config));\n return true;\n } catch (error) {\n logWarn('Failed to write config to keyring:', error);\n return false;\n }\n}\n\nfunction deleteFromKeyring(): void {\n try {\n const entry = getKeyringEntry();\n entry.deletePassword();\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n if (!msg.includes('not found') && !msg.includes('No such')) {\n logWarn('Failed to delete config from keyring:', error);\n }\n }\n}\n\nfunction showFallbackWarning(): void {\n if (fallbackWarningShown || forceInsecureStorage) return;\n fallbackWarningShown = true;\n logWarn(\n 'Unable to store config in system keyring. Using file storage.',\n 'Config saved to ~/.workos/config.json',\n 'Use --insecure-storage to suppress this warning.',\n );\n}\n\nexport function getConfig(): CliConfig | null {\n if (forceInsecureStorage) return readFromFile();\n\n const keyringConfig = readFromKeyring();\n if (keyringConfig) return keyringConfig;\n\n const fileConfig = readFromFile();\n if (fileConfig) {\n // Migrate file config to keyring if possible\n if (writeToKeyring(fileConfig)) deleteFile();\n return fileConfig;\n }\n\n return null;\n}\n\nexport function saveConfig(config: CliConfig): void {\n if (forceInsecureStorage) return writeToFile(config);\n\n if (writeToKeyring(config)) {\n deleteFile();\n } else {\n showFallbackWarning();\n writeToFile(config);\n }\n}\n\nexport function clearConfig(): void {\n deleteFromKeyring();\n deleteFile();\n}\n\nexport function getActiveEnvironment(): EnvironmentConfig | null {\n const config = getConfig();\n if (!config?.activeEnvironment) return null;\n return config.environments[config.activeEnvironment] ?? null;\n}\n\nexport function getConfigPath(): string {\n return getConfigFilePath();\n}\n"]}
@@ -25,4 +25,8 @@ export declare function getCredentials(): Credentials | null;
25
25
  export declare function saveCredentials(creds: Credentials): void;
26
26
  export declare function clearCredentials(): void;
27
27
  export declare function updateTokens(accessToken: string, expiresAt: number, refreshToken?: string): void;
28
+ /**
29
+ * Diagnostic info about credential storage state — for debugging auth failures.
30
+ */
31
+ export declare function diagnoseCredentials(): string[];
28
32
  export { getCredentialsPath };
@@ -59,12 +59,15 @@ function readFromKeyring() {
59
59
  try {
60
60
  const entry = getKeyringEntry();
61
61
  const data = entry.getPassword();
62
- if (!data)
62
+ if (!data) {
63
+ logWarn('[credential-store] keyring: entry exists but data is null/empty');
63
64
  return null;
65
+ }
64
66
  return JSON.parse(data);
65
67
  }
66
68
  catch (error) {
67
- logWarn('Failed to read from keyring:', error);
69
+ const msg = error instanceof Error ? error.message : String(error);
70
+ logWarn(`[credential-store] keyring read failed: ${msg}`);
68
71
  return null;
69
72
  }
70
73
  }
@@ -75,7 +78,8 @@ function writeToKeyring(creds) {
75
78
  return true;
76
79
  }
77
80
  catch (error) {
78
- logWarn('Failed to write to keyring:', error);
81
+ const msg = error instanceof Error ? error.message : String(error);
82
+ logWarn(`[credential-store] keyring write failed: ${msg}`);
79
83
  return false;
80
84
  }
81
85
  }
@@ -111,9 +115,7 @@ export function getCredentials() {
111
115
  return keyringCreds;
112
116
  const fileCreds = readFromFile();
113
117
  if (fileCreds) {
114
- // Migrate file creds to keyring if possible
115
- if (writeToKeyring(fileCreds))
116
- deleteFile();
118
+ writeToKeyring(fileCreds);
117
119
  return fileCreds;
118
120
  }
119
121
  return null;
@@ -121,12 +123,9 @@ export function getCredentials() {
121
123
  export function saveCredentials(creds) {
122
124
  if (forceInsecureStorage)
123
125
  return writeToFile(creds);
124
- if (writeToKeyring(creds)) {
125
- deleteFile();
126
- }
127
- else {
126
+ writeToFile(creds);
127
+ if (!writeToKeyring(creds)) {
128
128
  showFallbackWarning();
129
- writeToFile(creds);
130
129
  }
131
130
  }
132
131
  export function clearCredentials() {
@@ -146,5 +145,42 @@ export function updateTokens(accessToken, expiresAt, refreshToken) {
146
145
  };
147
146
  saveCredentials(updated);
148
147
  }
148
+ /**
149
+ * Diagnostic info about credential storage state — for debugging auth failures.
150
+ */
151
+ export function diagnoseCredentials() {
152
+ const lines = [];
153
+ const filePath = getCredentialsPath();
154
+ const filePresent = fileExists();
155
+ lines.push(`file: ${filePath} (exists=${filePresent})`);
156
+ if (filePresent) {
157
+ try {
158
+ const content = fs.readFileSync(filePath, 'utf-8');
159
+ const parsed = JSON.parse(content);
160
+ const expired = parsed.expiresAt ? Date.now() >= parsed.expiresAt : 'unknown';
161
+ lines.push(`file creds: userId=${parsed.userId ?? 'missing'}, expired=${expired}, hasRefreshToken=${!!parsed.refreshToken}`);
162
+ }
163
+ catch (e) {
164
+ lines.push(`file creds: parse error — ${e instanceof Error ? e.message : String(e)}`);
165
+ }
166
+ }
167
+ try {
168
+ const entry = getKeyringEntry();
169
+ const data = entry.getPassword();
170
+ if (data) {
171
+ const parsed = JSON.parse(data);
172
+ const expired = parsed.expiresAt ? Date.now() >= parsed.expiresAt : 'unknown';
173
+ lines.push(`keyring: found, userId=${parsed.userId ?? 'missing'}, expired=${expired}, hasRefreshToken=${!!parsed.refreshToken}`);
174
+ }
175
+ else {
176
+ lines.push('keyring: empty (getPassword returned null)');
177
+ }
178
+ }
179
+ catch (e) {
180
+ lines.push(`keyring: error — ${e instanceof Error ? e.message : String(e)}`);
181
+ }
182
+ lines.push(`insecureStorage=${forceInsecureStorage}`);
183
+ return lines;
184
+ }
149
185
  export { getCredentialsPath };
150
186
  //# sourceMappingURL=credential-store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../../src/lib/credential-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Credential storage abstraction with keyring support and file fallback.\n *\n * Storage priority:\n * 1. If --insecure-storage: use file only\n * 2. Try keyring, fall back to file with warning if unavailable\n */\n\nimport { Entry } from '@napi-rs/keyring';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { logWarn } from '../utils/debug.js';\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\nconst SERVICE_NAME = 'workos-cli';\nconst ACCOUNT_NAME = 'credentials';\n\nlet fallbackWarningShown = false;\nlet forceInsecureStorage = false;\n\nexport function setInsecureStorage(value: boolean): void {\n forceInsecureStorage = value;\n}\n\nfunction getCredentialsDir(): string {\n return path.join(os.homedir(), '.workos');\n}\n\nfunction getCredentialsPath(): string {\n return path.join(getCredentialsDir(), 'credentials.json');\n}\n\nfunction fileExists(): boolean {\n return fs.existsSync(getCredentialsPath());\n}\n\nfunction readFromFile(): Credentials | null {\n if (!fileExists()) return null;\n try {\n const content = fs.readFileSync(getCredentialsPath(), 'utf-8');\n return JSON.parse(content);\n } catch (error) {\n logWarn('Failed to read credentials file:', error);\n return null;\n }\n}\n\nfunction writeToFile(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\nfunction deleteFile(): void {\n if (fileExists()) {\n fs.unlinkSync(getCredentialsPath());\n }\n}\n\nfunction getKeyringEntry(): Entry {\n return new Entry(SERVICE_NAME, ACCOUNT_NAME);\n}\n\nfunction readFromKeyring(): Credentials | null {\n try {\n const entry = getKeyringEntry();\n const data = entry.getPassword();\n if (!data) return null;\n return JSON.parse(data);\n } catch (error) {\n logWarn('Failed to read from keyring:', error);\n return null;\n }\n}\n\nfunction writeToKeyring(creds: Credentials): boolean {\n try {\n const entry = getKeyringEntry();\n entry.setPassword(JSON.stringify(creds));\n return true;\n } catch (error) {\n logWarn('Failed to write to keyring:', error);\n return false;\n }\n}\n\nfunction deleteFromKeyring(): void {\n try {\n const entry = getKeyringEntry();\n entry.deletePassword();\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n if (!msg.includes('not found') && !msg.includes('No such')) {\n logWarn('Failed to delete from keyring:', error);\n }\n }\n}\n\nfunction showFallbackWarning(): void {\n if (fallbackWarningShown || forceInsecureStorage) return;\n fallbackWarningShown = true;\n logWarn(\n 'Unable to store credentials in system keyring. Using file storage.',\n 'Credentials saved to ~/.workos/credentials.json',\n 'Use --insecure-storage to suppress this warning.',\n );\n}\n\nexport function hasCredentials(): boolean {\n if (forceInsecureStorage) {\n return fileExists();\n }\n return readFromKeyring() !== null || fileExists();\n}\n\nexport function getCredentials(): Credentials | null {\n if (forceInsecureStorage) return readFromFile();\n\n const keyringCreds = readFromKeyring();\n if (keyringCreds) return keyringCreds;\n\n const fileCreds = readFromFile();\n if (fileCreds) {\n // Migrate file creds to keyring if possible\n if (writeToKeyring(fileCreds)) deleteFile();\n return fileCreds;\n }\n\n return null;\n}\n\nexport function saveCredentials(creds: Credentials): void {\n if (forceInsecureStorage) return writeToFile(creds);\n\n if (writeToKeyring(creds)) {\n deleteFile();\n } else {\n showFallbackWarning();\n writeToFile(creds);\n }\n}\n\nexport function clearCredentials(): void {\n deleteFromKeyring();\n deleteFile();\n}\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 saveCredentials(updated);\n}\n\nexport { getCredentialsPath };\n"]}
1
+ {"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../../src/lib/credential-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Credential storage abstraction with keyring support and file fallback.\n *\n * Storage priority:\n * 1. If --insecure-storage: use file only\n * 2. Try keyring, fall back to file with warning if unavailable\n */\n\nimport { Entry } from '@napi-rs/keyring';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { logWarn } from '../utils/debug.js';\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\nconst SERVICE_NAME = 'workos-cli';\nconst ACCOUNT_NAME = 'credentials';\n\nlet fallbackWarningShown = false;\nlet forceInsecureStorage = false;\n\nexport function setInsecureStorage(value: boolean): void {\n forceInsecureStorage = value;\n}\n\nfunction getCredentialsDir(): string {\n return path.join(os.homedir(), '.workos');\n}\n\nfunction getCredentialsPath(): string {\n return path.join(getCredentialsDir(), 'credentials.json');\n}\n\nfunction fileExists(): boolean {\n return fs.existsSync(getCredentialsPath());\n}\n\nfunction readFromFile(): Credentials | null {\n if (!fileExists()) return null;\n try {\n const content = fs.readFileSync(getCredentialsPath(), 'utf-8');\n return JSON.parse(content);\n } catch (error) {\n logWarn('Failed to read credentials file:', error);\n return null;\n }\n}\n\nfunction writeToFile(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\nfunction deleteFile(): void {\n if (fileExists()) {\n fs.unlinkSync(getCredentialsPath());\n }\n}\n\nfunction getKeyringEntry(): Entry {\n return new Entry(SERVICE_NAME, ACCOUNT_NAME);\n}\n\nfunction readFromKeyring(): Credentials | null {\n try {\n const entry = getKeyringEntry();\n const data = entry.getPassword();\n if (!data) {\n logWarn('[credential-store] keyring: entry exists but data is null/empty');\n return null;\n }\n return JSON.parse(data);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n logWarn(`[credential-store] keyring read failed: ${msg}`);\n return null;\n }\n}\n\nfunction writeToKeyring(creds: Credentials): boolean {\n try {\n const entry = getKeyringEntry();\n entry.setPassword(JSON.stringify(creds));\n return true;\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n logWarn(`[credential-store] keyring write failed: ${msg}`);\n return false;\n }\n}\n\nfunction deleteFromKeyring(): void {\n try {\n const entry = getKeyringEntry();\n entry.deletePassword();\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n if (!msg.includes('not found') && !msg.includes('No such')) {\n logWarn('Failed to delete from keyring:', error);\n }\n }\n}\n\nfunction showFallbackWarning(): void {\n if (fallbackWarningShown || forceInsecureStorage) return;\n fallbackWarningShown = true;\n logWarn(\n 'Unable to store credentials in system keyring. Using file storage.',\n 'Credentials saved to ~/.workos/credentials.json',\n 'Use --insecure-storage to suppress this warning.',\n );\n}\n\nexport function hasCredentials(): boolean {\n if (forceInsecureStorage) {\n return fileExists();\n }\n return readFromKeyring() !== null || fileExists();\n}\n\nexport function getCredentials(): Credentials | null {\n if (forceInsecureStorage) return readFromFile();\n\n const keyringCreds = readFromKeyring();\n if (keyringCreds) return keyringCreds;\n\n const fileCreds = readFromFile();\n if (fileCreds) {\n writeToKeyring(fileCreds);\n return fileCreds;\n }\n\n return null;\n}\n\nexport function saveCredentials(creds: Credentials): void {\n if (forceInsecureStorage) return writeToFile(creds);\n\n writeToFile(creds);\n if (!writeToKeyring(creds)) {\n showFallbackWarning();\n }\n}\n\nexport function clearCredentials(): void {\n deleteFromKeyring();\n deleteFile();\n}\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 saveCredentials(updated);\n}\n\n/**\n * Diagnostic info about credential storage state — for debugging auth failures.\n */\nexport function diagnoseCredentials(): string[] {\n const lines: string[] = [];\n const filePath = getCredentialsPath();\n const filePresent = fileExists();\n\n lines.push(`file: ${filePath} (exists=${filePresent})`);\n\n if (filePresent) {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const parsed = JSON.parse(content) as Partial<Credentials>;\n const expired = parsed.expiresAt ? Date.now() >= parsed.expiresAt : 'unknown';\n lines.push(\n `file creds: userId=${parsed.userId ?? 'missing'}, expired=${expired}, hasRefreshToken=${!!parsed.refreshToken}`,\n );\n } catch (e) {\n lines.push(`file creds: parse error — ${e instanceof Error ? e.message : String(e)}`);\n }\n }\n\n try {\n const entry = getKeyringEntry();\n const data = entry.getPassword();\n if (data) {\n const parsed = JSON.parse(data) as Partial<Credentials>;\n const expired = parsed.expiresAt ? Date.now() >= parsed.expiresAt : 'unknown';\n lines.push(\n `keyring: found, userId=${parsed.userId ?? 'missing'}, expired=${expired}, hasRefreshToken=${!!parsed.refreshToken}`,\n );\n } else {\n lines.push('keyring: empty (getPassword returned null)');\n }\n } catch (e) {\n lines.push(`keyring: error — ${e instanceof Error ? e.message : String(e)}`);\n }\n\n lines.push(`insecureStorage=${forceInsecureStorage}`);\n return lines;\n}\n\nexport { getCredentialsPath };\n"]}
@@ -1,5 +1,5 @@
1
1
  export type { StagingCache, Credentials } from './credential-store.js';
2
- export { hasCredentials, getCredentials, saveCredentials, clearCredentials, updateTokens, getCredentialsPath, setInsecureStorage, } from './credential-store.js';
2
+ export { hasCredentials, getCredentials, saveCredentials, clearCredentials, updateTokens, getCredentialsPath, setInsecureStorage, diagnoseCredentials, } from './credential-store.js';
3
3
  import type { Credentials } from './credential-store.js';
4
4
  export declare function isTokenExpired(creds: Credentials): boolean;
5
5
  export declare function getAccessToken(): string | null;
@@ -1,4 +1,4 @@
1
- export { hasCredentials, getCredentials, saveCredentials, clearCredentials, updateTokens, getCredentialsPath, setInsecureStorage, } from './credential-store.js';
1
+ export { hasCredentials, getCredentials, saveCredentials, clearCredentials, updateTokens, getCredentialsPath, setInsecureStorage, diagnoseCredentials, } from './credential-store.js';
2
2
  import { getCredentials, saveCredentials } from './credential-store.js';
3
3
  export function isTokenExpired(creds) {
4
4
  return Date.now() >= creds.expiresAt;
@@ -1 +1 @@
1
- {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/lib/credentials.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,cAAc,EACd,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExE,MAAM,UAAU,cAAc,CAAC,KAAkB;IAC/C,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,KAAK,CAAC,SAAS,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;IAC/B,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,IAAI,cAAc,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,KAAK,CAAC,WAAW,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAA6C;IAClF,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;IAC/B,IAAI,CAAC,KAAK;QAAE,OAAO;IAEnB,eAAe,CAAC;QACd,GAAG,KAAK;QACR,OAAO,EAAE;YACP,GAAG,OAAO;YACV,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;IAC/B,IAAI,CAAC,KAAK,EAAE,OAAO;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,cAAc,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;AAC5E,CAAC","sourcesContent":["export type { StagingCache, Credentials } from './credential-store.js';\n\nexport {\n hasCredentials,\n getCredentials,\n saveCredentials,\n clearCredentials,\n updateTokens,\n getCredentialsPath,\n setInsecureStorage,\n} from './credential-store.js';\n\nimport type { Credentials } from './credential-store.js';\nimport { getCredentials, saveCredentials } from './credential-store.js';\n\nexport function isTokenExpired(creds: Credentials): boolean {\n return Date.now() >= creds.expiresAt;\n}\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\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\nexport function getStagingCredentials(): { clientId: string; apiKey: string } | null {\n const creds = getCredentials();\n if (!creds?.staging) return null;\n if (isTokenExpired(creds)) return null;\n return { clientId: creds.staging.clientId, apiKey: creds.staging.apiKey };\n}\n"]}
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/lib/credentials.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,cAAc,EACd,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExE,MAAM,UAAU,cAAc,CAAC,KAAkB;IAC/C,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,KAAK,CAAC,SAAS,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;IAC/B,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,IAAI,cAAc,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,KAAK,CAAC,WAAW,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAA6C;IAClF,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;IAC/B,IAAI,CAAC,KAAK;QAAE,OAAO;IAEnB,eAAe,CAAC;QACd,GAAG,KAAK;QACR,OAAO,EAAE;YACP,GAAG,OAAO;YACV,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;IAC/B,IAAI,CAAC,KAAK,EAAE,OAAO;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,cAAc,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;AAC5E,CAAC","sourcesContent":["export type { StagingCache, Credentials } from './credential-store.js';\n\nexport {\n hasCredentials,\n getCredentials,\n saveCredentials,\n clearCredentials,\n updateTokens,\n getCredentialsPath,\n setInsecureStorage,\n diagnoseCredentials,\n} from './credential-store.js';\n\nimport type { Credentials } from './credential-store.js';\nimport { getCredentials, saveCredentials } from './credential-store.js';\n\nexport function isTokenExpired(creds: Credentials): boolean {\n return Date.now() >= creds.expiresAt;\n}\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\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\nexport function getStagingCredentials(): { clientId: string; apiKey: string } | null {\n const creds = getCredentials();\n if (!creds?.staging) return null;\n if (isTokenExpired(creds)) return null;\n return { clientId: creds.staging.clientId, apiKey: creds.staging.apiKey };\n}\n"]}
@@ -9,6 +9,7 @@ import { DashboardAdapter } from './adapters/dashboard-adapter.js';
9
9
  import { parseEnvFile } from '../utils/env-parser.js';
10
10
  import { enableDebugLogs, initLogFile, logInfo, logError } from '../utils/debug.js';
11
11
  import { getAccessToken, getCredentials, saveCredentials, getStagingCredentials, saveStagingCredentials, } from './credentials.js';
12
+ import { getConfig, saveConfig, getActiveEnvironment } from './config-store.js';
12
13
  import { checkForEnvFiles, discoverCredentials } from './credential-discovery.js';
13
14
  import { requestDeviceCode, pollForToken } from './device-auth.js';
14
15
  import { fetchStagingCredentials as fetchStagingCredentialsApi } from './staging-api.js';
@@ -278,16 +279,36 @@ export async function runWithCore(options) {
278
279
  return { result, deviceAuth };
279
280
  }),
280
281
  fetchStagingCredentials: fromPromise(async () => {
281
- // Check cached staging credentials first
282
+ const activeEnv = getActiveEnvironment();
283
+ if (activeEnv?.clientId && activeEnv?.apiKey) {
284
+ return { clientId: activeEnv.clientId, apiKey: activeEnv.apiKey };
285
+ }
282
286
  const cached = getStagingCredentials();
283
287
  if (cached)
284
288
  return cached;
285
- // Fetch fresh from API
286
289
  const token = getAccessToken();
287
290
  if (!token)
288
291
  throw new Error('No access token available');
289
292
  const staging = await fetchStagingCredentialsApi(token);
290
293
  saveStagingCredentials(staging);
294
+ try {
295
+ const config = getConfig() ?? { environments: {} };
296
+ if (!config.environments['default']) {
297
+ config.environments['default'] = {
298
+ name: 'default',
299
+ type: staging.apiKey.startsWith('sk_test_') ? 'sandbox' : 'production',
300
+ apiKey: staging.apiKey,
301
+ clientId: staging.clientId,
302
+ };
303
+ if (!config.activeEnvironment) {
304
+ config.activeEnvironment = 'default';
305
+ }
306
+ saveConfig(config);
307
+ }
308
+ }
309
+ catch {
310
+ // Don't block install if config-store write fails
311
+ }
291
312
  return staging;
292
313
  }),
293
314
  // Branch check actors