workos 0.6.0 → 0.7.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.
- package/README.md +51 -15
- package/dist/bin.js +151 -0
- package/dist/bin.js.map +1 -1
- package/dist/cli.config.d.ts +1 -0
- package/dist/cli.config.js +1 -0
- package/dist/cli.config.js.map +1 -1
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.js +1 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/env.d.ts +9 -0
- package/dist/commands/env.js +188 -0
- package/dist/commands/env.js.map +1 -0
- package/dist/commands/organization.d.ts +18 -0
- package/dist/commands/organization.js +142 -0
- package/dist/commands/organization.js.map +1 -0
- package/dist/commands/user.d.ts +19 -0
- package/dist/commands/user.js +128 -0
- package/dist/commands/user.js.map +1 -0
- package/dist/dashboard/components/CompletionView.js +5 -1
- package/dist/dashboard/components/CompletionView.js.map +1 -1
- package/dist/doctor/agent-prompt.d.ts +9 -0
- package/dist/doctor/agent-prompt.js +67 -0
- package/dist/doctor/agent-prompt.js.map +1 -0
- package/dist/doctor/checks/ai-analysis.d.ts +9 -0
- package/dist/doctor/checks/ai-analysis.js +122 -0
- package/dist/doctor/checks/ai-analysis.js.map +1 -0
- package/dist/doctor/checks/auth-patterns.d.ts +2 -0
- package/dist/doctor/checks/auth-patterns.js +530 -0
- package/dist/doctor/checks/auth-patterns.js.map +1 -0
- package/dist/doctor/checks/environment.js +22 -4
- package/dist/doctor/checks/environment.js.map +1 -1
- package/dist/doctor/checks/framework.js +27 -8
- package/dist/doctor/checks/framework.js.map +1 -1
- package/dist/doctor/checks/language.d.ts +6 -0
- package/dist/doctor/checks/language.js +104 -0
- package/dist/doctor/checks/language.js.map +1 -0
- package/dist/doctor/checks/sdk.js +113 -22
- package/dist/doctor/checks/sdk.js.map +1 -1
- package/dist/doctor/index.js +26 -3
- package/dist/doctor/index.js.map +1 -1
- package/dist/doctor/issues.js +22 -1
- package/dist/doctor/issues.js.map +1 -1
- package/dist/doctor/output.js +85 -18
- package/dist/doctor/output.js.map +1 -1
- package/dist/doctor/types.d.ts +38 -0
- package/dist/doctor/types.js.map +1 -1
- package/dist/lib/adapters/cli-adapter.js +4 -14
- package/dist/lib/adapters/cli-adapter.js.map +1 -1
- package/dist/lib/adapters/dashboard-adapter.js +3 -16
- package/dist/lib/adapters/dashboard-adapter.js.map +1 -1
- package/dist/lib/api-key.d.ts +13 -0
- package/dist/lib/api-key.js +26 -0
- package/dist/lib/api-key.js.map +1 -0
- package/dist/lib/config-store.d.ts +27 -0
- package/dist/lib/config-store.js +142 -0
- package/dist/lib/config-store.js.map +1 -0
- package/dist/lib/credential-store.d.ts +4 -0
- package/dist/lib/credential-store.js +47 -11
- package/dist/lib/credential-store.js.map +1 -1
- package/dist/lib/credentials.d.ts +1 -1
- package/dist/lib/credentials.js +1 -1
- package/dist/lib/credentials.js.map +1 -1
- package/dist/lib/run-with-core.js +23 -2
- package/dist/lib/run-with-core.js.map +1 -1
- package/dist/lib/settings.d.ts +1 -0
- package/dist/lib/settings.js.map +1 -1
- package/dist/lib/validation/build-validator.js +0 -1
- package/dist/lib/validation/build-validator.js.map +1 -1
- package/dist/lib/validation/quick-checks.js +0 -1
- package/dist/lib/validation/quick-checks.js.map +1 -1
- package/dist/lib/workos-api.d.ts +30 -0
- package/dist/lib/workos-api.js +69 -0
- package/dist/lib/workos-api.js.map +1 -0
- package/dist/utils/cli-symbols.d.ts +1 -1
- package/dist/utils/lock-art.d.ts +4 -0
- package/dist/utils/lock-art.js +73 -0
- package/dist/utils/lock-art.js.map +1 -0
- package/dist/utils/package-json.d.ts +1 -0
- package/dist/utils/package-json.js +11 -0
- package/dist/utils/package-json.js.map +1 -1
- package/dist/utils/summary-box.d.ts +18 -0
- package/dist/utils/summary-box.js +148 -0
- package/dist/utils/summary-box.js.map +1 -0
- package/dist/utils/table.d.ts +5 -0
- package/dist/utils/table.js +18 -0
- package/dist/utils/table.js.map +1 -0
- package/package.json +1 -1
- package/skills/workos-authkit-nextjs/SKILL.md +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"environment.js","sourceRoot":"","sources":["../../../src/doctor/checks/environment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
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 { EnvironmentInfo, 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,7 +1,6 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
import {
|
|
4
|
-
import { hasPackageInstalled, getPackageVersion } from '../../utils/package-json.js';
|
|
3
|
+
import { readPackageJson, hasPackageInstalled, getPackageVersion } from '../../utils/package-json.js';
|
|
5
4
|
import { detectPort, getCallbackPath } from '../../lib/port-detection.js';
|
|
6
5
|
import { KNOWN_INTEGRATIONS } from '../../lib/constants.js';
|
|
7
6
|
// Order matters - more specific frameworks should come first (array guarantees order)
|
|
@@ -28,15 +27,19 @@ const FRAMEWORKS = [
|
|
|
28
27
|
detectVariant: null,
|
|
29
28
|
},
|
|
30
29
|
{ package: 'express', name: 'Express', integration: null, detectVariant: null },
|
|
30
|
+
// Additional JS frameworks (after existing entries to avoid breaking current behavior)
|
|
31
|
+
{ package: 'expo', name: 'Expo', integration: null, detectVariant: detectExpoVariant },
|
|
32
|
+
{ package: 'react-native', name: 'React Native', integration: null, detectVariant: null },
|
|
33
|
+
{ package: '@sveltejs/kit', name: 'SvelteKit', integration: null, detectVariant: null },
|
|
34
|
+
{ package: 'nuxt', name: 'Nuxt', integration: null, detectVariant: detectNuxtVariant },
|
|
35
|
+
{ package: 'vue', name: 'Vue.js', integration: null, detectVariant: null },
|
|
36
|
+
{ package: 'astro', name: 'Astro', integration: null, detectVariant: null },
|
|
37
|
+
{ package: 'svelte', name: 'Svelte', integration: null, detectVariant: null },
|
|
31
38
|
];
|
|
32
39
|
export async function checkFramework(options) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
packageJson = await getPackageDotJson(options);
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
40
|
+
const packageJson = readPackageJson(options.installDir);
|
|
41
|
+
if (!packageJson)
|
|
38
42
|
return { name: null, version: null };
|
|
39
|
-
}
|
|
40
43
|
for (const config of FRAMEWORKS) {
|
|
41
44
|
if (hasPackageInstalled(config.package, packageJson)) {
|
|
42
45
|
const version = getPackageVersion(config.package, packageJson) ?? null;
|
|
@@ -59,6 +62,22 @@ export async function checkFramework(options) {
|
|
|
59
62
|
}
|
|
60
63
|
return { name: null, version: null };
|
|
61
64
|
}
|
|
65
|
+
async function detectExpoVariant(options) {
|
|
66
|
+
const iosDir = join(options.installDir, 'ios');
|
|
67
|
+
const androidDir = join(options.installDir, 'android');
|
|
68
|
+
const hasBare = existsSync(iosDir) || existsSync(androidDir);
|
|
69
|
+
return hasBare ? 'bare' : 'managed';
|
|
70
|
+
}
|
|
71
|
+
async function detectNuxtVariant(options) {
|
|
72
|
+
const packageJson = readPackageJson(options.installDir);
|
|
73
|
+
if (!packageJson)
|
|
74
|
+
return undefined;
|
|
75
|
+
const version = getPackageVersion('nuxt', packageJson);
|
|
76
|
+
if (!version)
|
|
77
|
+
return undefined;
|
|
78
|
+
const major = parseInt(version.replace(/^[\^~>=<]+/, '').split('.')[0], 10);
|
|
79
|
+
return isNaN(major) ? undefined : major >= 3 ? 'Nuxt 3' : 'Nuxt 2';
|
|
80
|
+
}
|
|
62
81
|
async function detectNextVariant(options) {
|
|
63
82
|
const appDir = join(options.installDir, 'app');
|
|
64
83
|
const pagesDir = join(options.installDir, 'pages');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"framework.js","sourceRoot":"","sources":["../../../src/doctor/checks/framework.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"framework.js","sourceRoot":"","sources":["../../../src/doctor/checks/framework.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { readPackageJson, hasPackageInstalled, getPackageVersion } from '../../utils/package-json.js';\nimport { detectPort, getCallbackPath } from '../../lib/port-detection.js';\nimport { KNOWN_INTEGRATIONS } from '../../lib/constants.js';\nimport type { Integration } from '../../lib/constants.js';\nimport type { DoctorOptions, FrameworkInfo } from '../types.js';\n\ninterface FrameworkConfig {\n package: string;\n name: string;\n integration: Integration | null; // Maps to Integration type for callback path/port\n detectVariant: ((options: DoctorOptions) => Promise<string | undefined>) | null;\n}\n\n// Order matters - more specific frameworks should come first (array guarantees order)\nconst FRAMEWORKS: FrameworkConfig[] = [\n { package: 'next', name: 'Next.js', integration: KNOWN_INTEGRATIONS.nextjs, detectVariant: detectNextVariant },\n {\n package: '@tanstack/react-start',\n name: 'TanStack Start',\n integration: KNOWN_INTEGRATIONS.tanstackStart,\n detectVariant: null,\n },\n {\n package: '@tanstack/start',\n name: 'TanStack Start',\n integration: KNOWN_INTEGRATIONS.tanstackStart,\n detectVariant: null,\n },\n { package: '@tanstack/react-router', name: 'TanStack Router', integration: null, detectVariant: null },\n { package: '@remix-run/node', name: 'Remix', integration: null, detectVariant: null },\n {\n package: 'react-router-dom',\n name: 'React Router',\n integration: KNOWN_INTEGRATIONS.reactRouter,\n detectVariant: null,\n },\n { package: 'express', name: 'Express', integration: null, detectVariant: null },\n // Additional JS frameworks (after existing entries to avoid breaking current behavior)\n { package: 'expo', name: 'Expo', integration: null, detectVariant: detectExpoVariant },\n { package: 'react-native', name: 'React Native', integration: null, detectVariant: null },\n { package: '@sveltejs/kit', name: 'SvelteKit', integration: null, detectVariant: null },\n { package: 'nuxt', name: 'Nuxt', integration: null, detectVariant: detectNuxtVariant },\n { package: 'vue', name: 'Vue.js', integration: null, detectVariant: null },\n { package: 'astro', name: 'Astro', integration: null, detectVariant: null },\n { package: 'svelte', name: 'Svelte', integration: null, detectVariant: null },\n];\n\nexport async function checkFramework(options: DoctorOptions): Promise<FrameworkInfo> {\n const packageJson = readPackageJson(options.installDir);\n if (!packageJson) return { name: null, version: null };\n\n for (const config of FRAMEWORKS) {\n if (hasPackageInstalled(config.package, packageJson)) {\n const version = getPackageVersion(config.package, packageJson) ?? null;\n const variant = config.detectVariant ? await config.detectVariant(options) : undefined;\n\n // Get expected callback path and port if we have an integration mapping\n let expectedCallbackPath: string | undefined;\n let detectedPort: number | undefined;\n\n if (config.integration) {\n expectedCallbackPath = getCallbackPath(config.integration);\n detectedPort = detectPort(config.integration, options.installDir);\n }\n\n return {\n name: config.name,\n version,\n variant,\n expectedCallbackPath,\n detectedPort,\n };\n }\n }\n\n return { name: null, version: null };\n}\n\nasync function detectExpoVariant(options: DoctorOptions): Promise<string> {\n const iosDir = join(options.installDir, 'ios');\n const androidDir = join(options.installDir, 'android');\n const hasBare = existsSync(iosDir) || existsSync(androidDir);\n return hasBare ? 'bare' : 'managed';\n}\n\nasync function detectNuxtVariant(options: DoctorOptions): Promise<string | undefined> {\n const packageJson = readPackageJson(options.installDir);\n if (!packageJson) return undefined;\n const version = getPackageVersion('nuxt', packageJson);\n if (!version) return undefined;\n const major = parseInt(version.replace(/^[\\^~>=<]+/, '').split('.')[0], 10);\n return isNaN(major) ? undefined : major >= 3 ? 'Nuxt 3' : 'Nuxt 2';\n}\n\nasync function detectNextVariant(options: DoctorOptions): Promise<string> {\n const appDir = join(options.installDir, 'app');\n const pagesDir = join(options.installDir, 'pages');\n const srcAppDir = join(options.installDir, 'src', 'app');\n const srcPagesDir = join(options.installDir, 'src', 'pages');\n\n const hasAppDir = existsSync(appDir) || existsSync(srcAppDir);\n const hasPagesDir = existsSync(pagesDir) || existsSync(srcPagesDir);\n\n if (hasAppDir && hasPagesDir) return 'hybrid';\n if (hasAppDir) return 'app-router';\n return 'pages-router';\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { LanguageInfo } from '../types.js';
|
|
2
|
+
export declare function checkLanguage(installDir: string): Promise<LanguageInfo>;
|
|
3
|
+
/** Map a LanguageInfo name to the SdkInfo.language string */
|
|
4
|
+
export declare function languageToSdkLanguage(languageName: string): string;
|
|
5
|
+
/** Get the SDK install command for a language */
|
|
6
|
+
export declare function getInstallHint(language: string): string;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { access, readdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
const DETECTORS = [
|
|
4
|
+
{ name: 'Go', language: 'go', manifestFiles: ['go.mod'], packageManager: 'go modules' },
|
|
5
|
+
{ name: 'Ruby', language: 'ruby', manifestFiles: ['Gemfile'], packageManager: 'bundler' },
|
|
6
|
+
{
|
|
7
|
+
name: 'Python',
|
|
8
|
+
language: 'python',
|
|
9
|
+
manifestFiles: ['pyproject.toml', 'requirements.txt', 'setup.py', 'Pipfile'],
|
|
10
|
+
packageManager: 'pip',
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
name: 'Java',
|
|
14
|
+
language: 'java',
|
|
15
|
+
manifestFiles: ['pom.xml', 'build.gradle', 'build.gradle.kts'],
|
|
16
|
+
packageManager: 'maven',
|
|
17
|
+
},
|
|
18
|
+
{ name: 'PHP', language: 'php', manifestFiles: ['composer.json'], packageManager: 'composer' },
|
|
19
|
+
{ name: 'C#/.NET', language: 'dotnet', manifestFiles: [], globPatterns: ['*.csproj', '*.sln'] },
|
|
20
|
+
// JS/TS last — most projects have a package.json even if they're primarily another language
|
|
21
|
+
{ name: 'JavaScript/TypeScript', language: 'javascript', manifestFiles: ['package.json'] },
|
|
22
|
+
];
|
|
23
|
+
async function fileExists(path) {
|
|
24
|
+
try {
|
|
25
|
+
await access(path);
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function findGlobMatch(dir, patterns) {
|
|
33
|
+
try {
|
|
34
|
+
const entries = await readdir(dir);
|
|
35
|
+
for (const pattern of patterns) {
|
|
36
|
+
const ext = pattern.replace('*', '');
|
|
37
|
+
const match = entries.find((e) => e.endsWith(ext));
|
|
38
|
+
if (match)
|
|
39
|
+
return match;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
function detectPythonPackageManager(manifestFile) {
|
|
48
|
+
if (manifestFile === 'pyproject.toml')
|
|
49
|
+
return 'poetry';
|
|
50
|
+
if (manifestFile === 'Pipfile')
|
|
51
|
+
return 'pipenv';
|
|
52
|
+
return 'pip';
|
|
53
|
+
}
|
|
54
|
+
export async function checkLanguage(installDir) {
|
|
55
|
+
for (const detector of DETECTORS) {
|
|
56
|
+
for (const manifest of detector.manifestFiles) {
|
|
57
|
+
const path = join(installDir, manifest);
|
|
58
|
+
if (await fileExists(path)) {
|
|
59
|
+
const pm = detector.language === 'python' ? detectPythonPackageManager(manifest) : detector.packageManager;
|
|
60
|
+
return {
|
|
61
|
+
name: detector.name,
|
|
62
|
+
manifestFile: manifest,
|
|
63
|
+
packageManager: pm,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (detector.globPatterns) {
|
|
68
|
+
const match = await findGlobMatch(installDir, detector.globPatterns);
|
|
69
|
+
if (match) {
|
|
70
|
+
return {
|
|
71
|
+
name: detector.name,
|
|
72
|
+
manifestFile: match,
|
|
73
|
+
packageManager: detector.packageManager,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return { name: 'Unknown' };
|
|
79
|
+
}
|
|
80
|
+
/** Map a LanguageInfo name to the SdkInfo.language string */
|
|
81
|
+
export function languageToSdkLanguage(languageName) {
|
|
82
|
+
const detector = DETECTORS.find((d) => d.name === languageName);
|
|
83
|
+
return detector?.language ?? 'unknown';
|
|
84
|
+
}
|
|
85
|
+
/** Get the SDK install command for a language */
|
|
86
|
+
export function getInstallHint(language) {
|
|
87
|
+
switch (language) {
|
|
88
|
+
case 'python':
|
|
89
|
+
return 'pip install workos';
|
|
90
|
+
case 'ruby':
|
|
91
|
+
return "gem install workos (or add gem 'workos' to Gemfile)";
|
|
92
|
+
case 'go':
|
|
93
|
+
return 'go get github.com/workos/workos-go/v4';
|
|
94
|
+
case 'java':
|
|
95
|
+
return 'Add com.workos:workos-java to your pom.xml or build.gradle';
|
|
96
|
+
case 'php':
|
|
97
|
+
return 'composer require workos/workos-php';
|
|
98
|
+
case 'dotnet':
|
|
99
|
+
return 'dotnet add package WorkOS.net';
|
|
100
|
+
default:
|
|
101
|
+
return 'npm install @workos-inc/authkit-nextjs';
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=language.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"language.js","sourceRoot":"","sources":["../../../src/doctor/checks/language.ts"],"names":[],"mappings":"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","sourcesContent":["import { access, readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { LanguageInfo } from '../types.js';\n\ninterface LanguageDetector {\n name: string;\n language: string; // matches SdkInfo.language\n manifestFiles: string[];\n /** Globs that need special handling (e.g., *.csproj) */\n globPatterns?: string[];\n packageManager?: string;\n}\n\nconst DETECTORS: LanguageDetector[] = [\n { name: 'Go', language: 'go', manifestFiles: ['go.mod'], packageManager: 'go modules' },\n { name: 'Ruby', language: 'ruby', manifestFiles: ['Gemfile'], packageManager: 'bundler' },\n {\n name: 'Python',\n language: 'python',\n manifestFiles: ['pyproject.toml', 'requirements.txt', 'setup.py', 'Pipfile'],\n packageManager: 'pip',\n },\n {\n name: 'Java',\n language: 'java',\n manifestFiles: ['pom.xml', 'build.gradle', 'build.gradle.kts'],\n packageManager: 'maven',\n },\n { name: 'PHP', language: 'php', manifestFiles: ['composer.json'], packageManager: 'composer' },\n { name: 'C#/.NET', language: 'dotnet', manifestFiles: [], globPatterns: ['*.csproj', '*.sln'] },\n // JS/TS last — most projects have a package.json even if they're primarily another language\n { name: 'JavaScript/TypeScript', language: 'javascript', manifestFiles: ['package.json'] },\n];\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function findGlobMatch(dir: string, patterns: string[]): Promise<string | undefined> {\n try {\n const entries = await readdir(dir);\n for (const pattern of patterns) {\n const ext = pattern.replace('*', '');\n const match = entries.find((e) => e.endsWith(ext));\n if (match) return match;\n }\n } catch {\n return undefined;\n }\n return undefined;\n}\n\nfunction detectPythonPackageManager(manifestFile: string): string {\n if (manifestFile === 'pyproject.toml') return 'poetry';\n if (manifestFile === 'Pipfile') return 'pipenv';\n return 'pip';\n}\n\nexport async function checkLanguage(installDir: string): Promise<LanguageInfo> {\n for (const detector of DETECTORS) {\n for (const manifest of detector.manifestFiles) {\n const path = join(installDir, manifest);\n if (await fileExists(path)) {\n const pm = detector.language === 'python' ? detectPythonPackageManager(manifest) : detector.packageManager;\n\n return {\n name: detector.name,\n manifestFile: manifest,\n packageManager: pm,\n };\n }\n }\n\n if (detector.globPatterns) {\n const match = await findGlobMatch(installDir, detector.globPatterns);\n if (match) {\n return {\n name: detector.name,\n manifestFile: match,\n packageManager: detector.packageManager,\n };\n }\n }\n }\n\n return { name: 'Unknown' };\n}\n\n/** Map a LanguageInfo name to the SdkInfo.language string */\nexport function languageToSdkLanguage(languageName: string): string {\n const detector = DETECTORS.find((d) => d.name === languageName);\n return detector?.language ?? 'unknown';\n}\n\n/** Get the SDK install command for a language */\nexport function getInstallHint(language: string): string {\n switch (language) {\n case 'python':\n return 'pip install workos';\n case 'ruby':\n return \"gem install workos (or add gem 'workos' to Gemfile)\";\n case 'go':\n return 'go get github.com/workos/workos-go/v4';\n case 'java':\n return 'Add com.workos:workos-java to your pom.xml or build.gradle';\n case 'php':\n return 'composer require workos/workos-php';\n case 'dotnet':\n return 'dotnet add package WorkOS.net';\n default:\n return 'npm install @workos-inc/authkit-nextjs';\n }\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { readPackageJson, hasPackageInstalled, getPackageVersion } from '../../utils/package-json.js';
|
|
3
4
|
// AuthKit SDKs - check newer @workos/* scope first, then legacy @workos-inc/*
|
|
4
5
|
const SDK_PACKAGES = [
|
|
5
6
|
// New @workos/* scope
|
|
@@ -33,30 +34,22 @@ const AUTHKIT_PACKAGES = new Set([
|
|
|
33
34
|
'@workos-inc/authkit-react',
|
|
34
35
|
'@workos-inc/authkit-js',
|
|
35
36
|
]);
|
|
37
|
+
const NO_SDK = {
|
|
38
|
+
name: null,
|
|
39
|
+
version: null,
|
|
40
|
+
latest: null,
|
|
41
|
+
outdated: false,
|
|
42
|
+
isAuthKit: false,
|
|
43
|
+
language: 'javascript',
|
|
44
|
+
};
|
|
36
45
|
export async function checkSdk(options) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
return {
|
|
43
|
-
name: null,
|
|
44
|
-
version: null,
|
|
45
|
-
latest: null,
|
|
46
|
-
outdated: false,
|
|
47
|
-
isAuthKit: false,
|
|
48
|
-
};
|
|
46
|
+
const packageJson = readPackageJson(options.installDir);
|
|
47
|
+
if (!packageJson) {
|
|
48
|
+
return (await checkNonJsSdk(options.installDir)) ?? NO_SDK;
|
|
49
49
|
}
|
|
50
|
-
// Find installed SDK (order matters—AuthKit before standalone)
|
|
51
50
|
const installedSdk = SDK_PACKAGES.find((pkg) => hasPackageInstalled(pkg, packageJson));
|
|
52
51
|
if (!installedSdk) {
|
|
53
|
-
return
|
|
54
|
-
name: null,
|
|
55
|
-
version: null,
|
|
56
|
-
latest: null,
|
|
57
|
-
outdated: false,
|
|
58
|
-
isAuthKit: false,
|
|
59
|
-
};
|
|
52
|
+
return (await checkNonJsSdk(options.installDir)) ?? NO_SDK;
|
|
60
53
|
}
|
|
61
54
|
const version = getPackageVersion(installedSdk, packageJson) ?? null;
|
|
62
55
|
const latest = await fetchLatestVersion(installedSdk);
|
|
@@ -66,6 +59,7 @@ export async function checkSdk(options) {
|
|
|
66
59
|
latest,
|
|
67
60
|
outdated: version && latest ? isVersionOutdated(version, latest) : false,
|
|
68
61
|
isAuthKit: AUTHKIT_PACKAGES.has(installedSdk),
|
|
62
|
+
language: 'javascript',
|
|
69
63
|
};
|
|
70
64
|
}
|
|
71
65
|
async function fetchLatestVersion(packageName) {
|
|
@@ -85,6 +79,103 @@ async function fetchLatestVersion(packageName) {
|
|
|
85
79
|
return null;
|
|
86
80
|
}
|
|
87
81
|
}
|
|
82
|
+
const NON_JS_DETECTORS = [
|
|
83
|
+
{
|
|
84
|
+
language: 'python',
|
|
85
|
+
file: 'requirements.txt',
|
|
86
|
+
pattern: /^workos(?:-python)?(?:==|>=|~=|!=)?([\d.]*)/m,
|
|
87
|
+
nameExtract: 'workos-python',
|
|
88
|
+
versionGroup: 1,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
language: 'python',
|
|
92
|
+
file: 'pyproject.toml',
|
|
93
|
+
pattern: /workos(?:-python)?/m,
|
|
94
|
+
nameExtract: 'workos-python',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
language: 'ruby',
|
|
98
|
+
file: 'Gemfile',
|
|
99
|
+
pattern: /gem\s+['"]workos(?:-ruby)?['"]/m,
|
|
100
|
+
nameExtract: 'workos-ruby',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
language: 'go',
|
|
104
|
+
file: 'go.mod',
|
|
105
|
+
pattern: /github\.com\/workos\/workos-go(?:\/v\d+)?\s+(v[\d.]+)/m,
|
|
106
|
+
nameExtract: 'workos-go',
|
|
107
|
+
versionGroup: 1,
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
language: 'java',
|
|
111
|
+
file: 'pom.xml',
|
|
112
|
+
pattern: /<groupId>com\.workos<\/groupId>/m,
|
|
113
|
+
nameExtract: 'workos-java',
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
language: 'java',
|
|
117
|
+
file: 'build.gradle',
|
|
118
|
+
pattern: /com\.workos/m,
|
|
119
|
+
nameExtract: 'workos-java',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
language: 'php',
|
|
123
|
+
file: 'composer.json',
|
|
124
|
+
pattern: /"workos\/workos-php"/m,
|
|
125
|
+
nameExtract: 'workos-php',
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
async function readFileSafe(path) {
|
|
129
|
+
try {
|
|
130
|
+
return await readFile(path, 'utf-8');
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async function checkNonJsSdk(installDir) {
|
|
137
|
+
for (const detector of NON_JS_DETECTORS) {
|
|
138
|
+
const content = await readFileSafe(join(installDir, detector.file));
|
|
139
|
+
if (!content)
|
|
140
|
+
continue;
|
|
141
|
+
const match = content.match(detector.pattern);
|
|
142
|
+
if (match) {
|
|
143
|
+
const version = detector.versionGroup ? match[detector.versionGroup] || null : null;
|
|
144
|
+
return {
|
|
145
|
+
name: detector.nameExtract ?? null,
|
|
146
|
+
version,
|
|
147
|
+
latest: null, // No registry checks for non-JS in this phase
|
|
148
|
+
outdated: false,
|
|
149
|
+
isAuthKit: false,
|
|
150
|
+
language: detector.language,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Check .csproj files for .NET (requires directory listing)
|
|
155
|
+
try {
|
|
156
|
+
const entries = await readdir(installDir);
|
|
157
|
+
for (const entry of entries) {
|
|
158
|
+
if (entry.endsWith('.csproj')) {
|
|
159
|
+
const content = await readFileSafe(join(installDir, entry));
|
|
160
|
+
if (content && /PackageReference.*Include="WorkOS\.net"/i.test(content)) {
|
|
161
|
+
const versionMatch = content.match(/Include="WorkOS\.net".*?Version="([\d.]+)"/i);
|
|
162
|
+
return {
|
|
163
|
+
name: 'WorkOS.net',
|
|
164
|
+
version: versionMatch?.[1] ?? null,
|
|
165
|
+
latest: null,
|
|
166
|
+
outdated: false,
|
|
167
|
+
isAuthKit: false,
|
|
168
|
+
language: 'dotnet',
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// directory not readable
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
88
179
|
function isVersionOutdated(current, latest) {
|
|
89
180
|
// Strip semver range prefixes (^, ~, etc.) and workspace protocol
|
|
90
181
|
const cleanCurrent = current.replace(/^[\^~>=<]+/, '').replace(/^workspace:\*?/, '');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.js","sourceRoot":"","sources":["../../../src/doctor/checks/sdk.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAGrF,8EAA8E;AAC9E,MAAM,YAAY,GAAG;IACnB,sBAAsB;IACtB,wBAAwB;IACxB,sCAAsC;IACtC,8BAA8B;IAC9B,uBAAuB;IACvB,2BAA2B;IAC3B,uBAAuB;IACvB,oBAAoB;IACpB,6BAA6B;IAC7B,4BAA4B;IAC5B,2BAA2B;IAC3B,kCAAkC;IAClC,2BAA2B;IAC3B,wBAAwB;IACxB,kBAAkB;IAClB,QAAQ,EAAE,kBAAkB;CACpB,CAAC;AAEX,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAC/B,wBAAwB;IACxB,sCAAsC;IACtC,8BAA8B;IAC9B,uBAAuB;IACvB,2BAA2B;IAC3B,uBAAuB;IACvB,oBAAoB;IACpB,4BAA4B;IAC5B,2BAA2B;IAC3B,kCAAkC;IAClC,2BAA2B;IAC3B,wBAAwB;CACzB,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAsB;IACnD,IAAI,WAAW,CAAC;IAChB,IAAI,CAAC;QACH,WAAW,GAAG,MAAM,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,IAAI;YACZ,QAAQ,EAAE,KAAK;YACf,SAAS,EAAE,KAAK;SACjB,CAAC;IACJ,CAAC;IAED,+DAA+D;IAC/D,MAAM,YAAY,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,mBAAmB,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;IAEvF,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO;YACL,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,IAAI;YACZ,QAAQ,EAAE,KAAK;YACf,SAAS,EAAE,KAAK;SACjB,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,iBAAiB,CAAC,YAAY,EAAE,WAAW,CAAC,IAAI,IAAI,CAAC;IACrE,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,YAAY,CAAC,CAAC;IAEtD,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,OAAO;QACP,MAAM;QACN,QAAQ,EAAE,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;QACxE,SAAS,EAAE,gBAAgB,CAAC,GAAG,CAAC,YAAY,CAAC;KAC9C,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,WAAmB;IACnD,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,CAAC;QAE7D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,8BAA8B,WAAW,SAAS,EAAE;YAC/E,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QAEH,YAAY,CAAC,SAAS,CAAC,CAAC;QAExB,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QAC9B,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAyB,CAAC;QAC7D,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAe,EAAE,MAAc;IACxD,kEAAkE;IAClE,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;IACrF,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAErD,yDAAyD;IACzD,MAAM,CAAC,QAAQ,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3C,MAAM,CAAC,OAAO,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAEzC,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAEhD,wEAAwE;IACxE,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,CAAC,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC;IAChE,MAAM,CAAC,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;IAE5D,IAAI,QAAQ,GAAG,SAAS;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,GAAG,SAAS;QAAE,OAAO,IAAI,CAAC;IAChE,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,GAAG,SAAS;QAAE,OAAO,IAAI,CAAC;IAC1F,OAAO,KAAK,CAAC;AACf,CAAC","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"]}
|
|
1
|
+
{"version":3,"file":"sdk.js","sourceRoot":"","sources":["../../../src/doctor/checks/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile, readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { readPackageJson, 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\nconst NO_SDK: SdkInfo = {\n name: null,\n version: null,\n latest: null,\n outdated: false,\n isAuthKit: false,\n language: 'javascript',\n};\n\nexport async function checkSdk(options: DoctorOptions): Promise<SdkInfo> {\n const packageJson = readPackageJson(options.installDir);\n if (!packageJson) {\n return (await checkNonJsSdk(options.installDir)) ?? NO_SDK;\n }\n\n const installedSdk = SDK_PACKAGES.find((pkg) => hasPackageInstalled(pkg, packageJson));\n if (!installedSdk) {\n return (await checkNonJsSdk(options.installDir)) ?? NO_SDK;\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 language: 'javascript',\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\ninterface NonJsDetector {\n language: string;\n file: string;\n pattern: RegExp;\n nameExtract?: string; // Static SDK name when pattern matches\n versionGroup?: number; // Capture group index for version\n}\n\nconst NON_JS_DETECTORS: NonJsDetector[] = [\n {\n language: 'python',\n file: 'requirements.txt',\n pattern: /^workos(?:-python)?(?:==|>=|~=|!=)?([\\d.]*)/m,\n nameExtract: 'workos-python',\n versionGroup: 1,\n },\n {\n language: 'python',\n file: 'pyproject.toml',\n pattern: /workos(?:-python)?/m,\n nameExtract: 'workos-python',\n },\n {\n language: 'ruby',\n file: 'Gemfile',\n pattern: /gem\\s+['\"]workos(?:-ruby)?['\"]/m,\n nameExtract: 'workos-ruby',\n },\n {\n language: 'go',\n file: 'go.mod',\n pattern: /github\\.com\\/workos\\/workos-go(?:\\/v\\d+)?\\s+(v[\\d.]+)/m,\n nameExtract: 'workos-go',\n versionGroup: 1,\n },\n {\n language: 'java',\n file: 'pom.xml',\n pattern: /<groupId>com\\.workos<\\/groupId>/m,\n nameExtract: 'workos-java',\n },\n {\n language: 'java',\n file: 'build.gradle',\n pattern: /com\\.workos/m,\n nameExtract: 'workos-java',\n },\n {\n language: 'php',\n file: 'composer.json',\n pattern: /\"workos\\/workos-php\"/m,\n nameExtract: 'workos-php',\n },\n];\n\nasync function readFileSafe(path: string): Promise<string | null> {\n try {\n return await readFile(path, 'utf-8');\n } catch {\n return null;\n }\n}\n\nasync function checkNonJsSdk(installDir: string): Promise<SdkInfo | null> {\n for (const detector of NON_JS_DETECTORS) {\n const content = await readFileSafe(join(installDir, detector.file));\n if (!content) continue;\n\n const match = content.match(detector.pattern);\n if (match) {\n const version = detector.versionGroup ? match[detector.versionGroup] || null : null;\n return {\n name: detector.nameExtract ?? null,\n version,\n latest: null, // No registry checks for non-JS in this phase\n outdated: false,\n isAuthKit: false,\n language: detector.language,\n };\n }\n }\n\n // Check .csproj files for .NET (requires directory listing)\n try {\n const entries = await readdir(installDir);\n for (const entry of entries) {\n if (entry.endsWith('.csproj')) {\n const content = await readFileSafe(join(installDir, entry));\n if (content && /PackageReference.*Include=\"WorkOS\\.net\"/i.test(content)) {\n const versionMatch = content.match(/Include=\"WorkOS\\.net\".*?Version=\"([\\d.]+)\"/i);\n return {\n name: 'WorkOS.net',\n version: versionMatch?.[1] ?? null,\n latest: null,\n outdated: false,\n isAuthKit: false,\n language: 'dotnet',\n };\n }\n }\n }\n } catch {\n // directory not readable\n }\n\n return null;\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"]}
|
package/dist/doctor/index.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { checkSdk } from './checks/sdk.js';
|
|
2
2
|
import { checkFramework } from './checks/framework.js';
|
|
3
3
|
import { checkRuntime } from './checks/runtime.js';
|
|
4
|
+
import { checkLanguage } from './checks/language.js';
|
|
4
5
|
import { checkEnvironment } from './checks/environment.js';
|
|
5
6
|
import { checkConnectivity } from './checks/connectivity.js';
|
|
6
7
|
import { checkDashboardSettings, compareRedirectUris } from './checks/dashboard.js';
|
|
8
|
+
import { checkAuthPatterns } from './checks/auth-patterns.js';
|
|
9
|
+
import { checkAiAnalysis } from './checks/ai-analysis.js';
|
|
7
10
|
import { detectIssues } from './issues.js';
|
|
8
11
|
import { formatReport } from './output.js';
|
|
9
12
|
import { formatReportAsJson } from './json-output.js';
|
|
@@ -15,14 +18,31 @@ export async function runDoctor(options) {
|
|
|
15
18
|
// Must run before connectivity so the resolved base URL is available
|
|
16
19
|
const { info: environment, raw: envRaw } = checkEnvironment(options);
|
|
17
20
|
// Run remaining checks concurrently
|
|
18
|
-
const [sdk, framework, runtime, connectivity] = await Promise.all([
|
|
21
|
+
const [sdk, framework, runtime, connectivity, language] = await Promise.all([
|
|
19
22
|
checkSdk(options),
|
|
20
23
|
checkFramework(options),
|
|
21
24
|
checkRuntime(options),
|
|
22
25
|
checkConnectivity(options, environment.baseUrl ?? 'https://api.workos.com'),
|
|
26
|
+
checkLanguage(options.installDir),
|
|
27
|
+
]);
|
|
28
|
+
// Dashboard settings + auth patterns + AI analysis (parallel, all need sdk/framework results)
|
|
29
|
+
// AI analysis also receives early issues as context to avoid duplication
|
|
30
|
+
const earlyIssues = detectIssues({
|
|
31
|
+
version: DOCTOR_VERSION,
|
|
32
|
+
timestamp: '',
|
|
33
|
+
project: { path: options.installDir, packageManager: runtime.packageManager },
|
|
34
|
+
sdk,
|
|
35
|
+
language,
|
|
36
|
+
runtime,
|
|
37
|
+
framework,
|
|
38
|
+
environment,
|
|
39
|
+
connectivity,
|
|
40
|
+
});
|
|
41
|
+
const [dashboardResult, authPatterns, aiAnalysis] = await Promise.all([
|
|
42
|
+
checkDashboardSettings(options, environment.apiKeyType, envRaw),
|
|
43
|
+
checkAuthPatterns(options, framework, environment, sdk),
|
|
44
|
+
checkAiAnalysis({ language, framework, sdk, environment, existingIssues: earlyIssues }, { skipAi: options.skipAi }),
|
|
23
45
|
]);
|
|
24
|
-
// Dashboard settings + credential validation (single pass, staging only)
|
|
25
|
-
const dashboardResult = await checkDashboardSettings(options, environment.apiKeyType, envRaw);
|
|
26
46
|
// Compute expected redirect URI from framework detection if not set in env
|
|
27
47
|
const redirectUriSource = environment.redirectUri ? 'env' : 'inferred';
|
|
28
48
|
const expectedRedirectUri = environment.redirectUri ??
|
|
@@ -42,6 +62,7 @@ export async function runDoctor(options) {
|
|
|
42
62
|
packageManager: runtime.packageManager,
|
|
43
63
|
},
|
|
44
64
|
sdk,
|
|
65
|
+
language,
|
|
45
66
|
runtime,
|
|
46
67
|
framework,
|
|
47
68
|
environment,
|
|
@@ -50,6 +71,8 @@ export async function runDoctor(options) {
|
|
|
50
71
|
dashboardSettings: dashboardResult.settings ?? undefined,
|
|
51
72
|
dashboardError: dashboardResult.settings ? undefined : dashboardResult.error,
|
|
52
73
|
redirectUris,
|
|
74
|
+
authPatterns,
|
|
75
|
+
aiAnalysis,
|
|
53
76
|
};
|
|
54
77
|
// Detect issues based on collected data
|
|
55
78
|
const issues = detectIssues(partialReport);
|
package/dist/doctor/index.js.map
CHANGED
|
@@ -1 +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;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/doctor/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { checkSdk } from './checks/sdk.js';\nimport { checkFramework } from './checks/framework.js';\nimport { checkRuntime } from './checks/runtime.js';\nimport { checkLanguage } from './checks/language.js';\nimport { checkEnvironment } from './checks/environment.js';\nimport { checkConnectivity } from './checks/connectivity.js';\nimport { checkDashboardSettings, compareRedirectUris } from './checks/dashboard.js';\nimport { checkAuthPatterns } from './checks/auth-patterns.js';\nimport { checkAiAnalysis } from './checks/ai-analysis.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, language] = await Promise.all([\n checkSdk(options),\n checkFramework(options),\n checkRuntime(options),\n checkConnectivity(options, environment.baseUrl ?? 'https://api.workos.com'),\n checkLanguage(options.installDir),\n ]);\n\n // Dashboard settings + auth patterns + AI analysis (parallel, all need sdk/framework results)\n // AI analysis also receives early issues as context to avoid duplication\n const earlyIssues = detectIssues({\n version: DOCTOR_VERSION,\n timestamp: '',\n project: { path: options.installDir, packageManager: runtime.packageManager },\n sdk,\n language,\n runtime,\n framework,\n environment,\n connectivity,\n });\n\n const [dashboardResult, authPatterns, aiAnalysis] = await Promise.all([\n checkDashboardSettings(options, environment.apiKeyType, envRaw),\n checkAuthPatterns(options, framework, environment, sdk),\n checkAiAnalysis({ language, framework, sdk, environment, existingIssues: earlyIssues }, { skipAi: options.skipAi }),\n ]);\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 language,\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 authPatterns,\n aiAnalysis,\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"]}
|
package/dist/doctor/issues.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getInstallHint, languageToSdkLanguage } from './checks/language.js';
|
|
1
2
|
export const ISSUE_DEFINITIONS = {
|
|
2
3
|
MISSING_API_KEY: {
|
|
3
4
|
severity: 'error',
|
|
@@ -60,7 +61,15 @@ export function detectIssues(report) {
|
|
|
60
61
|
const issues = [];
|
|
61
62
|
// SDK issues
|
|
62
63
|
if (!report.sdk.name) {
|
|
63
|
-
|
|
64
|
+
const lang = languageToSdkLanguage(report.language.name);
|
|
65
|
+
const hint = getInstallHint(lang);
|
|
66
|
+
issues.push({
|
|
67
|
+
code: 'NO_SDK_FOUND',
|
|
68
|
+
severity: 'error',
|
|
69
|
+
message: 'No WorkOS SDK found in dependencies',
|
|
70
|
+
remediation: `Install a WorkOS SDK: ${hint}`,
|
|
71
|
+
docsUrl: 'https://workos.com/docs',
|
|
72
|
+
});
|
|
64
73
|
}
|
|
65
74
|
else if (report.sdk.outdated && report.sdk.version && report.sdk.latest) {
|
|
66
75
|
issues.push({
|
|
@@ -116,6 +125,18 @@ export function detectIssues(report) {
|
|
|
116
125
|
});
|
|
117
126
|
}
|
|
118
127
|
}
|
|
128
|
+
// Auth pattern findings — map directly to issues
|
|
129
|
+
if (report.authPatterns) {
|
|
130
|
+
for (const finding of report.authPatterns.findings) {
|
|
131
|
+
issues.push({
|
|
132
|
+
code: finding.code,
|
|
133
|
+
severity: finding.severity,
|
|
134
|
+
message: finding.message,
|
|
135
|
+
remediation: finding.remediation,
|
|
136
|
+
docsUrl: finding.docsUrl,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
119
140
|
return issues;
|
|
120
141
|
}
|
|
121
142
|
function getUpdateCommand(packageManager, sdkName) {
|