Skip to content

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

Package listing

@kody/plaid

src/item.ts

116 lines · 3.3 KB · TypeScript
import {
	accessTokenForPreview,
	accessTokenSetupUrl,
	mutationPreview,
	normalizeItem,
	plaidRequest,
	requireString,
	resolveAccessTokenSecretName,
	type MutationGuardInput,
	type PlaidAuthInput,
} from './plaid-core.ts'

export type ItemInput = PlaidAuthInput

/**
 * Retrieve Item status (`/item/get`). Needs an Item access token, never a
 * bank password.
 */
export async function getItem(input: ItemInput = {}) {
	const data = await plaidRequest({
		...input,
		path: '/item/get',
		includeAccessToken: true,
	})
	return {
		item: normalizeItem(data?.item),
		status: data?.status ?? null,
		request_id: data?.request_id ?? null,
	}
}

export type ExchangePublicTokenInput = MutationGuardInput & {
	publicToken?: string
}

/**
 * Exchange a short-lived `public_token` from Link (or sandbox create) for an
 * `access_token`. Defaults to dry-run; live exchange needs `confirm: true`.
 * Save the returned access_token as `plaidAccessToken` — do not paste bank
 * passwords into chat.
 */
export async function exchangePublicToken(input: ExchangePublicTokenInput = {}) {
	const publicToken = input.confirm === true && input.dryRun !== true ? requireString(input.publicToken, 'publicToken') : (input.publicToken ?? '<public_token>')
	const preview = mutationPreview(input, {
		action: 'exchange public token',
		method: 'POST',
		path: '/item/public_token/exchange',
		body: { public_token: publicToken },
	})
	if (preview) return preview
	const data = await plaidRequest({
		...input,
		path: '/item/public_token/exchange',
		body: { public_token: requireString(input.publicToken, 'publicToken') },
	})
	return {
		access_token: data?.access_token ?? null,
		item_id: data?.item_id ?? null,
		request_id: data?.request_id ?? null,
		saveAccessToken: accessTokenSetupUrl(resolveAccessTokenSecretName(input)),
		note: 'Save access_token as a Kody secret. Never store a bank login password.',
	}
}

export type RemoveItemInput = MutationGuardInput

/** Remove an Item (`/item/remove`). Defaults to dry-run; live needs confirm. */
export async function removeItem(input: RemoveItemInput = {}) {
	const preview = mutationPreview(input, {
		action: 'remove item',
		method: 'POST',
		path: '/item/remove',
		body: { access_token: accessTokenForPreview(input) },
	})
	if (preview) return preview
	const data = await plaidRequest({
		...input,
		path: '/item/remove',
		includeAccessToken: true,
	})
	return {
		removed: Boolean(data?.removed ?? true),
		request_id: data?.request_id ?? null,
	}
}

export type UpdateItemWebhookInput = MutationGuardInput & {
	webhook?: string
}

/** Update the Item webhook URL. Defaults to dry-run; live needs confirm. */
export async function updateItemWebhook(input: UpdateItemWebhookInput = {}) {
	const webhook =
		input.confirm === true && input.dryRun !== true
			? requireString(input.webhook, 'webhook')
			: (input.webhook ?? '<webhook_url>')
	const preview = mutationPreview(input, {
		action: 'update item webhook',
		method: 'POST',
		path: '/item/webhook/update',
		body: { access_token: accessTokenForPreview(input), webhook },
	})
	if (preview) return preview
	const data = await plaidRequest({
		...input,
		path: '/item/webhook/update',
		includeAccessToken: true,
		body: { webhook: requireString(input.webhook, 'webhook') },
	})
	return {
		item: normalizeItem(data?.item),
		request_id: data?.request_id ?? null,
	}
}

export default getItem