Skip to content

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

Package listing

@kody/bluesky

src/facets.ts

46 lines · 1.3 KB · TypeScript
type AnyRecord = Record<string, any>

function normalizeHttpUrl(value: unknown, label: string) {
	let url: URL
	try {
		url = new URL(String(value || ''))
	} catch {
		throw new Error(`${label} must be a valid URL`)
	}
	if (url.protocol !== 'http:' && url.protocol !== 'https:') {
		throw new Error(`${label} must use http or https`)
	}
	return url.toString()
}

function trimTrailingUrlPunctuation(value: string) {
	return value.replace(/[.,!?;:)\]}]+$/u, '')
}

export function buildLinkFacets(text: string) {
	const facets: AnyRecord[] = []
	const encoder = new TextEncoder()
	const matches = text.matchAll(/https?:\/\/[^\s]+/gu)
	for (const match of matches) {
		if (match.index === undefined) continue
		const matchedUrl = trimTrailingUrlPunctuation(match[0])
		if (!matchedUrl) continue
		let uri: string
		try {
			uri = normalizeHttpUrl(matchedUrl, 'Post link')
		} catch {
			continue
		}
		const byteStart = encoder.encode(text.slice(0, match.index)).byteLength
		const byteEnd = byteStart + encoder.encode(matchedUrl).byteLength
		facets.push({
			index: { byteStart, byteEnd },
			features: [{ $type: 'app.bsky.richtext.facet#link', uri }],
		})
	}
	return facets
}

export function normalizeExternalHttpUrl(value: unknown, label: string) {
	return normalizeHttpUrl(value, label)
}