TypeScript 61.9%
HTML 37.2%
SQL 0.7%
1import { readFileSync } from 'node:fs';2import path from 'node:path';3import { fileURLToPath } from 'node:url';4import { RegistrySchema, type ConnectorMeta, type Registry, type RareIndexConnector } from './types.js';56const here = path.dirname(fileURLToPath(import.meta.url));7export const CONNECTORS_DIR = path.resolve(here, '../../../connectors');8export const REGISTRY_PATH = path.join(CONNECTORS_DIR, 'registry.json');910let cached: Registry | null = null;1112/** Load and validate connectors/registry.json (§106). */13export function loadRegistry(force = false): Registry {14 if (cached && !force) return cached;15 const raw = JSON.parse(readFileSync(REGISTRY_PATH, 'utf8'));16 cached = RegistrySchema.parse(raw);17 const ids = new Set<string>();18 for (const c of cached.connectors) {19 if (ids.has(c.id)) throw new Error(`registry: duplicate connector id ${c.id}`);20 ids.add(c.id);21 }22 return cached;23}2425export function getConnectorMeta(id: string): ConnectorMeta {26 const meta = loadRegistry().connectors.find((c) => c.id === id);27 if (!meta) throw new Error(`Unknown connector: ${id}`);28 return meta;29}3031export function listConnectorMeta(filter: { enabled?: boolean; category?: string; sourceType?: string } = {}): ConnectorMeta[] {32 return loadRegistry().connectors.filter((c) => {33 if (filter.enabled !== undefined && c.enabled !== filter.enabled) return false;34 if (filter.category && !c.categories.includes(filter.category)) return false;35 if (filter.sourceType && c.sourceType !== filter.sourceType) return false;36 return true;37 });38}3940/**41 * Dynamically import a connector module. Each module default-exports a factory42 * `(meta: ConnectorMeta) => RareIndexConnector`.43 */44export async function loadConnector(id: string): Promise<RareIndexConnector> {45 const meta = getConnectorMeta(id);46 const modPath = path.join(CONNECTORS_DIR, meta.module, 'index.ts');47 const mod = (await import(modPath)) as { default?: (meta: ConnectorMeta) => RareIndexConnector | Promise<RareIndexConnector>; createConnector?: (meta: ConnectorMeta) => RareIndexConnector | Promise<RareIndexConnector> };48 const factory = mod.default ?? mod.createConnector;49 if (!factory) throw new Error(`connector module ${meta.module} must default-export a factory`);50 return factory(meta);51}5253/** Find connectors whose urlPatterns match a URL (scanner paste-URL, §114). */54export async function connectorsForUrl(url: string): Promise<RareIndexConnector[]> {55 const out: RareIndexConnector[] = [];56 for (const meta of listConnectorMeta({ enabled: true })) {57 if (!meta.supportsLookup) continue;58 const c = await loadConnector(meta.id);59 if (c.urlPatterns?.some((re) => re.test(url))) out.push(c);60 }61 return out;62}63