Skip to content

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

Package listing

@kody/airtable

src/smoke-test.ts

96 lines · 2.8 KB · TypeScript
import { accounts } from './accounts.ts'
import { pickAuthInput } from './auth.ts'
import {
	inferOperationFromPath,
	normalizeAirtablePath,
	oauthConnectUrl,
	recordsPath,
	scopeForOperation,
} from './setup.ts'
import type { AirtableAuthInput } from './types.ts'
import { requireRecord } from './types.ts'
import { getViewer } from './viewer.ts'

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

/**
 * Verify Airtable auth without returning account PII. Without credentials this
 * still returns setup URLs so the package is forkable before anyone connects.
 * @example
 * import smokeTest from 'kody:@kody/airtable/smoke-test'
 * const result = await smokeTest()
 */
export async function smokeTest(params: SmokeTestInput = {}) {
	const connectUrl = oauthConnectUrl('airtable')
	const selfCheck = {
		ok: true as const,
		pathNormalizesApiPrefix: normalizeAirtablePath('/meta/whoami') === '/v0/meta/whoami',
		commentWriteScope: scopeForOperation('comments.write') === 'data.recordComments:write',
		recordWriteFromPath:
			inferOperationFromPath('POST', '/v0/appExample/tblExample') === 'records.write',
		recordsPathEncodesTable:
			recordsPath('appExample', 'Table 1') === '/v0/appExample/Table%201',
		connectUrlUsesAuthorizeHost: connectUrl.includes('airtable.com'),
		connectUrlHasRecordsRead: connectUrl.includes('data.records%3Aread'),
	}
	const info = await accounts(params)
	const canLive = Boolean(info.preferredAuth) && params.setupOnly !== true

	if (!canLive) {
		return {
			ok: true,
			live: false,
			selfCheck,
			authMode: info.preferredAuth,
			integrationName: info.integrationName,
			secretName: info.secretName,
			oauthConnected: info.oauthConnected,
			patSaved: info.patSaved,
			hasViewerId: false,
			setup: {
				connectUrl: info.connectUrl,
				patUrl: info.patUrl,
				callbackUrl: info.callbackUrl,
				requiredHost: info.requiredHost,
			},
		}
	}

	const viewer = await getViewer(params)
	return {
		ok: true,
		live: true,
		selfCheck,
		authMode: info.preferredAuth,
		integrationName: info.integrationName,
		secretName: info.secretName,
		oauthConnected: info.oauthConnected,
		patSaved: info.patSaved,
		hasViewerId: viewer.id.length > 0,
		setup: {
			connectUrl: info.connectUrl,
			patUrl: info.patUrl,
			callbackUrl: info.callbackUrl,
			requiredHost: info.requiredHost,
		},
	}
}

/**
 * Verify Airtable auth without returning account PII.
 * @example
 * import smokeTest from 'kody:@kody/airtable/smoke-test'
 * const result = await smokeTest({ setupOnly: true })
 */
export default async function smokeTestEntrypoint(
	params: SmokeTestInput & Record<string, unknown> = {},
) {
	const input = requireRecord(params, 'smoke-test')
	return smokeTest({
		...pickAuthInput(input),
		setupOnly: input.setupOnly === true,
	})
}