Skip to content
← Public packages

@kody/integrations-sh

Client for the public integrations.sh registry: search, detect, cached surface, and live discover.

src/detect.ts

83 lines · 2.6 KB · TypeScript
import { fetchRegistryJson } from './client.ts'
import { normalizeProviderDomain } from './domain.ts'
import { isRecord } from './is-record.ts'
import { stringOrUndefined } from './types.ts'
import { buildDetectUrl } from './urls.ts'

const DETECT_FETCH_TIMEOUT_MS = 20_000

export type DetectInput = {
	/** Bare provider hostname (for example stripe.com). */
	domain: string
}

export type DetectOutput = {
	domain: string
	found: Array<string>
	probed: Array<string> | null
	errors: Array<string>
	mcpCount: number
	hasIntegrationsJson: boolean
	hasApiCatalog: boolean
	hasApiSchema: boolean
	hasAuth: boolean
	hasAgentCard: boolean
	hasAgentSkills: boolean
	llmsTxtUrl: string | null
	source: string
}

function stringList(value: unknown): Array<string> {
	if (!Array.isArray(value)) {
		return []
	}
	return value.filter((item): item is string => typeof item === 'string')
}

/**
 * Probe a domain's well-known agent manifests and live capability signals.
 * Use when you need current readiness, not the cached surface document.
 *
 * @param input - Bare provider hostname
 * @returns Compact detect summary (found keys, errors, pointer flags)
 *
 * @example
 * import detect from 'kody:@<username>/integrations-sh/detect'
 * const readiness = await detect({ domain: 'stripe.com' })
 */
export default async function detect(
	input: DetectInput,
): Promise<DetectOutput> {
	const domain = normalizeProviderDomain(input.domain)
	const source = buildDetectUrl(domain)
	const fetched = await fetchRegistryJson(source, DETECT_FETCH_TIMEOUT_MS)
	if (fetched.outcome !== 'success') {
		const detail =
			fetched.outcome === 'not-found'
				? `HTTP 404 for ${source}`
				: fetched.message
		throw new Error(`integrations.sh detect failed: ${detail}`)
	}
	if (!isRecord(fetched.json) || typeof fetched.json.domain !== 'string') {
		throw new Error('integrations.sh detect failed: unexpected response shape')
	}

	const llmsTxt = isRecord(fetched.json.llmsTxt) ? fetched.json.llmsTxt : null
	return {
		domain: fetched.json.domain,
		found: stringList(fetched.json.found),
		probed: Array.isArray(fetched.json.probed)
			? stringList(fetched.json.probed)
			: null,
		errors: stringList(fetched.json.errors),
		mcpCount: Array.isArray(fetched.json.mcp) ? fetched.json.mcp.length : 0,
		hasIntegrationsJson: fetched.json.integrationsJson != null,
		hasApiCatalog: fetched.json.apiCatalog != null,
		hasApiSchema: fetched.json.apiSchema != null,
		hasAuth: fetched.json.auth != null,
		hasAgentCard: fetched.json.agentCard != null,
		hasAgentSkills: fetched.json.agentSkills != null,
		llmsTxtUrl: stringOrUndefined(llmsTxt?.url) ?? null,
		source,
	}
}