@get-technology-inc/jamf-docs-mcp-server 3.0.6 → 3.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/constants/doc-types.d.ts +48 -0
- package/dist/core/constants/doc-types.d.ts.map +1 -0
- package/dist/core/constants/doc-types.js +58 -0
- package/dist/core/constants/doc-types.js.map +1 -0
- package/dist/core/constants/index.d.ts +16 -0
- package/dist/core/constants/index.d.ts.map +1 -0
- package/dist/core/constants/index.js +12 -0
- package/dist/core/constants/index.js.map +1 -0
- package/dist/core/constants/limits.d.ts +39 -0
- package/dist/core/constants/limits.d.ts.map +1 -0
- package/dist/core/constants/limits.js +51 -0
- package/dist/core/constants/limits.js.map +1 -0
- package/dist/core/constants/locales.d.ts +34 -0
- package/dist/core/constants/locales.d.ts.map +1 -0
- package/dist/core/constants/locales.js +20 -0
- package/dist/core/constants/locales.js.map +1 -0
- package/dist/core/constants/products.d.ts +127 -0
- package/dist/core/constants/products.d.ts.map +1 -0
- package/dist/core/constants/products.js +135 -0
- package/dist/core/constants/products.js.map +1 -0
- package/dist/core/constants/topics.d.ts +168 -0
- package/dist/core/constants/topics.d.ts.map +1 -0
- package/dist/core/constants/topics.js +186 -0
- package/dist/core/constants/topics.js.map +1 -0
- package/dist/core/constants.d.ts +7 -404
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/core/constants.js +16 -427
- package/dist/core/constants.js.map +1 -1
- package/dist/core/http-client.d.ts +14 -2
- package/dist/core/http-client.d.ts.map +1 -1
- package/dist/core/http-client.js +148 -17
- package/dist/core/http-client.js.map +1 -1
- package/dist/core/index.d.ts +12 -12
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +12 -13
- package/dist/core/index.js.map +1 -1
- package/dist/core/resources/index.js +1 -1
- package/dist/core/resources/index.js.map +1 -1
- package/dist/core/schemas/index.d.ts +3 -1
- package/dist/core/schemas/index.d.ts.map +1 -1
- package/dist/core/schemas/index.js +12 -1
- package/dist/core/schemas/index.js.map +1 -1
- package/dist/core/schemas/output.d.ts +7 -0
- package/dist/core/schemas/output.d.ts.map +1 -1
- package/dist/core/schemas/output.js +7 -0
- package/dist/core/schemas/output.js.map +1 -1
- package/dist/core/services/article-service.d.ts +24 -0
- package/dist/core/services/article-service.d.ts.map +1 -0
- package/dist/core/services/article-service.js +118 -0
- package/dist/core/services/article-service.js.map +1 -0
- package/dist/core/services/content-parser.d.ts +38 -0
- package/dist/core/services/content-parser.d.ts.map +1 -0
- package/dist/core/services/content-parser.js +146 -0
- package/dist/core/services/content-parser.js.map +1 -0
- package/dist/core/services/ft-client.d.ts +52 -0
- package/dist/core/services/ft-client.d.ts.map +1 -0
- package/dist/core/services/ft-client.js +87 -0
- package/dist/core/services/ft-client.js.map +1 -0
- package/dist/core/services/glossary.d.ts +9 -5
- package/dist/core/services/glossary.d.ts.map +1 -1
- package/dist/core/services/glossary.js +174 -107
- package/dist/core/services/glossary.js.map +1 -1
- package/dist/core/services/interfaces/cache.d.ts +6 -6
- package/dist/core/services/interfaces/cache.d.ts.map +1 -1
- package/dist/core/services/interfaces/index.d.ts +3 -3
- package/dist/core/services/interfaces/index.d.ts.map +1 -1
- package/dist/core/services/interfaces/logger.d.ts +17 -10
- package/dist/core/services/interfaces/logger.d.ts.map +1 -1
- package/dist/core/services/interfaces/metadata.d.ts +0 -10
- package/dist/core/services/interfaces/metadata.d.ts.map +1 -1
- package/dist/core/services/interfaces/providers.d.ts +23 -10
- package/dist/core/services/interfaces/providers.d.ts.map +1 -1
- package/dist/core/services/logging.d.ts +38 -18
- package/dist/core/services/logging.d.ts.map +1 -1
- package/dist/core/services/logging.js +78 -29
- package/dist/core/services/logging.js.map +1 -1
- package/dist/core/services/maps-registry.d.ts +82 -0
- package/dist/core/services/maps-registry.d.ts.map +1 -0
- package/dist/core/services/maps-registry.js +232 -0
- package/dist/core/services/maps-registry.js.map +1 -0
- package/dist/core/services/metadata.d.ts +18 -9
- package/dist/core/services/metadata.d.ts.map +1 -1
- package/dist/core/services/metadata.js +113 -254
- package/dist/core/services/metadata.js.map +1 -1
- package/dist/core/services/search-service.d.ts +31 -0
- package/dist/core/services/search-service.d.ts.map +1 -0
- package/dist/core/services/search-service.js +471 -0
- package/dist/core/services/search-service.js.map +1 -0
- package/dist/core/services/toc-service.d.ts +30 -0
- package/dist/core/services/toc-service.d.ts.map +1 -0
- package/dist/core/services/toc-service.js +101 -0
- package/dist/core/services/toc-service.js.map +1 -0
- package/dist/core/services/tokenizer.d.ts +1 -1
- package/dist/core/services/tokenizer.d.ts.map +1 -1
- package/dist/core/services/tokenizer.js +3 -3
- package/dist/core/services/tokenizer.js.map +1 -1
- package/dist/core/services/topic-resolver.d.ts +57 -0
- package/dist/core/services/topic-resolver.d.ts.map +1 -0
- package/dist/core/services/topic-resolver.js +185 -0
- package/dist/core/services/topic-resolver.js.map +1 -0
- package/dist/core/tools/batch-get-articles.d.ts +0 -2
- package/dist/core/tools/batch-get-articles.d.ts.map +1 -1
- package/dist/core/tools/batch-get-articles.js +12 -46
- package/dist/core/tools/batch-get-articles.js.map +1 -1
- package/dist/core/tools/get-article.d.ts.map +1 -1
- package/dist/core/tools/get-article.js +29 -112
- package/dist/core/tools/get-article.js.map +1 -1
- package/dist/core/tools/get-toc.js +1 -1
- package/dist/core/tools/get-toc.js.map +1 -1
- package/dist/core/tools/search.js +5 -5
- package/dist/core/tools/search.js.map +1 -1
- package/dist/core/types/context.d.ts +5 -2
- package/dist/core/types/context.d.ts.map +1 -1
- package/dist/core/types.d.ts +141 -31
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/utils/bundle.d.ts +14 -1
- package/dist/core/utils/bundle.d.ts.map +1 -1
- package/dist/core/utils/bundle.js +19 -2
- package/dist/core/utils/bundle.js.map +1 -1
- package/dist/core/utils/format-article.d.ts +45 -0
- package/dist/core/utils/format-article.d.ts.map +1 -0
- package/dist/core/utils/format-article.js +138 -0
- package/dist/core/utils/format-article.js.map +1 -0
- package/dist/core/utils/ft-metadata.d.ts +22 -0
- package/dist/core/utils/ft-metadata.d.ts.map +1 -0
- package/dist/core/utils/ft-metadata.js +30 -0
- package/dist/core/utils/ft-metadata.js.map +1 -0
- package/dist/core/utils/sanitize.d.ts.map +1 -1
- package/dist/core/utils/sanitize.js +0 -2
- package/dist/core/utils/sanitize.js.map +1 -1
- package/dist/core/utils/url.d.ts.map +1 -1
- package/dist/core/utils/url.js +0 -1
- package/dist/core/utils/url.js.map +1 -1
- package/dist/index.js +10 -6
- package/dist/index.js.map +1 -1
- package/dist/platforms/node/http-server.d.ts +13 -0
- package/dist/platforms/node/http-server.d.ts.map +1 -0
- package/dist/platforms/node/http-server.js +231 -0
- package/dist/platforms/node/http-server.js.map +1 -0
- package/dist/platforms/node/index.d.ts +1 -1
- package/dist/platforms/node/index.d.ts.map +1 -1
- package/dist/platforms/node/index.js +1 -1
- package/dist/platforms/node/index.js.map +1 -1
- package/dist/platforms/node/logger.d.ts +13 -2
- package/dist/platforms/node/logger.d.ts.map +1 -1
- package/dist/platforms/node/logger.js +17 -4
- package/dist/platforms/node/logger.js.map +1 -1
- package/dist/transport/http-handler.d.ts +25 -0
- package/dist/transport/http-handler.d.ts.map +1 -0
- package/dist/transport/http-handler.js +193 -0
- package/dist/transport/http-handler.js.map +1 -0
- package/dist/transport/http-types.d.ts +22 -0
- package/dist/transport/http-types.d.ts.map +1 -0
- package/dist/transport/http-types.js +65 -0
- package/dist/transport/http-types.js.map +1 -0
- package/dist/transport/http.d.ts +4 -8
- package/dist/transport/http.d.ts.map +1 -1
- package/dist/transport/http.js +4 -376
- package/dist/transport/http.js.map +1 -1
- package/dist/transport/index.js +2 -2
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/rate-limiter.d.ts +16 -0
- package/dist/transport/rate-limiter.d.ts.map +1 -0
- package/dist/transport/rate-limiter.js +55 -0
- package/dist/transport/rate-limiter.js.map +1 -0
- package/package.json +3 -3
- package/dist/core/services/interfaces.d.ts +0 -94
- package/dist/core/services/interfaces.d.ts.map +0 -1
- package/dist/core/services/interfaces.js +0 -8
- package/dist/core/services/interfaces.js.map +0 -1
- package/dist/core/services/scraper.d.ts +0 -90
- package/dist/core/services/scraper.d.ts.map +0 -1
- package/dist/core/services/scraper.js +0 -990
- package/dist/core/services/scraper.js.map +0 -1
- package/dist/core/utils/doc-type.d.ts +0 -12
- package/dist/core/utils/doc-type.d.ts.map +0 -1
- package/dist/core/utils/doc-type.js +0 -24
- package/dist/core/utils/doc-type.js.map +0 -1
- package/dist/platforms/node/metadata.d.ts +0 -18
- package/dist/platforms/node/metadata.d.ts.map +0 -1
- package/dist/platforms/node/metadata.js +0 -35
- package/dist/platforms/node/metadata.js.map +0 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared article-fetch service
|
|
3
|
+
*
|
|
4
|
+
* Consolidates the duplicated fetch-parse-tokenize pipeline that was in
|
|
5
|
+
* both get-article.ts and batch-get-articles.ts into a single function.
|
|
6
|
+
*
|
|
7
|
+
* Key optimization: metadata and content are fetched in parallel via
|
|
8
|
+
* Promise.all when the cache misses.
|
|
9
|
+
*/
|
|
10
|
+
import { TOKEN_CONFIG } from '../constants.js';
|
|
11
|
+
import { buildDisplayUrl } from './topic-resolver.js';
|
|
12
|
+
import { fetchTopicContent, fetchTopicMetadata } from './ft-client.js';
|
|
13
|
+
import { parseArticle } from './content-parser.js';
|
|
14
|
+
import { getMetaValue, bundleStemToDisplayName, FT_META } from '../utils/ft-metadata.js';
|
|
15
|
+
import { extractSections, extractSummary, extractSection, truncateToTokenLimit, createTokenInfo, } from './tokenizer.js';
|
|
16
|
+
export async function fetchArticleFromFt(cache, mapId, contentId, articleUrl, options, cacheTtl) {
|
|
17
|
+
const maxTokens = options.maxTokens ?? TOKEN_CONFIG.DEFAULT_MAX_TOKENS;
|
|
18
|
+
const cacheKey = `ft:article:v2:${mapId}:${contentId}`;
|
|
19
|
+
let cached = await cache.get(cacheKey);
|
|
20
|
+
if (cached === null) {
|
|
21
|
+
// Cache miss — fetch metadata AND content in parallel
|
|
22
|
+
const [topicMeta, html] = await Promise.all([
|
|
23
|
+
fetchTopicMetadata(mapId, contentId),
|
|
24
|
+
fetchTopicContent(mapId, contentId),
|
|
25
|
+
]);
|
|
26
|
+
const displayUrl = deriveDisplayUrl(topicMeta.readerUrl, articleUrl);
|
|
27
|
+
const { product, version } = extractProductVersion(topicMeta.metadata);
|
|
28
|
+
const rawContent = parseArticle(html, displayUrl, { includeRelated: true });
|
|
29
|
+
cached = { content: rawContent, displayUrl, product, version };
|
|
30
|
+
await cache.set(cacheKey, cached, cacheTtl);
|
|
31
|
+
}
|
|
32
|
+
const { content: rawContent, displayUrl, product, version } = cached;
|
|
33
|
+
// Build base result (shared across all code paths)
|
|
34
|
+
const allSections = extractSections(rawContent.content);
|
|
35
|
+
const base = {
|
|
36
|
+
title: rawContent.title,
|
|
37
|
+
url: displayUrl,
|
|
38
|
+
product,
|
|
39
|
+
version,
|
|
40
|
+
breadcrumb: rawContent.breadcrumb.length > 0 ? rawContent.breadcrumb : undefined,
|
|
41
|
+
relatedArticles: options.includeRelated === true && rawContent.relatedArticles.length > 0
|
|
42
|
+
? rawContent.relatedArticles : undefined,
|
|
43
|
+
mapId,
|
|
44
|
+
contentId,
|
|
45
|
+
sections: allSections,
|
|
46
|
+
};
|
|
47
|
+
// ── summaryOnly mode ──
|
|
48
|
+
if (options.summaryOnly === true) {
|
|
49
|
+
const summaryResult = extractSummary(rawContent.content, rawContent.title, maxTokens);
|
|
50
|
+
let summaryContent = `## Summary\n\n${summaryResult.summary}\n\n`;
|
|
51
|
+
summaryContent += `## Article Outline (${summaryResult.outline.length} sections)\n\n`;
|
|
52
|
+
for (const section of summaryResult.outline) {
|
|
53
|
+
const indent = ' '.repeat(Math.max(0, section.level - 1));
|
|
54
|
+
summaryContent += `${indent}- ${section.title} (~${section.tokenCount} tokens)\n`;
|
|
55
|
+
}
|
|
56
|
+
summaryContent += `\n*Estimated read time: ${summaryResult.estimatedReadTime} min`
|
|
57
|
+
+ ` (${summaryResult.totalTokens.toLocaleString()} tokens)*\n`;
|
|
58
|
+
return { ...base, content: summaryContent, tokenInfo: summaryResult.tokenInfo };
|
|
59
|
+
}
|
|
60
|
+
// ── Section extraction ──
|
|
61
|
+
if (options.section !== undefined && options.section !== '') {
|
|
62
|
+
const sectionResult = extractSection(rawContent.content, options.section, maxTokens);
|
|
63
|
+
if (sectionResult.section !== null) {
|
|
64
|
+
return { ...base, content: sectionResult.content, tokenInfo: sectionResult.tokenInfo };
|
|
65
|
+
}
|
|
66
|
+
const sectionsList = allSections.map(s => `- ${s.title}`).join('\n');
|
|
67
|
+
const notFoundMsg = `*Section "${options.section}" not found.*\n\n**Available sections:**\n${sectionsList}`;
|
|
68
|
+
return { ...base, content: notFoundMsg, tokenInfo: createTokenInfo(notFoundMsg, maxTokens) };
|
|
69
|
+
}
|
|
70
|
+
// ── Full content with truncation ──
|
|
71
|
+
const truncateResult = truncateToTokenLimit(rawContent.content, maxTokens, allSections);
|
|
72
|
+
return { ...base, content: truncateResult.content, tokenInfo: truncateResult.tokenInfo };
|
|
73
|
+
}
|
|
74
|
+
// ─── Resolve + fetch (shared by get-article & batch-get-articles) ──
|
|
75
|
+
/**
|
|
76
|
+
* Full article retrieval pipeline:
|
|
77
|
+
* 1. Resolve mapId + contentId (skip if already provided)
|
|
78
|
+
* 2. Try provider shortcuts (articleProvider)
|
|
79
|
+
* 3. Fall back to FT API via fetchArticleFromFt
|
|
80
|
+
*
|
|
81
|
+
* Both get-article and batch-get-articles delegate here.
|
|
82
|
+
*/
|
|
83
|
+
export async function resolveAndFetchArticle(ctx, input, options) {
|
|
84
|
+
const { topicResolver, cache, articleProvider } = ctx;
|
|
85
|
+
const articleUrl = input.url ?? '';
|
|
86
|
+
// Step 1: Resolve mapId + contentId
|
|
87
|
+
let mapId = input.mapId;
|
|
88
|
+
let contentId = input.contentId;
|
|
89
|
+
if (mapId === undefined || contentId === undefined) {
|
|
90
|
+
const resolved = await topicResolver.resolve({ url: articleUrl });
|
|
91
|
+
({ mapId, contentId } = resolved);
|
|
92
|
+
}
|
|
93
|
+
// Step 2: Try provider shortcuts (ID-based is primary, URL-based is fallback)
|
|
94
|
+
let article = null;
|
|
95
|
+
if (articleProvider !== undefined) {
|
|
96
|
+
article = await articleProvider.getArticleByIds(mapId, contentId, options);
|
|
97
|
+
}
|
|
98
|
+
if (article === null && articleProvider?.getArticle !== undefined && articleUrl !== '') {
|
|
99
|
+
article = await articleProvider.getArticle(articleUrl, options);
|
|
100
|
+
}
|
|
101
|
+
if (article !== null) {
|
|
102
|
+
return { ...article, mapId, contentId };
|
|
103
|
+
}
|
|
104
|
+
// Step 3: Default — fetch from FT API + parse
|
|
105
|
+
return await fetchArticleFromFt(cache, mapId, contentId, articleUrl, options, ctx.config.cacheTtl.article);
|
|
106
|
+
}
|
|
107
|
+
// ─── Helpers ───────────────────────────────────────────────────
|
|
108
|
+
function deriveDisplayUrl(readerUrl, fallbackUrl) {
|
|
109
|
+
const prettyUrl = readerUrl ?? '';
|
|
110
|
+
return prettyUrl !== '' ? buildDisplayUrl(prettyUrl) : fallbackUrl;
|
|
111
|
+
}
|
|
112
|
+
function extractProductVersion(metadata) {
|
|
113
|
+
const stem = getMetaValue(metadata, FT_META.VERSION_BUNDLE_STEM);
|
|
114
|
+
const product = stem !== '' ? bundleStemToDisplayName(stem) : undefined;
|
|
115
|
+
const version = getMetaValue(metadata, FT_META.VERSION);
|
|
116
|
+
return { product, version: version !== '' ? version : 'current' };
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=article-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"article-service.js","sourceRoot":"","sources":["../../../src/core/services/article-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Parser — HTML → Markdown article structure
|
|
3
|
+
*
|
|
4
|
+
* Handles:
|
|
5
|
+
* - HTML cleaning (remove scripts, fix relative URLs)
|
|
6
|
+
* - HTML → Markdown conversion (Turndown)
|
|
7
|
+
* - Article structure extraction (title, breadcrumb, related articles)
|
|
8
|
+
* - Search snippet cleaning
|
|
9
|
+
*/
|
|
10
|
+
import * as cheerio from 'cheerio';
|
|
11
|
+
/**
|
|
12
|
+
* Clean HTML content: remove unwanted elements, fix relative URLs.
|
|
13
|
+
*/
|
|
14
|
+
export declare function cleanHtml($: cheerio.CheerioAPI): void;
|
|
15
|
+
export interface ParsedArticleContent {
|
|
16
|
+
title: string;
|
|
17
|
+
content: string;
|
|
18
|
+
breadcrumb: string[];
|
|
19
|
+
relatedArticles: {
|
|
20
|
+
title: string;
|
|
21
|
+
url: string;
|
|
22
|
+
}[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Parse HTML into article structure (title, markdown content, breadcrumb).
|
|
26
|
+
*/
|
|
27
|
+
export declare function parseArticle(html: string, displayUrl: string, options?: {
|
|
28
|
+
includeRelated?: boolean;
|
|
29
|
+
}): ParsedArticleContent;
|
|
30
|
+
/**
|
|
31
|
+
* Clean an HTML search snippet: strip tags, clean breadcrumb prefixes.
|
|
32
|
+
*/
|
|
33
|
+
export declare function cleanSnippet(snippet: string, title: string, product: string | null): string;
|
|
34
|
+
/**
|
|
35
|
+
* Convert raw HTML to Markdown using the shared Turndown instance.
|
|
36
|
+
*/
|
|
37
|
+
export declare function htmlToMarkdown(html: string): string;
|
|
38
|
+
//# sourceMappingURL=content-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-parser.d.ts","sourceRoot":"","sources":["../../../src/core/services/content-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAiCnC;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,UAAU,GAAG,IAAI,CAgBrD;AAID,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,eAAe,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACnD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAE,GACrC,oBAAoB,CAgEtB;AAUD;;GAEG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GAAG,IAAI,GACrB,MAAM,CAwBR;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Parser — HTML → Markdown article structure
|
|
3
|
+
*
|
|
4
|
+
* Handles:
|
|
5
|
+
* - HTML cleaning (remove scripts, fix relative URLs)
|
|
6
|
+
* - HTML → Markdown conversion (Turndown)
|
|
7
|
+
* - Article structure extraction (title, breadcrumb, related articles)
|
|
8
|
+
* - Search snippet cleaning
|
|
9
|
+
*/
|
|
10
|
+
import * as cheerio from 'cheerio';
|
|
11
|
+
import TurndownService from 'turndown';
|
|
12
|
+
import { DOCS_BASE_URL, SELECTORS } from '../constants.js';
|
|
13
|
+
// ─── Turndown instance ──────────────────────────────────────────
|
|
14
|
+
const turndown = new TurndownService({
|
|
15
|
+
headingStyle: 'atx',
|
|
16
|
+
codeBlockStyle: 'fenced',
|
|
17
|
+
bulletListMarker: '-',
|
|
18
|
+
emDelimiter: '*',
|
|
19
|
+
strongDelimiter: '**',
|
|
20
|
+
});
|
|
21
|
+
turndown.addRule('codeBlocks', {
|
|
22
|
+
filter: 'pre',
|
|
23
|
+
replacement: (content, node) => {
|
|
24
|
+
const nodeElement = node;
|
|
25
|
+
const codeElement = nodeElement.querySelector?.('code');
|
|
26
|
+
const language = codeElement?.className?.replace('language-', '') ?? '';
|
|
27
|
+
return `\n\`\`\`${language}\n${content.trim()}\n\`\`\`\n`;
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
turndown.addRule('stripScripts', {
|
|
31
|
+
filter: ['script', 'style', 'noscript'],
|
|
32
|
+
replacement: () => '',
|
|
33
|
+
});
|
|
34
|
+
// ─── HTML cleaning ──────────────────────────────────────────────
|
|
35
|
+
/**
|
|
36
|
+
* Clean HTML content: remove unwanted elements, fix relative URLs.
|
|
37
|
+
*/
|
|
38
|
+
export function cleanHtml($) {
|
|
39
|
+
$(SELECTORS.REMOVE).remove();
|
|
40
|
+
$('a[href^="/"]').each((_, el) => {
|
|
41
|
+
const href = $(el).attr('href');
|
|
42
|
+
if (href !== undefined && href !== '') {
|
|
43
|
+
$(el).attr('href', `${DOCS_BASE_URL}${href}`);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
$('img[src^="/"]').each((_, el) => {
|
|
47
|
+
const src = $(el).attr('src');
|
|
48
|
+
if (src !== undefined && src !== '') {
|
|
49
|
+
$(el).attr('src', `${DOCS_BASE_URL}${src}`);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Parse HTML into article structure (title, markdown content, breadcrumb).
|
|
55
|
+
*/
|
|
56
|
+
export function parseArticle(html, displayUrl, options) {
|
|
57
|
+
const $ = cheerio.load(html);
|
|
58
|
+
cleanHtml($);
|
|
59
|
+
// Extract content — try FT API selectors first (most common path),
|
|
60
|
+
// then fall back to generic page selectors.
|
|
61
|
+
// 1. FT API returns HTML fragments wrapped in <div class="content-locale-...">
|
|
62
|
+
let contentHtml = $('div[class*="content-locale"]').first().html() ?? '';
|
|
63
|
+
// 2. Common FT body wrappers (taskbody, conbody, refbody, etc.)
|
|
64
|
+
if (contentHtml === '') {
|
|
65
|
+
contentHtml = $('[class*="body"]').first().html() ?? '';
|
|
66
|
+
}
|
|
67
|
+
// 3. Standard selectors for full HTML pages (article, .article-content, etc.)
|
|
68
|
+
if (contentHtml === '') {
|
|
69
|
+
contentHtml = $(SELECTORS.CONTENT).html() ?? '';
|
|
70
|
+
}
|
|
71
|
+
// 4. Fallback: inner HTML of <body> (cheerio wraps fragments in <html><body>)
|
|
72
|
+
if (contentHtml === '') {
|
|
73
|
+
contentHtml = $('body').html() ?? '';
|
|
74
|
+
}
|
|
75
|
+
// 5. Last resort: use raw HTML as-is
|
|
76
|
+
if (contentHtml === '') {
|
|
77
|
+
contentHtml = html;
|
|
78
|
+
}
|
|
79
|
+
const extractedTitle = $(SELECTORS.TITLE).first().text().trim();
|
|
80
|
+
const title = extractedTitle !== '' ? extractedTitle : 'Untitled';
|
|
81
|
+
// Convert to Markdown and strip Turndown anchor artifacts from headings
|
|
82
|
+
const content = turndown.turndown(contentHtml)
|
|
83
|
+
.replace(/^(#{1,6}\s+)\[([^\]]*)\]\(#[^)]*\)/gm, '$1$2');
|
|
84
|
+
// Extract breadcrumb
|
|
85
|
+
const breadcrumb = $(SELECTORS.BREADCRUMB)
|
|
86
|
+
.map((_, el) => $(el).text().trim())
|
|
87
|
+
.get()
|
|
88
|
+
.filter(Boolean);
|
|
89
|
+
// Extract related articles
|
|
90
|
+
const relatedArticles = options?.includeRelated === true
|
|
91
|
+
? $(SELECTORS.RELATED).map((_, el) => {
|
|
92
|
+
const rawHref = $(el).attr('href') ?? '';
|
|
93
|
+
if (rawHref === '' || rawHref.startsWith('#')) {
|
|
94
|
+
return { title: '', url: '' };
|
|
95
|
+
}
|
|
96
|
+
let resolvedUrl;
|
|
97
|
+
try {
|
|
98
|
+
resolvedUrl = new URL(rawHref, displayUrl).toString();
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
resolvedUrl = rawHref;
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
title: $(el).text().trim(),
|
|
105
|
+
url: resolvedUrl,
|
|
106
|
+
};
|
|
107
|
+
}).get().filter(r => r.title !== '' && r.url !== '')
|
|
108
|
+
: [];
|
|
109
|
+
return { title, content, breadcrumb, relatedArticles };
|
|
110
|
+
}
|
|
111
|
+
// ─── Snippet cleaning ───────────────────────────────────────────
|
|
112
|
+
const MIN_SNIPPET_LENGTH = 50;
|
|
113
|
+
const NAV_PATTERNS = [
|
|
114
|
+
/^Home\s*>/i,
|
|
115
|
+
/^[\w\s]+>\s*[\w\s]+>\s*[\w\s]+/,
|
|
116
|
+
];
|
|
117
|
+
/**
|
|
118
|
+
* Clean an HTML search snippet: strip tags, clean breadcrumb prefixes.
|
|
119
|
+
*/
|
|
120
|
+
export function cleanSnippet(snippet, title, product) {
|
|
121
|
+
// Strip HTML tags — loop until stable to handle nested/malformed fragments
|
|
122
|
+
let cleaned = snippet;
|
|
123
|
+
let prev;
|
|
124
|
+
do {
|
|
125
|
+
prev = cleaned;
|
|
126
|
+
cleaned = cleaned.replace(/<[^>]*>?/g, '').trim();
|
|
127
|
+
} while (cleaned !== prev);
|
|
128
|
+
for (const pattern of NAV_PATTERNS) {
|
|
129
|
+
cleaned = cleaned.replace(pattern, '').trim();
|
|
130
|
+
}
|
|
131
|
+
// As an extra safety step, strip any remaining angle brackets to avoid
|
|
132
|
+
// residual fragments like "<script" from being interpreted as HTML.
|
|
133
|
+
cleaned = cleaned.replace(/[<>]/g, '').trim();
|
|
134
|
+
if (cleaned.length < MIN_SNIPPET_LENGTH) {
|
|
135
|
+
const productSuffix = product !== null && product !== '' ? ` \u2014 ${product}` : '';
|
|
136
|
+
return `${title}${productSuffix}`;
|
|
137
|
+
}
|
|
138
|
+
return cleaned;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Convert raw HTML to Markdown using the shared Turndown instance.
|
|
142
|
+
*/
|
|
143
|
+
export function htmlToMarkdown(html) {
|
|
144
|
+
return turndown.turndown(html);
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=content-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-parser.js","sourceRoot":"","sources":["../../../src/core/services/content-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fluid Topics API client
|
|
3
|
+
*
|
|
4
|
+
* Pure HTTP client for the Fluid Topics platform on learn.jamf.com.
|
|
5
|
+
* Stateless — no caching, no business logic, no provider fallback.
|
|
6
|
+
* All functions map 1:1 to FT REST API endpoints.
|
|
7
|
+
*/
|
|
8
|
+
import type { FtClusteredSearchResponse, FtSearchRequest, FtMapInfo, FtTocNode, FtTopicInfo } from '../types.js';
|
|
9
|
+
/**
|
|
10
|
+
* POST /api/khub/clustered-search
|
|
11
|
+
*
|
|
12
|
+
* Primary search endpoint. Returns clusters of results grouped by topic,
|
|
13
|
+
* each cluster may contain multiple version entries.
|
|
14
|
+
*/
|
|
15
|
+
export declare function search(request: FtSearchRequest): Promise<FtClusteredSearchResponse>;
|
|
16
|
+
/**
|
|
17
|
+
* GET /api/khub/maps
|
|
18
|
+
*
|
|
19
|
+
* Returns all publications (~577 maps across all locales and versions).
|
|
20
|
+
* Each map includes metadata with version_bundle_stem, version,
|
|
21
|
+
* latestVersion, ft:locale, etc.
|
|
22
|
+
*/
|
|
23
|
+
export declare function fetchMaps(): Promise<FtMapInfo[]>;
|
|
24
|
+
/**
|
|
25
|
+
* GET /api/khub/maps/{mapId}/toc
|
|
26
|
+
*
|
|
27
|
+
* Returns the full table of contents as a JSON tree.
|
|
28
|
+
* The response is either a single root node or an array of root nodes.
|
|
29
|
+
*/
|
|
30
|
+
export declare function fetchMapToc(mapId: string): Promise<FtTocNode[]>;
|
|
31
|
+
/**
|
|
32
|
+
* GET /api/khub/maps/{mapId}/topics
|
|
33
|
+
*
|
|
34
|
+
* Returns a flat list of all topics in a map.
|
|
35
|
+
* Richer than TOC: includes readerUrl, breadcrumb, and full metadata.
|
|
36
|
+
*/
|
|
37
|
+
export declare function fetchMapTopics(mapId: string): Promise<FtTopicInfo[]>;
|
|
38
|
+
/**
|
|
39
|
+
* GET /api/khub/maps/{mapId}/topics/{contentId}/content
|
|
40
|
+
*
|
|
41
|
+
* Returns the HTML content of a single topic.
|
|
42
|
+
* Always returns text/html regardless of Accept header.
|
|
43
|
+
*/
|
|
44
|
+
export declare function fetchTopicContent(mapId: string, contentId: string): Promise<string>;
|
|
45
|
+
/**
|
|
46
|
+
* GET /api/khub/maps/{mapId}/topics/{contentId}
|
|
47
|
+
*
|
|
48
|
+
* Returns topic metadata including title, contentApiEndpoint,
|
|
49
|
+
* and all metadata key-value pairs.
|
|
50
|
+
*/
|
|
51
|
+
export declare function fetchTopicMetadata(mapId: string, contentId: string): Promise<FtTopicInfo>;
|
|
52
|
+
//# sourceMappingURL=ft-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ft-client.d.ts","sourceRoot":"","sources":["../../../src/core/services/ft-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EACV,yBAAyB,EACzB,eAAe,EACf,SAAS,EACT,SAAS,EACT,WAAW,EACZ,MAAM,aAAa,CAAC;AAgBrB;;;;;GAKG;AACH,wBAAsB,MAAM,CAC1B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,yBAAyB,CAAC,CAGpC;AAID;;;;;;GAMG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAGtD;AAID;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,SAAS,EAAE,CAAC,CAItB;AAID;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,WAAW,EAAE,CAAC,CAGxB;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC,CAGtB"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fluid Topics API client
|
|
3
|
+
*
|
|
4
|
+
* Pure HTTP client for the Fluid Topics platform on learn.jamf.com.
|
|
5
|
+
* Stateless — no caching, no business logic, no provider fallback.
|
|
6
|
+
* All functions map 1:1 to FT REST API endpoints.
|
|
7
|
+
*/
|
|
8
|
+
import { httpGetJson, httpGetText, httpPostJson } from '../http-client.js';
|
|
9
|
+
import { FT_API_BASE } from '../constants.js';
|
|
10
|
+
// ─── URL helpers ───────────────────────────────────────────────
|
|
11
|
+
/**
|
|
12
|
+
* Build a /api/khub/maps/{mapId}/... URL with proper encoding.
|
|
13
|
+
* All path segments are encoded via encodeURIComponent.
|
|
14
|
+
*/
|
|
15
|
+
function mapsUrl(mapId, ...segments) {
|
|
16
|
+
const base = `${FT_API_BASE}/api/khub/maps/${encodeURIComponent(mapId)}`;
|
|
17
|
+
if (segments.length === 0)
|
|
18
|
+
return base;
|
|
19
|
+
return `${base}/${segments.map(encodeURIComponent).join('/')}`;
|
|
20
|
+
}
|
|
21
|
+
// ─── Search ─────────────────────────────────────────────────────
|
|
22
|
+
/**
|
|
23
|
+
* POST /api/khub/clustered-search
|
|
24
|
+
*
|
|
25
|
+
* Primary search endpoint. Returns clusters of results grouped by topic,
|
|
26
|
+
* each cluster may contain multiple version entries.
|
|
27
|
+
*/
|
|
28
|
+
export async function search(request) {
|
|
29
|
+
const url = `${FT_API_BASE}/api/khub/clustered-search`;
|
|
30
|
+
return await httpPostJson(url, request);
|
|
31
|
+
}
|
|
32
|
+
// ─── Maps (Publications) ────────────────────────────────────────
|
|
33
|
+
/**
|
|
34
|
+
* GET /api/khub/maps
|
|
35
|
+
*
|
|
36
|
+
* Returns all publications (~577 maps across all locales and versions).
|
|
37
|
+
* Each map includes metadata with version_bundle_stem, version,
|
|
38
|
+
* latestVersion, ft:locale, etc.
|
|
39
|
+
*/
|
|
40
|
+
export async function fetchMaps() {
|
|
41
|
+
const url = `${FT_API_BASE}/api/khub/maps`;
|
|
42
|
+
return await httpGetJson(url);
|
|
43
|
+
}
|
|
44
|
+
// ─── TOC ────────────────────────────────────────────────────────
|
|
45
|
+
/**
|
|
46
|
+
* GET /api/khub/maps/{mapId}/toc
|
|
47
|
+
*
|
|
48
|
+
* Returns the full table of contents as a JSON tree.
|
|
49
|
+
* The response is either a single root node or an array of root nodes.
|
|
50
|
+
*/
|
|
51
|
+
export async function fetchMapToc(mapId) {
|
|
52
|
+
const url = mapsUrl(mapId, 'toc');
|
|
53
|
+
const raw = await httpGetJson(url);
|
|
54
|
+
return Array.isArray(raw) ? raw : [raw];
|
|
55
|
+
}
|
|
56
|
+
// ─── Topics ─────────────────────────────────────────────────────
|
|
57
|
+
/**
|
|
58
|
+
* GET /api/khub/maps/{mapId}/topics
|
|
59
|
+
*
|
|
60
|
+
* Returns a flat list of all topics in a map.
|
|
61
|
+
* Richer than TOC: includes readerUrl, breadcrumb, and full metadata.
|
|
62
|
+
*/
|
|
63
|
+
export async function fetchMapTopics(mapId) {
|
|
64
|
+
const url = mapsUrl(mapId, 'topics');
|
|
65
|
+
return await httpGetJson(url);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* GET /api/khub/maps/{mapId}/topics/{contentId}/content
|
|
69
|
+
*
|
|
70
|
+
* Returns the HTML content of a single topic.
|
|
71
|
+
* Always returns text/html regardless of Accept header.
|
|
72
|
+
*/
|
|
73
|
+
export async function fetchTopicContent(mapId, contentId) {
|
|
74
|
+
const url = mapsUrl(mapId, 'topics', contentId, 'content');
|
|
75
|
+
return await httpGetText(url);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* GET /api/khub/maps/{mapId}/topics/{contentId}
|
|
79
|
+
*
|
|
80
|
+
* Returns topic metadata including title, contentApiEndpoint,
|
|
81
|
+
* and all metadata key-value pairs.
|
|
82
|
+
*/
|
|
83
|
+
export async function fetchTopicMetadata(mapId, contentId) {
|
|
84
|
+
const url = mapsUrl(mapId, 'topics', contentId);
|
|
85
|
+
return await httpGetJson(url);
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=ft-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ft-client.js","sourceRoot":"","sources":["../../../src/core/services/ft-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAS9C,kEAAkE;AAElE;;;GAGG;AACH,SAAS,OAAO,CAAC,KAAa,EAAE,GAAG,QAAkB;IACnD,MAAM,IAAI,GAAG,GAAG,WAAW,kBAAkB,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;IACzE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,GAAG,IAAI,IAAI,QAAQ,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AACjE,CAAC;AAED,mEAAmE;AAEnE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,OAAwB;IAExB,MAAM,GAAG,GAAG,GAAG,WAAW,4BAA4B,CAAC;IACvD,OAAO,MAAM,YAAY,CAA4B,GAAG,EAAE,OAAO,CAAC,CAAC;AACrE,CAAC;AAED,mEAAmE;AAEnE;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,GAAG,GAAG,GAAG,WAAW,gBAAgB,CAAC;IAC3C,OAAO,MAAM,WAAW,CAAc,GAAG,CAAC,CAAC;AAC7C,CAAC;AAED,mEAAmE;AAEnE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAa;IAEb,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAClC,MAAM,GAAG,GAAG,MAAM,WAAW,CAA0B,GAAG,CAAC,CAAC;IAC5D,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC1C,CAAC;AAED,mEAAmE;AAEnE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAa;IAEb,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACrC,OAAO,MAAM,WAAW,CAAgB,GAAG,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAa,EACb,SAAiB;IAEjB,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC3D,OAAO,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;AAChC,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAAa,EACb,SAAiB;IAEjB,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IAChD,OAAO,MAAM,WAAW,CAAc,GAAG,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Glossary service for parsing and looking up Jamf documentation glossary terms
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Uses Fluid Topics API on learn.jamf.com:
|
|
5
|
+
* - GET /api/khub/maps/{mapId}/toc — list all glossary terms
|
|
6
|
+
* - GET /api/khub/maps/{mapId}/topics/{contentId}/content — term HTML
|
|
7
|
+
*
|
|
8
|
+
* Jamf's glossary uses DITA glossentry format where each term is a separate topic:
|
|
6
9
|
* <div class="glossdef"><p>Definition text</p></div>
|
|
7
10
|
*
|
|
8
11
|
* Also supports fallback formats:
|
|
@@ -33,9 +36,10 @@ export declare function searchGlossaryEntries(entries: GlossaryEntry[], term: st
|
|
|
33
36
|
* Look up a glossary term across Jamf documentation.
|
|
34
37
|
*
|
|
35
38
|
* Strategy:
|
|
36
|
-
* 1.
|
|
37
|
-
* 2.
|
|
38
|
-
* 3.
|
|
39
|
+
* 1. Fetch glossary TOC from Fluid Topics API (cached)
|
|
40
|
+
* 2. Fuzzy-match term against TOC titles
|
|
41
|
+
* 3. Fetch and parse matching glossary topics
|
|
42
|
+
* 4. Rank results with fuse.js and apply token limit
|
|
39
43
|
*/
|
|
40
44
|
export declare function lookupGlossaryTerm(ctx: ServerContext, params: {
|
|
41
45
|
term: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glossary.d.ts","sourceRoot":"","sources":["../../../src/core/services/glossary.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"glossary.d.ts","sourceRoot":"","sources":["../../../src/core/services/glossary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,QAAQ,EACd,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EACV,aAAa,EACb,oBAAoB,EAErB,MAAM,aAAa,CAAC;AAIrB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA4EzD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,GACf,aAAa,EAAE,CAyBjB;AAiND;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,aAAa,EAAE,EACxB,IAAI,EAAE,MAAM,GACX,aAAa,EAAE,CAsBjB;AAID;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE;IACN,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAChC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,GACA,OAAO,CAAC,oBAAoB,CAAC,CAqI/B"}
|