workos 0.4.5 → 0.5.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 (144) hide show
  1. package/dist/bin.js +32 -3
  2. package/dist/bin.js.map +1 -1
  3. package/dist/commands/doctor.d.ts +10 -0
  4. package/dist/commands/doctor.js +30 -0
  5. package/dist/commands/doctor.js.map +1 -0
  6. package/dist/doctor/checks/connectivity.d.ts +2 -0
  7. package/dist/doctor/checks/connectivity.js +35 -0
  8. package/dist/doctor/checks/connectivity.js.map +1 -0
  9. package/dist/doctor/checks/dashboard.d.ts +3 -0
  10. package/dist/doctor/checks/dashboard.js +123 -0
  11. package/dist/doctor/checks/dashboard.js.map +1 -0
  12. package/dist/doctor/checks/environment.d.ts +2 -0
  13. package/dist/doctor/checks/environment.js +68 -0
  14. package/dist/doctor/checks/environment.js.map +1 -0
  15. package/dist/doctor/checks/framework.d.ts +2 -0
  16. package/dist/doctor/checks/framework.js +75 -0
  17. package/dist/doctor/checks/framework.js.map +1 -0
  18. package/dist/doctor/checks/runtime.d.ts +2 -0
  19. package/dist/doctor/checks/runtime.js +20 -0
  20. package/dist/doctor/checks/runtime.js.map +1 -0
  21. package/dist/doctor/checks/sdk.d.ts +2 -0
  22. package/dist/doctor/checks/sdk.js +111 -0
  23. package/dist/doctor/checks/sdk.js.map +1 -0
  24. package/dist/doctor/clipboard.d.ts +1 -0
  25. package/dist/doctor/clipboard.js +43 -0
  26. package/dist/doctor/clipboard.js.map +1 -0
  27. package/dist/doctor/index.d.ts +6 -0
  28. package/dist/doctor/index.js +94 -0
  29. package/dist/doctor/index.js.map +1 -0
  30. package/dist/doctor/issues.d.ts +58 -0
  31. package/dist/doctor/issues.js +134 -0
  32. package/dist/doctor/issues.js.map +1 -0
  33. package/dist/doctor/json-output.d.ts +2 -0
  34. package/dist/doctor/json-output.js +4 -0
  35. package/dist/doctor/json-output.js.map +1 -0
  36. package/dist/doctor/output.d.ts +5 -0
  37. package/dist/doctor/output.js +149 -0
  38. package/dist/doctor/output.js.map +1 -0
  39. package/dist/doctor/types.d.ts +105 -0
  40. package/dist/doctor/types.js +2 -0
  41. package/dist/doctor/types.js.map +1 -0
  42. package/dist/integrations/dotnet/index.d.ts +8 -0
  43. package/dist/integrations/dotnet/index.js +163 -0
  44. package/dist/integrations/dotnet/index.js.map +1 -0
  45. package/dist/integrations/elixir/index.d.ts +8 -0
  46. package/dist/integrations/elixir/index.js +152 -0
  47. package/dist/integrations/elixir/index.js.map +1 -0
  48. package/dist/integrations/go/index.d.ts +11 -0
  49. package/dist/integrations/go/index.js +220 -0
  50. package/dist/integrations/go/index.js.map +1 -0
  51. package/dist/integrations/kotlin/index.d.ts +4 -0
  52. package/dist/integrations/kotlin/index.js +53 -0
  53. package/dist/integrations/kotlin/index.js.map +1 -0
  54. package/dist/integrations/nextjs/index.d.ts +4 -0
  55. package/dist/integrations/nextjs/index.js +90 -0
  56. package/dist/integrations/nextjs/index.js.map +1 -0
  57. package/dist/integrations/nextjs/utils.d.ts +8 -0
  58. package/dist/integrations/nextjs/utils.js +53 -0
  59. package/dist/integrations/nextjs/utils.js.map +1 -0
  60. package/dist/integrations/node/index.d.ts +4 -0
  61. package/dist/integrations/node/index.js +52 -0
  62. package/dist/integrations/node/index.js.map +1 -0
  63. package/dist/integrations/php/index.d.ts +4 -0
  64. package/dist/integrations/php/index.js +51 -0
  65. package/dist/integrations/php/index.js.map +1 -0
  66. package/dist/integrations/php-laravel/index.d.ts +4 -0
  67. package/dist/integrations/php-laravel/index.js +51 -0
  68. package/dist/integrations/php-laravel/index.js.map +1 -0
  69. package/dist/integrations/python/index.d.ts +9 -0
  70. package/dist/integrations/python/index.js +254 -0
  71. package/dist/integrations/python/index.js.map +1 -0
  72. package/dist/integrations/react/index.d.ts +4 -0
  73. package/dist/integrations/react/index.js +49 -0
  74. package/dist/integrations/react/index.js.map +1 -0
  75. package/dist/integrations/react-router/index.d.ts +4 -0
  76. package/dist/integrations/react-router/index.js +94 -0
  77. package/dist/integrations/react-router/index.js.map +1 -0
  78. package/dist/integrations/react-router/utils.d.ts +10 -0
  79. package/dist/integrations/react-router/utils.js +146 -0
  80. package/dist/integrations/react-router/utils.js.map +1 -0
  81. package/dist/integrations/ruby/index.d.ts +8 -0
  82. package/dist/integrations/ruby/index.js +142 -0
  83. package/dist/integrations/ruby/index.js.map +1 -0
  84. package/dist/integrations/sveltekit/index.d.ts +4 -0
  85. package/dist/integrations/sveltekit/index.js +50 -0
  86. package/dist/integrations/sveltekit/index.js.map +1 -0
  87. package/dist/integrations/tanstack-start/index.d.ts +4 -0
  88. package/dist/integrations/tanstack-start/index.js +51 -0
  89. package/dist/integrations/tanstack-start/index.js.map +1 -0
  90. package/dist/integrations/vanilla-js/index.d.ts +4 -0
  91. package/dist/integrations/vanilla-js/index.js +49 -0
  92. package/dist/integrations/vanilla-js/index.js.map +1 -0
  93. package/dist/lib/agent-interface.js +66 -1
  94. package/dist/lib/agent-interface.js.map +1 -1
  95. package/dist/lib/config.d.ts +32 -58
  96. package/dist/lib/config.js +19 -70
  97. package/dist/lib/config.js.map +1 -1
  98. package/dist/lib/constants.d.ts +17 -14
  99. package/dist/lib/constants.js +12 -31
  100. package/dist/lib/constants.js.map +1 -1
  101. package/dist/lib/framework-config.d.ts +13 -4
  102. package/dist/lib/framework-config.js.map +1 -1
  103. package/dist/lib/language-detection.d.ts +20 -0
  104. package/dist/lib/language-detection.js +96 -0
  105. package/dist/lib/language-detection.js.map +1 -0
  106. package/dist/lib/port-detection.js +4 -2
  107. package/dist/lib/port-detection.js.map +1 -1
  108. package/dist/lib/registry.d.ts +43 -0
  109. package/dist/lib/registry.js +96 -0
  110. package/dist/lib/registry.js.map +1 -0
  111. package/dist/lib/run-with-core.js +70 -26
  112. package/dist/lib/run-with-core.js.map +1 -1
  113. package/dist/nextjs/nextjs-installer-agent.d.ts +3 -4
  114. package/dist/nextjs/nextjs-installer-agent.js +3 -94
  115. package/dist/nextjs/nextjs-installer-agent.js.map +1 -1
  116. package/dist/nextjs/utils.d.ts +4 -8
  117. package/dist/nextjs/utils.js +4 -52
  118. package/dist/nextjs/utils.js.map +1 -1
  119. package/dist/react/react-installer-agent.d.ts +4 -2
  120. package/dist/react/react-installer-agent.js +4 -46
  121. package/dist/react/react-installer-agent.js.map +1 -1
  122. package/dist/react-router/react-router-installer-agent.d.ts +2 -4
  123. package/dist/react-router/react-router-installer-agent.js +2 -100
  124. package/dist/react-router/react-router-installer-agent.js.map +1 -1
  125. package/dist/react-router/utils.d.ts +2 -17
  126. package/dist/react-router/utils.js +2 -207
  127. package/dist/react-router/utils.js.map +1 -1
  128. package/dist/tanstack-start/tanstack-start-installer-agent.d.ts +4 -2
  129. package/dist/tanstack-start/tanstack-start-installer-agent.js +4 -48
  130. package/dist/tanstack-start/tanstack-start-installer-agent.js.map +1 -1
  131. package/dist/vanilla-js/vanilla-js-installer-agent.d.ts +4 -2
  132. package/dist/vanilla-js/vanilla-js-installer-agent.js +4 -46
  133. package/dist/vanilla-js/vanilla-js-installer-agent.js.map +1 -1
  134. package/package.json +6 -5
  135. package/skills/workos-authkit-sveltekit/SKILL.md +160 -0
  136. package/skills/workos-dotnet/SKILL.md +163 -0
  137. package/skills/workos-elixir/SKILL.md +194 -0
  138. package/skills/workos-go/SKILL.md +191 -0
  139. package/skills/workos-kotlin/SKILL.md +161 -0
  140. package/skills/workos-node/SKILL.md +164 -0
  141. package/skills/workos-php/SKILL.md +127 -0
  142. package/skills/workos-php-laravel/SKILL.md +147 -0
  143. package/skills/workos-python/SKILL.md +159 -0
  144. package/skills/workos-ruby/SKILL.md +163 -0
@@ -0,0 +1,111 @@
1
+ import { getPackageDotJson } from '../../utils/clack-utils.js';
2
+ import { hasPackageInstalled, getPackageVersion } from '../../utils/package-json.js';
3
+ // AuthKit SDKs - check newer @workos/* scope first, then legacy @workos-inc/*
4
+ const SDK_PACKAGES = [
5
+ // New @workos/* scope
6
+ '@workos/authkit-nextjs',
7
+ '@workos/authkit-tanstack-react-start',
8
+ '@workos/authkit-react-router',
9
+ '@workos/authkit-remix',
10
+ '@workos/authkit-sveltekit',
11
+ '@workos/authkit-react',
12
+ '@workos/authkit-js',
13
+ // Legacy @workos-inc/* scope
14
+ '@workos-inc/authkit-nextjs',
15
+ '@workos-inc/authkit-remix',
16
+ '@workos-inc/authkit-react-router',
17
+ '@workos-inc/authkit-react',
18
+ '@workos-inc/authkit-js',
19
+ '@workos-inc/node',
20
+ 'workos', // very old legacy
21
+ ];
22
+ const AUTHKIT_PACKAGES = new Set([
23
+ '@workos/authkit-nextjs',
24
+ '@workos/authkit-tanstack-react-start',
25
+ '@workos/authkit-react-router',
26
+ '@workos/authkit-remix',
27
+ '@workos/authkit-sveltekit',
28
+ '@workos/authkit-react',
29
+ '@workos/authkit-js',
30
+ '@workos-inc/authkit-nextjs',
31
+ '@workos-inc/authkit-remix',
32
+ '@workos-inc/authkit-react-router',
33
+ '@workos-inc/authkit-react',
34
+ '@workos-inc/authkit-js',
35
+ ]);
36
+ export async function checkSdk(options) {
37
+ let packageJson;
38
+ try {
39
+ packageJson = await getPackageDotJson(options);
40
+ }
41
+ catch {
42
+ return {
43
+ name: null,
44
+ version: null,
45
+ latest: null,
46
+ outdated: false,
47
+ isAuthKit: false,
48
+ };
49
+ }
50
+ // Find installed SDK (order matters—AuthKit before standalone)
51
+ const installedSdk = SDK_PACKAGES.find((pkg) => hasPackageInstalled(pkg, packageJson));
52
+ if (!installedSdk) {
53
+ return {
54
+ name: null,
55
+ version: null,
56
+ latest: null,
57
+ outdated: false,
58
+ isAuthKit: false,
59
+ };
60
+ }
61
+ const version = getPackageVersion(installedSdk, packageJson) ?? null;
62
+ const latest = await fetchLatestVersion(installedSdk);
63
+ return {
64
+ name: installedSdk,
65
+ version,
66
+ latest,
67
+ outdated: version && latest ? isVersionOutdated(version, latest) : false,
68
+ isAuthKit: AUTHKIT_PACKAGES.has(installedSdk),
69
+ };
70
+ }
71
+ async function fetchLatestVersion(packageName) {
72
+ try {
73
+ const controller = new AbortController();
74
+ const timeoutId = setTimeout(() => controller.abort(), 5000);
75
+ const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`, {
76
+ signal: controller.signal,
77
+ });
78
+ clearTimeout(timeoutId);
79
+ if (!response.ok)
80
+ return null;
81
+ const data = (await response.json());
82
+ return data.version ?? null;
83
+ }
84
+ catch {
85
+ return null;
86
+ }
87
+ }
88
+ function isVersionOutdated(current, latest) {
89
+ // Strip semver range prefixes (^, ~, etc.) and workspace protocol
90
+ const cleanCurrent = current.replace(/^[\^~>=<]+/, '').replace(/^workspace:\*?/, '');
91
+ const cleanLatest = latest.replace(/^[\^~>=<]+/, '');
92
+ // Handle prerelease: "1.0.0-beta.1" → "1.0.0", "-beta.1"
93
+ const [currBase] = cleanCurrent.split('-');
94
+ const [latBase] = cleanLatest.split('-');
95
+ const currParts = currBase.split('.').map(Number);
96
+ const latParts = latBase.split('.').map(Number);
97
+ // If we got NaN values, we can't reliably compare - assume not outdated
98
+ if (currParts.some(isNaN) || latParts.some(isNaN)) {
99
+ return false;
100
+ }
101
+ const [currMajor = 0, currMinor = 0, currPatch = 0] = currParts;
102
+ const [latMajor = 0, latMinor = 0, latPatch = 0] = latParts;
103
+ if (latMajor > currMajor)
104
+ return true;
105
+ if (latMajor === currMajor && latMinor > currMinor)
106
+ return true;
107
+ if (latMajor === currMajor && latMinor === currMinor && latPatch > currPatch)
108
+ return true;
109
+ return false;
110
+ }
111
+ //# sourceMappingURL=sdk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk.js","sourceRoot":"","sources":["../../../src/doctor/checks/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["import { getPackageDotJson } from '../../utils/clack-utils.js';\nimport { hasPackageInstalled, getPackageVersion } from '../../utils/package-json.js';\nimport type { DoctorOptions, SdkInfo } from '../types.js';\n\n// AuthKit SDKs - check newer @workos/* scope first, then legacy @workos-inc/*\nconst SDK_PACKAGES = [\n // New @workos/* scope\n '@workos/authkit-nextjs',\n '@workos/authkit-tanstack-react-start',\n '@workos/authkit-react-router',\n '@workos/authkit-remix',\n '@workos/authkit-sveltekit',\n '@workos/authkit-react',\n '@workos/authkit-js',\n // Legacy @workos-inc/* scope\n '@workos-inc/authkit-nextjs',\n '@workos-inc/authkit-remix',\n '@workos-inc/authkit-react-router',\n '@workos-inc/authkit-react',\n '@workos-inc/authkit-js',\n '@workos-inc/node',\n 'workos', // very old legacy\n] as const;\n\nconst AUTHKIT_PACKAGES = new Set([\n '@workos/authkit-nextjs',\n '@workos/authkit-tanstack-react-start',\n '@workos/authkit-react-router',\n '@workos/authkit-remix',\n '@workos/authkit-sveltekit',\n '@workos/authkit-react',\n '@workos/authkit-js',\n '@workos-inc/authkit-nextjs',\n '@workos-inc/authkit-remix',\n '@workos-inc/authkit-react-router',\n '@workos-inc/authkit-react',\n '@workos-inc/authkit-js',\n]);\n\nexport async function checkSdk(options: DoctorOptions): Promise<SdkInfo> {\n let packageJson;\n try {\n packageJson = await getPackageDotJson(options);\n } catch {\n return {\n name: null,\n version: null,\n latest: null,\n outdated: false,\n isAuthKit: false,\n };\n }\n\n // Find installed SDK (order matters—AuthKit before standalone)\n const installedSdk = SDK_PACKAGES.find((pkg) => hasPackageInstalled(pkg, packageJson));\n\n if (!installedSdk) {\n return {\n name: null,\n version: null,\n latest: null,\n outdated: false,\n isAuthKit: false,\n };\n }\n\n const version = getPackageVersion(installedSdk, packageJson) ?? null;\n const latest = await fetchLatestVersion(installedSdk);\n\n return {\n name: installedSdk,\n version,\n latest,\n outdated: version && latest ? isVersionOutdated(version, latest) : false,\n isAuthKit: AUTHKIT_PACKAGES.has(installedSdk),\n };\n}\n\nasync function fetchLatestVersion(packageName: string): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 5000);\n\n const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`, {\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) return null;\n const data = (await response.json()) as { version?: string };\n return data.version ?? null;\n } catch {\n return null;\n }\n}\n\nfunction isVersionOutdated(current: string, latest: string): boolean {\n // Strip semver range prefixes (^, ~, etc.) and workspace protocol\n const cleanCurrent = current.replace(/^[\\^~>=<]+/, '').replace(/^workspace:\\*?/, '');\n const cleanLatest = latest.replace(/^[\\^~>=<]+/, '');\n\n // Handle prerelease: \"1.0.0-beta.1\" → \"1.0.0\", \"-beta.1\"\n const [currBase] = cleanCurrent.split('-');\n const [latBase] = cleanLatest.split('-');\n\n const currParts = currBase.split('.').map(Number);\n const latParts = latBase.split('.').map(Number);\n\n // If we got NaN values, we can't reliably compare - assume not outdated\n if (currParts.some(isNaN) || latParts.some(isNaN)) {\n return false;\n }\n\n const [currMajor = 0, currMinor = 0, currPatch = 0] = currParts;\n const [latMajor = 0, latMinor = 0, latPatch = 0] = latParts;\n\n if (latMajor > currMajor) return true;\n if (latMajor === currMajor && latMinor > currMinor) return true;\n if (latMajor === currMajor && latMinor === currMinor && latPatch > currPatch) return true;\n return false;\n}\n"]}
@@ -0,0 +1 @@
1
+ export declare function copyToClipboard(text: string): Promise<boolean>;
@@ -0,0 +1,43 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { platform } from 'node:os';
3
+ /**
4
+ * Execute a command with stdin input.
5
+ * Returns true if the command succeeded (exit code 0).
6
+ */
7
+ function execWithStdin(command, args, input) {
8
+ return new Promise((resolve) => {
9
+ const child = spawn(command, args, {
10
+ shell: false,
11
+ stdio: ['pipe', 'ignore', 'ignore'],
12
+ });
13
+ child.on('error', () => resolve(false));
14
+ child.on('close', (code) => resolve(code === 0));
15
+ child.stdin?.write(input);
16
+ child.stdin?.end();
17
+ });
18
+ }
19
+ export async function copyToClipboard(text) {
20
+ const os = platform();
21
+ try {
22
+ if (os === 'darwin') {
23
+ // macOS: use pbcopy
24
+ return await execWithStdin('pbcopy', [], text);
25
+ }
26
+ else if (os === 'linux') {
27
+ // Linux: try xclip first, then xsel
28
+ const xclipResult = await execWithStdin('xclip', ['-selection', 'clipboard'], text);
29
+ if (xclipResult)
30
+ return true;
31
+ return await execWithStdin('xsel', ['--clipboard', '--input'], text);
32
+ }
33
+ else if (os === 'win32') {
34
+ // Windows: use clip.exe
35
+ return await execWithStdin('clip', [], text);
36
+ }
37
+ return false;
38
+ }
39
+ catch {
40
+ return false;
41
+ }
42
+ }
43
+ //# sourceMappingURL=clipboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../src/doctor/clipboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC;;;GAGG;AACH,SAAS,aAAa,CAAC,OAAe,EAAE,IAAc,EAAE,KAAa;IACnE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;YACjC,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QACxC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;QAEjD,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1B,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY;IAChD,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;IAEtB,IAAI,CAAC;QACH,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;YACpB,oBAAoB;YACpB,OAAO,MAAM,aAAa,CAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QACjD,CAAC;aAAM,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;YAC1B,oCAAoC;YACpC,MAAM,WAAW,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC;YACpF,IAAI,WAAW;gBAAE,OAAO,IAAI,CAAC;YAC7B,OAAO,MAAM,aAAa,CAAC,MAAM,EAAE,CAAC,aAAa,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC;QACvE,CAAC;aAAM,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;YAC1B,wBAAwB;YACxB,OAAO,MAAM,aAAa,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QAC/C,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC","sourcesContent":["import { spawn } from 'node:child_process';\nimport { platform } from 'node:os';\n\n/**\n * Execute a command with stdin input.\n * Returns true if the command succeeded (exit code 0).\n */\nfunction execWithStdin(command: string, args: string[], input: string): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn(command, args, {\n shell: false,\n stdio: ['pipe', 'ignore', 'ignore'],\n });\n\n child.on('error', () => resolve(false));\n child.on('close', (code) => resolve(code === 0));\n\n child.stdin?.write(input);\n child.stdin?.end();\n });\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n const os = platform();\n\n try {\n if (os === 'darwin') {\n // macOS: use pbcopy\n return await execWithStdin('pbcopy', [], text);\n } else if (os === 'linux') {\n // Linux: try xclip first, then xsel\n const xclipResult = await execWithStdin('xclip', ['-selection', 'clipboard'], text);\n if (xclipResult) return true;\n return await execWithStdin('xsel', ['--clipboard', '--input'], text);\n } else if (os === 'win32') {\n // Windows: use clip.exe\n return await execWithStdin('clip', [], text);\n }\n return false;\n } catch {\n return false;\n }\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import type { DoctorOptions, DoctorReport } from './types.js';
2
+ export declare function runDoctor(options: DoctorOptions): Promise<DoctorReport>;
3
+ export declare function outputReport(report: DoctorReport, options: DoctorOptions): Promise<void>;
4
+ export { formatReport } from './output.js';
5
+ export { formatReportAsJson } from './json-output.js';
6
+ export type { DoctorReport, DoctorOptions } from './types.js';
@@ -0,0 +1,94 @@
1
+ import { checkSdk } from './checks/sdk.js';
2
+ import { checkFramework } from './checks/framework.js';
3
+ import { checkRuntime } from './checks/runtime.js';
4
+ import { checkEnvironment } from './checks/environment.js';
5
+ import { checkConnectivity } from './checks/connectivity.js';
6
+ import { checkDashboardSettings, compareRedirectUris } from './checks/dashboard.js';
7
+ import { detectIssues } from './issues.js';
8
+ import { formatReport } from './output.js';
9
+ import { formatReportAsJson } from './json-output.js';
10
+ import { copyToClipboard } from './clipboard.js';
11
+ import Chalk from 'chalk';
12
+ const DOCTOR_VERSION = '1.0.0';
13
+ export async function runDoctor(options) {
14
+ // Environment check first - loads project's .env/.env.local files
15
+ // Must run before connectivity so the resolved base URL is available
16
+ const { info: environment, raw: envRaw } = checkEnvironment(options);
17
+ // Run remaining checks concurrently
18
+ const [sdk, framework, runtime, connectivity] = await Promise.all([
19
+ checkSdk(options),
20
+ checkFramework(options),
21
+ checkRuntime(options),
22
+ checkConnectivity(options, environment.baseUrl ?? 'https://api.workos.com'),
23
+ ]);
24
+ // Dashboard settings + credential validation (single pass, staging only)
25
+ const dashboardResult = await checkDashboardSettings(options, environment.apiKeyType, envRaw);
26
+ // Compute expected redirect URI from framework detection if not set in env
27
+ const redirectUriSource = environment.redirectUri ? 'env' : 'inferred';
28
+ const expectedRedirectUri = environment.redirectUri ??
29
+ (framework.expectedCallbackPath && framework.detectedPort
30
+ ? `http://localhost:${framework.detectedPort}${framework.expectedCallbackPath}`
31
+ : null);
32
+ // Compare redirect URIs if we have dashboard data
33
+ const redirectUris = dashboardResult.settings
34
+ ? compareRedirectUris(expectedRedirectUri, dashboardResult.settings.redirectUris, redirectUriSource)
35
+ : undefined;
36
+ // Build partial report
37
+ const partialReport = {
38
+ version: DOCTOR_VERSION,
39
+ timestamp: new Date().toISOString(),
40
+ project: {
41
+ path: options.installDir,
42
+ packageManager: runtime.packageManager,
43
+ },
44
+ sdk,
45
+ runtime,
46
+ framework,
47
+ environment,
48
+ connectivity,
49
+ credentialValidation: dashboardResult.credentialValidation,
50
+ dashboardSettings: dashboardResult.settings ?? undefined,
51
+ dashboardError: dashboardResult.settings ? undefined : dashboardResult.error,
52
+ redirectUris,
53
+ };
54
+ // Detect issues based on collected data
55
+ const issues = detectIssues(partialReport);
56
+ // Calculate summary
57
+ const errors = issues.filter((i) => i.severity === 'error').length;
58
+ const warnings = issues.filter((i) => i.severity === 'warning').length;
59
+ const report = {
60
+ ...partialReport,
61
+ issues,
62
+ summary: {
63
+ errors,
64
+ warnings,
65
+ healthy: errors === 0,
66
+ },
67
+ };
68
+ return report;
69
+ }
70
+ export async function outputReport(report, options) {
71
+ if (options.json) {
72
+ const json = formatReportAsJson(report);
73
+ console.log(json);
74
+ if (options.copy) {
75
+ const success = await copyToClipboard(json);
76
+ if (success) {
77
+ console.error('(Copied to clipboard)');
78
+ }
79
+ }
80
+ }
81
+ else {
82
+ formatReport(report, { verbose: options.verbose });
83
+ if (options.copy) {
84
+ const json = formatReportAsJson(report);
85
+ const success = await copyToClipboard(json);
86
+ if (success) {
87
+ console.log(Chalk.dim('Report copied to clipboard'));
88
+ }
89
+ }
90
+ }
91
+ }
92
+ export { formatReport } from './output.js';
93
+ export { formatReportAsJson } from './json-output.js';
94
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/doctor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAsB;IACpD,kEAAkE;IAClE,qEAAqE;IACrE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAErE,oCAAoC;IACpC,MAAM,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAChE,QAAQ,CAAC,OAAO,CAAC;QACjB,cAAc,CAAC,OAAO,CAAC;QACvB,YAAY,CAAC,OAAO,CAAC;QACrB,iBAAiB,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,IAAI,wBAAwB,CAAC;KAC5E,CAAC,CAAC;IAEH,yEAAyE;IACzE,MAAM,eAAe,GAAG,MAAM,sBAAsB,CAAC,OAAO,EAAE,WAAW,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAE9F,2EAA2E;IAC3E,MAAM,iBAAiB,GAAuB,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;IAC3F,MAAM,mBAAmB,GACvB,WAAW,CAAC,WAAW;QACvB,CAAC,SAAS,CAAC,oBAAoB,IAAI,SAAS,CAAC,YAAY;YACvD,CAAC,CAAC,oBAAoB,SAAS,CAAC,YAAY,GAAG,SAAS,CAAC,oBAAoB,EAAE;YAC/E,CAAC,CAAC,IAAI,CAAC,CAAC;IAEZ,kDAAkD;IAClD,MAAM,YAAY,GAAG,eAAe,CAAC,QAAQ;QAC3C,CAAC,CAAC,mBAAmB,CAAC,mBAAmB,EAAE,eAAe,CAAC,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAAC;QACpG,CAAC,CAAC,SAAS,CAAC;IAEd,uBAAuB;IACvB,MAAM,aAAa,GAAG;QACpB,OAAO,EAAE,cAAc;QACvB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,OAAO,EAAE;YACP,IAAI,EAAE,OAAO,CAAC,UAAU;YACxB,cAAc,EAAE,OAAO,CAAC,cAAc;SACvC;QACD,GAAG;QACH,OAAO;QACP,SAAS;QACT,WAAW;QACX,YAAY;QACZ,oBAAoB,EAAE,eAAe,CAAC,oBAAoB;QAC1D,iBAAiB,EAAE,eAAe,CAAC,QAAQ,IAAI,SAAS;QACxD,cAAc,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK;QAC5E,YAAY;KACb,CAAC;IAEF,wCAAwC;IACxC,MAAM,MAAM,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;IAE3C,oBAAoB;IACpB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IACnE,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IAEvE,MAAM,MAAM,GAAiB;QAC3B,GAAG,aAAa;QAChB,MAAM;QACN,OAAO,EAAE;YACP,MAAM;YACN,QAAQ;YACR,OAAO,EAAE,MAAM,KAAK,CAAC;SACtB;KACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAoB,EAAE,OAAsB;IAC7E,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAElB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,YAAY,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QAEnD,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;YACxC,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC","sourcesContent":["import { checkSdk } from './checks/sdk.js';\nimport { checkFramework } from './checks/framework.js';\nimport { checkRuntime } from './checks/runtime.js';\nimport { checkEnvironment } from './checks/environment.js';\nimport { checkConnectivity } from './checks/connectivity.js';\nimport { checkDashboardSettings, compareRedirectUris } from './checks/dashboard.js';\nimport { detectIssues } from './issues.js';\nimport { formatReport } from './output.js';\nimport { formatReportAsJson } from './json-output.js';\nimport { copyToClipboard } from './clipboard.js';\nimport Chalk from 'chalk';\nimport type { DoctorOptions, DoctorReport } from './types.js';\n\nconst DOCTOR_VERSION = '1.0.0';\n\nexport async function runDoctor(options: DoctorOptions): Promise<DoctorReport> {\n // Environment check first - loads project's .env/.env.local files\n // Must run before connectivity so the resolved base URL is available\n const { info: environment, raw: envRaw } = checkEnvironment(options);\n\n // Run remaining checks concurrently\n const [sdk, framework, runtime, connectivity] = await Promise.all([\n checkSdk(options),\n checkFramework(options),\n checkRuntime(options),\n checkConnectivity(options, environment.baseUrl ?? 'https://api.workos.com'),\n ]);\n\n // Dashboard settings + credential validation (single pass, staging only)\n const dashboardResult = await checkDashboardSettings(options, environment.apiKeyType, envRaw);\n\n // Compute expected redirect URI from framework detection if not set in env\n const redirectUriSource: 'env' | 'inferred' = environment.redirectUri ? 'env' : 'inferred';\n const expectedRedirectUri =\n environment.redirectUri ??\n (framework.expectedCallbackPath && framework.detectedPort\n ? `http://localhost:${framework.detectedPort}${framework.expectedCallbackPath}`\n : null);\n\n // Compare redirect URIs if we have dashboard data\n const redirectUris = dashboardResult.settings\n ? compareRedirectUris(expectedRedirectUri, dashboardResult.settings.redirectUris, redirectUriSource)\n : undefined;\n\n // Build partial report\n const partialReport = {\n version: DOCTOR_VERSION,\n timestamp: new Date().toISOString(),\n project: {\n path: options.installDir,\n packageManager: runtime.packageManager,\n },\n sdk,\n runtime,\n framework,\n environment,\n connectivity,\n credentialValidation: dashboardResult.credentialValidation,\n dashboardSettings: dashboardResult.settings ?? undefined,\n dashboardError: dashboardResult.settings ? undefined : dashboardResult.error,\n redirectUris,\n };\n\n // Detect issues based on collected data\n const issues = detectIssues(partialReport);\n\n // Calculate summary\n const errors = issues.filter((i) => i.severity === 'error').length;\n const warnings = issues.filter((i) => i.severity === 'warning').length;\n\n const report: DoctorReport = {\n ...partialReport,\n issues,\n summary: {\n errors,\n warnings,\n healthy: errors === 0,\n },\n };\n\n return report;\n}\n\nexport async function outputReport(report: DoctorReport, options: DoctorOptions): Promise<void> {\n if (options.json) {\n const json = formatReportAsJson(report);\n console.log(json);\n\n if (options.copy) {\n const success = await copyToClipboard(json);\n if (success) {\n console.error('(Copied to clipboard)');\n }\n }\n } else {\n formatReport(report, { verbose: options.verbose });\n\n if (options.copy) {\n const json = formatReportAsJson(report);\n const success = await copyToClipboard(json);\n if (success) {\n console.log(Chalk.dim('Report copied to clipboard'));\n }\n }\n }\n}\n\nexport { formatReport } from './output.js';\nexport { formatReportAsJson } from './json-output.js';\nexport type { DoctorReport, DoctorOptions } from './types.js';\n"]}
@@ -0,0 +1,58 @@
1
+ import type { Issue, DoctorReport } from './types.js';
2
+ export declare const ISSUE_DEFINITIONS: {
3
+ MISSING_API_KEY: {
4
+ severity: "error";
5
+ message: string;
6
+ remediation: string;
7
+ docsUrl: string;
8
+ };
9
+ MISSING_CLIENT_ID: {
10
+ severity: "error";
11
+ message: string;
12
+ remediation: string;
13
+ docsUrl: string;
14
+ };
15
+ SDK_OUTDATED: {
16
+ severity: "warning";
17
+ message: string;
18
+ };
19
+ COOKIE_DOMAIN_NOT_SET: {
20
+ severity: "warning";
21
+ message: string;
22
+ remediation: string;
23
+ docsUrl: string;
24
+ };
25
+ NO_SDK_FOUND: {
26
+ severity: "error";
27
+ message: string;
28
+ remediation: string;
29
+ docsUrl: string;
30
+ };
31
+ API_UNREACHABLE: {
32
+ severity: "warning";
33
+ message: string;
34
+ };
35
+ REDIRECT_URI_MISMATCH: {
36
+ severity: "warning";
37
+ message: string;
38
+ docsUrl: string;
39
+ };
40
+ PROD_API_CALL_BLOCKED: {
41
+ severity: "warning";
42
+ message: string;
43
+ remediation: string;
44
+ };
45
+ INVALID_API_KEY: {
46
+ severity: "error";
47
+ message: string;
48
+ remediation: string;
49
+ docsUrl: string;
50
+ };
51
+ CLIENT_ID_MISMATCH: {
52
+ severity: "error";
53
+ message: string;
54
+ remediation: string;
55
+ docsUrl: string;
56
+ };
57
+ };
58
+ export declare function detectIssues(report: Omit<DoctorReport, 'issues' | 'summary'>): Issue[];
@@ -0,0 +1,134 @@
1
+ export const ISSUE_DEFINITIONS = {
2
+ MISSING_API_KEY: {
3
+ severity: 'error',
4
+ message: 'WORKOS_API_KEY environment variable not set',
5
+ remediation: 'Set WORKOS_API_KEY in your .env.local file',
6
+ docsUrl: 'https://dashboard.workos.com/api-keys',
7
+ },
8
+ MISSING_CLIENT_ID: {
9
+ severity: 'error',
10
+ message: 'WORKOS_CLIENT_ID environment variable not set',
11
+ remediation: 'Set WORKOS_CLIENT_ID in your .env.local file',
12
+ docsUrl: 'https://dashboard.workos.com/configuration',
13
+ },
14
+ SDK_OUTDATED: {
15
+ severity: 'warning',
16
+ message: 'SDK version is outdated',
17
+ // remediation generated dynamically
18
+ },
19
+ COOKIE_DOMAIN_NOT_SET: {
20
+ severity: 'warning',
21
+ message: 'Cookie domain not explicitly set',
22
+ remediation: 'Consider setting WORKOS_COOKIE_DOMAIN for cross-subdomain auth',
23
+ docsUrl: 'https://workos.com/docs/authkit/cookie-domain',
24
+ },
25
+ NO_SDK_FOUND: {
26
+ severity: 'error',
27
+ message: 'No WorkOS SDK found in dependencies',
28
+ remediation: 'Install a WorkOS SDK: npm install @workos-inc/authkit-nextjs',
29
+ docsUrl: 'https://workos.com/docs',
30
+ },
31
+ API_UNREACHABLE: {
32
+ severity: 'warning',
33
+ message: 'Cannot reach WorkOS API',
34
+ // remediation generated dynamically based on error
35
+ },
36
+ REDIRECT_URI_MISMATCH: {
37
+ severity: 'warning',
38
+ message: 'Redirect URI not found in dashboard configuration',
39
+ docsUrl: 'https://workos.com/docs/authkit/redirect-uri',
40
+ },
41
+ PROD_API_CALL_BLOCKED: {
42
+ severity: 'warning',
43
+ message: 'Dashboard settings not fetched (production API key)',
44
+ remediation: 'Use a staging API key to fetch dashboard settings',
45
+ },
46
+ INVALID_API_KEY: {
47
+ severity: 'error',
48
+ message: 'API key is invalid or expired',
49
+ remediation: 'Check your WORKOS_API_KEY in the WorkOS dashboard',
50
+ docsUrl: 'https://dashboard.workos.com/api-keys',
51
+ },
52
+ CLIENT_ID_MISMATCH: {
53
+ severity: 'error',
54
+ message: 'Client ID does not match the API key environment',
55
+ remediation: 'Ensure WORKOS_CLIENT_ID matches the environment for your API key',
56
+ docsUrl: 'https://dashboard.workos.com/configuration',
57
+ },
58
+ };
59
+ export function detectIssues(report) {
60
+ const issues = [];
61
+ // SDK issues
62
+ if (!report.sdk.name) {
63
+ issues.push({ code: 'NO_SDK_FOUND', ...ISSUE_DEFINITIONS.NO_SDK_FOUND });
64
+ }
65
+ else if (report.sdk.outdated && report.sdk.version && report.sdk.latest) {
66
+ issues.push({
67
+ code: 'SDK_OUTDATED',
68
+ severity: 'warning',
69
+ message: `SDK version outdated (${report.sdk.version} → ${report.sdk.latest})`,
70
+ remediation: `Run: ${getUpdateCommand(report.runtime.packageManager, report.sdk.name)}`,
71
+ details: { installed: report.sdk.version, latest: report.sdk.latest },
72
+ });
73
+ }
74
+ // Environment issues
75
+ if (!report.environment.apiKeyConfigured) {
76
+ issues.push({ code: 'MISSING_API_KEY', ...ISSUE_DEFINITIONS.MISSING_API_KEY });
77
+ }
78
+ if (!report.environment.clientId) {
79
+ issues.push({ code: 'MISSING_CLIENT_ID', ...ISSUE_DEFINITIONS.MISSING_CLIENT_ID });
80
+ }
81
+ if (report.sdk.isAuthKit && !report.environment.cookieDomain) {
82
+ issues.push({ code: 'COOKIE_DOMAIN_NOT_SET', ...ISSUE_DEFINITIONS.COOKIE_DOMAIN_NOT_SET });
83
+ }
84
+ // Connectivity issues
85
+ if (!report.connectivity.apiReachable && !report.connectivity.error?.includes('Skipped')) {
86
+ issues.push({
87
+ code: 'API_UNREACHABLE',
88
+ severity: 'warning',
89
+ message: `Cannot reach WorkOS API: ${report.connectivity.error}`,
90
+ remediation: 'Check your network connection and firewall settings',
91
+ });
92
+ }
93
+ // Note: Redirect URI mismatch detection disabled - WorkOS API doesn't expose
94
+ // a public endpoint to list configured redirect URIs for verification
95
+ // Production key warning (no dashboard data)
96
+ if (report.environment.apiKeyType === 'production' && !report.dashboardSettings) {
97
+ issues.push({
98
+ code: 'PROD_API_CALL_BLOCKED',
99
+ ...ISSUE_DEFINITIONS.PROD_API_CALL_BLOCKED,
100
+ });
101
+ }
102
+ // Credential validation issues
103
+ if (report.credentialValidation) {
104
+ if (!report.credentialValidation.valid) {
105
+ issues.push({
106
+ code: 'INVALID_API_KEY',
107
+ ...ISSUE_DEFINITIONS.INVALID_API_KEY,
108
+ details: { error: report.credentialValidation.error },
109
+ });
110
+ }
111
+ else if (!report.credentialValidation.clientIdMatch) {
112
+ issues.push({
113
+ code: 'CLIENT_ID_MISMATCH',
114
+ ...ISSUE_DEFINITIONS.CLIENT_ID_MISMATCH,
115
+ details: { error: report.credentialValidation.error },
116
+ });
117
+ }
118
+ }
119
+ return issues;
120
+ }
121
+ function getUpdateCommand(packageManager, sdkName) {
122
+ switch (packageManager) {
123
+ case 'pnpm':
124
+ return `pnpm update ${sdkName}`;
125
+ case 'Yarn V1':
126
+ case 'Yarn V2/3/4':
127
+ return `yarn upgrade ${sdkName}`;
128
+ case 'Bun':
129
+ return `bun update ${sdkName}`;
130
+ default:
131
+ return `npm update ${sdkName}`;
132
+ }
133
+ }
134
+ //# sourceMappingURL=issues.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues.js","sourceRoot":"","sources":["../../src/doctor/issues.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Issue, DoctorReport } from './types.js';\n\nexport const ISSUE_DEFINITIONS = {\n MISSING_API_KEY: {\n severity: 'error' as const,\n message: 'WORKOS_API_KEY environment variable not set',\n remediation: 'Set WORKOS_API_KEY in your .env.local file',\n docsUrl: 'https://dashboard.workos.com/api-keys',\n },\n MISSING_CLIENT_ID: {\n severity: 'error' as const,\n message: 'WORKOS_CLIENT_ID environment variable not set',\n remediation: 'Set WORKOS_CLIENT_ID in your .env.local file',\n docsUrl: 'https://dashboard.workos.com/configuration',\n },\n SDK_OUTDATED: {\n severity: 'warning' as const,\n message: 'SDK version is outdated',\n // remediation generated dynamically\n },\n COOKIE_DOMAIN_NOT_SET: {\n severity: 'warning' as const,\n message: 'Cookie domain not explicitly set',\n remediation: 'Consider setting WORKOS_COOKIE_DOMAIN for cross-subdomain auth',\n docsUrl: 'https://workos.com/docs/authkit/cookie-domain',\n },\n NO_SDK_FOUND: {\n severity: 'error' as const,\n message: 'No WorkOS SDK found in dependencies',\n remediation: 'Install a WorkOS SDK: npm install @workos-inc/authkit-nextjs',\n docsUrl: 'https://workos.com/docs',\n },\n API_UNREACHABLE: {\n severity: 'warning' as const,\n message: 'Cannot reach WorkOS API',\n // remediation generated dynamically based on error\n },\n REDIRECT_URI_MISMATCH: {\n severity: 'warning' as const,\n message: 'Redirect URI not found in dashboard configuration',\n docsUrl: 'https://workos.com/docs/authkit/redirect-uri',\n },\n PROD_API_CALL_BLOCKED: {\n severity: 'warning' as const,\n message: 'Dashboard settings not fetched (production API key)',\n remediation: 'Use a staging API key to fetch dashboard settings',\n },\n INVALID_API_KEY: {\n severity: 'error' as const,\n message: 'API key is invalid or expired',\n remediation: 'Check your WORKOS_API_KEY in the WorkOS dashboard',\n docsUrl: 'https://dashboard.workos.com/api-keys',\n },\n CLIENT_ID_MISMATCH: {\n severity: 'error' as const,\n message: 'Client ID does not match the API key environment',\n remediation: 'Ensure WORKOS_CLIENT_ID matches the environment for your API key',\n docsUrl: 'https://dashboard.workos.com/configuration',\n },\n};\n\nexport function detectIssues(report: Omit<DoctorReport, 'issues' | 'summary'>): Issue[] {\n const issues: Issue[] = [];\n\n // SDK issues\n if (!report.sdk.name) {\n issues.push({ code: 'NO_SDK_FOUND', ...ISSUE_DEFINITIONS.NO_SDK_FOUND });\n } else if (report.sdk.outdated && report.sdk.version && report.sdk.latest) {\n issues.push({\n code: 'SDK_OUTDATED',\n severity: 'warning',\n message: `SDK version outdated (${report.sdk.version} → ${report.sdk.latest})`,\n remediation: `Run: ${getUpdateCommand(report.runtime.packageManager, report.sdk.name)}`,\n details: { installed: report.sdk.version, latest: report.sdk.latest },\n });\n }\n\n // Environment issues\n if (!report.environment.apiKeyConfigured) {\n issues.push({ code: 'MISSING_API_KEY', ...ISSUE_DEFINITIONS.MISSING_API_KEY });\n }\n\n if (!report.environment.clientId) {\n issues.push({ code: 'MISSING_CLIENT_ID', ...ISSUE_DEFINITIONS.MISSING_CLIENT_ID });\n }\n\n if (report.sdk.isAuthKit && !report.environment.cookieDomain) {\n issues.push({ code: 'COOKIE_DOMAIN_NOT_SET', ...ISSUE_DEFINITIONS.COOKIE_DOMAIN_NOT_SET });\n }\n\n // Connectivity issues\n if (!report.connectivity.apiReachable && !report.connectivity.error?.includes('Skipped')) {\n issues.push({\n code: 'API_UNREACHABLE',\n severity: 'warning',\n message: `Cannot reach WorkOS API: ${report.connectivity.error}`,\n remediation: 'Check your network connection and firewall settings',\n });\n }\n\n // Note: Redirect URI mismatch detection disabled - WorkOS API doesn't expose\n // a public endpoint to list configured redirect URIs for verification\n\n // Production key warning (no dashboard data)\n if (report.environment.apiKeyType === 'production' && !report.dashboardSettings) {\n issues.push({\n code: 'PROD_API_CALL_BLOCKED',\n ...ISSUE_DEFINITIONS.PROD_API_CALL_BLOCKED,\n });\n }\n\n // Credential validation issues\n if (report.credentialValidation) {\n if (!report.credentialValidation.valid) {\n issues.push({\n code: 'INVALID_API_KEY',\n ...ISSUE_DEFINITIONS.INVALID_API_KEY,\n details: { error: report.credentialValidation.error },\n });\n } else if (!report.credentialValidation.clientIdMatch) {\n issues.push({\n code: 'CLIENT_ID_MISMATCH',\n ...ISSUE_DEFINITIONS.CLIENT_ID_MISMATCH,\n details: { error: report.credentialValidation.error },\n });\n }\n }\n\n return issues;\n}\n\nfunction getUpdateCommand(packageManager: string | null, sdkName: string): string {\n switch (packageManager) {\n case 'pnpm':\n return `pnpm update ${sdkName}`;\n case 'Yarn V1':\n case 'Yarn V2/3/4':\n return `yarn upgrade ${sdkName}`;\n case 'Bun':\n return `bun update ${sdkName}`;\n default:\n return `npm update ${sdkName}`;\n }\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { DoctorReport } from './types.js';
2
+ export declare function formatReportAsJson(report: DoctorReport): string;
@@ -0,0 +1,4 @@
1
+ export function formatReportAsJson(report) {
2
+ return JSON.stringify(report, null, 2);
3
+ }
4
+ //# sourceMappingURL=json-output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-output.js","sourceRoot":"","sources":["../../src/doctor/json-output.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,kBAAkB,CAAC,MAAoB;IACrD,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACzC,CAAC","sourcesContent":["import type { DoctorReport } from './types.js';\n\nexport function formatReportAsJson(report: DoctorReport): string {\n return JSON.stringify(report, null, 2);\n}\n"]}
@@ -0,0 +1,5 @@
1
+ import type { DoctorReport } from './types.js';
2
+ export interface FormatOptions {
3
+ verbose?: boolean;
4
+ }
5
+ export declare function formatReport(report: DoctorReport, options?: FormatOptions): void;