/** * Topic Resolver — URL/ID → {mapId, contentId} resolution * * Supports three input formats: * 1. Direct IDs: {mapId, contentId} passthrough (from search/TOC results) * 2. Legacy bundle URL: /bundle/{bundleId}/page/{page}.html * 3. FT prettyUrl: /r/{locale}/{product}/{page} */ import { type LocaleId } from '../constants.js'; import type { MapsRegistry } from './maps-registry.js'; import { fetchMapTopics } from './ft-client.js'; import type { CacheProvider } from './interfaces/index.js'; export interface ResolvedTopic { mapId: string; contentId: string; locale: LocaleId; } export interface TopicResolverInput { url?: string; mapId?: string; contentId?: string; /** Optional locale override — takes precedence over locale extracted from URL */ locale?: string | undefined; } interface ParsedLegacyUrl { type: 'legacy'; locale: string; bundleId: string; pageSlug: string; } interface ParsedPrettyUrl { type: 'pretty'; locale: string; productSlug: string; topicSlug: string; } type ParsedUrl = ParsedLegacyUrl | ParsedPrettyUrl; export declare function parseUrl(url: string): ParsedUrl | null; export declare class TopicResolver { private readonly registry; private readonly cache; /** * In-flight deduplication for fetchMapTopics calls. * Prevents thundering-herd when batch-get-articles fires N concurrent * workers that all need the topic index for the same mapId. * * Instance member (not module-level) so it is scoped to a single * server lifetime and doesn't leak across requests in runtimes * where module scope persists (e.g. Cloudflare Workers). */ private readonly inflight; private readonly fetchMapTopicsFn; private readonly cacheTtl; constructor(registry: MapsRegistry, cache: CacheProvider, fetchMapTopicsFn?: typeof fetchMapTopics, cacheTtl?: number); private getTopicIndex; /** * Resolve input to {mapId, contentId, locale}. * * Accepts: * - Direct IDs: {mapId, contentId} — passthrough, zero cost * - URL string: legacy bundle URL or FT prettyUrl * - Combined: {url, mapId?, contentId?} — IDs preferred if present */ resolve(input: TopicResolverInput): Promise; private resolveLegacy; private resolvePretty; } /** * Build a full display URL from a FT prettyUrl path. * Validates that absolute URLs point to known Jamf hostnames. */ export declare function buildDisplayUrl(prettyUrl: string): string; export {}; //# sourceMappingURL=topic-resolver.d.ts.map