Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/workos

src/setup.ts

95 lines · 2.9 KB · TypeScript
import type { WorkosPortalIntent } from './types.ts'
import { requireString } from './types.ts'

export const WORKOS_API_BASE_URL = 'https://api.workos.com'
export const WORKOS_API_HOST = 'api.workos.com'
export const WORKOS_DASHBOARD_API_KEYS_URL = 'https://dashboard.workos.com/api-keys'
export const DEFAULT_API_KEY_SECRET = 'workosApiKey'

export const WORKOS_PORTAL_INTENTS = [
	'sso',
	'dsync',
	'audit_logs',
	'log_streams',
	'domain_verification',
	'certificate_renewal',
] as const satisfies ReadonlyArray<WorkosPortalIntent>

export type WorkosOperation =
	| 'organizations.read'
	| 'organizations.write'
	| 'users.read'
	| 'connections.read'
	| 'directories.read'
	| 'events.read'
	| 'portal.write'
	| 'unknownRead'
	| 'unknownMutation'

export function apiKeySetupUrl(secretName: string = DEFAULT_API_KEY_SECRET): string {
	const name = requireString(secretName, 'secretName')
	const params = new URLSearchParams({
		name,
		description: 'WorkOS API key (Bearer token for api.workos.com)',
		allowedHosts: WORKOS_API_HOST,
		scope: 'user',
	})
	return `https://kody.codes/account/secrets/new?${params.toString()}`
}

export function missingCredentialsMessage(options: { secretName: string }): string {
	return [
		'WorkOS credentials are missing.',
		`Create an API key at ${WORKOS_DASHBOARD_API_KEYS_URL}`,
		'(sk_test_… or sk_live_…), then save it (do not paste the value in chat):',
		apiKeySetupUrl(options.secretName),
		`Required API host: ${WORKOS_API_HOST}.`,
	].join(' ')
}

export function isMutatingMethod(method: string): boolean {
	const normalized = method.toUpperCase()
	return (
		normalized === 'POST' ||
		normalized === 'PUT' ||
		normalized === 'PATCH' ||
		normalized === 'DELETE'
	)
}

export function inferOperationFromPath(
	method: string,
	path: string,
	explicit?: WorkosOperation,
): WorkosOperation {
	if (explicit) return explicit
	const mutating = isMutatingMethod(method)
	if (/\/portal(?:\/|$)/.test(path)) {
		return mutating ? 'portal.write' : 'unknownRead'
	}
	if (/\/user_management\/users(?:\/|$)/.test(path)) {
		return mutating ? 'unknownMutation' : 'users.read'
	}
	if (/\/directory_users(?:\/|$)/.test(path) || /\/directories(?:\/|$)/.test(path)) {
		return mutating ? 'unknownMutation' : 'directories.read'
	}
	if (/\/connections(?:\/|$)/.test(path)) {
		return mutating ? 'unknownMutation' : 'connections.read'
	}
	if (/\/events(?:\/|$)/.test(path)) {
		return mutating ? 'unknownMutation' : 'events.read'
	}
	if (/\/organizations(?:\/|$)/.test(path)) {
		return mutating ? 'organizations.write' : 'organizations.read'
	}
	return mutating ? 'unknownMutation' : 'unknownRead'
}

export function nextStepForAuthFailure(secretName: string): string {
	return [
		'WorkOS rejected the API key (401/403). Confirm the key is an environment API key from',
		WORKOS_DASHBOARD_API_KEYS_URL,
		'and that host api.workos.com is approved on the secret.',
		apiKeySetupUrl(secretName),
	].join(' ')
}