workos 0.3.3 → 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.
- package/dist/bin.js +57 -9
- package/dist/bin.js.map +1 -1
- package/dist/commands/doctor.d.ts +10 -0
- package/dist/commands/doctor.js +30 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/login.js +21 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/doctor/checks/connectivity.d.ts +2 -0
- package/dist/doctor/checks/connectivity.js +35 -0
- package/dist/doctor/checks/connectivity.js.map +1 -0
- package/dist/doctor/checks/dashboard.d.ts +3 -0
- package/dist/doctor/checks/dashboard.js +123 -0
- package/dist/doctor/checks/dashboard.js.map +1 -0
- package/dist/doctor/checks/environment.d.ts +2 -0
- package/dist/doctor/checks/environment.js +68 -0
- package/dist/doctor/checks/environment.js.map +1 -0
- package/dist/doctor/checks/framework.d.ts +2 -0
- package/dist/doctor/checks/framework.js +75 -0
- package/dist/doctor/checks/framework.js.map +1 -0
- package/dist/doctor/checks/runtime.d.ts +2 -0
- package/dist/doctor/checks/runtime.js +20 -0
- package/dist/doctor/checks/runtime.js.map +1 -0
- package/dist/doctor/checks/sdk.d.ts +2 -0
- package/dist/doctor/checks/sdk.js +111 -0
- package/dist/doctor/checks/sdk.js.map +1 -0
- package/dist/doctor/clipboard.d.ts +1 -0
- package/dist/doctor/clipboard.js +43 -0
- package/dist/doctor/clipboard.js.map +1 -0
- package/dist/doctor/index.d.ts +6 -0
- package/dist/doctor/index.js +94 -0
- package/dist/doctor/index.js.map +1 -0
- package/dist/doctor/issues.d.ts +58 -0
- package/dist/doctor/issues.js +134 -0
- package/dist/doctor/issues.js.map +1 -0
- package/dist/doctor/json-output.d.ts +2 -0
- package/dist/doctor/json-output.js +4 -0
- package/dist/doctor/json-output.js.map +1 -0
- package/dist/doctor/output.d.ts +5 -0
- package/dist/doctor/output.js +149 -0
- package/dist/doctor/output.js.map +1 -0
- package/dist/doctor/types.d.ts +105 -0
- package/dist/doctor/types.js +2 -0
- package/dist/doctor/types.js.map +1 -0
- package/dist/integrations/dotnet/index.d.ts +8 -0
- package/dist/integrations/dotnet/index.js +163 -0
- package/dist/integrations/dotnet/index.js.map +1 -0
- package/dist/integrations/elixir/index.d.ts +8 -0
- package/dist/integrations/elixir/index.js +152 -0
- package/dist/integrations/elixir/index.js.map +1 -0
- package/dist/integrations/go/index.d.ts +11 -0
- package/dist/integrations/go/index.js +220 -0
- package/dist/integrations/go/index.js.map +1 -0
- package/dist/integrations/kotlin/index.d.ts +4 -0
- package/dist/integrations/kotlin/index.js +53 -0
- package/dist/integrations/kotlin/index.js.map +1 -0
- package/dist/integrations/nextjs/index.d.ts +4 -0
- package/dist/integrations/nextjs/index.js +90 -0
- package/dist/integrations/nextjs/index.js.map +1 -0
- package/dist/integrations/nextjs/utils.d.ts +8 -0
- package/dist/integrations/nextjs/utils.js +53 -0
- package/dist/integrations/nextjs/utils.js.map +1 -0
- package/dist/integrations/node/index.d.ts +4 -0
- package/dist/integrations/node/index.js +52 -0
- package/dist/integrations/node/index.js.map +1 -0
- package/dist/integrations/php/index.d.ts +4 -0
- package/dist/integrations/php/index.js +51 -0
- package/dist/integrations/php/index.js.map +1 -0
- package/dist/integrations/php-laravel/index.d.ts +4 -0
- package/dist/integrations/php-laravel/index.js +51 -0
- package/dist/integrations/php-laravel/index.js.map +1 -0
- package/dist/integrations/python/index.d.ts +9 -0
- package/dist/integrations/python/index.js +254 -0
- package/dist/integrations/python/index.js.map +1 -0
- package/dist/integrations/react/index.d.ts +4 -0
- package/dist/integrations/react/index.js +49 -0
- package/dist/integrations/react/index.js.map +1 -0
- package/dist/integrations/react-router/index.d.ts +4 -0
- package/dist/integrations/react-router/index.js +94 -0
- package/dist/integrations/react-router/index.js.map +1 -0
- package/dist/integrations/react-router/utils.d.ts +10 -0
- package/dist/integrations/react-router/utils.js +146 -0
- package/dist/integrations/react-router/utils.js.map +1 -0
- package/dist/integrations/ruby/index.d.ts +8 -0
- package/dist/integrations/ruby/index.js +142 -0
- package/dist/integrations/ruby/index.js.map +1 -0
- package/dist/integrations/sveltekit/index.d.ts +4 -0
- package/dist/integrations/sveltekit/index.js +50 -0
- package/dist/integrations/sveltekit/index.js.map +1 -0
- package/dist/integrations/tanstack-start/index.d.ts +4 -0
- package/dist/integrations/tanstack-start/index.js +51 -0
- package/dist/integrations/tanstack-start/index.js.map +1 -0
- package/dist/integrations/vanilla-js/index.d.ts +4 -0
- package/dist/integrations/vanilla-js/index.js +49 -0
- package/dist/integrations/vanilla-js/index.js.map +1 -0
- package/dist/lib/agent-interface.js +66 -1
- package/dist/lib/agent-interface.js.map +1 -1
- package/dist/lib/config.d.ts +32 -58
- package/dist/lib/config.js +19 -70
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/constants.d.ts +17 -14
- package/dist/lib/constants.js +12 -31
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/credential-store.d.ts +28 -0
- package/dist/lib/credential-store.js +150 -0
- package/dist/lib/credential-store.js.map +1 -0
- package/dist/lib/credentials.d.ts +3 -37
- package/dist/lib/credentials.js +2 -85
- package/dist/lib/credentials.js.map +1 -1
- package/dist/lib/framework-config.d.ts +13 -4
- package/dist/lib/framework-config.js.map +1 -1
- package/dist/lib/language-detection.d.ts +20 -0
- package/dist/lib/language-detection.js +96 -0
- package/dist/lib/language-detection.js.map +1 -0
- package/dist/lib/port-detection.js +4 -2
- package/dist/lib/port-detection.js.map +1 -1
- package/dist/lib/registry.d.ts +43 -0
- package/dist/lib/registry.js +96 -0
- package/dist/lib/registry.js.map +1 -0
- package/dist/lib/run-with-core.js +70 -26
- package/dist/lib/run-with-core.js.map +1 -1
- package/dist/nextjs/nextjs-installer-agent.d.ts +3 -4
- package/dist/nextjs/nextjs-installer-agent.js +3 -94
- package/dist/nextjs/nextjs-installer-agent.js.map +1 -1
- package/dist/nextjs/utils.d.ts +4 -8
- package/dist/nextjs/utils.js +4 -52
- package/dist/nextjs/utils.js.map +1 -1
- package/dist/react/react-installer-agent.d.ts +4 -2
- package/dist/react/react-installer-agent.js +4 -46
- package/dist/react/react-installer-agent.js.map +1 -1
- package/dist/react-router/react-router-installer-agent.d.ts +2 -4
- package/dist/react-router/react-router-installer-agent.js +2 -100
- package/dist/react-router/react-router-installer-agent.js.map +1 -1
- package/dist/react-router/utils.d.ts +2 -17
- package/dist/react-router/utils.js +2 -207
- package/dist/react-router/utils.js.map +1 -1
- package/dist/tanstack-start/tanstack-start-installer-agent.d.ts +4 -2
- package/dist/tanstack-start/tanstack-start-installer-agent.js +4 -48
- package/dist/tanstack-start/tanstack-start-installer-agent.js.map +1 -1
- package/dist/vanilla-js/vanilla-js-installer-agent.d.ts +4 -2
- package/dist/vanilla-js/vanilla-js-installer-agent.js +4 -46
- package/dist/vanilla-js/vanilla-js-installer-agent.js.map +1 -1
- package/package.json +9 -6
- package/skills/workos-authkit-sveltekit/SKILL.md +160 -0
- package/skills/workos-dotnet/SKILL.md +163 -0
- package/skills/workos-elixir/SKILL.md +194 -0
- package/skills/workos-go/SKILL.md +191 -0
- package/skills/workos-kotlin/SKILL.md +161 -0
- package/skills/workos-node/SKILL.md +164 -0
- package/skills/workos-php/SKILL.md +127 -0
- package/skills/workos-php-laravel/SKILL.md +147 -0
- package/skills/workos-python/SKILL.md +159 -0
- package/skills/workos-ruby/SKILL.md +163 -0
package/dist/bin.js
CHANGED
|
@@ -7,7 +7,7 @@ if (process.argv.includes('--local') || process.env.INSTALLER_DEV) {
|
|
|
7
7
|
}
|
|
8
8
|
import { satisfies } from 'semver';
|
|
9
9
|
import { red } from './utils/logging.js';
|
|
10
|
-
import { getConfig } from './lib/settings.js';
|
|
10
|
+
import { getConfig, getVersion } from './lib/settings.js';
|
|
11
11
|
import yargs from 'yargs';
|
|
12
12
|
import { hideBin } from 'yargs/helpers';
|
|
13
13
|
import { ensureAuthenticated } from './lib/ensure-auth.js';
|
|
@@ -21,7 +21,21 @@ if (!satisfies(process.version, NODE_VERSION_RANGE)) {
|
|
|
21
21
|
}
|
|
22
22
|
import { isNonInteractiveEnvironment } from './utils/environment.js';
|
|
23
23
|
import clack from './utils/clack.js';
|
|
24
|
-
|
|
24
|
+
/** Apply insecure storage flag if set */
|
|
25
|
+
async function applyInsecureStorage(insecureStorage) {
|
|
26
|
+
if (insecureStorage) {
|
|
27
|
+
const { setInsecureStorage } = await import('./lib/credentials.js');
|
|
28
|
+
setInsecureStorage(true);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** Shared insecure-storage option for commands that access credentials */
|
|
32
|
+
const insecureStorageOption = {
|
|
33
|
+
'insecure-storage': {
|
|
34
|
+
default: false,
|
|
35
|
+
describe: 'Store credentials in plaintext file instead of system keyring',
|
|
36
|
+
type: 'boolean',
|
|
37
|
+
},
|
|
38
|
+
};
|
|
25
39
|
/**
|
|
26
40
|
* Wrap a command handler with authentication check.
|
|
27
41
|
* Ensures valid auth before executing the handler.
|
|
@@ -29,9 +43,10 @@ import clack from './utils/clack.js';
|
|
|
29
43
|
*/
|
|
30
44
|
function withAuth(handler) {
|
|
31
45
|
return async (argv) => {
|
|
32
|
-
|
|
46
|
+
const typedArgv = argv;
|
|
47
|
+
await applyInsecureStorage(typedArgv.insecureStorage);
|
|
48
|
+
if (!typedArgv.skipAuth)
|
|
33
49
|
await ensureAuthenticated();
|
|
34
|
-
}
|
|
35
50
|
await handler(argv);
|
|
36
51
|
};
|
|
37
52
|
}
|
|
@@ -47,6 +62,7 @@ const installerOptions = {
|
|
|
47
62
|
describe: 'Enable verbose logging',
|
|
48
63
|
type: 'boolean',
|
|
49
64
|
},
|
|
65
|
+
...insecureStorageOption,
|
|
50
66
|
// Hidden dev/automation flags (use env vars)
|
|
51
67
|
local: {
|
|
52
68
|
default: false,
|
|
@@ -96,7 +112,6 @@ const installerOptions = {
|
|
|
96
112
|
},
|
|
97
113
|
integration: {
|
|
98
114
|
describe: 'Integration to set up',
|
|
99
|
-
choices: ['nextjs', 'react', 'tanstack-start', 'react-router', 'vanilla-js'],
|
|
100
115
|
type: 'string',
|
|
101
116
|
},
|
|
102
117
|
'force-install': {
|
|
@@ -115,12 +130,14 @@ const installerOptions = {
|
|
|
115
130
|
await checkForUpdates();
|
|
116
131
|
yargs(hideBin(process.argv))
|
|
117
132
|
.env('WORKOS_INSTALLER')
|
|
118
|
-
.command('login', 'Authenticate with WorkOS',
|
|
133
|
+
.command('login', 'Authenticate with WorkOS', insecureStorageOption, async (argv) => {
|
|
134
|
+
await applyInsecureStorage(argv.insecureStorage);
|
|
119
135
|
const { runLogin } = await import('./commands/login.js');
|
|
120
136
|
await runLogin();
|
|
121
137
|
process.exit(0);
|
|
122
138
|
})
|
|
123
|
-
.command('logout', 'Remove stored credentials',
|
|
139
|
+
.command('logout', 'Remove stored credentials', insecureStorageOption, async (argv) => {
|
|
140
|
+
await applyInsecureStorage(argv.insecureStorage);
|
|
124
141
|
const { runLogout } = await import('./commands/logout.js');
|
|
125
142
|
await runLogout();
|
|
126
143
|
})
|
|
@@ -151,6 +168,36 @@ yargs(hideBin(process.argv))
|
|
|
151
168
|
agent: argv.agent,
|
|
152
169
|
});
|
|
153
170
|
}))
|
|
171
|
+
.command('doctor', 'Diagnose WorkOS integration issues', (yargs) => yargs.options({
|
|
172
|
+
verbose: {
|
|
173
|
+
type: 'boolean',
|
|
174
|
+
default: false,
|
|
175
|
+
description: 'Include additional diagnostic information',
|
|
176
|
+
},
|
|
177
|
+
'skip-api': {
|
|
178
|
+
type: 'boolean',
|
|
179
|
+
default: false,
|
|
180
|
+
description: 'Skip API calls (offline mode)',
|
|
181
|
+
},
|
|
182
|
+
'install-dir': {
|
|
183
|
+
type: 'string',
|
|
184
|
+
default: process.cwd(),
|
|
185
|
+
description: 'Project directory to analyze',
|
|
186
|
+
},
|
|
187
|
+
json: {
|
|
188
|
+
type: 'boolean',
|
|
189
|
+
default: false,
|
|
190
|
+
description: 'Output report as JSON',
|
|
191
|
+
},
|
|
192
|
+
copy: {
|
|
193
|
+
type: 'boolean',
|
|
194
|
+
default: false,
|
|
195
|
+
description: 'Copy report to clipboard',
|
|
196
|
+
},
|
|
197
|
+
}), async (argv) => {
|
|
198
|
+
const { handleDoctor } = await import('./commands/doctor.js');
|
|
199
|
+
await handleDoctor(argv);
|
|
200
|
+
})
|
|
154
201
|
.command('install', 'Install WorkOS AuthKit into your project', (yargs) => yargs.options(installerOptions), withAuth(async (argv) => {
|
|
155
202
|
const { handleInstall } = await import('./commands/install.js');
|
|
156
203
|
await handleInstall(argv);
|
|
@@ -160,7 +207,7 @@ yargs(hideBin(process.argv))
|
|
|
160
207
|
const { handleInstall } = await import('./commands/install.js');
|
|
161
208
|
await handleInstall({ ...argv, dashboard: true });
|
|
162
209
|
}))
|
|
163
|
-
.command(['$0'], 'WorkOS AuthKit CLI', (yargs) => yargs, async () => {
|
|
210
|
+
.command(['$0'], 'WorkOS AuthKit CLI', (yargs) => yargs.options(insecureStorageOption), async (argv) => {
|
|
164
211
|
// Non-TTY: show help
|
|
165
212
|
if (isNonInteractiveEnvironment()) {
|
|
166
213
|
yargs(hideBin(process.argv)).showHelp();
|
|
@@ -174,6 +221,7 @@ yargs(hideBin(process.argv))
|
|
|
174
221
|
process.exit(0);
|
|
175
222
|
}
|
|
176
223
|
// Auth check happens HERE, after user confirms
|
|
224
|
+
await applyInsecureStorage(argv.insecureStorage);
|
|
177
225
|
await ensureAuthenticated();
|
|
178
226
|
const { handleInstall } = await import('./commands/install.js');
|
|
179
227
|
await handleInstall({ dashboard: false });
|
|
@@ -182,7 +230,7 @@ yargs(hideBin(process.argv))
|
|
|
182
230
|
.strict()
|
|
183
231
|
.help()
|
|
184
232
|
.alias('help', 'h')
|
|
185
|
-
.version()
|
|
233
|
+
.version(getVersion())
|
|
186
234
|
.alias('version', 'v')
|
|
187
235
|
.wrap(process.stdout.isTTY && process.stdout.columns ? process.stdout.columns : 80).argv;
|
|
188
236
|
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n\n// Load .env.local for local development when --local flag is used\nif (process.argv.includes('--local') || process.env.INSTALLER_DEV) {\n const { config } = await import('dotenv');\n // bin.ts compiles to dist/bin.js, so go up one level to find .env.local\n config({ path: new URL('../.env.local', import.meta.url).pathname });\n}\n\nimport { satisfies } from 'semver';\nimport { red } from './utils/logging.js';\nimport { getConfig } from './lib/settings.js';\n\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport chalk from 'chalk';\nimport { ensureAuthenticated } from './lib/ensure-auth.js';\nimport { checkForUpdates } from './lib/version-check.js';\n\nconst NODE_VERSION_RANGE = getConfig().nodeVersion;\n\n// Have to run this above the other imports because they are importing clack that\n// has the problematic imports.\nif (!satisfies(process.version, NODE_VERSION_RANGE)) {\n red(\n `WorkOS AuthKit installer requires Node.js ${NODE_VERSION_RANGE}. You are using Node.js ${process.version}. Please upgrade your Node.js version.`,\n );\n process.exit(1);\n}\n\nimport { isNonInteractiveEnvironment } from './utils/environment.js';\nimport clack from './utils/clack.js';\n\n// Shared options for wizard commands (default and dashboard)\n/**\n * Wrap a command handler with authentication check.\n * Ensures valid auth before executing the handler.\n * Respects --skip-auth flag for CI/testing.\n */\nfunction withAuth<T>(handler: (argv: T) => Promise<void>): (argv: T) => Promise<void> {\n return async (argv: T) => {\n if (!(argv as { skipAuth?: boolean }).skipAuth) {\n await ensureAuthenticated();\n }\n await handler(argv);\n };\n}\n\nconst installerOptions = {\n direct: {\n alias: 'D',\n default: false,\n describe: 'Use your own Anthropic API key (bypass llm-gateway)',\n type: 'boolean' as const,\n },\n debug: {\n default: false,\n describe: 'Enable verbose logging',\n type: 'boolean' as const,\n },\n // Hidden dev/automation flags (use env vars)\n local: {\n default: false,\n type: 'boolean' as const,\n hidden: true,\n },\n ci: {\n default: false,\n type: 'boolean' as const,\n hidden: true,\n },\n 'skip-auth': {\n default: false,\n type: 'boolean' as const,\n hidden: true,\n },\n 'api-key': {\n type: 'string' as const,\n hidden: true,\n },\n 'client-id': {\n type: 'string' as const,\n hidden: true,\n },\n inspect: {\n default: false,\n type: 'boolean' as const,\n hidden: true,\n },\n // User-facing flags\n 'homepage-url': {\n describe: 'App homepage URL for WorkOS (defaults to http://localhost:{port})',\n type: 'string' as const,\n },\n 'redirect-uri': {\n describe: 'Redirect URI for WorkOS callback (defaults to framework convention)',\n type: 'string' as const,\n },\n 'no-validate': {\n default: false,\n describe: 'Skip post-installation validation (includes build check)',\n type: 'boolean' as const,\n },\n 'install-dir': {\n describe: 'Directory to install WorkOS AuthKit in',\n type: 'string' as const,\n },\n integration: {\n describe: 'Integration to set up',\n choices: ['nextjs', 'react', 'tanstack-start', 'react-router', 'vanilla-js'] as const,\n type: 'string' as const,\n },\n 'force-install': {\n default: false,\n describe: 'Force install packages even if peer dependency checks fail',\n type: 'boolean' as const,\n },\n dashboard: {\n alias: 'd',\n default: false,\n describe: 'Run with visual dashboard mode',\n type: 'boolean' as const,\n },\n};\n\n// Check for updates (blocks up to 500ms)\nawait checkForUpdates();\n\nyargs(hideBin(process.argv))\n .env('WORKOS_INSTALLER')\n .command('login', 'Authenticate with WorkOS', {}, async () => {\n const { runLogin } = await import('./commands/login.js');\n await runLogin();\n process.exit(0);\n })\n .command('logout', 'Remove stored credentials', {}, async () => {\n const { runLogout } = await import('./commands/logout.js');\n await runLogout();\n })\n .command(\n 'install-skill',\n 'Install bundled AuthKit skills to coding agents',\n (yargs) => {\n return yargs\n .option('list', {\n alias: 'l',\n type: 'boolean',\n description: 'List available skills without installing',\n })\n .option('skill', {\n alias: 's',\n type: 'array',\n string: true,\n description: 'Install specific skill(s)',\n })\n .option('agent', {\n alias: 'a',\n type: 'array',\n string: true,\n description: 'Target specific agent(s): claude-code, codex, cursor, goose',\n });\n },\n withAuth(async (argv) => {\n const { runInstallSkill } = await import('./commands/install-skill.js');\n await runInstallSkill({\n list: argv.list as boolean | undefined,\n skill: argv.skill as string[] | undefined,\n agent: argv.agent as string[] | undefined,\n });\n }),\n )\n .command(\n 'install',\n 'Install WorkOS AuthKit into your project',\n (yargs) => yargs.options(installerOptions),\n withAuth(async (argv) => {\n const { handleInstall } = await import('./commands/install.js');\n await handleInstall(argv);\n }),\n )\n .command(\n 'dashboard',\n false, // hidden from help\n (yargs) => yargs.options(installerOptions),\n withAuth(async (argv) => {\n const { handleInstall } = await import('./commands/install.js');\n await handleInstall({ ...argv, dashboard: true });\n }),\n )\n .command(\n ['$0'],\n 'WorkOS AuthKit CLI',\n (yargs) => yargs,\n async () => {\n // Non-TTY: show help\n if (isNonInteractiveEnvironment()) {\n yargs(hideBin(process.argv)).showHelp();\n return;\n }\n\n // TTY: ask if user wants to run installer\n const shouldInstall = await clack.confirm({\n message: 'Run the AuthKit installer?',\n });\n\n if (clack.isCancel(shouldInstall) || !shouldInstall) {\n process.exit(0);\n }\n\n // Auth check happens HERE, after user confirms\n await ensureAuthenticated();\n\n const { handleInstall } = await import('./commands/install.js');\n await handleInstall({ dashboard: false } as any);\n process.exit(0);\n },\n )\n .strict()\n .help()\n .alias('help', 'h')\n .version()\n .alias('version', 'v')\n .wrap(process.stdout.isTTY && process.stdout.columns ? process.stdout.columns : 80).argv;\n"]}
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n\n// Load .env.local for local development when --local flag is used\nif (process.argv.includes('--local') || process.env.INSTALLER_DEV) {\n const { config } = await import('dotenv');\n // bin.ts compiles to dist/bin.js, so go up one level to find .env.local\n config({ path: new URL('../.env.local', import.meta.url).pathname });\n}\n\nimport { satisfies } from 'semver';\nimport { red } from './utils/logging.js';\nimport { getConfig, getVersion } from './lib/settings.js';\n\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport chalk from 'chalk';\nimport { ensureAuthenticated } from './lib/ensure-auth.js';\nimport { checkForUpdates } from './lib/version-check.js';\n\nconst NODE_VERSION_RANGE = getConfig().nodeVersion;\n\n// Have to run this above the other imports because they are importing clack that\n// has the problematic imports.\nif (!satisfies(process.version, NODE_VERSION_RANGE)) {\n red(\n `WorkOS AuthKit installer requires Node.js ${NODE_VERSION_RANGE}. You are using Node.js ${process.version}. Please upgrade your Node.js version.`,\n );\n process.exit(1);\n}\n\nimport { isNonInteractiveEnvironment } from './utils/environment.js';\nimport clack from './utils/clack.js';\n\n/** Apply insecure storage flag if set */\nasync function applyInsecureStorage(insecureStorage?: boolean): Promise<void> {\n if (insecureStorage) {\n const { setInsecureStorage } = await import('./lib/credentials.js');\n setInsecureStorage(true);\n }\n}\n\n/** Shared insecure-storage option for commands that access credentials */\nconst insecureStorageOption = {\n 'insecure-storage': {\n default: false,\n describe: 'Store credentials in plaintext file instead of system keyring',\n type: 'boolean' as const,\n },\n} as const;\n\n/**\n * Wrap a command handler with authentication check.\n * Ensures valid auth before executing the handler.\n * Respects --skip-auth flag for CI/testing.\n */\nfunction withAuth<T>(handler: (argv: T) => Promise<void>): (argv: T) => Promise<void> {\n return async (argv: T) => {\n const typedArgv = argv as { skipAuth?: boolean; insecureStorage?: boolean };\n await applyInsecureStorage(typedArgv.insecureStorage);\n if (!typedArgv.skipAuth) await ensureAuthenticated();\n await handler(argv);\n };\n}\n\nconst installerOptions = {\n direct: {\n alias: 'D',\n default: false,\n describe: 'Use your own Anthropic API key (bypass llm-gateway)',\n type: 'boolean' as const,\n },\n debug: {\n default: false,\n describe: 'Enable verbose logging',\n type: 'boolean' as const,\n },\n ...insecureStorageOption,\n // Hidden dev/automation flags (use env vars)\n local: {\n default: false,\n type: 'boolean' as const,\n hidden: true,\n },\n ci: {\n default: false,\n type: 'boolean' as const,\n hidden: true,\n },\n 'skip-auth': {\n default: false,\n type: 'boolean' as const,\n hidden: true,\n },\n 'api-key': {\n type: 'string' as const,\n hidden: true,\n },\n 'client-id': {\n type: 'string' as const,\n hidden: true,\n },\n inspect: {\n default: false,\n type: 'boolean' as const,\n hidden: true,\n },\n // User-facing flags\n 'homepage-url': {\n describe: 'App homepage URL for WorkOS (defaults to http://localhost:{port})',\n type: 'string' as const,\n },\n 'redirect-uri': {\n describe: 'Redirect URI for WorkOS callback (defaults to framework convention)',\n type: 'string' as const,\n },\n 'no-validate': {\n default: false,\n describe: 'Skip post-installation validation (includes build check)',\n type: 'boolean' as const,\n },\n 'install-dir': {\n describe: 'Directory to install WorkOS AuthKit in',\n type: 'string' as const,\n },\n integration: {\n describe: 'Integration to set up',\n type: 'string' as const,\n },\n 'force-install': {\n default: false,\n describe: 'Force install packages even if peer dependency checks fail',\n type: 'boolean' as const,\n },\n dashboard: {\n alias: 'd',\n default: false,\n describe: 'Run with visual dashboard mode',\n type: 'boolean' as const,\n },\n};\n\n// Check for updates (blocks up to 500ms)\nawait checkForUpdates();\n\nyargs(hideBin(process.argv))\n .env('WORKOS_INSTALLER')\n .command('login', 'Authenticate with WorkOS', insecureStorageOption, async (argv) => {\n await applyInsecureStorage(argv.insecureStorage);\n const { runLogin } = await import('./commands/login.js');\n await runLogin();\n process.exit(0);\n })\n .command('logout', 'Remove stored credentials', insecureStorageOption, async (argv) => {\n await applyInsecureStorage(argv.insecureStorage);\n const { runLogout } = await import('./commands/logout.js');\n await runLogout();\n })\n .command(\n 'install-skill',\n 'Install bundled AuthKit skills to coding agents',\n (yargs) => {\n return yargs\n .option('list', {\n alias: 'l',\n type: 'boolean',\n description: 'List available skills without installing',\n })\n .option('skill', {\n alias: 's',\n type: 'array',\n string: true,\n description: 'Install specific skill(s)',\n })\n .option('agent', {\n alias: 'a',\n type: 'array',\n string: true,\n description: 'Target specific agent(s): claude-code, codex, cursor, goose',\n });\n },\n withAuth(async (argv) => {\n const { runInstallSkill } = await import('./commands/install-skill.js');\n await runInstallSkill({\n list: argv.list as boolean | undefined,\n skill: argv.skill as string[] | undefined,\n agent: argv.agent as string[] | undefined,\n });\n }),\n )\n .command(\n 'doctor',\n 'Diagnose WorkOS integration issues',\n (yargs) =>\n yargs.options({\n verbose: {\n type: 'boolean',\n default: false,\n description: 'Include additional diagnostic information',\n },\n 'skip-api': {\n type: 'boolean',\n default: false,\n description: 'Skip API calls (offline mode)',\n },\n 'install-dir': {\n type: 'string',\n default: process.cwd(),\n description: 'Project directory to analyze',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Output report as JSON',\n },\n copy: {\n type: 'boolean',\n default: false,\n description: 'Copy report to clipboard',\n },\n }),\n async (argv) => {\n const { handleDoctor } = await import('./commands/doctor.js');\n await handleDoctor(argv);\n },\n )\n .command(\n 'install',\n 'Install WorkOS AuthKit into your project',\n (yargs) => yargs.options(installerOptions),\n withAuth(async (argv) => {\n const { handleInstall } = await import('./commands/install.js');\n await handleInstall(argv);\n }),\n )\n .command(\n 'dashboard',\n false, // hidden from help\n (yargs) => yargs.options(installerOptions),\n withAuth(async (argv) => {\n const { handleInstall } = await import('./commands/install.js');\n await handleInstall({ ...argv, dashboard: true });\n }),\n )\n .command(\n ['$0'],\n 'WorkOS AuthKit CLI',\n (yargs) => yargs.options(insecureStorageOption),\n async (argv) => {\n // Non-TTY: show help\n if (isNonInteractiveEnvironment()) {\n yargs(hideBin(process.argv)).showHelp();\n return;\n }\n\n // TTY: ask if user wants to run installer\n const shouldInstall = await clack.confirm({\n message: 'Run the AuthKit installer?',\n });\n\n if (clack.isCancel(shouldInstall) || !shouldInstall) {\n process.exit(0);\n }\n\n // Auth check happens HERE, after user confirms\n await applyInsecureStorage(argv.insecureStorage);\n await ensureAuthenticated();\n\n const { handleInstall } = await import('./commands/install.js');\n await handleInstall({ dashboard: false } as any);\n process.exit(0);\n },\n )\n .strict()\n .help()\n .alias('help', 'h')\n .version(getVersion())\n .alias('version', 'v')\n .wrap(process.stdout.isTTY && process.stdout.columns ? process.stdout.columns : 80).argv;\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ArgumentsCamelCase } from 'yargs';
|
|
2
|
+
interface DoctorArgs {
|
|
3
|
+
verbose?: boolean;
|
|
4
|
+
skipApi?: boolean;
|
|
5
|
+
installDir?: string;
|
|
6
|
+
json?: boolean;
|
|
7
|
+
copy?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function handleDoctor(argv: ArgumentsCamelCase<DoctorArgs>): Promise<void>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { runDoctor, outputReport } from '../doctor/index.js';
|
|
2
|
+
import clack from '../utils/clack.js';
|
|
3
|
+
export async function handleDoctor(argv) {
|
|
4
|
+
const options = {
|
|
5
|
+
installDir: argv.installDir ?? process.cwd(),
|
|
6
|
+
verbose: argv.verbose ?? false,
|
|
7
|
+
skipApi: argv.skipApi ?? false,
|
|
8
|
+
json: argv.json ?? false,
|
|
9
|
+
copy: argv.copy ?? false,
|
|
10
|
+
};
|
|
11
|
+
try {
|
|
12
|
+
const report = await runDoctor(options);
|
|
13
|
+
await outputReport(report, options);
|
|
14
|
+
// Exit with error code if critical issues found
|
|
15
|
+
if (report.summary.errors > 0) {
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
process.exit(0);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
if (!options.json) {
|
|
22
|
+
clack.log.error(`Doctor failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.error(JSON.stringify({ error: error instanceof Error ? error.message : 'Unknown error' }));
|
|
26
|
+
}
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,MAAM,mBAAmB,CAAC;AAUtC,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAoC;IACrE,MAAM,OAAO,GAAG;QACd,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE;QAC5C,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,KAAK;QAC9B,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,KAAK;QAC9B,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,KAAK;QACxB,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,KAAK;KACzB,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAEpC,gDAAgD;QAChD,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,kBAAkB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;QAChG,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;QACrG,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC","sourcesContent":["import type { ArgumentsCamelCase } from 'yargs';\nimport { runDoctor, outputReport } from '../doctor/index.js';\nimport clack from '../utils/clack.js';\n\ninterface DoctorArgs {\n verbose?: boolean;\n skipApi?: boolean;\n installDir?: string;\n json?: boolean;\n copy?: boolean;\n}\n\nexport async function handleDoctor(argv: ArgumentsCamelCase<DoctorArgs>): Promise<void> {\n const options = {\n installDir: argv.installDir ?? process.cwd(),\n verbose: argv.verbose ?? false,\n skipApi: argv.skipApi ?? false,\n json: argv.json ?? false,\n copy: argv.copy ?? false,\n };\n\n try {\n const report = await runDoctor(options);\n await outputReport(report, options);\n\n // Exit with error code if critical issues found\n if (report.summary.errors > 0) {\n process.exit(1);\n }\n process.exit(0);\n } catch (error) {\n if (!options.json) {\n clack.log.error(`Doctor failed: ${error instanceof Error ? error.message : 'Unknown error'}`);\n } else {\n console.error(JSON.stringify({ error: error instanceof Error ? error.message : 'Unknown error' }));\n }\n process.exit(1);\n }\n}\n"]}
|
package/dist/commands/login.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import open from 'opn';
|
|
2
2
|
import clack from '../utils/clack.js';
|
|
3
|
-
import { saveCredentials, getCredentials, getAccessToken } from '../lib/credentials.js';
|
|
3
|
+
import { saveCredentials, getCredentials, getAccessToken, isTokenExpired, updateTokens } from '../lib/credentials.js';
|
|
4
4
|
import { getCliAuthClientId, getAuthkitDomain } from '../lib/settings.js';
|
|
5
|
+
import { refreshAccessToken } from '../lib/token-refresh-client.js';
|
|
5
6
|
/**
|
|
6
7
|
* Parse JWT payload
|
|
7
8
|
*/
|
|
@@ -45,12 +46,31 @@ export async function runLogin() {
|
|
|
45
46
|
clack.log.error('CLI auth not configured. Set WORKOS_CLI_CLIENT_ID environment variable.');
|
|
46
47
|
process.exit(1);
|
|
47
48
|
}
|
|
49
|
+
// Check if already logged in with valid token
|
|
48
50
|
if (getAccessToken()) {
|
|
49
51
|
const creds = getCredentials();
|
|
50
52
|
clack.log.info(`Already logged in as ${creds?.email ?? 'unknown'}`);
|
|
51
53
|
clack.log.info('Run `workos logout` to log out');
|
|
52
54
|
return;
|
|
53
55
|
}
|
|
56
|
+
// Try to refresh if we have expired credentials with a refresh token
|
|
57
|
+
const existingCreds = getCredentials();
|
|
58
|
+
if (existingCreds?.refreshToken && isTokenExpired(existingCreds)) {
|
|
59
|
+
try {
|
|
60
|
+
const authkitDomain = getAuthkitDomain();
|
|
61
|
+
const result = await refreshAccessToken(authkitDomain, clientId);
|
|
62
|
+
if (result.accessToken && result.expiresAt) {
|
|
63
|
+
updateTokens(result.accessToken, result.expiresAt, result.refreshToken);
|
|
64
|
+
clack.log.info(`Already logged in as ${existingCreds.email ?? 'unknown'}`);
|
|
65
|
+
clack.log.info('(Session refreshed)');
|
|
66
|
+
clack.log.info('Run `workos logout` to log out');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Refresh failed, proceed with fresh login
|
|
72
|
+
}
|
|
73
|
+
}
|
|
54
74
|
clack.log.step('Starting authentication...');
|
|
55
75
|
const endpoints = getConnectEndpoints();
|
|
56
76
|
const authResponse = await fetch(endpoints.deviceAuthorization, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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","sourcesContent":["import open from 'opn';\nimport clack from '../utils/clack.js';\nimport { saveCredentials, getCredentials, getAccessToken } from '../lib/credentials.js';\nimport { getCliAuthClientId, getAuthkitDomain } from '../lib/settings.js';\n\n/**\n * Parse JWT payload\n */\nfunction parseJwt(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n return JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf-8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Extract expiry time from JWT token\n */\nfunction getJwtExpiry(token: string): number | null {\n const payload = parseJwt(token);\n if (!payload || typeof payload.exp !== 'number') return null;\n return payload.exp * 1000;\n}\n\nconst POLL_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\n\n/**\n * Get Connect OAuth endpoints from AuthKit domain\n */\nfunction getConnectEndpoints() {\n const domain = getAuthkitDomain();\n return {\n deviceAuthorization: `${domain}/oauth2/device_authorization`,\n token: `${domain}/oauth2/token`,\n };\n}\n\ninterface DeviceAuthResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n expires_in: number;\n interval: number;\n}\n\ninterface ConnectTokenResponse {\n access_token: string;\n id_token: string;\n token_type: string;\n expires_in: number;\n refresh_token?: string;\n}\n\ninterface AuthErrorResponse {\n error: string;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function runLogin(): Promise<void> {\n const clientId = getCliAuthClientId();\n\n if (!clientId) {\n clack.log.error('CLI auth not configured. Set WORKOS_CLI_CLIENT_ID environment variable.');\n process.exit(1);\n }\n\n if (getAccessToken()) {\n const creds = getCredentials();\n clack.log.info(`Already logged in as ${creds?.email ?? 'unknown'}`);\n clack.log.info('Run `workos logout` to log out');\n return;\n }\n\n clack.log.step('Starting authentication...');\n\n const endpoints = getConnectEndpoints();\n\n const authResponse = await fetch(endpoints.deviceAuthorization, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n client_id: clientId,\n scope: 'openid email staging-environment:credentials:read offline_access',\n }),\n });\n\n if (!authResponse.ok) {\n clack.log.error(`Failed to start authentication: ${authResponse.status}`);\n process.exit(1);\n }\n\n const deviceAuth = (await authResponse.json()) as DeviceAuthResponse;\n const pollIntervalMs = (deviceAuth.interval || 5) * 1000;\n\n clack.log.info(`\\nOpen this URL in your browser:\\n`);\n console.log(` ${deviceAuth.verification_uri}`);\n console.log(`\\nEnter code: ${deviceAuth.user_code}\\n`);\n\n try {\n open(deviceAuth.verification_uri_complete);\n clack.log.info('Browser opened automatically');\n } catch {\n // User can open manually\n }\n\n const spinner = clack.spinner();\n spinner.start('Waiting for authentication...');\n\n const startTime = Date.now();\n let currentInterval = pollIntervalMs;\n\n while (Date.now() - startTime < POLL_TIMEOUT_MS) {\n await sleep(currentInterval);\n\n try {\n const tokenResponse = await fetch(endpoints.token, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceAuth.device_code,\n client_id: clientId,\n }),\n });\n\n const data = await tokenResponse.json();\n\n if (tokenResponse.ok) {\n const result = data as ConnectTokenResponse;\n\n // Parse user info from id_token JWT\n const idTokenPayload = parseJwt(result.id_token);\n const userId = (idTokenPayload?.sub as string) || 'unknown';\n const email = (idTokenPayload?.email as string) || undefined;\n\n // Extract actual expiry from access token JWT, fallback to response or 15 min\n const jwtExpiry = getJwtExpiry(result.access_token);\n const expiresAt =\n jwtExpiry ?? (result.expires_in ? Date.now() + result.expires_in * 1000 : Date.now() + 15 * 60 * 1000);\n\n const expiresInSec = Math.round((expiresAt - Date.now()) / 1000);\n\n saveCredentials({\n accessToken: result.access_token,\n expiresAt,\n userId,\n email,\n refreshToken: result.refresh_token,\n });\n\n spinner.stop('Authentication successful!');\n clack.log.success(`Logged in as ${email || userId}`);\n clack.log.info(`Token expires in ${expiresInSec} seconds`);\n return;\n }\n\n const errorData = data as AuthErrorResponse;\n if (errorData.error === 'authorization_pending') continue;\n if (errorData.error === 'slow_down') {\n currentInterval += 5000;\n continue;\n }\n\n spinner.stop('Authentication failed');\n clack.log.error(`Authentication error: ${errorData.error}`);\n process.exit(1);\n } catch {\n continue;\n }\n }\n\n spinner.stop('Authentication timed out');\n clack.log.error('Authentication timed out. Please try again.');\n process.exit(1);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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","sourcesContent":["import open from 'opn';\nimport clack from '../utils/clack.js';\nimport { saveCredentials, getCredentials, getAccessToken, isTokenExpired, updateTokens } from '../lib/credentials.js';\nimport { getCliAuthClientId, getAuthkitDomain } from '../lib/settings.js';\nimport { refreshAccessToken } from '../lib/token-refresh-client.js';\n\n/**\n * Parse JWT payload\n */\nfunction parseJwt(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n return JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf-8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Extract expiry time from JWT token\n */\nfunction getJwtExpiry(token: string): number | null {\n const payload = parseJwt(token);\n if (!payload || typeof payload.exp !== 'number') return null;\n return payload.exp * 1000;\n}\n\nconst POLL_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\n\n/**\n * Get Connect OAuth endpoints from AuthKit domain\n */\nfunction getConnectEndpoints() {\n const domain = getAuthkitDomain();\n return {\n deviceAuthorization: `${domain}/oauth2/device_authorization`,\n token: `${domain}/oauth2/token`,\n };\n}\n\ninterface DeviceAuthResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n expires_in: number;\n interval: number;\n}\n\ninterface ConnectTokenResponse {\n access_token: string;\n id_token: string;\n token_type: string;\n expires_in: number;\n refresh_token?: string;\n}\n\ninterface AuthErrorResponse {\n error: string;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function runLogin(): Promise<void> {\n const clientId = getCliAuthClientId();\n\n if (!clientId) {\n clack.log.error('CLI auth not configured. Set WORKOS_CLI_CLIENT_ID environment variable.');\n process.exit(1);\n }\n\n // Check if already logged in with valid token\n if (getAccessToken()) {\n const creds = getCredentials();\n clack.log.info(`Already logged in as ${creds?.email ?? 'unknown'}`);\n clack.log.info('Run `workos logout` to log out');\n return;\n }\n\n // Try to refresh if we have expired credentials with a refresh token\n const existingCreds = getCredentials();\n if (existingCreds?.refreshToken && isTokenExpired(existingCreds)) {\n try {\n const authkitDomain = getAuthkitDomain();\n const result = await refreshAccessToken(authkitDomain, clientId);\n if (result.accessToken && result.expiresAt) {\n updateTokens(result.accessToken, result.expiresAt, result.refreshToken);\n clack.log.info(`Already logged in as ${existingCreds.email ?? 'unknown'}`);\n clack.log.info('(Session refreshed)');\n clack.log.info('Run `workos logout` to log out');\n return;\n }\n } catch {\n // Refresh failed, proceed with fresh login\n }\n }\n\n clack.log.step('Starting authentication...');\n\n const endpoints = getConnectEndpoints();\n\n const authResponse = await fetch(endpoints.deviceAuthorization, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n client_id: clientId,\n scope: 'openid email staging-environment:credentials:read offline_access',\n }),\n });\n\n if (!authResponse.ok) {\n clack.log.error(`Failed to start authentication: ${authResponse.status}`);\n process.exit(1);\n }\n\n const deviceAuth = (await authResponse.json()) as DeviceAuthResponse;\n const pollIntervalMs = (deviceAuth.interval || 5) * 1000;\n\n clack.log.info(`\\nOpen this URL in your browser:\\n`);\n console.log(` ${deviceAuth.verification_uri}`);\n console.log(`\\nEnter code: ${deviceAuth.user_code}\\n`);\n\n try {\n open(deviceAuth.verification_uri_complete);\n clack.log.info('Browser opened automatically');\n } catch {\n // User can open manually\n }\n\n const spinner = clack.spinner();\n spinner.start('Waiting for authentication...');\n\n const startTime = Date.now();\n let currentInterval = pollIntervalMs;\n\n while (Date.now() - startTime < POLL_TIMEOUT_MS) {\n await sleep(currentInterval);\n\n try {\n const tokenResponse = await fetch(endpoints.token, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceAuth.device_code,\n client_id: clientId,\n }),\n });\n\n const data = await tokenResponse.json();\n\n if (tokenResponse.ok) {\n const result = data as ConnectTokenResponse;\n\n // Parse user info from id_token JWT\n const idTokenPayload = parseJwt(result.id_token);\n const userId = (idTokenPayload?.sub as string) || 'unknown';\n const email = (idTokenPayload?.email as string) || undefined;\n\n // Extract actual expiry from access token JWT, fallback to response or 15 min\n const jwtExpiry = getJwtExpiry(result.access_token);\n const expiresAt =\n jwtExpiry ?? (result.expires_in ? Date.now() + result.expires_in * 1000 : Date.now() + 15 * 60 * 1000);\n\n const expiresInSec = Math.round((expiresAt - Date.now()) / 1000);\n\n saveCredentials({\n accessToken: result.access_token,\n expiresAt,\n userId,\n email,\n refreshToken: result.refresh_token,\n });\n\n spinner.stop('Authentication successful!');\n clack.log.success(`Logged in as ${email || userId}`);\n clack.log.info(`Token expires in ${expiresInSec} seconds`);\n return;\n }\n\n const errorData = data as AuthErrorResponse;\n if (errorData.error === 'authorization_pending') continue;\n if (errorData.error === 'slow_down') {\n currentInterval += 5000;\n continue;\n }\n\n spinner.stop('Authentication failed');\n clack.log.error(`Authentication error: ${errorData.error}`);\n process.exit(1);\n } catch {\n continue;\n }\n }\n\n spinner.stop('Authentication timed out');\n clack.log.error('Authentication timed out. Please try again.');\n process.exit(1);\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export async function checkConnectivity(options, baseUrl) {
|
|
2
|
+
if (options.skipApi) {
|
|
3
|
+
return {
|
|
4
|
+
apiReachable: false,
|
|
5
|
+
latencyMs: null,
|
|
6
|
+
tlsValid: false,
|
|
7
|
+
error: 'Skipped (--skip-api)',
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
const startTime = Date.now();
|
|
11
|
+
try {
|
|
12
|
+
const controller = new AbortController();
|
|
13
|
+
const timeoutId = setTimeout(() => controller.abort(), 10000);
|
|
14
|
+
const response = await fetch(`${baseUrl}/health`, {
|
|
15
|
+
signal: controller.signal,
|
|
16
|
+
});
|
|
17
|
+
clearTimeout(timeoutId);
|
|
18
|
+
const latencyMs = Date.now() - startTime;
|
|
19
|
+
return {
|
|
20
|
+
apiReachable: response.ok,
|
|
21
|
+
latencyMs,
|
|
22
|
+
tlsValid: true, // If fetch succeeded over HTTPS, TLS is valid
|
|
23
|
+
error: response.ok ? undefined : `HTTP ${response.status}`,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
return {
|
|
28
|
+
apiReachable: false,
|
|
29
|
+
latencyMs: null,
|
|
30
|
+
tlsValid: false,
|
|
31
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=connectivity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connectivity.js","sourceRoot":"","sources":["../../../src/doctor/checks/connectivity.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAsB,EAAE,OAAe;IAC7E,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO;YACL,YAAY,EAAE,KAAK;YACnB,SAAS,EAAE,IAAI;YACf,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,sBAAsB;SAC9B,CAAC;IACJ,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,KAAK,CAAC,CAAC;QAE9D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,SAAS,EAAE;YAChD,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QAEH,YAAY,CAAC,SAAS,CAAC,CAAC;QACxB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAEzC,OAAO;YACL,YAAY,EAAE,QAAQ,CAAC,EAAE;YACzB,SAAS;YACT,QAAQ,EAAE,IAAI,EAAE,8CAA8C;YAC9D,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,QAAQ,CAAC,MAAM,EAAE;SAC3D,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,YAAY,EAAE,KAAK;YACnB,SAAS,EAAE,IAAI;YACf,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;SAChE,CAAC;IACJ,CAAC;AACH,CAAC","sourcesContent":["import type { DoctorOptions, ConnectivityInfo } from '../types.js';\n\nexport async function checkConnectivity(options: DoctorOptions, baseUrl: string): Promise<ConnectivityInfo> {\n if (options.skipApi) {\n return {\n apiReachable: false,\n latencyMs: null,\n tlsValid: false,\n error: 'Skipped (--skip-api)',\n };\n }\n const startTime = Date.now();\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 10000);\n\n const response = await fetch(`${baseUrl}/health`, {\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n const latencyMs = Date.now() - startTime;\n\n return {\n apiReachable: response.ok,\n latencyMs,\n tlsValid: true, // If fetch succeeded over HTTPS, TLS is valid\n error: response.ok ? undefined : `HTTP ${response.status}`,\n };\n } catch (error) {\n return {\n apiReachable: false,\n latencyMs: null,\n tlsValid: false,\n error: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n}\n"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { DashboardFetchResult, DoctorOptions, RedirectUriComparison, EnvironmentRaw } from '../types.js';
|
|
2
|
+
export declare function checkDashboardSettings(options: DoctorOptions, apiKeyType: 'staging' | 'production' | null, raw: EnvironmentRaw): Promise<DashboardFetchResult>;
|
|
3
|
+
export declare function compareRedirectUris(codeUri: string | null, dashboardUris: string[], source?: 'env' | 'inferred'): RedirectUriComparison;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
const WORKOS_API_URL = 'https://api.workos.com';
|
|
2
|
+
export async function checkDashboardSettings(options, apiKeyType, raw) {
|
|
3
|
+
// Never call API with production keys
|
|
4
|
+
if (apiKeyType === 'production') {
|
|
5
|
+
return { settings: null, error: 'Skipped (production API key)' };
|
|
6
|
+
}
|
|
7
|
+
if (options.skipApi) {
|
|
8
|
+
return { settings: null, error: 'Skipped (--skip-api)' };
|
|
9
|
+
}
|
|
10
|
+
const apiKey = raw.apiKey;
|
|
11
|
+
if (!apiKey) {
|
|
12
|
+
return { settings: null, error: 'No API key configured' };
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
return await fetchDashboardSettings(apiKey, raw.baseUrl);
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
19
|
+
return { settings: null, error: message };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async function fetchDashboardSettings(apiKey, baseUrlOverride) {
|
|
23
|
+
const baseUrl = baseUrlOverride ?? WORKOS_API_URL;
|
|
24
|
+
const controller = new AbortController();
|
|
25
|
+
const timeoutId = setTimeout(() => controller.abort(), 10000);
|
|
26
|
+
try {
|
|
27
|
+
const redirectUris = [];
|
|
28
|
+
// Single /organizations?limit=1 call — validates credentials AND gets org count
|
|
29
|
+
const orgsResponse = await fetch(`${baseUrl}/organizations?limit=1`, {
|
|
30
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
31
|
+
signal: controller.signal,
|
|
32
|
+
});
|
|
33
|
+
if (orgsResponse.status === 401) {
|
|
34
|
+
return {
|
|
35
|
+
settings: null,
|
|
36
|
+
credentialValidation: { valid: false, clientIdMatch: true, error: 'Invalid API key' },
|
|
37
|
+
error: 'Invalid API key (401)',
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (orgsResponse.status === 403) {
|
|
41
|
+
return {
|
|
42
|
+
settings: null,
|
|
43
|
+
credentialValidation: { valid: false, clientIdMatch: true, error: 'API key lacks permissions' },
|
|
44
|
+
error: 'API key lacks permissions (403)',
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (!orgsResponse.ok) {
|
|
48
|
+
return {
|
|
49
|
+
settings: null,
|
|
50
|
+
credentialValidation: { valid: false, clientIdMatch: true, error: `API error: ${orgsResponse.status}` },
|
|
51
|
+
error: `API error: ${orgsResponse.status}`,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// Credentials valid — extract org count from the same response
|
|
55
|
+
const credentialValidation = { valid: true, clientIdMatch: true };
|
|
56
|
+
let organizationCount = 0;
|
|
57
|
+
const orgsData = (await orgsResponse.json());
|
|
58
|
+
organizationCount = orgsData.list_metadata?.total_count ?? orgsData.data?.length ?? 0;
|
|
59
|
+
// Fetch environment settings
|
|
60
|
+
const envResponse = await fetch(`${baseUrl}/environments/current`, {
|
|
61
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
62
|
+
signal: controller.signal,
|
|
63
|
+
});
|
|
64
|
+
let authMethods = [];
|
|
65
|
+
let sessionTimeout = null;
|
|
66
|
+
let mfa = null;
|
|
67
|
+
if (envResponse.ok) {
|
|
68
|
+
const envData = (await envResponse.json());
|
|
69
|
+
authMethods = envData.auth_methods ?? [];
|
|
70
|
+
sessionTimeout = envData.session_timeout ?? null;
|
|
71
|
+
mfa = envData.mfa_policy ?? null;
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
settings: { redirectUris, authMethods, sessionTimeout, mfa, organizationCount },
|
|
75
|
+
credentialValidation,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
80
|
+
throw new Error('Request timeout (10s)');
|
|
81
|
+
}
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
clearTimeout(timeoutId);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Normalize a URI for comparison:
|
|
90
|
+
* - Remove trailing slashes
|
|
91
|
+
* - Normalize localhost variants (127.0.0.1 → localhost)
|
|
92
|
+
* - Lowercase the host portion
|
|
93
|
+
*/
|
|
94
|
+
function normalizeUri(uri) {
|
|
95
|
+
try {
|
|
96
|
+
const url = new URL(uri);
|
|
97
|
+
// Normalize localhost variants
|
|
98
|
+
if (url.hostname === '127.0.0.1' || url.hostname === '[::1]') {
|
|
99
|
+
url.hostname = 'localhost';
|
|
100
|
+
}
|
|
101
|
+
// Lowercase hostname (but preserve path case for compatibility)
|
|
102
|
+
url.hostname = url.hostname.toLowerCase();
|
|
103
|
+
// Remove trailing slash from pathname (unless it's just "/")
|
|
104
|
+
if (url.pathname.length > 1 && url.pathname.endsWith('/')) {
|
|
105
|
+
url.pathname = url.pathname.slice(0, -1);
|
|
106
|
+
}
|
|
107
|
+
return url.toString();
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// If URL parsing fails, return as-is for exact match fallback
|
|
111
|
+
return uri;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
export function compareRedirectUris(codeUri, dashboardUris, source) {
|
|
115
|
+
if (!codeUri) {
|
|
116
|
+
return { codeUri, dashboardUris, match: false, source };
|
|
117
|
+
}
|
|
118
|
+
const normalizedCode = normalizeUri(codeUri);
|
|
119
|
+
const normalizedDashboard = dashboardUris.map(normalizeUri);
|
|
120
|
+
const match = normalizedDashboard.includes(normalizedCode);
|
|
121
|
+
return { codeUri, dashboardUris, match, source };
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../src/doctor/checks/dashboard.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CredentialValidation,\n DashboardSettings,\n DashboardFetchResult,\n DoctorOptions,\n RedirectUriComparison,\n EnvironmentRaw,\n} from '../types.js';\n\nconst WORKOS_API_URL = 'https://api.workos.com';\n\nexport async function checkDashboardSettings(\n options: DoctorOptions,\n apiKeyType: 'staging' | 'production' | null,\n raw: EnvironmentRaw,\n): Promise<DashboardFetchResult> {\n // Never call API with production keys\n if (apiKeyType === 'production') {\n return { settings: null, error: 'Skipped (production API key)' };\n }\n\n if (options.skipApi) {\n return { settings: null, error: 'Skipped (--skip-api)' };\n }\n\n const apiKey = raw.apiKey;\n if (!apiKey) {\n return { settings: null, error: 'No API key configured' };\n }\n\n try {\n return await fetchDashboardSettings(apiKey, raw.baseUrl);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n return { settings: null, error: message };\n }\n}\n\nasync function fetchDashboardSettings(apiKey: string, baseUrlOverride: string | null): Promise<DashboardFetchResult> {\n const baseUrl = baseUrlOverride ?? WORKOS_API_URL;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 10000);\n\n try {\n const redirectUris: string[] = [];\n\n // Single /organizations?limit=1 call — validates credentials AND gets org count\n const orgsResponse = await fetch(`${baseUrl}/organizations?limit=1`, {\n headers: { Authorization: `Bearer ${apiKey}` },\n signal: controller.signal,\n });\n\n if (orgsResponse.status === 401) {\n return {\n settings: null,\n credentialValidation: { valid: false, clientIdMatch: true, error: 'Invalid API key' },\n error: 'Invalid API key (401)',\n };\n }\n if (orgsResponse.status === 403) {\n return {\n settings: null,\n credentialValidation: { valid: false, clientIdMatch: true, error: 'API key lacks permissions' },\n error: 'API key lacks permissions (403)',\n };\n }\n if (!orgsResponse.ok) {\n return {\n settings: null,\n credentialValidation: { valid: false, clientIdMatch: true, error: `API error: ${orgsResponse.status}` },\n error: `API error: ${orgsResponse.status}`,\n };\n }\n\n // Credentials valid — extract org count from the same response\n const credentialValidation: CredentialValidation = { valid: true, clientIdMatch: true };\n\n let organizationCount = 0;\n const orgsData = (await orgsResponse.json()) as {\n list_metadata?: { total_count?: number };\n data?: unknown[];\n };\n organizationCount = orgsData.list_metadata?.total_count ?? orgsData.data?.length ?? 0;\n\n // Fetch environment settings\n const envResponse = await fetch(`${baseUrl}/environments/current`, {\n headers: { Authorization: `Bearer ${apiKey}` },\n signal: controller.signal,\n });\n\n let authMethods: string[] = [];\n let sessionTimeout: string | null = null;\n let mfa: 'optional' | 'required' | 'disabled' | null = null;\n\n if (envResponse.ok) {\n const envData = (await envResponse.json()) as {\n auth_methods?: string[];\n session_timeout?: string;\n mfa_policy?: 'optional' | 'required' | 'disabled';\n };\n authMethods = envData.auth_methods ?? [];\n sessionTimeout = envData.session_timeout ?? null;\n mfa = envData.mfa_policy ?? null;\n }\n\n return {\n settings: { redirectUris, authMethods, sessionTimeout, mfa, organizationCount },\n credentialValidation,\n };\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error('Request timeout (10s)');\n }\n throw err;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\n/**\n * Normalize a URI for comparison:\n * - Remove trailing slashes\n * - Normalize localhost variants (127.0.0.1 → localhost)\n * - Lowercase the host portion\n */\nfunction normalizeUri(uri: string): string {\n try {\n const url = new URL(uri);\n // Normalize localhost variants\n if (url.hostname === '127.0.0.1' || url.hostname === '[::1]') {\n url.hostname = 'localhost';\n }\n // Lowercase hostname (but preserve path case for compatibility)\n url.hostname = url.hostname.toLowerCase();\n // Remove trailing slash from pathname (unless it's just \"/\")\n if (url.pathname.length > 1 && url.pathname.endsWith('/')) {\n url.pathname = url.pathname.slice(0, -1);\n }\n return url.toString();\n } catch {\n // If URL parsing fails, return as-is for exact match fallback\n return uri;\n }\n}\n\nexport function compareRedirectUris(\n codeUri: string | null,\n dashboardUris: string[],\n source?: 'env' | 'inferred',\n): RedirectUriComparison {\n if (!codeUri) {\n return { codeUri, dashboardUris, match: false, source };\n }\n\n const normalizedCode = normalizeUri(codeUri);\n const normalizedDashboard = dashboardUris.map(normalizeUri);\n const match = normalizedDashboard.includes(normalizedCode);\n\n return { codeUri, dashboardUris, match, source };\n}\n"]}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { parse as parseDotenv } from 'dotenv';
|
|
4
|
+
/**
|
|
5
|
+
* Load environment variables from project's .env files.
|
|
6
|
+
* Priority: .env.local > .env (matching Next.js/Vite conventions)
|
|
7
|
+
* Uses dotenv parser for proper handling of quotes, multiline, exports, etc.
|
|
8
|
+
*/
|
|
9
|
+
function loadProjectEnv(installDir) {
|
|
10
|
+
const env = {};
|
|
11
|
+
// Load in order: .env first, then .env.local (later overrides earlier)
|
|
12
|
+
const envFiles = ['.env', '.env.local'];
|
|
13
|
+
for (const file of envFiles) {
|
|
14
|
+
const filePath = join(installDir, file);
|
|
15
|
+
if (existsSync(filePath)) {
|
|
16
|
+
try {
|
|
17
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
18
|
+
const parsed = parseDotenv(content);
|
|
19
|
+
Object.assign(env, parsed);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// Ignore read errors
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return env;
|
|
27
|
+
}
|
|
28
|
+
export function checkEnvironment(options) {
|
|
29
|
+
// Load project env files, then fall back to process.env
|
|
30
|
+
const projectEnv = options?.installDir ? loadProjectEnv(options.installDir) : {};
|
|
31
|
+
const apiKey = projectEnv.WORKOS_API_KEY ?? process.env.WORKOS_API_KEY ?? null;
|
|
32
|
+
const clientId = projectEnv.WORKOS_CLIENT_ID ?? process.env.WORKOS_CLIENT_ID ?? null;
|
|
33
|
+
const redirectUri = projectEnv.WORKOS_REDIRECT_URI ?? process.env.WORKOS_REDIRECT_URI ?? null;
|
|
34
|
+
const cookieDomain = projectEnv.WORKOS_COOKIE_DOMAIN ?? process.env.WORKOS_COOKIE_DOMAIN ?? null;
|
|
35
|
+
const baseUrl = projectEnv.WORKOS_BASE_URL ?? process.env.WORKOS_BASE_URL ?? null;
|
|
36
|
+
return {
|
|
37
|
+
info: {
|
|
38
|
+
apiKeyConfigured: !!apiKey,
|
|
39
|
+
apiKeyType: getApiKeyType(apiKey),
|
|
40
|
+
clientId: truncateClientId(clientId),
|
|
41
|
+
redirectUri: redirectUri,
|
|
42
|
+
cookieDomain: cookieDomain,
|
|
43
|
+
baseUrl: baseUrl ?? 'https://api.workos.com',
|
|
44
|
+
},
|
|
45
|
+
raw: {
|
|
46
|
+
apiKey,
|
|
47
|
+
clientId,
|
|
48
|
+
baseUrl: baseUrl ?? 'https://api.workos.com',
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function getApiKeyType(apiKey) {
|
|
53
|
+
if (!apiKey)
|
|
54
|
+
return null;
|
|
55
|
+
if (apiKey.startsWith('sk_test_'))
|
|
56
|
+
return 'staging';
|
|
57
|
+
if (apiKey.startsWith('sk_live_'))
|
|
58
|
+
return 'production';
|
|
59
|
+
return null; // Unknown format
|
|
60
|
+
}
|
|
61
|
+
function truncateClientId(clientId) {
|
|
62
|
+
if (!clientId)
|
|
63
|
+
return null;
|
|
64
|
+
if (clientId.length <= 15)
|
|
65
|
+
return clientId;
|
|
66
|
+
return `${clientId.slice(0, 10)}...${clientId.slice(-3)}`;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=environment.js.map
|
|
@@ -0,0 +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;AACjC,OAAO,EAAE,KAAK,IAAI,WAAW,EAAE,MAAM,QAAQ,CAAC;AAG9C;;;;GAIG;AACH,SAAS,cAAc,CAAC,UAAkB;IACxC,MAAM,GAAG,GAA2B,EAAE,CAAC;IAEvC,uEAAuE;IACvE,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAExC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACxC,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBAChD,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;gBACpC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC7B,CAAC;YAAC,MAAM,CAAC;gBACP,qBAAqB;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAuB;IACtD,wDAAwD;IACxD,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEjF,MAAM,MAAM,GAAG,UAAU,CAAC,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI,CAAC;IAC/E,MAAM,QAAQ,GAAG,UAAU,CAAC,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,IAAI,CAAC;IACrF,MAAM,WAAW,GAAG,UAAU,CAAC,mBAAmB,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,IAAI,CAAC;IAC9F,MAAM,YAAY,GAAG,UAAU,CAAC,oBAAoB,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,IAAI,CAAC;IACjG,MAAM,OAAO,GAAG,UAAU,CAAC,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC;IAElF,OAAO;QACL,IAAI,EAAE;YACJ,gBAAgB,EAAE,CAAC,CAAC,MAAM;YAC1B,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC;YACjC,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,CAAC;YACpC,WAAW,EAAE,WAAW;YACxB,YAAY,EAAE,YAAY;YAC1B,OAAO,EAAE,OAAO,IAAI,wBAAwB;SAC7C;QACD,GAAG,EAAE;YACH,MAAM;YACN,QAAQ;YACR,OAAO,EAAE,OAAO,IAAI,wBAAwB;SAC7C;KACF,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,MAA0B;IAC/C,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,SAAS,CAAC;IACpD,IAAI,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,YAAY,CAAC;IACvD,OAAO,IAAI,CAAC,CAAC,iBAAiB;AAChC,CAAC;AAED,SAAS,gBAAgB,CAAC,QAA4B;IACpD,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,IAAI,QAAQ,CAAC,MAAM,IAAI,EAAE;QAAE,OAAO,QAAQ,CAAC;IAC3C,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5D,CAAC","sourcesContent":["import { readFileSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { parse as parseDotenv } from 'dotenv';\nimport type { EnvironmentInfo, EnvironmentCheckResult, DoctorOptions } from '../types.js';\n\n/**\n * Load environment variables from project's .env files.\n * Priority: .env.local > .env (matching Next.js/Vite conventions)\n * Uses dotenv parser for proper handling of quotes, multiline, exports, etc.\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 const parsed = parseDotenv(content);\n Object.assign(env, parsed);\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"]}
|