workos 0.15.1 → 0.16.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 (138) hide show
  1. package/README.md +37 -11
  2. package/dist/bin.js +1441 -1258
  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/api/index.js +7 -2
  8. package/dist/commands/api/index.js.map +1 -1
  9. package/dist/commands/api/interactive.js +9 -3
  10. package/dist/commands/api/interactive.js.map +1 -1
  11. package/dist/commands/claim.js +1 -1
  12. package/dist/commands/claim.js.map +1 -1
  13. package/dist/commands/debug.d.ts +2 -1
  14. package/dist/commands/debug.js +43 -3
  15. package/dist/commands/debug.js.map +1 -1
  16. package/dist/commands/dev.js +10 -4
  17. package/dist/commands/dev.js.map +1 -1
  18. package/dist/commands/doctor.js +13 -4
  19. package/dist/commands/doctor.js.map +1 -1
  20. package/dist/commands/emulate.js +6 -2
  21. package/dist/commands/emulate.js.map +1 -1
  22. package/dist/commands/env.js +5 -4
  23. package/dist/commands/env.js.map +1 -1
  24. package/dist/commands/install-skill.js +11 -8
  25. package/dist/commands/install-skill.js.map +1 -1
  26. package/dist/commands/install.js +2 -2
  27. package/dist/commands/install.js.map +1 -1
  28. package/dist/commands/login.js +4 -4
  29. package/dist/commands/login.js.map +1 -1
  30. package/dist/commands/migrations.d.ts +1 -1
  31. package/dist/commands/migrations.js +4 -1
  32. package/dist/commands/migrations.js.map +1 -1
  33. package/dist/commands/telemetry.d.ts +3 -0
  34. package/dist/commands/telemetry.js +88 -0
  35. package/dist/commands/telemetry.js.map +1 -0
  36. package/dist/commands/uninstall-skill.js +3 -2
  37. package/dist/commands/uninstall-skill.js.map +1 -1
  38. package/dist/commands/vault-run.d.ts +13 -0
  39. package/dist/commands/vault-run.js +194 -0
  40. package/dist/commands/vault-run.js.map +1 -0
  41. package/dist/commands/vault.d.ts +3 -2
  42. package/dist/commands/vault.js +41 -8
  43. package/dist/commands/vault.js.map +1 -1
  44. package/dist/doctor/checks/auth-patterns.js +2 -2
  45. package/dist/doctor/checks/auth-patterns.js.map +1 -1
  46. package/dist/doctor/checks/environment.js +1 -1
  47. package/dist/doctor/checks/environment.js.map +1 -1
  48. package/dist/lib/api-error-handler.d.ts +15 -3
  49. package/dist/lib/api-error-handler.js +52 -34
  50. package/dist/lib/api-error-handler.js.map +1 -1
  51. package/dist/lib/command-aliases.d.ts +8 -0
  52. package/dist/lib/command-aliases.js +12 -0
  53. package/dist/lib/command-aliases.js.map +1 -0
  54. package/dist/lib/constants.d.ts +0 -1
  55. package/dist/lib/constants.js +0 -1
  56. package/dist/lib/constants.js.map +1 -1
  57. package/dist/lib/credential-discovery.js +1 -1
  58. package/dist/lib/credential-discovery.js.map +1 -1
  59. package/dist/lib/dev-command.js +8 -1
  60. package/dist/lib/dev-command.js.map +1 -1
  61. package/dist/lib/device-id.d.ts +25 -0
  62. package/dist/lib/device-id.js +102 -0
  63. package/dist/lib/device-id.js.map +1 -0
  64. package/dist/lib/preferences.d.ts +101 -0
  65. package/dist/lib/preferences.js +198 -0
  66. package/dist/lib/preferences.js.map +1 -0
  67. package/dist/lib/registry.js +2 -2
  68. package/dist/lib/registry.js.map +1 -1
  69. package/dist/lib/run-with-core.js +17 -17
  70. package/dist/lib/run-with-core.js.map +1 -1
  71. package/dist/lib/settings.d.ts +6 -0
  72. package/dist/lib/settings.js +7 -0
  73. package/dist/lib/settings.js.map +1 -1
  74. package/dist/lib/telemetry-notice.d.ts +25 -0
  75. package/dist/lib/telemetry-notice.js +56 -0
  76. package/dist/lib/telemetry-notice.js.map +1 -0
  77. package/dist/lib/validation/build-validator.js +6 -1
  78. package/dist/lib/validation/build-validator.js.map +1 -1
  79. package/dist/lib/validation/quick-checks.js +2 -0
  80. package/dist/lib/validation/quick-checks.js.map +1 -1
  81. package/dist/lib/validation/validator.js +1 -1
  82. package/dist/lib/validation/validator.js.map +1 -1
  83. package/dist/steps/run-prettier.js +9 -13
  84. package/dist/steps/run-prettier.js.map +1 -1
  85. package/dist/steps/upload-environment-variables/providers/vercel.js +6 -3
  86. package/dist/steps/upload-environment-variables/providers/vercel.js.map +1 -1
  87. package/dist/test/force-insecure-storage.d.ts +1 -0
  88. package/dist/test/force-insecure-storage.js +9 -0
  89. package/dist/test/force-insecure-storage.js.map +1 -0
  90. package/dist/test/setup.d.ts +1 -0
  91. package/dist/test/setup.js +38 -0
  92. package/dist/test/setup.js.map +1 -0
  93. package/dist/utils/analytics.d.ts +41 -0
  94. package/dist/utils/analytics.js +199 -12
  95. package/dist/utils/analytics.js.map +1 -1
  96. package/dist/utils/box.d.ts +29 -1
  97. package/dist/utils/box.js +92 -4
  98. package/dist/utils/box.js.map +1 -1
  99. package/dist/utils/clack-utils.js +22 -4
  100. package/dist/utils/clack-utils.js.map +1 -1
  101. package/dist/utils/cli-exit.d.ts +15 -0
  102. package/dist/utils/cli-exit.js +11 -0
  103. package/dist/utils/cli-exit.js.map +1 -0
  104. package/dist/utils/cli-symbols.d.ts +1 -1
  105. package/dist/utils/command-telemetry.d.ts +17 -0
  106. package/dist/utils/command-telemetry.js +67 -0
  107. package/dist/utils/command-telemetry.js.map +1 -0
  108. package/dist/utils/crash-reporter.d.ts +13 -0
  109. package/dist/utils/crash-reporter.js +91 -0
  110. package/dist/utils/crash-reporter.js.map +1 -0
  111. package/dist/utils/debug.d.ts +1 -0
  112. package/dist/utils/debug.js +4 -1
  113. package/dist/utils/debug.js.map +1 -1
  114. package/dist/utils/env-parser.js +1 -1
  115. package/dist/utils/env-parser.js.map +1 -1
  116. package/dist/utils/exec-file.js +2 -1
  117. package/dist/utils/exec-file.js.map +1 -1
  118. package/dist/utils/exit-codes.d.ts +5 -0
  119. package/dist/utils/exit-codes.js +30 -1
  120. package/dist/utils/exit-codes.js.map +1 -1
  121. package/dist/utils/help-json.d.ts +6 -0
  122. package/dist/utils/help-json.js +87 -10
  123. package/dist/utils/help-json.js.map +1 -1
  124. package/dist/utils/output.d.ts +7 -2
  125. package/dist/utils/output.js +9 -2
  126. package/dist/utils/output.js.map +1 -1
  127. package/dist/utils/platform.d.ts +8 -0
  128. package/dist/utils/platform.js +7 -0
  129. package/dist/utils/platform.js.map +1 -0
  130. package/dist/utils/telemetry-client.d.ts +30 -2
  131. package/dist/utils/telemetry-client.js +122 -12
  132. package/dist/utils/telemetry-client.js.map +1 -1
  133. package/dist/utils/telemetry-store-forward.d.ts +11 -0
  134. package/dist/utils/telemetry-store-forward.js +94 -0
  135. package/dist/utils/telemetry-store-forward.js.map +1 -0
  136. package/dist/utils/telemetry-types.d.ts +58 -9
  137. package/dist/utils/telemetry-types.js.map +1 -1
  138. package/package.json +3 -3
@@ -1,7 +1,7 @@
1
1
  import chalk from 'chalk';
2
2
  import { createWorkOSClient } from '../lib/workos-client.js';
3
3
  import { formatTable } from '../utils/table.js';
4
- import { outputSuccess, outputJson, isJsonMode } from '../utils/output.js';
4
+ import { outputSuccess, outputJson, isJsonMode, exitWithError } from '../utils/output.js';
5
5
  import { createApiErrorHandler } from '../lib/api-error-handler.js';
6
6
  const handleApiError = createApiErrorHandler('Vault');
7
7
  export async function runVaultList(options, apiKey, baseUrl) {
@@ -38,34 +38,51 @@ export async function runVaultList(options, apiKey, baseUrl) {
38
38
  handleApiError(error);
39
39
  }
40
40
  }
41
- export async function runVaultGet(id, apiKey, baseUrl) {
41
+ export async function runVaultGet(id, decrypt, apiKey, baseUrl) {
42
42
  const client = createWorkOSClient(apiKey, baseUrl);
43
43
  try {
44
- const result = await client.sdk.vault.readObject({ id });
45
- outputJson(result);
44
+ if (decrypt) {
45
+ const result = await client.sdk.vault.readObject({ id });
46
+ outputJson(result);
47
+ }
48
+ else {
49
+ const result = await client.sdk.vault.describeObject({ id });
50
+ outputJson(result);
51
+ }
46
52
  }
47
53
  catch (error) {
48
54
  handleApiError(error);
49
55
  }
50
56
  }
51
- export async function runVaultGetByName(name, apiKey, baseUrl) {
57
+ export async function runVaultGetByName(name, decrypt, apiKey, baseUrl) {
52
58
  const client = createWorkOSClient(apiKey, baseUrl);
53
59
  try {
54
60
  const result = await client.sdk.vault.readObjectByName(name);
55
- outputJson(result);
61
+ if (decrypt) {
62
+ outputJson(result);
63
+ }
64
+ else {
65
+ const { value: _stripped, ...metadata } = result;
66
+ outputJson(metadata);
67
+ }
56
68
  }
57
69
  catch (error) {
58
70
  handleApiError(error);
59
71
  }
60
72
  }
61
73
  export async function runVaultCreate(options, apiKey, baseUrl) {
74
+ if (!options.org) {
75
+ exitWithError({
76
+ code: 'missing_org',
77
+ message: 'The --org flag is required. Vault objects must be scoped to an organization.',
78
+ });
79
+ }
62
80
  const client = createWorkOSClient(apiKey, baseUrl);
63
81
  try {
64
- const context = options.org ? { organizationId: options.org } : {};
65
82
  const result = await client.sdk.vault.createObject({
66
83
  name: options.name,
67
84
  value: options.value,
68
- context,
85
+ context: { organizationId: options.org },
69
86
  });
70
87
  outputSuccess('Created vault object', result);
71
88
  }
@@ -117,4 +134,20 @@ export async function runVaultListVersions(id, apiKey, baseUrl) {
117
134
  handleApiError(error);
118
135
  }
119
136
  }
137
+ export async function readValueFromStdin() {
138
+ const chunks = [];
139
+ for await (const chunk of process.stdin) {
140
+ chunks.push(chunk);
141
+ }
142
+ const value = Buffer.concat(chunks)
143
+ .toString('utf-8')
144
+ .replace(/\r?\n$/, '');
145
+ if (value.length === 0) {
146
+ exitWithError({
147
+ code: 'empty_stdin',
148
+ message: 'No value provided on stdin. Pipe a value or pass --value directly.',
149
+ });
150
+ }
151
+ return value;
152
+ }
120
153
  //# sourceMappingURL=vault.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"vault.js","sourceRoot":"","sources":["../../src/commands/vault.ts"],"names":[],"mappings":"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","sourcesContent":["import chalk from 'chalk';\nimport { createWorkOSClient } from '../lib/workos-client.js';\nimport { formatTable } from '../utils/table.js';\nimport { outputSuccess, outputJson, isJsonMode } from '../utils/output.js';\nimport { createApiErrorHandler } from '../lib/api-error-handler.js';\n\nconst handleApiError = createApiErrorHandler('Vault');\n\nexport interface VaultListOptions {\n limit?: number;\n before?: string;\n after?: string;\n order?: string;\n}\n\nexport async function runVaultList(options: VaultListOptions, apiKey: string, baseUrl?: string): Promise<void> {\n const client = createWorkOSClient(apiKey, baseUrl);\n\n try {\n const result = await client.sdk.vault.listObjects({\n limit: options.limit,\n before: options.before,\n after: options.after,\n order: options.order as 'asc' | 'desc' | undefined,\n });\n\n if (isJsonMode()) {\n outputJson({ data: result.data, listMetadata: result.listMetadata });\n return;\n }\n\n if (result.data.length === 0) {\n console.log('No vault objects found.');\n return;\n }\n\n const rows = result.data.map((obj) => [obj.id, obj.name, obj.updatedAt ? String(obj.updatedAt) : chalk.dim('-')]);\n\n console.log(formatTable([{ header: 'ID' }, { header: 'Name' }, { header: 'Updated At' }], rows));\n\n const { before, after } = result.listMetadata;\n if (before && after) {\n console.log(chalk.dim(`Before: ${before} After: ${after}`));\n } else if (before) {\n console.log(chalk.dim(`Before: ${before}`));\n } else if (after) {\n console.log(chalk.dim(`After: ${after}`));\n }\n } catch (error) {\n handleApiError(error);\n }\n}\n\nexport async function runVaultGet(id: string, apiKey: string, baseUrl?: string): Promise<void> {\n const client = createWorkOSClient(apiKey, baseUrl);\n\n try {\n const result = await client.sdk.vault.readObject({ id });\n outputJson(result);\n } catch (error) {\n handleApiError(error);\n }\n}\n\nexport async function runVaultGetByName(name: string, apiKey: string, baseUrl?: string): Promise<void> {\n const client = createWorkOSClient(apiKey, baseUrl);\n\n try {\n const result = await client.sdk.vault.readObjectByName(name);\n outputJson(result);\n } catch (error) {\n handleApiError(error);\n }\n}\n\nexport interface VaultCreateOptions {\n name: string;\n value: string;\n org?: string;\n}\n\nexport async function runVaultCreate(options: VaultCreateOptions, apiKey: string, baseUrl?: string): Promise<void> {\n const client = createWorkOSClient(apiKey, baseUrl);\n\n try {\n const context = options.org ? { organizationId: options.org } : {};\n const result = await client.sdk.vault.createObject({\n name: options.name,\n value: options.value,\n context,\n });\n outputSuccess('Created vault object', result);\n } catch (error) {\n handleApiError(error);\n }\n}\n\nexport interface VaultUpdateOptions {\n id: string;\n value: string;\n versionCheck?: string;\n}\n\nexport async function runVaultUpdate(options: VaultUpdateOptions, apiKey: string, baseUrl?: string): Promise<void> {\n const client = createWorkOSClient(apiKey, baseUrl);\n\n try {\n const result = await client.sdk.vault.updateObject({\n id: options.id,\n value: options.value,\n ...(options.versionCheck && { versionCheck: options.versionCheck }),\n });\n outputSuccess('Updated vault object', result);\n } catch (error) {\n handleApiError(error);\n }\n}\n\nexport async function runVaultDelete(id: string, apiKey: string, baseUrl?: string): Promise<void> {\n const client = createWorkOSClient(apiKey, baseUrl);\n\n try {\n await client.sdk.vault.deleteObject({ id });\n outputSuccess('Deleted vault object', { id });\n } catch (error) {\n handleApiError(error);\n }\n}\n\nexport async function runVaultDescribe(id: string, apiKey: string, baseUrl?: string): Promise<void> {\n const client = createWorkOSClient(apiKey, baseUrl);\n\n try {\n const result = await client.sdk.vault.describeObject({ id });\n outputJson(result);\n } catch (error) {\n handleApiError(error);\n }\n}\n\nexport async function runVaultListVersions(id: string, apiKey: string, baseUrl?: string): Promise<void> {\n const client = createWorkOSClient(apiKey, baseUrl);\n\n try {\n const result = await client.sdk.vault.listObjectVersions({ id });\n outputJson(result);\n } catch (error) {\n handleApiError(error);\n }\n}\n"]}
1
+ {"version":3,"file":"vault.js","sourceRoot":"","sources":["../../src/commands/vault.ts"],"names":[],"mappings":"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","sourcesContent":["import chalk from 'chalk';\nimport { createWorkOSClient } from '../lib/workos-client.js';\nimport { formatTable } from '../utils/table.js';\nimport { outputSuccess, outputJson, isJsonMode, exitWithError } from '../utils/output.js';\nimport { createApiErrorHandler } from '../lib/api-error-handler.js';\n\nconst handleApiError = createApiErrorHandler('Vault');\n\nexport interface VaultListOptions {\n limit?: number;\n before?: string;\n after?: string;\n order?: string;\n}\n\nexport async function runVaultList(options: VaultListOptions, apiKey: string, baseUrl?: string): Promise<void> {\n const client = createWorkOSClient(apiKey, baseUrl);\n\n try {\n const result = await client.sdk.vault.listObjects({\n limit: options.limit,\n before: options.before,\n after: options.after,\n order: options.order as 'asc' | 'desc' | undefined,\n });\n\n if (isJsonMode()) {\n outputJson({ data: result.data, listMetadata: result.listMetadata });\n return;\n }\n\n if (result.data.length === 0) {\n console.log('No vault objects found.');\n return;\n }\n\n const rows = result.data.map((obj) => [obj.id, obj.name, obj.updatedAt ? String(obj.updatedAt) : chalk.dim('-')]);\n\n console.log(formatTable([{ header: 'ID' }, { header: 'Name' }, { header: 'Updated At' }], rows));\n\n const { before, after } = result.listMetadata;\n if (before && after) {\n console.log(chalk.dim(`Before: ${before} After: ${after}`));\n } else if (before) {\n console.log(chalk.dim(`Before: ${before}`));\n } else if (after) {\n console.log(chalk.dim(`After: ${after}`));\n }\n } catch (error) {\n handleApiError(error);\n }\n}\n\nexport async function runVaultGet(id: string, decrypt: boolean, apiKey: string, baseUrl?: string): Promise<void> {\n const client = createWorkOSClient(apiKey, baseUrl);\n\n try {\n if (decrypt) {\n const result = await client.sdk.vault.readObject({ id });\n outputJson(result);\n } else {\n const result = await client.sdk.vault.describeObject({ id });\n outputJson(result);\n }\n } catch (error) {\n handleApiError(error);\n }\n}\n\nexport async function runVaultGetByName(\n name: string,\n decrypt: boolean,\n apiKey: string,\n baseUrl?: string,\n): Promise<void> {\n const client = createWorkOSClient(apiKey, baseUrl);\n\n try {\n const result = await client.sdk.vault.readObjectByName(name);\n if (decrypt) {\n outputJson(result);\n } else {\n const { value: _stripped, ...metadata } = result;\n outputJson(metadata);\n }\n } catch (error) {\n handleApiError(error);\n }\n}\n\nexport interface VaultCreateOptions {\n name: string;\n value: string;\n org?: string;\n}\n\nexport async function runVaultCreate(options: VaultCreateOptions, apiKey: string, baseUrl?: string): Promise<void> {\n if (!options.org) {\n exitWithError({\n code: 'missing_org',\n message: 'The --org flag is required. Vault objects must be scoped to an organization.',\n });\n }\n\n const client = createWorkOSClient(apiKey, baseUrl);\n\n try {\n const result = await client.sdk.vault.createObject({\n name: options.name,\n value: options.value,\n context: { organizationId: options.org },\n });\n outputSuccess('Created vault object', result);\n } catch (error) {\n handleApiError(error);\n }\n}\n\nexport interface VaultUpdateOptions {\n id: string;\n value: string;\n versionCheck?: string;\n}\n\nexport async function runVaultUpdate(options: VaultUpdateOptions, apiKey: string, baseUrl?: string): Promise<void> {\n const client = createWorkOSClient(apiKey, baseUrl);\n\n try {\n const result = await client.sdk.vault.updateObject({\n id: options.id,\n value: options.value,\n ...(options.versionCheck && { versionCheck: options.versionCheck }),\n });\n outputSuccess('Updated vault object', result);\n } catch (error) {\n handleApiError(error);\n }\n}\n\nexport async function runVaultDelete(id: string, apiKey: string, baseUrl?: string): Promise<void> {\n const client = createWorkOSClient(apiKey, baseUrl);\n\n try {\n await client.sdk.vault.deleteObject({ id });\n outputSuccess('Deleted vault object', { id });\n } catch (error) {\n handleApiError(error);\n }\n}\n\nexport async function runVaultDescribe(id: string, apiKey: string, baseUrl?: string): Promise<void> {\n const client = createWorkOSClient(apiKey, baseUrl);\n\n try {\n const result = await client.sdk.vault.describeObject({ id });\n outputJson(result);\n } catch (error) {\n handleApiError(error);\n }\n}\n\nexport async function runVaultListVersions(id: string, apiKey: string, baseUrl?: string): Promise<void> {\n const client = createWorkOSClient(apiKey, baseUrl);\n\n try {\n const result = await client.sdk.vault.listObjectVersions({ id });\n outputJson(result);\n } catch (error) {\n handleApiError(error);\n }\n}\n\nexport async function readValueFromStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk);\n }\n const value = Buffer.concat(chunks)\n .toString('utf-8')\n .replace(/\\r?\\n$/, '');\n if (value.length === 0) {\n exitWithError({\n code: 'empty_stdin',\n message: 'No value provided on stdin. Pipe a value or pass --value directly.',\n });\n }\n return value;\n}\n"]}
@@ -60,7 +60,7 @@ function findFilesShallow(dir, namePattern, maxDepth = 3) {
60
60
  }
61
61
  function parseEnvFile(content) {
62
62
  const result = {};
63
- for (const line of content.split('\n')) {
63
+ for (const line of content.split(/\r?\n/)) {
64
64
  const trimmed = line.trim();
65
65
  if (!trimmed || trimmed.startsWith('#'))
66
66
  continue;
@@ -455,7 +455,7 @@ function checkEnvFileNotGitignored(ctx) {
455
455
  const findings = [];
456
456
  for (const envFile of envFiles) {
457
457
  const isIgnored = gitignore !== null &&
458
- gitignore.split('\n').some((line) => {
458
+ gitignore.split(/\r?\n/).some((line) => {
459
459
  const trimmed = line.trim();
460
460
  if (trimmed.startsWith('#') || trimmed === '')
461
461
  return false;
@@ -1 +1 @@
1
- {"version":3,"file":"auth-patterns.js","sourceRoot":"","sources":["../../../src/doctor/checks/auth-patterns.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport type {\n AuthPatternFinding,\n AuthPatternInfo,\n FrameworkInfo,\n EnvironmentInfo,\n SdkInfo,\n DoctorOptions,\n} from '../types.js';\n\n// --- Helpers ---\n\n/** Return the first path that exists, or null */\nfunction findFile(paths: string[]): string | null {\n for (const p of paths) {\n if (existsSync(p)) return p;\n }\n return null;\n}\n\n/** Read file content safely, return null on any error */\nfunction readFileSafe(filePath: string): string | null {\n try {\n return readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n}\n\n/** Test if a file exists and its content matches a regex */\nfunction fileContains(filePath: string, pattern: RegExp): boolean {\n const content = readFileSafe(filePath);\n if (!content) return false;\n return pattern.test(content);\n}\n\nconst SKIP_DIRS = new Set(['node_modules', '.next', '.turbo', 'dist', '.git', 'coverage']);\n\n/**\n * Find files matching a name pattern in a directory tree, limited to maxDepth levels.\n * Skips node_modules, .next, dist, etc.\n */\nfunction findFilesShallow(dir: string, namePattern: RegExp, maxDepth = 3): string[] {\n const results: string[] = [];\n if (!existsSync(dir)) return results;\n\n function walk(currentDir: string, depth: number) {\n if (depth > maxDepth) return;\n try {\n const dirents = readdirSync(currentDir, { withFileTypes: true });\n for (const dirent of dirents) {\n const fullPath = join(currentDir, dirent.name);\n if (dirent.isDirectory()) {\n if (!SKIP_DIRS.has(dirent.name)) {\n walk(fullPath, depth + 1);\n }\n } else if (dirent.isFile() && namePattern.test(dirent.name)) {\n results.push(fullPath);\n }\n }\n } catch {\n // Directory unreadable\n }\n }\n\n walk(dir, 0);\n return results;\n}\n\nfunction parseEnvFile(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const entry = trimmed.startsWith('export ') ? trimmed.slice(7) : trimmed;\n const eqIndex = entry.indexOf('=');\n if (eqIndex === -1) continue;\n const key = entry.slice(0, eqIndex).trim();\n let value = entry.slice(eqIndex + 1).trim();\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n result[key] = value;\n }\n return result;\n}\n\n/** Load all env vars from .env and .env.local files */\nfunction loadProjectEnvRaw(installDir: string): Record<string, string> {\n const env: Record<string, string> = {};\n for (const file of ['.env', '.env.local']) {\n const content = readFileSafe(join(installDir, file));\n if (content) Object.assign(env, parseEnvFile(content));\n }\n return env;\n}\n\n// --- Check Context ---\n\ninterface CheckContext {\n framework: FrameworkInfo;\n environment: EnvironmentInfo;\n sdk: SdkInfo;\n installDir: string;\n}\n\n// --- Individual Checks ---\n\n/** Resolve the app directory root (app/ or src/app/) for Next.js */\nfunction resolveAppDir(installDir: string): string | null {\n const srcApp = join(installDir, 'src', 'app');\n if (existsSync(srcApp)) return srcApp;\n const app = join(installDir, 'app');\n if (existsSync(app)) return app;\n return null;\n}\n\nfunction checkSignoutGetHandler(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n const appDir = resolveAppDir(ctx.installDir);\n if (!appDir) return [];\n\n const routeFiles = findFilesShallow(appDir, /^route\\.(ts|tsx|js|jsx)$/);\n const signoutRoutes = routeFiles.filter((f) => /[/\\\\](sign-?out|logout)[/\\\\]/.test(f));\n\n const findings: AuthPatternFinding[] = [];\n const GET_EXPORT = /export\\s+(async\\s+)?function\\s+GET|export\\s+const\\s+GET/;\n\n for (const route of signoutRoutes) {\n if (fileContains(route, GET_EXPORT)) {\n findings.push({\n code: 'SIGNOUT_GET_HANDLER',\n severity: 'error',\n message: 'Signout/logout route uses GET handler — vulnerable to CSRF and prefetch-triggered logouts',\n filePath: relative(ctx.installDir, route),\n remediation:\n 'Convert to a POST server action. GET routes with side effects are vulnerable to CSRF and will be triggered by Next.js link prefetching.',\n docsUrl: 'https://workos.com/docs/authkit/sign-out',\n });\n }\n }\n return findings;\n}\n\nfunction checkSignoutLinkPrefetch(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n const appDir = resolveAppDir(ctx.installDir);\n if (!appDir) return [];\n\n const tsxFiles = findFilesShallow(appDir, /\\.(tsx|jsx)$/);\n // Match <Link>, <NextLink>, or other common aliases\n const LINK_PATTERN = /<(?:Next)?Link\\s[^>]*href\\s*=\\s*[\"'{`/]*(\\/sign-?out|\\/logout)/;\n\n const findings: AuthPatternFinding[] = [];\n for (const file of tsxFiles) {\n if (fileContains(file, LINK_PATTERN)) {\n findings.push({\n code: 'SIGNOUT_LINK_PREFETCH',\n severity: 'warning',\n message:\n 'Link component points to signout/logout — Next.js will prefetch this in production, potentially triggering logouts',\n filePath: relative(ctx.installDir, file),\n remediation:\n 'Use a <form> with a server action or <button> with onClick handler instead of <Link> for signout.',\n });\n }\n }\n return findings;\n}\n\nfunction checkMissingMiddleware(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n\n const middlewarePaths = [\n 'middleware.ts',\n 'middleware.js',\n 'proxy.ts',\n 'proxy.js',\n 'src/middleware.ts',\n 'src/middleware.js',\n 'src/proxy.ts',\n 'src/proxy.js',\n ].map((p) => join(ctx.installDir, p));\n\n if (findFile(middlewarePaths)) return [];\n\n return [\n {\n code: 'MISSING_MIDDLEWARE',\n severity: 'error',\n message: 'No middleware.ts or proxy.ts found — AuthKit session handling requires middleware',\n remediation: 'Create middleware.ts at the project root with authkitMiddleware() from @workos-inc/authkit-nextjs.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/middleware',\n },\n ];\n}\n\nfunction checkMiddlewareWrongLocation(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n\n const wrongPaths = ['app/middleware.ts', 'app/middleware.js', 'src/app/middleware.ts', 'src/app/middleware.js'].map(\n (p) => join(ctx.installDir, p),\n );\n\n const found = findFile(wrongPaths);\n if (!found) return [];\n\n return [\n {\n code: 'MIDDLEWARE_WRONG_LOCATION',\n severity: 'warning',\n message: 'middleware.ts found inside app/ directory — must be at project root or src/',\n filePath: relative(ctx.installDir, found),\n remediation: 'Move middleware.ts to the project root (or src/ if using src/ directory).',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/middleware',\n },\n ];\n}\n\nfunction checkMissingAuthKitProvider(ctx: CheckContext): AuthPatternFinding[] {\n const layoutPaths: string[] = [];\n\n if (ctx.framework.name === 'Next.js') {\n layoutPaths.push(\n join(ctx.installDir, 'app', 'layout.tsx'),\n join(ctx.installDir, 'app', 'layout.jsx'),\n join(ctx.installDir, 'src', 'app', 'layout.tsx'),\n join(ctx.installDir, 'src', 'app', 'layout.jsx'),\n );\n } else if (ctx.framework.name === 'React Router' && ctx.framework.variant === 'declarative') {\n layoutPaths.push(\n join(ctx.installDir, 'src', 'App.tsx'),\n join(ctx.installDir, 'src', 'App.jsx'),\n join(ctx.installDir, 'app', 'root.tsx'),\n join(ctx.installDir, 'app', 'root.jsx'),\n );\n } else {\n return [];\n }\n\n const layoutFile = findFile(layoutPaths);\n if (!layoutFile) return []; // Can't check if layout doesn't exist\n\n if (fileContains(layoutFile, /AuthKitProvider/)) return [];\n\n return [\n {\n code: 'MISSING_AUTHKIT_PROVIDER',\n severity: 'warning',\n message: 'AuthKitProvider not found in root layout — required for AuthKit session management',\n filePath: relative(ctx.installDir, layoutFile),\n remediation: 'Wrap your app with <AuthKitProvider> in the root layout.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/setup',\n },\n ];\n}\n\n/** Extract callback path from redirect URI env vars or framework default */\nfunction resolveCallbackPath(ctx: CheckContext): string | null {\n // Check env vars for actual redirect URI (including NEXT_PUBLIC_ variant)\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const redirectUri =\n projectEnv.WORKOS_REDIRECT_URI ?? projectEnv.NEXT_PUBLIC_WORKOS_REDIRECT_URI ?? ctx.environment.redirectUri;\n\n if (redirectUri) {\n try {\n return new URL(redirectUri).pathname;\n } catch {\n // Invalid URL, fall through to framework default\n }\n }\n\n return ctx.framework.expectedCallbackPath ?? null;\n}\n\nfunction checkCallbackRouteMissing(ctx: CheckContext): AuthPatternFinding[] {\n const callbackPath = resolveCallbackPath(ctx);\n if (!callbackPath) return [];\n\n // Build expected route file paths based on framework\n const possiblePaths: string[] = [];\n\n if (ctx.framework.name === 'Next.js') {\n // app/auth/callback/route.ts (or src/app/)\n const routeDir = callbackPath.replace(/^\\//, ''); // 'auth/callback'\n for (const prefix of ['app', 'src/app']) {\n for (const ext of ['ts', 'tsx', 'js', 'jsx']) {\n possiblePaths.push(join(ctx.installDir, prefix, routeDir, `route.${ext}`));\n }\n }\n } else if (ctx.framework.name === 'React Router') {\n // Flat: app/routes/auth.callback.tsx Nested: app/routes/auth/callback.tsx\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n } else if (ctx.framework.name === 'TanStack Start') {\n // Flat: routes/api.auth.callback.tsx Nested: routes/api/auth/callback.tsx\n // Both conventions work in both src/ and app/ directories\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n for (const prefix of ['src', 'app']) {\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, prefix, 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, prefix, 'routes', nested + `.${ext}`));\n }\n }\n }\n\n if (possiblePaths.length === 0) return [];\n if (findFile(possiblePaths)) return [];\n\n return [\n {\n code: 'CALLBACK_ROUTE_MISSING',\n severity: 'error',\n message: `No callback route found at expected path ${callbackPath}`,\n remediation: `Create the callback route handler at the path matching your WORKOS_REDIRECT_URI.`,\n docsUrl: 'https://workos.com/docs/authkit/redirect-uri',\n },\n ];\n}\n\nconst CLIENT_ENV_PREFIXES = ['NEXT_PUBLIC_', 'VITE_', 'REACT_APP_', 'EXPO_PUBLIC_'];\n\nfunction checkApiKeyLeakedToClient(ctx: CheckContext): AuthPatternFinding[] {\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const findings: AuthPatternFinding[] = [];\n\n for (const [key, value] of Object.entries(projectEnv)) {\n const hasClientPrefix = CLIENT_ENV_PREFIXES.some((prefix) => key.startsWith(prefix));\n if (!hasClientPrefix) continue;\n\n const isApiKey = key.includes('WORKOS_API_KEY');\n const isSecretValue = value?.startsWith('sk_test_') || value?.startsWith('sk_live_');\n\n if (isApiKey || isSecretValue) {\n findings.push({\n code: 'API_KEY_LEAKED_TO_CLIENT',\n severity: 'error',\n message: `Secret API key exposed via client-accessible env var ${key}`,\n remediation: `Remove the client prefix. WORKOS_API_KEY must be server-only (no NEXT_PUBLIC_, VITE_, REACT_APP_, or EXPO_PUBLIC_ prefix).`,\n });\n }\n }\n return findings;\n}\n\nfunction checkWrongCallbackLoader(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router') return [];\n const callbackPath = ctx.framework.expectedCallbackPath;\n if (!callbackPath) return [];\n\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n\n const possiblePaths: string[] = [];\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n\n const callbackFile = findFile(possiblePaths);\n if (!callbackFile) return []; // No callback route to check\n\n // authkitLoader is for regular routes; authLoader is for the callback\n if (fileContains(callbackFile, /authkitLoader/) && !fileContains(callbackFile, /authLoader/)) {\n return [\n {\n code: 'WRONG_CALLBACK_LOADER',\n severity: 'warning',\n message: 'Callback route uses authkitLoader instead of authLoader',\n filePath: relative(ctx.installDir, callbackFile),\n remediation:\n 'Use authLoader (not authkitLoader) for the callback route. authkitLoader is for regular routes that need auth context.',\n },\n ];\n }\n return [];\n}\n\nfunction checkMissingRootAuthLoader(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router') return [];\n\n const rootPaths = ['app/root.tsx', 'app/root.jsx', 'app/routes/_index.tsx', 'app/routes/_index.jsx'].map((p) =>\n join(ctx.installDir, p),\n );\n\n const rootFile = findFile(rootPaths);\n if (!rootFile) return [];\n\n if (fileContains(rootFile, /authkitLoader/)) return [];\n\n return [\n {\n code: 'MISSING_ROOT_AUTH_LOADER',\n severity: 'warning',\n message: 'Root route does not use authkitLoader — child routes will not have auth context',\n filePath: relative(ctx.installDir, rootFile),\n remediation: 'Add authkitLoader to your root route so child routes can access auth state.',\n },\n ];\n}\n\nfunction checkMissingAuthkitMiddleware(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'TanStack Start') return [];\n\n const startPaths = ['src/start.ts', 'src/start.tsx', 'app/start.ts', 'app/start.tsx'].map((p) =>\n join(ctx.installDir, p),\n );\n\n const startFile = findFile(startPaths);\n if (!startFile) return []; // Can't check if start file doesn't exist\n\n if (fileContains(startFile, /authkitMiddleware/)) return [];\n\n return [\n {\n code: 'MISSING_AUTHKIT_MIDDLEWARE',\n severity: 'warning',\n message: 'start.ts does not reference authkitMiddleware — AuthKit session handling requires it',\n filePath: relative(ctx.installDir, startFile),\n remediation:\n 'Add authkitMiddleware to requestMiddleware in src/start.ts:\\n' +\n ' import { authkitMiddleware } from \"@workos/authkit-tanstack-react-start\";\\n' +\n ' export default createStart({ requestMiddleware: [authkitMiddleware()] });',\n },\n ];\n}\n\nfunction checkCookiePasswordTooShort(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router' && ctx.framework.name !== 'TanStack Start') return [];\n\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const password = projectEnv.WORKOS_COOKIE_PASSWORD;\n\n // Only warn if password is set but too short; missing password is a separate concern\n if (!password || password.length >= 32) return [];\n\n return [\n {\n code: 'COOKIE_PASSWORD_TOO_SHORT',\n severity: 'warning',\n message: `WORKOS_COOKIE_PASSWORD is ${password.length} characters — minimum 32 required for secure encryption`,\n remediation: 'Set WORKOS_COOKIE_PASSWORD to a random string of at least 32 characters.',\n },\n ];\n}\n\nconst REACT_SPA_SDKS = new Set(['@workos-inc/authkit-react']);\n\nfunction checkMissingApiHostname(ctx: CheckContext): AuthPatternFinding[] {\n if (!ctx.sdk.name || !REACT_SPA_SDKS.has(ctx.sdk.name)) return [];\n\n const sourceFiles = findFilesShallow(ctx.installDir, /\\.(tsx|jsx|ts|js)$/, 4);\n const providerFiles = sourceFiles.filter((f) => fileContains(f, /AuthKitProvider/));\n if (providerFiles.length === 0) return [];\n\n const hasApiHostname = providerFiles.some((f) => fileContains(f, /apiHostname/));\n if (hasApiHostname) return [];\n\n return [\n {\n code: 'MISSING_API_HOSTNAME',\n severity: 'warning',\n message: 'AuthKitProvider does not specify apiHostname — authorize requests will route through api.workos.com',\n filePath: relative(ctx.installDir, providerFiles[0]),\n remediation:\n 'Set the apiHostname prop on AuthKitProvider to your custom Authentication API domain (e.g. auth.example.com) to avoid routing through api.workos.com.',\n docsUrl: 'https://workos.com/docs/custom-domains',\n },\n ];\n}\n\n// --- Cross-language checks (run for ALL projects, not just JS/AuthKit) ---\n\nconst SOURCE_EXTENSIONS = /\\.(ts|tsx|js|jsx|py|rb|go|java|kt|php|cs|swift|dart)$/;\nconst SECRET_SOURCE_IGNORED_SEGMENTS = new Set(['__fixtures__', '__tests__', 'evals', 'fixtures', 'test', 'tests']);\n\nfunction isIgnoredSecretSourcePath(relativePath: string): boolean {\n const normalized = relativePath.replace(/\\\\/g, '/');\n const parts = normalized.split('/');\n if (parts.some((part) => SECRET_SOURCE_IGNORED_SEGMENTS.has(part))) return true;\n return /\\.(spec|test)\\.[^.]+$/.test(normalized);\n}\n\nfunction checkApiKeyInSource(ctx: CheckContext): AuthPatternFinding[] {\n const API_KEY_PATTERN = /sk_(test|live)_[A-Za-z0-9]{10,}/;\n const sourceFiles = findFilesShallow(ctx.installDir, SOURCE_EXTENSIONS, 4);\n const findings: AuthPatternFinding[] = [];\n\n for (const file of sourceFiles) {\n const relativePath = relative(ctx.installDir, file);\n if (isIgnoredSecretSourcePath(relativePath)) continue;\n const content = readFileSafe(file);\n if (!content) continue;\n if (API_KEY_PATTERN.test(content)) {\n findings.push({\n code: 'API_KEY_IN_SOURCE',\n severity: 'error',\n message: `WorkOS API key hardcoded in source file`,\n filePath: relativePath,\n remediation:\n 'Move the API key to an environment variable (WORKOS_API_KEY) and load it from .env or your secret manager.',\n });\n }\n }\n return findings;\n}\n\nfunction checkEnvFileNotGitignored(ctx: CheckContext): AuthPatternFinding[] {\n const envFiles = ['.env', '.env.local'].filter((f) => existsSync(join(ctx.installDir, f)));\n if (envFiles.length === 0) return [];\n\n const gitignorePath = join(ctx.installDir, '.gitignore');\n const gitignore = readFileSafe(gitignorePath);\n\n const findings: AuthPatternFinding[] = [];\n for (const envFile of envFiles) {\n const isIgnored =\n gitignore !== null &&\n gitignore.split('\\n').some((line) => {\n const trimmed = line.trim();\n if (trimmed.startsWith('#') || trimmed === '') return false;\n return trimmed === envFile || trimmed === '.env*' || trimmed === '.env.*' || trimmed === '.env';\n });\n\n if (!isIgnored) {\n findings.push({\n code: 'ENV_FILE_NOT_GITIGNORED',\n severity: 'warning',\n message: `${envFile} is not in .gitignore — secrets may be committed to version control`,\n filePath: envFile,\n remediation: `Add ${envFile} to your .gitignore file.`,\n });\n }\n }\n return findings;\n}\n\nfunction checkMixedEnvironmentCredentials(ctx: CheckContext): AuthPatternFinding[] {\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const apiKey = projectEnv.WORKOS_API_KEY;\n const redirectUri = projectEnv.WORKOS_REDIRECT_URI ?? projectEnv.NEXT_PUBLIC_WORKOS_REDIRECT_URI;\n\n if (!apiKey || !redirectUri) return [];\n\n const isTestKey = apiKey.startsWith('sk_test_');\n const isLiveKey = apiKey.startsWith('sk_live_');\n\n let isProductionUri = false;\n try {\n const url = new URL(redirectUri);\n isProductionUri = url.hostname !== 'localhost' && !url.hostname.startsWith('127.0.0.');\n } catch {\n return [];\n }\n\n if (isTestKey && isProductionUri) {\n return [\n {\n code: 'MIXED_ENVIRONMENT',\n severity: 'warning',\n message: 'Staging API key (sk_test_) used with a production redirect URI',\n remediation:\n 'Use sk_live_ API key for production redirect URIs, or change the redirect URI to localhost for staging.',\n },\n ];\n }\n\n if (isLiveKey && !isProductionUri) {\n return [\n {\n code: 'MIXED_ENVIRONMENT',\n severity: 'warning',\n message: 'Production API key (sk_live_) used with a localhost redirect URI',\n remediation:\n 'Use sk_test_ API key for localhost development, or update the redirect URI to your production domain.',\n },\n ];\n }\n\n return [];\n}\n\n// --- Main Entry Point ---\n\ntype CheckFn = (ctx: CheckContext) => AuthPatternFinding[];\n\nconst CROSS_FRAMEWORK_CHECKS: CheckFn[] = [\n checkApiKeyLeakedToClient,\n checkApiKeyInSource,\n checkEnvFileNotGitignored,\n checkMixedEnvironmentCredentials,\n checkMissingApiHostname,\n];\n\nconst NEXTJS_CHECKS: CheckFn[] = [\n checkSignoutGetHandler,\n checkSignoutLinkPrefetch,\n checkMissingMiddleware,\n checkMiddlewareWrongLocation,\n checkMissingAuthKitProvider,\n checkCallbackRouteMissing,\n];\n\nconst REACT_ROUTER_CHECKS: CheckFn[] = [\n checkWrongCallbackLoader,\n checkMissingRootAuthLoader,\n checkMissingAuthKitProvider,\n checkCallbackRouteMissing,\n checkCookiePasswordTooShort,\n];\n\nconst TANSTACK_CHECKS: CheckFn[] = [\n checkMissingAuthkitMiddleware,\n checkCallbackRouteMissing,\n checkCookiePasswordTooShort,\n];\n\nexport async function checkAuthPatterns(\n options: DoctorOptions,\n framework: FrameworkInfo,\n environment: EnvironmentInfo,\n sdk: SdkInfo,\n): Promise<AuthPatternInfo> {\n const ctx: CheckContext = {\n framework,\n environment,\n sdk,\n installDir: options.installDir,\n };\n\n const checks: CheckFn[] = [...CROSS_FRAMEWORK_CHECKS];\n\n switch (framework.name) {\n case 'Next.js':\n checks.push(...NEXTJS_CHECKS);\n break;\n case 'React Router':\n checks.push(...REACT_ROUTER_CHECKS);\n break;\n case 'TanStack Start':\n checks.push(...TANSTACK_CHECKS);\n break;\n }\n\n const findings: AuthPatternFinding[] = [];\n for (const check of checks) {\n findings.push(...check(ctx));\n }\n\n return {\n checksRun: checks.length,\n findings,\n };\n}\n"]}
1
+ {"version":3,"file":"auth-patterns.js","sourceRoot":"","sources":["../../../src/doctor/checks/auth-patterns.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport type {\n AuthPatternFinding,\n AuthPatternInfo,\n FrameworkInfo,\n EnvironmentInfo,\n SdkInfo,\n DoctorOptions,\n} from '../types.js';\n\n// --- Helpers ---\n\n/** Return the first path that exists, or null */\nfunction findFile(paths: string[]): string | null {\n for (const p of paths) {\n if (existsSync(p)) return p;\n }\n return null;\n}\n\n/** Read file content safely, return null on any error */\nfunction readFileSafe(filePath: string): string | null {\n try {\n return readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n}\n\n/** Test if a file exists and its content matches a regex */\nfunction fileContains(filePath: string, pattern: RegExp): boolean {\n const content = readFileSafe(filePath);\n if (!content) return false;\n return pattern.test(content);\n}\n\nconst SKIP_DIRS = new Set(['node_modules', '.next', '.turbo', 'dist', '.git', 'coverage']);\n\n/**\n * Find files matching a name pattern in a directory tree, limited to maxDepth levels.\n * Skips node_modules, .next, dist, etc.\n */\nfunction findFilesShallow(dir: string, namePattern: RegExp, maxDepth = 3): string[] {\n const results: string[] = [];\n if (!existsSync(dir)) return results;\n\n function walk(currentDir: string, depth: number) {\n if (depth > maxDepth) return;\n try {\n const dirents = readdirSync(currentDir, { withFileTypes: true });\n for (const dirent of dirents) {\n const fullPath = join(currentDir, dirent.name);\n if (dirent.isDirectory()) {\n if (!SKIP_DIRS.has(dirent.name)) {\n walk(fullPath, depth + 1);\n }\n } else if (dirent.isFile() && namePattern.test(dirent.name)) {\n results.push(fullPath);\n }\n }\n } catch {\n // Directory unreadable\n }\n }\n\n walk(dir, 0);\n return results;\n}\n\nfunction parseEnvFile(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of content.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const entry = trimmed.startsWith('export ') ? trimmed.slice(7) : trimmed;\n const eqIndex = entry.indexOf('=');\n if (eqIndex === -1) continue;\n const key = entry.slice(0, eqIndex).trim();\n let value = entry.slice(eqIndex + 1).trim();\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n result[key] = value;\n }\n return result;\n}\n\n/** Load all env vars from .env and .env.local files */\nfunction loadProjectEnvRaw(installDir: string): Record<string, string> {\n const env: Record<string, string> = {};\n for (const file of ['.env', '.env.local']) {\n const content = readFileSafe(join(installDir, file));\n if (content) Object.assign(env, parseEnvFile(content));\n }\n return env;\n}\n\n// --- Check Context ---\n\ninterface CheckContext {\n framework: FrameworkInfo;\n environment: EnvironmentInfo;\n sdk: SdkInfo;\n installDir: string;\n}\n\n// --- Individual Checks ---\n\n/** Resolve the app directory root (app/ or src/app/) for Next.js */\nfunction resolveAppDir(installDir: string): string | null {\n const srcApp = join(installDir, 'src', 'app');\n if (existsSync(srcApp)) return srcApp;\n const app = join(installDir, 'app');\n if (existsSync(app)) return app;\n return null;\n}\n\nfunction checkSignoutGetHandler(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n const appDir = resolveAppDir(ctx.installDir);\n if (!appDir) return [];\n\n const routeFiles = findFilesShallow(appDir, /^route\\.(ts|tsx|js|jsx)$/);\n const signoutRoutes = routeFiles.filter((f) => /[/\\\\](sign-?out|logout)[/\\\\]/.test(f));\n\n const findings: AuthPatternFinding[] = [];\n const GET_EXPORT = /export\\s+(async\\s+)?function\\s+GET|export\\s+const\\s+GET/;\n\n for (const route of signoutRoutes) {\n if (fileContains(route, GET_EXPORT)) {\n findings.push({\n code: 'SIGNOUT_GET_HANDLER',\n severity: 'error',\n message: 'Signout/logout route uses GET handler — vulnerable to CSRF and prefetch-triggered logouts',\n filePath: relative(ctx.installDir, route),\n remediation:\n 'Convert to a POST server action. GET routes with side effects are vulnerable to CSRF and will be triggered by Next.js link prefetching.',\n docsUrl: 'https://workos.com/docs/authkit/sign-out',\n });\n }\n }\n return findings;\n}\n\nfunction checkSignoutLinkPrefetch(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n const appDir = resolveAppDir(ctx.installDir);\n if (!appDir) return [];\n\n const tsxFiles = findFilesShallow(appDir, /\\.(tsx|jsx)$/);\n // Match <Link>, <NextLink>, or other common aliases\n const LINK_PATTERN = /<(?:Next)?Link\\s[^>]*href\\s*=\\s*[\"'{`/]*(\\/sign-?out|\\/logout)/;\n\n const findings: AuthPatternFinding[] = [];\n for (const file of tsxFiles) {\n if (fileContains(file, LINK_PATTERN)) {\n findings.push({\n code: 'SIGNOUT_LINK_PREFETCH',\n severity: 'warning',\n message:\n 'Link component points to signout/logout — Next.js will prefetch this in production, potentially triggering logouts',\n filePath: relative(ctx.installDir, file),\n remediation:\n 'Use a <form> with a server action or <button> with onClick handler instead of <Link> for signout.',\n });\n }\n }\n return findings;\n}\n\nfunction checkMissingMiddleware(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n\n const middlewarePaths = [\n 'middleware.ts',\n 'middleware.js',\n 'proxy.ts',\n 'proxy.js',\n 'src/middleware.ts',\n 'src/middleware.js',\n 'src/proxy.ts',\n 'src/proxy.js',\n ].map((p) => join(ctx.installDir, p));\n\n if (findFile(middlewarePaths)) return [];\n\n return [\n {\n code: 'MISSING_MIDDLEWARE',\n severity: 'error',\n message: 'No middleware.ts or proxy.ts found — AuthKit session handling requires middleware',\n remediation: 'Create middleware.ts at the project root with authkitMiddleware() from @workos-inc/authkit-nextjs.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/middleware',\n },\n ];\n}\n\nfunction checkMiddlewareWrongLocation(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n\n const wrongPaths = ['app/middleware.ts', 'app/middleware.js', 'src/app/middleware.ts', 'src/app/middleware.js'].map(\n (p) => join(ctx.installDir, p),\n );\n\n const found = findFile(wrongPaths);\n if (!found) return [];\n\n return [\n {\n code: 'MIDDLEWARE_WRONG_LOCATION',\n severity: 'warning',\n message: 'middleware.ts found inside app/ directory — must be at project root or src/',\n filePath: relative(ctx.installDir, found),\n remediation: 'Move middleware.ts to the project root (or src/ if using src/ directory).',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/middleware',\n },\n ];\n}\n\nfunction checkMissingAuthKitProvider(ctx: CheckContext): AuthPatternFinding[] {\n const layoutPaths: string[] = [];\n\n if (ctx.framework.name === 'Next.js') {\n layoutPaths.push(\n join(ctx.installDir, 'app', 'layout.tsx'),\n join(ctx.installDir, 'app', 'layout.jsx'),\n join(ctx.installDir, 'src', 'app', 'layout.tsx'),\n join(ctx.installDir, 'src', 'app', 'layout.jsx'),\n );\n } else if (ctx.framework.name === 'React Router' && ctx.framework.variant === 'declarative') {\n layoutPaths.push(\n join(ctx.installDir, 'src', 'App.tsx'),\n join(ctx.installDir, 'src', 'App.jsx'),\n join(ctx.installDir, 'app', 'root.tsx'),\n join(ctx.installDir, 'app', 'root.jsx'),\n );\n } else {\n return [];\n }\n\n const layoutFile = findFile(layoutPaths);\n if (!layoutFile) return []; // Can't check if layout doesn't exist\n\n if (fileContains(layoutFile, /AuthKitProvider/)) return [];\n\n return [\n {\n code: 'MISSING_AUTHKIT_PROVIDER',\n severity: 'warning',\n message: 'AuthKitProvider not found in root layout — required for AuthKit session management',\n filePath: relative(ctx.installDir, layoutFile),\n remediation: 'Wrap your app with <AuthKitProvider> in the root layout.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/setup',\n },\n ];\n}\n\n/** Extract callback path from redirect URI env vars or framework default */\nfunction resolveCallbackPath(ctx: CheckContext): string | null {\n // Check env vars for actual redirect URI (including NEXT_PUBLIC_ variant)\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const redirectUri =\n projectEnv.WORKOS_REDIRECT_URI ?? projectEnv.NEXT_PUBLIC_WORKOS_REDIRECT_URI ?? ctx.environment.redirectUri;\n\n if (redirectUri) {\n try {\n return new URL(redirectUri).pathname;\n } catch {\n // Invalid URL, fall through to framework default\n }\n }\n\n return ctx.framework.expectedCallbackPath ?? null;\n}\n\nfunction checkCallbackRouteMissing(ctx: CheckContext): AuthPatternFinding[] {\n const callbackPath = resolveCallbackPath(ctx);\n if (!callbackPath) return [];\n\n // Build expected route file paths based on framework\n const possiblePaths: string[] = [];\n\n if (ctx.framework.name === 'Next.js') {\n // app/auth/callback/route.ts (or src/app/)\n const routeDir = callbackPath.replace(/^\\//, ''); // 'auth/callback'\n for (const prefix of ['app', 'src/app']) {\n for (const ext of ['ts', 'tsx', 'js', 'jsx']) {\n possiblePaths.push(join(ctx.installDir, prefix, routeDir, `route.${ext}`));\n }\n }\n } else if (ctx.framework.name === 'React Router') {\n // Flat: app/routes/auth.callback.tsx Nested: app/routes/auth/callback.tsx\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n } else if (ctx.framework.name === 'TanStack Start') {\n // Flat: routes/api.auth.callback.tsx Nested: routes/api/auth/callback.tsx\n // Both conventions work in both src/ and app/ directories\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n for (const prefix of ['src', 'app']) {\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, prefix, 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, prefix, 'routes', nested + `.${ext}`));\n }\n }\n }\n\n if (possiblePaths.length === 0) return [];\n if (findFile(possiblePaths)) return [];\n\n return [\n {\n code: 'CALLBACK_ROUTE_MISSING',\n severity: 'error',\n message: `No callback route found at expected path ${callbackPath}`,\n remediation: `Create the callback route handler at the path matching your WORKOS_REDIRECT_URI.`,\n docsUrl: 'https://workos.com/docs/authkit/redirect-uri',\n },\n ];\n}\n\nconst CLIENT_ENV_PREFIXES = ['NEXT_PUBLIC_', 'VITE_', 'REACT_APP_', 'EXPO_PUBLIC_'];\n\nfunction checkApiKeyLeakedToClient(ctx: CheckContext): AuthPatternFinding[] {\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const findings: AuthPatternFinding[] = [];\n\n for (const [key, value] of Object.entries(projectEnv)) {\n const hasClientPrefix = CLIENT_ENV_PREFIXES.some((prefix) => key.startsWith(prefix));\n if (!hasClientPrefix) continue;\n\n const isApiKey = key.includes('WORKOS_API_KEY');\n const isSecretValue = value?.startsWith('sk_test_') || value?.startsWith('sk_live_');\n\n if (isApiKey || isSecretValue) {\n findings.push({\n code: 'API_KEY_LEAKED_TO_CLIENT',\n severity: 'error',\n message: `Secret API key exposed via client-accessible env var ${key}`,\n remediation: `Remove the client prefix. WORKOS_API_KEY must be server-only (no NEXT_PUBLIC_, VITE_, REACT_APP_, or EXPO_PUBLIC_ prefix).`,\n });\n }\n }\n return findings;\n}\n\nfunction checkWrongCallbackLoader(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router') return [];\n const callbackPath = ctx.framework.expectedCallbackPath;\n if (!callbackPath) return [];\n\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n\n const possiblePaths: string[] = [];\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n\n const callbackFile = findFile(possiblePaths);\n if (!callbackFile) return []; // No callback route to check\n\n // authkitLoader is for regular routes; authLoader is for the callback\n if (fileContains(callbackFile, /authkitLoader/) && !fileContains(callbackFile, /authLoader/)) {\n return [\n {\n code: 'WRONG_CALLBACK_LOADER',\n severity: 'warning',\n message: 'Callback route uses authkitLoader instead of authLoader',\n filePath: relative(ctx.installDir, callbackFile),\n remediation:\n 'Use authLoader (not authkitLoader) for the callback route. authkitLoader is for regular routes that need auth context.',\n },\n ];\n }\n return [];\n}\n\nfunction checkMissingRootAuthLoader(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router') return [];\n\n const rootPaths = ['app/root.tsx', 'app/root.jsx', 'app/routes/_index.tsx', 'app/routes/_index.jsx'].map((p) =>\n join(ctx.installDir, p),\n );\n\n const rootFile = findFile(rootPaths);\n if (!rootFile) return [];\n\n if (fileContains(rootFile, /authkitLoader/)) return [];\n\n return [\n {\n code: 'MISSING_ROOT_AUTH_LOADER',\n severity: 'warning',\n message: 'Root route does not use authkitLoader — child routes will not have auth context',\n filePath: relative(ctx.installDir, rootFile),\n remediation: 'Add authkitLoader to your root route so child routes can access auth state.',\n },\n ];\n}\n\nfunction checkMissingAuthkitMiddleware(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'TanStack Start') return [];\n\n const startPaths = ['src/start.ts', 'src/start.tsx', 'app/start.ts', 'app/start.tsx'].map((p) =>\n join(ctx.installDir, p),\n );\n\n const startFile = findFile(startPaths);\n if (!startFile) return []; // Can't check if start file doesn't exist\n\n if (fileContains(startFile, /authkitMiddleware/)) return [];\n\n return [\n {\n code: 'MISSING_AUTHKIT_MIDDLEWARE',\n severity: 'warning',\n message: 'start.ts does not reference authkitMiddleware — AuthKit session handling requires it',\n filePath: relative(ctx.installDir, startFile),\n remediation:\n 'Add authkitMiddleware to requestMiddleware in src/start.ts:\\n' +\n ' import { authkitMiddleware } from \"@workos/authkit-tanstack-react-start\";\\n' +\n ' export default createStart({ requestMiddleware: [authkitMiddleware()] });',\n },\n ];\n}\n\nfunction checkCookiePasswordTooShort(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router' && ctx.framework.name !== 'TanStack Start') return [];\n\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const password = projectEnv.WORKOS_COOKIE_PASSWORD;\n\n // Only warn if password is set but too short; missing password is a separate concern\n if (!password || password.length >= 32) return [];\n\n return [\n {\n code: 'COOKIE_PASSWORD_TOO_SHORT',\n severity: 'warning',\n message: `WORKOS_COOKIE_PASSWORD is ${password.length} characters — minimum 32 required for secure encryption`,\n remediation: 'Set WORKOS_COOKIE_PASSWORD to a random string of at least 32 characters.',\n },\n ];\n}\n\nconst REACT_SPA_SDKS = new Set(['@workos-inc/authkit-react']);\n\nfunction checkMissingApiHostname(ctx: CheckContext): AuthPatternFinding[] {\n if (!ctx.sdk.name || !REACT_SPA_SDKS.has(ctx.sdk.name)) return [];\n\n const sourceFiles = findFilesShallow(ctx.installDir, /\\.(tsx|jsx|ts|js)$/, 4);\n const providerFiles = sourceFiles.filter((f) => fileContains(f, /AuthKitProvider/));\n if (providerFiles.length === 0) return [];\n\n const hasApiHostname = providerFiles.some((f) => fileContains(f, /apiHostname/));\n if (hasApiHostname) return [];\n\n return [\n {\n code: 'MISSING_API_HOSTNAME',\n severity: 'warning',\n message: 'AuthKitProvider does not specify apiHostname — authorize requests will route through api.workos.com',\n filePath: relative(ctx.installDir, providerFiles[0]),\n remediation:\n 'Set the apiHostname prop on AuthKitProvider to your custom Authentication API domain (e.g. auth.example.com) to avoid routing through api.workos.com.',\n docsUrl: 'https://workos.com/docs/custom-domains',\n },\n ];\n}\n\n// --- Cross-language checks (run for ALL projects, not just JS/AuthKit) ---\n\nconst SOURCE_EXTENSIONS = /\\.(ts|tsx|js|jsx|py|rb|go|java|kt|php|cs|swift|dart)$/;\nconst SECRET_SOURCE_IGNORED_SEGMENTS = new Set(['__fixtures__', '__tests__', 'evals', 'fixtures', 'test', 'tests']);\n\nfunction isIgnoredSecretSourcePath(relativePath: string): boolean {\n const normalized = relativePath.replace(/\\\\/g, '/');\n const parts = normalized.split('/');\n if (parts.some((part) => SECRET_SOURCE_IGNORED_SEGMENTS.has(part))) return true;\n return /\\.(spec|test)\\.[^.]+$/.test(normalized);\n}\n\nfunction checkApiKeyInSource(ctx: CheckContext): AuthPatternFinding[] {\n const API_KEY_PATTERN = /sk_(test|live)_[A-Za-z0-9]{10,}/;\n const sourceFiles = findFilesShallow(ctx.installDir, SOURCE_EXTENSIONS, 4);\n const findings: AuthPatternFinding[] = [];\n\n for (const file of sourceFiles) {\n const relativePath = relative(ctx.installDir, file);\n if (isIgnoredSecretSourcePath(relativePath)) continue;\n const content = readFileSafe(file);\n if (!content) continue;\n if (API_KEY_PATTERN.test(content)) {\n findings.push({\n code: 'API_KEY_IN_SOURCE',\n severity: 'error',\n message: `WorkOS API key hardcoded in source file`,\n filePath: relativePath,\n remediation:\n 'Move the API key to an environment variable (WORKOS_API_KEY) and load it from .env or your secret manager.',\n });\n }\n }\n return findings;\n}\n\nfunction checkEnvFileNotGitignored(ctx: CheckContext): AuthPatternFinding[] {\n const envFiles = ['.env', '.env.local'].filter((f) => existsSync(join(ctx.installDir, f)));\n if (envFiles.length === 0) return [];\n\n const gitignorePath = join(ctx.installDir, '.gitignore');\n const gitignore = readFileSafe(gitignorePath);\n\n const findings: AuthPatternFinding[] = [];\n for (const envFile of envFiles) {\n const isIgnored =\n gitignore !== null &&\n gitignore.split(/\\r?\\n/).some((line) => {\n const trimmed = line.trim();\n if (trimmed.startsWith('#') || trimmed === '') return false;\n return trimmed === envFile || trimmed === '.env*' || trimmed === '.env.*' || trimmed === '.env';\n });\n\n if (!isIgnored) {\n findings.push({\n code: 'ENV_FILE_NOT_GITIGNORED',\n severity: 'warning',\n message: `${envFile} is not in .gitignore — secrets may be committed to version control`,\n filePath: envFile,\n remediation: `Add ${envFile} to your .gitignore file.`,\n });\n }\n }\n return findings;\n}\n\nfunction checkMixedEnvironmentCredentials(ctx: CheckContext): AuthPatternFinding[] {\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const apiKey = projectEnv.WORKOS_API_KEY;\n const redirectUri = projectEnv.WORKOS_REDIRECT_URI ?? projectEnv.NEXT_PUBLIC_WORKOS_REDIRECT_URI;\n\n if (!apiKey || !redirectUri) return [];\n\n const isTestKey = apiKey.startsWith('sk_test_');\n const isLiveKey = apiKey.startsWith('sk_live_');\n\n let isProductionUri = false;\n try {\n const url = new URL(redirectUri);\n isProductionUri = url.hostname !== 'localhost' && !url.hostname.startsWith('127.0.0.');\n } catch {\n return [];\n }\n\n if (isTestKey && isProductionUri) {\n return [\n {\n code: 'MIXED_ENVIRONMENT',\n severity: 'warning',\n message: 'Staging API key (sk_test_) used with a production redirect URI',\n remediation:\n 'Use sk_live_ API key for production redirect URIs, or change the redirect URI to localhost for staging.',\n },\n ];\n }\n\n if (isLiveKey && !isProductionUri) {\n return [\n {\n code: 'MIXED_ENVIRONMENT',\n severity: 'warning',\n message: 'Production API key (sk_live_) used with a localhost redirect URI',\n remediation:\n 'Use sk_test_ API key for localhost development, or update the redirect URI to your production domain.',\n },\n ];\n }\n\n return [];\n}\n\n// --- Main Entry Point ---\n\ntype CheckFn = (ctx: CheckContext) => AuthPatternFinding[];\n\nconst CROSS_FRAMEWORK_CHECKS: CheckFn[] = [\n checkApiKeyLeakedToClient,\n checkApiKeyInSource,\n checkEnvFileNotGitignored,\n checkMixedEnvironmentCredentials,\n checkMissingApiHostname,\n];\n\nconst NEXTJS_CHECKS: CheckFn[] = [\n checkSignoutGetHandler,\n checkSignoutLinkPrefetch,\n checkMissingMiddleware,\n checkMiddlewareWrongLocation,\n checkMissingAuthKitProvider,\n checkCallbackRouteMissing,\n];\n\nconst REACT_ROUTER_CHECKS: CheckFn[] = [\n checkWrongCallbackLoader,\n checkMissingRootAuthLoader,\n checkMissingAuthKitProvider,\n checkCallbackRouteMissing,\n checkCookiePasswordTooShort,\n];\n\nconst TANSTACK_CHECKS: CheckFn[] = [\n checkMissingAuthkitMiddleware,\n checkCallbackRouteMissing,\n checkCookiePasswordTooShort,\n];\n\nexport async function checkAuthPatterns(\n options: DoctorOptions,\n framework: FrameworkInfo,\n environment: EnvironmentInfo,\n sdk: SdkInfo,\n): Promise<AuthPatternInfo> {\n const ctx: CheckContext = {\n framework,\n environment,\n sdk,\n installDir: options.installDir,\n };\n\n const checks: CheckFn[] = [...CROSS_FRAMEWORK_CHECKS];\n\n switch (framework.name) {\n case 'Next.js':\n checks.push(...NEXTJS_CHECKS);\n break;\n case 'React Router':\n checks.push(...REACT_ROUTER_CHECKS);\n break;\n case 'TanStack Start':\n checks.push(...TANSTACK_CHECKS);\n break;\n }\n\n const findings: AuthPatternFinding[] = [];\n for (const check of checks) {\n findings.push(...check(ctx));\n }\n\n return {\n checksRun: checks.length,\n findings,\n };\n}\n"]}
@@ -2,7 +2,7 @@ import { readFileSync, existsSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  function parseEnvFile(content) {
4
4
  const result = {};
5
- for (const line of content.split('\n')) {
5
+ for (const line of content.split(/\r?\n/)) {
6
6
  const trimmed = line.trim();
7
7
  if (!trimmed || trimmed.startsWith('#'))
8
8
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"environment.js","sourceRoot":"","sources":["../../../src/doctor/checks/environment.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { EnvironmentCheckResult, DoctorOptions } from '../types.js';\n\nfunction parseEnvFile(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n\n // Strip optional `export ` prefix\n const entry = trimmed.startsWith('export ') ? trimmed.slice(7) : trimmed;\n const eqIndex = entry.indexOf('=');\n if (eqIndex === -1) continue;\n\n const key = entry.slice(0, eqIndex).trim();\n let value = entry.slice(eqIndex + 1).trim();\n\n // Remove surrounding quotes (single or double)\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n\n result[key] = value;\n }\n\n return result;\n}\n\n/**\n * Load environment variables from project's .env files.\n * Priority: .env.local > .env (matching Next.js/Vite conventions)\n */\nfunction loadProjectEnv(installDir: string): Record<string, string> {\n const env: Record<string, string> = {};\n\n // Load in order: .env first, then .env.local (later overrides earlier)\n const envFiles = ['.env', '.env.local'];\n\n for (const file of envFiles) {\n const filePath = join(installDir, file);\n if (existsSync(filePath)) {\n try {\n const content = readFileSync(filePath, 'utf-8');\n Object.assign(env, parseEnvFile(content));\n } catch {\n // Ignore read errors\n }\n }\n }\n\n return env;\n}\n\nexport function checkEnvironment(options?: DoctorOptions): EnvironmentCheckResult {\n // Load project env files, then fall back to process.env\n const projectEnv = options?.installDir ? loadProjectEnv(options.installDir) : {};\n\n const apiKey = projectEnv.WORKOS_API_KEY ?? process.env.WORKOS_API_KEY ?? null;\n const clientId = projectEnv.WORKOS_CLIENT_ID ?? process.env.WORKOS_CLIENT_ID ?? null;\n const redirectUri = projectEnv.WORKOS_REDIRECT_URI ?? process.env.WORKOS_REDIRECT_URI ?? null;\n const cookieDomain = projectEnv.WORKOS_COOKIE_DOMAIN ?? process.env.WORKOS_COOKIE_DOMAIN ?? null;\n const baseUrl = projectEnv.WORKOS_BASE_URL ?? process.env.WORKOS_BASE_URL ?? null;\n\n return {\n info: {\n apiKeyConfigured: !!apiKey,\n apiKeyType: getApiKeyType(apiKey),\n clientId: truncateClientId(clientId),\n redirectUri: redirectUri,\n cookieDomain: cookieDomain,\n baseUrl: baseUrl ?? 'https://api.workos.com',\n },\n raw: {\n apiKey,\n clientId,\n baseUrl: baseUrl ?? 'https://api.workos.com',\n },\n };\n}\n\nfunction getApiKeyType(apiKey: string | undefined): 'staging' | 'production' | null {\n if (!apiKey) return null;\n if (apiKey.startsWith('sk_test_')) return 'staging';\n if (apiKey.startsWith('sk_live_')) return 'production';\n return null; // Unknown format\n}\n\nfunction truncateClientId(clientId: string | undefined): string | null {\n if (!clientId) return null;\n if (clientId.length <= 15) return clientId;\n return `${clientId.slice(0, 10)}...${clientId.slice(-3)}`;\n}\n"]}
1
+ {"version":3,"file":"environment.js","sourceRoot":"","sources":["../../../src/doctor/checks/environment.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { EnvironmentCheckResult, DoctorOptions } from '../types.js';\n\nfunction parseEnvFile(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n\n for (const line of content.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n\n // Strip optional `export ` prefix\n const entry = trimmed.startsWith('export ') ? trimmed.slice(7) : trimmed;\n const eqIndex = entry.indexOf('=');\n if (eqIndex === -1) continue;\n\n const key = entry.slice(0, eqIndex).trim();\n let value = entry.slice(eqIndex + 1).trim();\n\n // Remove surrounding quotes (single or double)\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n\n result[key] = value;\n }\n\n return result;\n}\n\n/**\n * Load environment variables from project's .env files.\n * Priority: .env.local > .env (matching Next.js/Vite conventions)\n */\nfunction loadProjectEnv(installDir: string): Record<string, string> {\n const env: Record<string, string> = {};\n\n // Load in order: .env first, then .env.local (later overrides earlier)\n const envFiles = ['.env', '.env.local'];\n\n for (const file of envFiles) {\n const filePath = join(installDir, file);\n if (existsSync(filePath)) {\n try {\n const content = readFileSync(filePath, 'utf-8');\n Object.assign(env, parseEnvFile(content));\n } catch {\n // Ignore read errors\n }\n }\n }\n\n return env;\n}\n\nexport function checkEnvironment(options?: DoctorOptions): EnvironmentCheckResult {\n // Load project env files, then fall back to process.env\n const projectEnv = options?.installDir ? loadProjectEnv(options.installDir) : {};\n\n const apiKey = projectEnv.WORKOS_API_KEY ?? process.env.WORKOS_API_KEY ?? null;\n const clientId = projectEnv.WORKOS_CLIENT_ID ?? process.env.WORKOS_CLIENT_ID ?? null;\n const redirectUri = projectEnv.WORKOS_REDIRECT_URI ?? process.env.WORKOS_REDIRECT_URI ?? null;\n const cookieDomain = projectEnv.WORKOS_COOKIE_DOMAIN ?? process.env.WORKOS_COOKIE_DOMAIN ?? null;\n const baseUrl = projectEnv.WORKOS_BASE_URL ?? process.env.WORKOS_BASE_URL ?? null;\n\n return {\n info: {\n apiKeyConfigured: !!apiKey,\n apiKeyType: getApiKeyType(apiKey),\n clientId: truncateClientId(clientId),\n redirectUri: redirectUri,\n cookieDomain: cookieDomain,\n baseUrl: baseUrl ?? 'https://api.workos.com',\n },\n raw: {\n apiKey,\n clientId,\n baseUrl: baseUrl ?? 'https://api.workos.com',\n },\n };\n}\n\nfunction getApiKeyType(apiKey: string | undefined): 'staging' | 'production' | null {\n if (!apiKey) return null;\n if (apiKey.startsWith('sk_test_')) return 'staging';\n if (apiKey.startsWith('sk_live_')) return 'production';\n return null; // Unknown format\n}\n\nfunction truncateClientId(clientId: string | undefined): string | null {\n if (!clientId) return null;\n if (clientId.length <= 15) return clientId;\n return `${clientId.slice(0, 10)}...${clientId.slice(-3)}`;\n}\n"]}
@@ -1,6 +1,18 @@
1
+ export declare function isSdkException(error: unknown): error is {
2
+ status: number;
3
+ message: string;
4
+ requestID: string;
5
+ code?: string;
6
+ errors?: Array<{
7
+ message: string;
8
+ }>;
9
+ };
1
10
  /**
2
11
  * Create a resource-specific API error handler.
3
- * Handles both raw fetch errors (WorkOSApiError) and SDK exceptions.
4
- * Returns a `never` function that writes structured errors and exits.
12
+ * Handles raw fetch errors (WorkOSApiError), SDK exceptions, and the SDK's
13
+ * "errors is not iterable" TypeError from malformed 422 responses.
14
+ *
15
+ * `context` optionally names the specific resource instance (e.g. a vault
16
+ * object name) so 404 messages can be more specific.
5
17
  */
6
- export declare function createApiErrorHandler(resourceName: string): (error: unknown) => never;
18
+ export declare function createApiErrorHandler(resourceName: string): (error: unknown, context?: string) => never;
@@ -1,57 +1,75 @@
1
1
  import { WorkOSApiError } from './workos-api.js';
2
2
  import { exitWithError } from '../utils/output.js';
3
- /**
4
- * Duck-type check for @workos-inc/node SDK exceptions.
5
- *
6
- * The SDK throws typed errors (UnauthorizedException, NotFoundException, etc.)
7
- * that implement the RequestException interface: { status, message, requestID }.
8
- * We duck-type rather than instanceof to avoid coupling to the SDK's class hierarchy.
9
- */
10
- function isSdkException(error) {
3
+ export function isSdkException(error) {
11
4
  if (!(error instanceof Error))
12
5
  return false;
13
6
  const e = error;
14
7
  return typeof e.status === 'number' && typeof e.requestID === 'string';
15
8
  }
9
+ function normalizeApiError(error) {
10
+ if (error instanceof WorkOSApiError) {
11
+ return {
12
+ status: error.statusCode,
13
+ code: error.code,
14
+ errors: error.errors,
15
+ message: error.message,
16
+ };
17
+ }
18
+ if (isSdkException(error)) {
19
+ return {
20
+ status: error.status,
21
+ code: error.code,
22
+ errors: error.errors,
23
+ message: error.message,
24
+ };
25
+ }
26
+ return null;
27
+ }
28
+ function getApiErrorMessage(error, label) {
29
+ if (error.status === 401)
30
+ return 'Invalid API key. Check your environment configuration.';
31
+ if (error.status === 404)
32
+ return `${label} not found.`;
33
+ if (error.status === 422 && error.errors?.length)
34
+ return error.errors.map((e) => e.message).join(', ');
35
+ return error.message;
36
+ }
16
37
  /**
17
38
  * Create a resource-specific API error handler.
18
- * Handles both raw fetch errors (WorkOSApiError) and SDK exceptions.
19
- * Returns a `never` function that writes structured errors and exits.
39
+ * Handles raw fetch errors (WorkOSApiError), SDK exceptions, and the SDK's
40
+ * "errors is not iterable" TypeError from malformed 422 responses.
41
+ *
42
+ * `context` optionally names the specific resource instance (e.g. a vault
43
+ * object name) so 404 messages can be more specific.
20
44
  */
21
45
  export function createApiErrorHandler(resourceName) {
22
- return (error) => {
23
- // 1. Raw fetch errors (workos-api.ts)
24
- if (error instanceof WorkOSApiError) {
46
+ return (error, context) => {
47
+ if (error instanceof TypeError && error.message.includes('errors is not iterable')) {
25
48
  exitWithError({
26
- code: error.code ?? `http_${error.statusCode}`,
27
- message: error.statusCode === 401
28
- ? 'Invalid API key. Check your environment configuration.'
29
- : error.statusCode === 404
30
- ? `${resourceName} not found.`
31
- : error.statusCode === 422 && error.errors?.length
32
- ? error.errors.map((e) => e.message).join(', ')
33
- : error.message,
34
- details: error.errors,
49
+ code: 'unprocessable_entity',
50
+ message: `${resourceName} API rejected the request. Check that all required fields are provided.`,
51
+ apiContext: { resource: resourceName },
35
52
  });
36
53
  }
37
- // 2. SDK exceptions (@workos-inc/node)
38
- if (isSdkException(error)) {
54
+ const label = context ? `${resourceName} '${context}'` : resourceName;
55
+ const apiError = normalizeApiError(error);
56
+ if (apiError) {
57
+ const code = apiError.code ?? `http_${apiError.status}`;
39
58
  exitWithError({
40
- code: error.code ?? `http_${error.status}`,
41
- message: error.status === 401
42
- ? 'Invalid API key. Check your environment configuration.'
43
- : error.status === 404
44
- ? `${resourceName} not found.`
45
- : error.status === 422 && error.errors?.length
46
- ? error.errors.map((e) => e.message).join(', ')
47
- : error.message,
48
- details: error.errors,
59
+ code,
60
+ message: getApiErrorMessage(apiError, label),
61
+ details: apiError.errors,
62
+ apiContext: {
63
+ status: apiError.status,
64
+ code,
65
+ resource: resourceName,
66
+ },
49
67
  });
50
68
  }
51
- // 3. Fallback
52
69
  exitWithError({
53
70
  code: 'unknown_error',
54
71
  message: error instanceof Error ? error.message : 'Unknown error',
72
+ apiContext: { resource: resourceName },
55
73
  });
56
74
  };
57
75
  }
@@ -1 +1 @@
1
- {"version":3,"file":"api-error-handler.js","sourceRoot":"","sources":["../../src/lib/api-error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;;;GAMG;AACH,SAAS,cAAc,CACrB,KAAc;IAEd,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5C,MAAM,CAAC,GAAG,KAA0D,CAAC;IACrE,OAAO,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,CAAC;AACzE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,YAAoB;IACxD,OAAO,CAAC,KAAc,EAAS,EAAE;QAC/B,sCAAsC;QACtC,IAAI,KAAK,YAAY,cAAc,EAAE,CAAC;YACpC,aAAa,CAAC;gBACZ,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,QAAQ,KAAK,CAAC,UAAU,EAAE;gBAC9C,OAAO,EACL,KAAK,CAAC,UAAU,KAAK,GAAG;oBACtB,CAAC,CAAC,wDAAwD;oBAC1D,CAAC,CAAC,KAAK,CAAC,UAAU,KAAK,GAAG;wBACxB,CAAC,CAAC,GAAG,YAAY,aAAa;wBAC9B,CAAC,CAAC,KAAK,CAAC,UAAU,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,EAAE,MAAM;4BAChD,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;4BAC/C,CAAC,CAAC,KAAK,CAAC,OAAO;gBACvB,OAAO,EAAE,KAAK,CAAC,MAAM;aACtB,CAAC,CAAC;QACL,CAAC;QAED,uCAAuC;QACvC,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,aAAa,CAAC;gBACZ,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,QAAQ,KAAK,CAAC,MAAM,EAAE;gBAC1C,OAAO,EACL,KAAK,CAAC,MAAM,KAAK,GAAG;oBAClB,CAAC,CAAC,wDAAwD;oBAC1D,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,GAAG;wBACpB,CAAC,CAAC,GAAG,YAAY,aAAa;wBAC9B,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,EAAE,MAAM;4BAC5C,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;4BAC/C,CAAC,CAAC,KAAK,CAAC,OAAO;gBACvB,OAAO,EAAE,KAAK,CAAC,MAAM;aACtB,CAAC,CAAC;QACL,CAAC;QAED,cAAc;QACd,aAAa,CAAC;YACZ,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;SAClE,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { WorkOSApiError } from './workos-api.js';\nimport { exitWithError } from '../utils/output.js';\n\n/**\n * Duck-type check for @workos-inc/node SDK exceptions.\n *\n * The SDK throws typed errors (UnauthorizedException, NotFoundException, etc.)\n * that implement the RequestException interface: { status, message, requestID }.\n * We duck-type rather than instanceof to avoid coupling to the SDK's class hierarchy.\n */\nfunction isSdkException(\n error: unknown,\n): error is { status: number; message: string; requestID: string; code?: string; errors?: Array<{ message: string }> } {\n if (!(error instanceof Error)) return false;\n const e = error as Error & { status?: unknown; requestID?: unknown };\n return typeof e.status === 'number' && typeof e.requestID === 'string';\n}\n\n/**\n * Create a resource-specific API error handler.\n * Handles both raw fetch errors (WorkOSApiError) and SDK exceptions.\n * Returns a `never` function that writes structured errors and exits.\n */\nexport function createApiErrorHandler(resourceName: string) {\n return (error: unknown): never => {\n // 1. Raw fetch errors (workos-api.ts)\n if (error instanceof WorkOSApiError) {\n exitWithError({\n code: error.code ?? `http_${error.statusCode}`,\n message:\n error.statusCode === 401\n ? 'Invalid API key. Check your environment configuration.'\n : error.statusCode === 404\n ? `${resourceName} not found.`\n : error.statusCode === 422 && error.errors?.length\n ? error.errors.map((e) => e.message).join(', ')\n : error.message,\n details: error.errors,\n });\n }\n\n // 2. SDK exceptions (@workos-inc/node)\n if (isSdkException(error)) {\n exitWithError({\n code: error.code ?? `http_${error.status}`,\n message:\n error.status === 401\n ? 'Invalid API key. Check your environment configuration.'\n : error.status === 404\n ? `${resourceName} not found.`\n : error.status === 422 && error.errors?.length\n ? error.errors.map((e) => e.message).join(', ')\n : error.message,\n details: error.errors,\n });\n }\n\n // 3. Fallback\n exitWithError({\n code: 'unknown_error',\n message: error instanceof Error ? error.message : 'Unknown error',\n });\n };\n}\n"]}
1
+ {"version":3,"file":"api-error-handler.js","sourceRoot":"","sources":["../../src/lib/api-error-handler.ts"],"names":[],"mappings":"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","sourcesContent":["import { WorkOSApiError } from './workos-api.js';\nimport { exitWithError } from '../utils/output.js';\n\nexport function isSdkException(\n error: unknown,\n): error is { status: number; message: string; requestID: string; code?: string; errors?: Array<{ message: string }> } {\n if (!(error instanceof Error)) return false;\n const e = error as Error & { status?: unknown; requestID?: unknown };\n return typeof e.status === 'number' && typeof e.requestID === 'string';\n}\n\ninterface NormalizedApiError {\n status: number;\n code?: string;\n errors?: Array<{ message: string }>;\n message: string;\n}\n\nfunction normalizeApiError(error: unknown): NormalizedApiError | null {\n if (error instanceof WorkOSApiError) {\n return {\n status: error.statusCode,\n code: error.code,\n errors: error.errors,\n message: error.message,\n };\n }\n\n if (isSdkException(error)) {\n return {\n status: error.status,\n code: error.code,\n errors: error.errors,\n message: error.message,\n };\n }\n\n return null;\n}\n\nfunction getApiErrorMessage(error: NormalizedApiError, label: string): string {\n if (error.status === 401) return 'Invalid API key. Check your environment configuration.';\n if (error.status === 404) return `${label} not found.`;\n if (error.status === 422 && error.errors?.length) return error.errors.map((e) => e.message).join(', ');\n return error.message;\n}\n\n/**\n * Create a resource-specific API error handler.\n * Handles raw fetch errors (WorkOSApiError), SDK exceptions, and the SDK's\n * \"errors is not iterable\" TypeError from malformed 422 responses.\n *\n * `context` optionally names the specific resource instance (e.g. a vault\n * object name) so 404 messages can be more specific.\n */\nexport function createApiErrorHandler(resourceName: string) {\n return (error: unknown, context?: string): never => {\n if (error instanceof TypeError && error.message.includes('errors is not iterable')) {\n exitWithError({\n code: 'unprocessable_entity',\n message: `${resourceName} API rejected the request. Check that all required fields are provided.`,\n apiContext: { resource: resourceName },\n });\n }\n\n const label = context ? `${resourceName} '${context}'` : resourceName;\n const apiError = normalizeApiError(error);\n if (apiError) {\n const code = apiError.code ?? `http_${apiError.status}`;\n exitWithError({\n code,\n message: getApiErrorMessage(apiError, label),\n details: apiError.errors,\n apiContext: {\n status: apiError.status,\n code,\n resource: resourceName,\n },\n });\n }\n\n exitWithError({\n code: 'unknown_error',\n message: error instanceof Error ? error.message : 'Unknown error',\n apiContext: { resource: resourceName },\n });\n };\n}\n"]}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Shared canonical command alias map.
3
+ * Single source of truth for both telemetry and help-json.
4
+ *
5
+ * Keys are user-facing aliases, values are canonical command names.
6
+ * Adding an alias here updates both metrics aggregation and --help --json output.
7
+ */
8
+ export declare const COMMAND_ALIASES: Record<string, string>;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Shared canonical command alias map.
3
+ * Single source of truth for both telemetry and help-json.
4
+ *
5
+ * Keys are user-facing aliases, values are canonical command names.
6
+ * Adding an alias here updates both metrics aggregation and --help --json output.
7
+ */
8
+ export const COMMAND_ALIASES = {
9
+ org: 'organization',
10
+ claim: 'env.claim',
11
+ };
12
+ //# sourceMappingURL=command-aliases.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-aliases.js","sourceRoot":"","sources":["../../src/lib/command-aliases.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAA2B;IACrD,GAAG,EAAE,cAAc;IACnB,KAAK,EAAE,WAAW;CACnB,CAAC","sourcesContent":["/**\n * Shared canonical command alias map.\n * Single source of truth for both telemetry and help-json.\n *\n * Keys are user-facing aliases, values are canonical command names.\n * Adding an alias here updates both metrics aggregation and --help --json output.\n */\nexport const COMMAND_ALIASES: Record<string, string> = {\n org: 'organization',\n claim: 'env.claim',\n};\n"]}