Skip to content

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

Package listing

@kody/plaid

src/link.ts

79 lines · 2.5 KB · TypeScript
import {
	asStringArray,
	DEFAULT_COUNTRY_CODES,
	DEFAULT_PRODUCTS,
	mutationPreview,
	plaidRequest,
	requireString,
	type MutationGuardInput,
} from './plaid-core.ts'

export type CreateLinkTokenInput = MutationGuardInput & {
	clientName?: string
	language?: string
	countryCodes?: string[]
	products?: string[]
	clientUserId?: string
	webhook?: string
	redirectUri?: string
	/** Link update mode for an existing Item. Never collect a bank password. */
	accessToken?: string
}

/**
 * Create a Plaid Link token (`/link/token/create`). Defaults to dry-run;
 * live creation needs `confirm: true`.
 *
 * Link itself collects bank credentials in Plaid's UI. Agents must never ask
 * for or store a bank username or password in chat.
 */
export async function createLinkToken(input: CreateLinkTokenInput = {}) {
	const live = input.confirm === true && input.dryRun !== true
	const clientName = live ? requireString(input.clientName ?? 'Kody', 'clientName') : (input.clientName ?? 'Kody')
	const clientUserId = live
		? requireString(input.clientUserId, 'clientUserId')
		: (input.clientUserId ?? '<client_user_id>')
	const products = asStringArray(input.products, DEFAULT_PRODUCTS)
	const countryCodes = asStringArray(input.countryCodes, DEFAULT_COUNTRY_CODES)
	const body: Record<string, unknown> = {
		client_name: clientName,
		language: input.language ?? 'en',
		country_codes: countryCodes,
		user: { client_user_id: clientUserId },
		products,
		...(input.webhook ? { webhook: input.webhook } : {}),
		...(input.redirectUri ? { redirect_uri: input.redirectUri } : {}),
		...(input.accessToken ? { access_token: '<access_token>' } : {}),
	}
	const preview = mutationPreview(input, {
		action: 'create link token',
		method: 'POST',
		path: '/link/token/create',
		body,
	})
	if (preview) return preview
	const liveBody: Record<string, unknown> = {
		client_name: clientName,
		language: input.language ?? 'en',
		country_codes: countryCodes,
		user: { client_user_id: clientUserId },
		products,
		...(input.webhook ? { webhook: input.webhook } : {}),
		...(input.redirectUri ? { redirect_uri: input.redirectUri } : {}),
		...(input.accessToken ? { access_token: input.accessToken } : {}),
	}
	const data = await plaidRequest({
		...input,
		path: '/link/token/create',
		body: liveBody,
	})
	return {
		link_token: data?.link_token ?? null,
		expiration: data?.expiration ?? null,
		request_id: data?.request_id ?? null,
		hosted_link_url: data?.hosted_link_url ?? null,
		note: 'Open Plaid Link with this token. Do not collect bank login passwords in chat.',
	}
}

export default createLinkToken