import { parseAuth, listUserSecretNames, listZendeskIntegrationNames } from './auth.ts'
import { readStoredConfig, resolveEmail } from './config.ts'
import type { ZendeskAuthInput, ZendeskAuthMode } from './types.ts'
import { requireRecord } from './types.ts'
import {
API_TOKEN_SETUP_URL,
API_USERNAME_SETUP_URL,
DEFAULT_INTEGRATION_NAME,
DEFAULT_TOKEN_SECRET,
DEFAULT_USERNAME_SECRET,
OAUTH_CONNECT_URL,
SUBDOMAIN_PLACEHOLDER,
ZENDESK_CALLBACK_URL,
ZENDESK_SCOPES,
apiTokenSetupUrl,
apiUsernameSetupUrl,
oauthConnectUrl,
optionalSubdomain,
resolveIntegrationName,
resolveSecretName,
resolveUsernameSecretName,
zendeskHost,
} from './setup.ts'
export type ZendeskAccountResolution = {
integrationName: string
secretName: string
usernameSecretName: string
oauthConnected: boolean
apiTokenSaved: boolean
apiUsernameSaved: boolean
preferredAuth: ZendeskAuthMode | null
subdomain: string | null
hasEmail: boolean
apiHost: string | null
connectUrl: string
apiTokenUrl: string
apiUsernameUrl: string
callbackUrl: string
requiredHosts: Array<string>
scopes: typeof ZENDESK_SCOPES
}
/**
* Resolve which Zendesk OAuth integration or API token to use.
*
* - `integration` / `integrationName` wins when set (exact name, e.g. `zendesk-work`)
* - `account: 'work'` → `zendesk-work`
* - `account: 'default'` / `'zendesk'` / omitted → `zendesk`
* - Subdomain comes from the call or packageStorage `config.subdomain`
*
* @example
* import listZendeskAccounts from 'kody:@kody/zendesk/accounts'
* const accounts = await listZendeskAccounts({ subdomain: 'acme' })
*/
export async function accounts(
params: ZendeskAuthInput = {},
): Promise<ZendeskAccountResolution> {
const integrationName = resolveIntegrationName(params)
const secretName = resolveSecretName(params)
const usernameSecretName = resolveUsernameSecretName(params)
const [secrets, integrations, stored, email] = await Promise.all([
listUserSecretNames(),
listZendeskIntegrationNames(),
readStoredConfig(),
resolveEmail(params),
])
const oauthConnected = integrations.includes(integrationName)
const apiTokenSaved = secrets.has(secretName)
const apiUsernameSaved = secrets.has(usernameSecretName)
const forced = params.auth
let preferredAuth: ZendeskAuthMode | null = null
if (forced === 'oauth' && oauthConnected) preferredAuth = 'oauth'
else if (forced === 'apiToken' && apiTokenSaved && apiUsernameSaved) preferredAuth = 'apiToken'
else if (oauthConnected) preferredAuth = 'oauth'
else if (apiTokenSaved && apiUsernameSaved) preferredAuth = 'apiToken'
const subdomain =
optionalSubdomain(params.subdomain) ?? stored.subdomain ?? null
const host = subdomain ? zendeskHost(subdomain) : null
return {
integrationName,
secretName,
usernameSecretName,
oauthConnected,
apiTokenSaved,
apiUsernameSaved,
preferredAuth,
subdomain,
hasEmail: Boolean(email),
apiHost: host,
connectUrl: oauthConnectUrl(integrationName, subdomain ?? SUBDOMAIN_PLACEHOLDER),
apiTokenUrl: apiTokenSetupUrl(secretName, subdomain ?? SUBDOMAIN_PLACEHOLDER),
apiUsernameUrl: apiUsernameSetupUrl(
usernameSecretName,
subdomain ?? SUBDOMAIN_PLACEHOLDER,
email,
),
callbackUrl: ZENDESK_CALLBACK_URL,
requiredHosts: host ? [host] : [`${SUBDOMAIN_PLACEHOLDER}.zendesk.com`],
scopes: ZENDESK_SCOPES,
}
}
export {
API_TOKEN_SETUP_URL,
API_USERNAME_SETUP_URL,
DEFAULT_INTEGRATION_NAME,
DEFAULT_TOKEN_SECRET,
DEFAULT_USERNAME_SECRET,
OAUTH_CONNECT_URL,
}
/**
* Resolve which Zendesk OAuth integration or API token to use.
* @example
* import listZendeskAccounts from 'kody:@kody/zendesk/accounts'
* const info = await listZendeskAccounts({ account: 'work', subdomain: 'acme' })
*/
export default async function accountsEntrypoint(
params: ZendeskAuthInput & Record<string, unknown> = {},
) {
return accounts(parseAuth(requireRecord(params, 'accounts')))
}