Skip to content

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

Package listing

@kody/hubspot

src/accounts.ts

100 lines · 3.1 KB · TypeScript
import {
	privateAppSetupUrl,
	oauthConnectUrl,
	DEFAULT_INTEGRATION_NAME,
	DEFAULT_OAUTH_SCOPES,
	DEFAULT_TOKEN_SECRET,
	HUBSPOT_CALLBACK_URL,
	HUBSPOT_OAUTH_APP_URL,
	HUBSPOT_PRIVATE_APP_URL,
	HUBSPOT_REQUIRED_HOSTS,
	HUBSPOT_SCOPES,
} from './setup.ts'
import {
	listHubSpotIntegrationNames,
	listUserSecretNames,
	requireAuthMode,
	resolveIntegrationName,
	resolveSecretName,
	type ResolvedHubSpotAuth,
} from './auth.ts'
import type { HubSpotAuthInput } from './types.ts'
import { requireRecord } from './types.ts'

export type HubSpotAccountResolution = {
	integrationName: string
	secretName: string
	oauthConnected: boolean
	privateAppSaved: boolean
	preferredAuth: ResolvedHubSpotAuth['mode'] | null
	connectUrl: string
	privateAppUrl: string
	scopes: typeof HUBSPOT_SCOPES
	defaultScopes: Array<string>
	requiredHosts: Array<string>
	callbackUrl: string
	oauthAppUrl: string
	privateAppDashboardUrl: string
}

/**
 * Resolve which HubSpot OAuth integration or private-app token to use.
 *
 * - `integration` / `integrationName` wins when set (exact name, e.g. `hubspot-work`)
 * - `account: 'work'` → `hubspot-work`
 * - `account: 'default'` / `'hubspot'` / omitted → `hubspot`
 * - Private-app secret defaults to `hubspotPrivateAppToken`, or
 *   `hubspotPrivateAppToken-<purpose>` for `hubspot-<purpose>` integrations
 *
 * @example
 * import listHubSpotAccounts from 'kody:@kody/hubspot/accounts'
 * const accounts = await listHubSpotAccounts()
 */
export async function accounts(
	params: HubSpotAuthInput = {},
): Promise<HubSpotAccountResolution> {
	const integrationName = resolveIntegrationName(params)
	const secretName = resolveSecretName(params)
	const [secrets, integrations] = await Promise.all([
		listUserSecretNames(),
		listHubSpotIntegrationNames(),
	])
	const oauthConnected = integrations.includes(integrationName)
	const privateAppSaved = secrets.has(secretName)
	const forced = requireAuthMode(params.auth)
	let preferredAuth: HubSpotAccountResolution['preferredAuth'] = null
	if (forced === 'oauth' && oauthConnected) preferredAuth = 'oauth'
	else if (forced === 'privateApp' && privateAppSaved) preferredAuth = 'privateApp'
	else if (oauthConnected) preferredAuth = 'oauth'
	else if (privateAppSaved) preferredAuth = 'privateApp'

	return {
		integrationName,
		secretName,
		oauthConnected,
		privateAppSaved,
		preferredAuth,
		connectUrl: oauthConnectUrl(integrationName),
		privateAppUrl: privateAppSetupUrl(secretName),
		scopes: HUBSPOT_SCOPES,
		defaultScopes: [...DEFAULT_OAUTH_SCOPES],
		requiredHosts: [...HUBSPOT_REQUIRED_HOSTS],
		callbackUrl: HUBSPOT_CALLBACK_URL,
		oauthAppUrl: HUBSPOT_OAUTH_APP_URL,
		privateAppDashboardUrl: HUBSPOT_PRIVATE_APP_URL,
	}
}

export { DEFAULT_INTEGRATION_NAME, DEFAULT_TOKEN_SECRET }

/**
 * Resolve which HubSpot OAuth integration or private-app token to use.
 * @example
 * import listHubSpotAccounts from 'kody:@kody/hubspot/accounts'
 * const info = await listHubSpotAccounts({ account: 'work' })
 */
export default async function accountsEntrypoint(
	params: HubSpotAuthInput & Record<string, unknown> = {},
) {
	return accounts(requireRecord(params, 'accounts') as HubSpotAuthInput)
}