← Public packages
@kody/api-research
Research third-party APIs: registry search, provider discovery, OpenAPI summarize, and client scaffold.
src/scaffold-client.ts
83 lines · 3.0 KB · TypeScriptimport { assertOpenApiBoundAuth, type OpenApiBoundAuth } from './auth.ts'
import { fetchOpenApiSpecText } from './fetch-spec-lib.ts'
import { assertHttpsUrl } from './https.ts'
import { parseOpenApiSpec } from './parse-spec-lib.ts'
import {
scaffoldOpenApiClient,
type OpenApiClientScaffold,
} from './scaffold-client-lib.ts'
export type ScaffoldClientInput = {
/** HTTPS URL of an OpenAPI 3.x document (JSON or YAML). */
specUrl: string
/** Operation slugs from summarize-spec (stable snake_case ids). */
operationIds: Array<string>
/** How the generated client authenticates. Names only — never credential values. */
auth: OpenApiBoundAuth
/** Absolute https API base URL used by the generated client. */
apiBaseUrl: string
/** Optional label included only in generated source comments. */
providerLabel?: string
}
export type ScaffoldClientOutput = OpenApiClientScaffold & {
usageNotes: string
}
function buildUsageNotes(authKind: string): string {
const integrationNote =
authKind === 'integration'
? ' For integration auth, complete the connect flow for that provider first.'
: ''
return [
'Paste moduleSource into execute as an ephemeral module, or into a package client.ts.',
'Hosts and secrets still require approval in the account security UI; the OpenAPI spec never widens host approval.',
`Auth kind for this scaffold: ${authKind}.${integrationNote}`,
].join(' ')
}
/**
* Fetch an OpenAPI spec and scaffold a small dependency-free ESM client.
* Use after summarize-spec to turn chosen operation slugs into package source.
*
* @param input - Spec URL, selected slugs, auth names, and API base URL
* @returns Generated module source plus selected operations
*
* @example
* import scaffoldClient from 'kody:@kody/api-research/scaffold-client'
* const client = await scaffoldClient({
* specUrl: 'https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json',
* operationIds: ['users_get_authenticated'],
* auth: { kind: 'integration', provider: 'github' },
* apiBaseUrl: 'https://api.github.com',
* })
*/
export default async function scaffoldClient(
input: ScaffoldClientInput,
): Promise<ScaffoldClientOutput> {
assertHttpsUrl(input.specUrl, 'OpenAPI spec URL')
assertHttpsUrl(input.apiBaseUrl, 'API base URL')
const auth = assertOpenApiBoundAuth(input.auth)
if (!Array.isArray(input.operationIds) || input.operationIds.length === 0) {
throw new Error('operationIds must include at least one slug')
}
if (input.operationIds.length > 50) {
throw new Error('operationIds is limited to 50 slugs')
}
const rawText = await fetchOpenApiSpecText({ specUrl: input.specUrl })
const parsed = parseOpenApiSpec(rawText)
const scaffold = scaffoldOpenApiClient({
spec: parsed,
operationSlugs: input.operationIds,
auth,
apiBaseUrl: input.apiBaseUrl,
providerLabel: input.providerLabel,
})
return {
...scaffold,
usageNotes: buildUsageNotes(auth.kind),
}
}
export { scaffoldOpenApiClient } from './scaffold-client-lib.ts'