Skip to content

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

Package listing

@kody/linear

src/request.ts

92 lines · 2.8 KB · TypeScript
import { inferOperation, isReadOnlyQuery, linearGraphql } from './client.ts'
import { LINEAR_GRAPHQL_URL } from './setup.ts'
import type { JsonRecord, LinearAuthInput } from './types.ts'
import {
	optionalBoolean,
	optionalString,
	requireRecord,
	requireString,
} from './types.ts'
import { requireAuthMode } from './auth.ts'

export type LinearRequestInput = LinearAuthInput & {
	query: string
	variables?: JsonRecord
	confirm?: boolean
	dryRun?: boolean
}

/**
 * Call Linear GraphQL with a saved OAuth integration or personal API key.
 * Unknown and mutating operations require `confirm: true`; use `dryRun: true`
 * to preview.
 * @example
 * import request from 'kody:@kody/linear/request'
 * const result = await request({
 *   query: 'query { viewer { id } }',
 * })
 */
export async function request(input: LinearRequestInput) {
	const query = requireString(input.query, 'query')
	const operation = inferOperation(query)
	const integrationName =
		optionalString(input.integrationName, 'integrationName') ??
		optionalString(input.integration, 'integration')
	const secretName = optionalString(input.secretName, 'secretName')
	const account = optionalString(input.account, 'account')

	if (input.dryRun) {
		return {
			dryRun: true,
			url: LINEAR_GRAPHQL_URL,
			operation,
			query,
			variables: input.variables ?? {},
			integrationName: integrationName ?? null,
			secretName: secretName ?? null,
			account: account ?? null,
			readOnly: isReadOnlyQuery(query, operation),
		}
	}

	if (!isReadOnlyQuery(query, operation) && input.confirm !== true) {
		throw new Error(
			'This Linear GraphQL request may mutate data. Pass confirm: true only after explicit user approval, or use dryRun: true.',
		)
	}

	return linearGraphql({
		query,
		variables: input.variables,
		operation,
		integrationName,
		integration: input.integration,
		account,
		secretName,
		auth: input.auth,
	})
}

/**
 * Call Linear GraphQL with a saved OAuth integration or personal API key.
 * Mutating documents require `confirm: true`; use `dryRun: true` to preview.
 * @example
 * import request from 'kody:@kody/linear/request'
 * const result = await request({ query: 'query { teams { nodes { id key } } }' })
 */
export default async function requestEntrypoint(
	params: Partial<LinearRequestInput> & Record<string, unknown> = {},
) {
	const input = requireRecord(params, 'request')
	return request({
		query: requireString(input.query, 'query'),
		variables: input.variables as JsonRecord | undefined,
		integrationName: optionalString(input.integrationName, 'integrationName'),
		integration: optionalString(input.integration, 'integration'),
		account: optionalString(input.account, 'account'),
		secretName: optionalString(input.secretName, 'secretName'),
		auth: requireAuthMode(input.auth),
		confirm: optionalBoolean(input.confirm, 'confirm'),
		dryRun: optionalBoolean(input.dryRun, 'dryRun'),
	})
}