Skip to content

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

Package listing

@kody/trello

src/smoke-test.ts

166 lines · 4.7 KB · TypeScript
import { accounts } from './accounts.ts'
import { createBoard } from './boards.ts'
import { createCard } from './cards.ts'
import { addComment } from './comments.ts'
import { createList } from './lists.ts'
import { getViewer } from './viewer.ts'
import { listBoards } from './boards.ts'
import { parseAuthInput } from './auth.ts'
import {
	API_KEY_SETUP_URL,
	OAUTH_CONNECT_URL,
	TOKEN_SETUP_URL,
	TRELLO_CALLBACK_URL,
	TRELLO_REQUIRED_HOSTS,
} from './setup.ts'
import { isDryRunResult, mutationPreview } from './client.ts'
import type { TrelloAuthInput } from './types.ts'
import { requireRecord } from './types.ts'

export type SmokeTestInput = TrelloAuthInput & {
	/** When true, skip the live member/board query even if credentials exist. */
	setupOnly?: boolean
}

/**
 * Local dry-run self-check plus an optional live member + board list.
 * Never creates boards, lists, cards, or comments.
 * @example
 * import trello from 'kody:@kody/trello'
 * const result = await trello({ action: 'smoke-test' })
 */
export async function smokeTest(input: SmokeTestInput = {}) {
	const boardPreview = await createBoard({
		name: 'Kody Trello smoke',
		dryRun: true,
	})
	if (!isDryRunResult(boardPreview)) {
		throw new Error('createBoard dryRun self-check failed.')
	}

	const listPreview = await createList({
		boardId: 'board-id-from-caller',
		name: 'Ready',
		dryRun: true,
	})
	if (!isDryRunResult(listPreview)) {
		throw new Error('createList dryRun self-check failed.')
	}

	const cardPreview = await createCard({
		listId: 'list-id-from-caller',
		name: 'Draft card',
		dryRun: true,
	})
	if (!isDryRunResult(cardPreview)) {
		throw new Error('createCard dryRun self-check failed.')
	}

	const commentPreview = await addComment({
		cardId: 'card-id-from-caller',
		text: 'Dry run only',
		dryRun: true,
	})
	if (!isDryRunResult(commentPreview)) {
		throw new Error('addComment dryRun self-check failed.')
	}

	let confirmRequired = false
	try {
		mutationPreview({}, { method: 'POST', path: '/cards', body: { name: 'Nope' } })
	} catch {
		confirmRequired = true
	}
	if (!confirmRequired) throw new Error('confirm rejection self-check failed.')

	const info = await accounts(input)
	const canLive = Boolean(info.preferredAuth) && input.setupOnly !== true
	const selfCheck = {
		dryRunCreateBoard: true,
		dryRunCreateList: true,
		dryRunCreateCard: true,
		dryRunAddComment: true,
		confirmRequired,
		connectUrlUsesTrelloHost: info.connectUrl.includes('api.trello.com'),
		apiKeyUrlUsesTrelloHost: info.apiKeyUrl.includes('api.trello.com'),
		tokenUrlUsesTrelloHost: info.tokenUrl.includes('api.trello.com'),
		callbackUrl: info.callbackUrl === TRELLO_CALLBACK_URL,
	}

	if (!canLive) {
		return {
			ok: true,
			live: false,
			selfCheck,
			authMode: info.preferredAuth,
			integrationName: info.integrationName,
			apiKeySecretName: info.apiKeySecretName,
			tokenSecretName: info.tokenSecretName,
			oauthConnected: info.oauthConnected,
			keyTokenSaved: info.keyTokenSaved,
			setup: {
				connectUrl: info.connectUrl,
				reconnectUrl: info.reconnectUrl,
				apiKeyUrl: info.apiKeyUrl,
				tokenUrl: info.tokenUrl,
				authorizeUrl: info.authorizeUrl,
				callbackUrl: info.callbackUrl,
				requiredHosts: info.requiredHosts,
				nextSteps: [
					`Save the Trello API key (do not paste it in chat): ${info.apiKeyUrl}`,
					`Authorize a user token, then save it: ${info.authorizeUrl} then ${info.tokenUrl}`,
					`Or reconnect a saved OAuth integration: ${info.reconnectUrl}`,
					`Approve host ${TRELLO_REQUIRED_HOSTS.join(', ')}.`,
				],
			},
		}
	}

	const [viewer, boards] = await Promise.all([
		getViewer(input),
		listBoards({ ...input, limit: 5 }),
	])

	return {
		ok: true,
		live: true,
		selfCheck,
		authMode: info.preferredAuth,
		integrationName: info.integrationName,
		apiKeySecretName: info.apiKeySecretName,
		tokenSecretName: info.tokenSecretName,
		oauthConnected: info.oauthConnected,
		keyTokenSaved: info.keyTokenSaved,
		viewer: {
			id: viewer.id,
			username: viewer.username,
			fullName: viewer.fullName,
		},
		boardCount: boards.length,
		sampleBoard: boards[0]
			? { id: boards[0].id, name: boards[0].name, url: boards[0].url }
			: null,
		setup: {
			connectUrl: OAUTH_CONNECT_URL,
			apiKeyUrl: API_KEY_SETUP_URL,
			tokenUrl: TOKEN_SETUP_URL,
			requiredHosts: [...TRELLO_REQUIRED_HOSTS],
		},
	}
}

/**
 * Local dry-run self-check plus an optional live member read.
 * @example
 * import smokeTest from 'kody:@kody/trello/smoke-test'
 * const result = await smokeTest()
 */
export default async function smokeTestEntrypoint(
	params: SmokeTestInput & Record<string, unknown> = {},
) {
	const input = requireRecord(params, 'smoke-test')
	return smokeTest({
		...parseAuthInput(input),
		setupOnly: input.setupOnly === true,
	})
}