import { originRequest } from './request.ts'
import { type OriginRepoSummary } from './types.ts'
/**
* List Origin repositories for an owner the app installation can see.
*
* @param params.ownerSlug - Origin owner slug (for example `kentcdodds`).
* @param params.pageSize - Optional page size.
* @param params.pageToken - Optional pagination token from a previous call.
* @param params.filter - Optional Origin list filter string.
* @param params.installationId - Optional installation id override.
* @returns `{ items, nextPageToken }` of slim repo summaries.
* @example
* import listOriginRepos from 'kody:@kentcdodds/origin/repos'
* const { items } = await listOriginRepos({ ownerSlug: 'kentcdodds', pageSize: 5 })
* // => { items: [{ id: '...', name: 'kody', fullName: 'kentcdodds/kody', ... }], nextPageToken: null }
*/
export async function listOriginRepos(params: {
ownerSlug: string
pageSize?: number
pageToken?: string
filter?: string
installationId?: string
}): Promise<{ items: Array<OriginRepoSummary>; nextPageToken: string | null }> {
const ownerSlug = params.ownerSlug.trim()
if (!ownerSlug) {
throw new Error('ownerSlug is required.')
}
const result = await originRequest({
path: `/repos/${encodeURIComponent(ownerSlug)}`,
auth: 'installation',
installationId: params.installationId,
query: {
pageSize: params.pageSize,
pageToken: params.pageToken,
filter: params.filter,
},
})
if (!result.ok) {
const message =
isRecord(result.body) && typeof result.body.message === 'string'
? result.body.message
: `HTTP ${String(result.status)}`
throw new Error(`Failed to list Origin repos: ${message}`)
}
const payload = isRecord(result.body) ? result.body : {}
const raw = Array.isArray(payload.repositories) ? payload.repositories : []
return {
items: raw.map((item) => slimRepo(asRecord(item))),
nextPageToken:
typeof payload.nextPageToken === 'string' && payload.nextPageToken
? payload.nextPageToken
: null,
}
}
export async function getOriginRepo(params: {
ownerSlug: string
repoName: string
installationId?: string
}): Promise<OriginRepoSummary> {
const ownerSlug = params.ownerSlug.trim()
const repoName = params.repoName.trim()
if (!ownerSlug || !repoName) {
throw new Error('ownerSlug and repoName are required.')
}
const result = await originRequest({
path: `/repos/${encodeURIComponent(ownerSlug)}/${encodeURIComponent(repoName)}`,
auth: 'installation',
installationId: params.installationId,
})
if (!result.ok) {
const message =
isRecord(result.body) && typeof result.body.message === 'string'
? result.body.message
: `HTTP ${String(result.status)}`
throw new Error(`Failed to get Origin repo: ${message}`)
}
return slimRepo(asRecord(result.body))
}
export default listOriginRepos
function slimRepo(item: Record<string, unknown>): OriginRepoSummary {
const owner = isRecord(item.owner) ? item.owner : null
const mirror = isRecord(item.mirror) ? item.mirror : null
return {
id: stringField(item.id) ?? '',
name: stringField(item.name) ?? '',
fullName: stringField(item.fullName),
owner: owner
? {
slug: stringField(owner.slug) ?? '',
id: stringField(owner.id) ?? '',
}
: null,
defaultBranch: stringField(item.defaultBranch),
cloneUrl: stringField(item.cloneUrl),
mirror: mirror
? {
source: stringField(mirror.source),
status: stringField(mirror.status),
}
: null,
}
}
function asRecord(value: unknown): Record<string, unknown> {
return isRecord(value) ? value : {}
}
function isRecord(value: unknown): value is Record<string, unknown> {
return value !== null && typeof value === 'object' && !Array.isArray(value)
}
function stringField(value: unknown): string | null {
return typeof value === 'string' && value.length > 0 ? value : null
}