@get-technology-inc/jamf-docs-mcp-server 0.0.1 → 1.0.0
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/LICENSE +21 -0
- package/README.md +189 -29
- package/dist/constants.d.ts +260 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +303 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/schemas/index.d.ts +98 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +110 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/services/cache.d.ts +56 -0
- package/dist/services/cache.d.ts.map +1 -0
- package/dist/services/cache.js +189 -0
- package/dist/services/cache.js.map +1 -0
- package/dist/services/scraper.d.ts +62 -0
- package/dist/services/scraper.d.ts.map +1 -0
- package/dist/services/scraper.js +568 -0
- package/dist/services/scraper.js.map +1 -0
- package/dist/services/tokenizer.d.ts +77 -0
- package/dist/services/tokenizer.d.ts.map +1 -0
- package/dist/services/tokenizer.js +274 -0
- package/dist/services/tokenizer.js.map +1 -0
- package/dist/tools/get-article.d.ts +7 -0
- package/dist/tools/get-article.d.ts.map +1 -0
- package/dist/tools/get-article.js +195 -0
- package/dist/tools/get-article.js.map +1 -0
- package/dist/tools/get-toc.d.ts +7 -0
- package/dist/tools/get-toc.d.ts.map +1 -0
- package/dist/tools/get-toc.js +172 -0
- package/dist/tools/get-toc.js.map +1 -0
- package/dist/tools/list-products.d.ts +7 -0
- package/dist/tools/list-products.d.ts.map +1 -0
- package/dist/tools/list-products.js +132 -0
- package/dist/tools/list-products.js.map +1 -0
- package/dist/tools/search.d.ts +7 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +212 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/types.d.ts +197 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +28 -0
- package/dist/types.js.map +1 -0
- package/package.json +68 -6
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web scraping service for Jamf documentation
|
|
3
|
+
*
|
|
4
|
+
* This module handles fetching and parsing HTML from learn.jamf.com
|
|
5
|
+
* (Jamf documentation has moved from docs.jamf.com to learn.jamf.com)
|
|
6
|
+
*/
|
|
7
|
+
import axios from 'axios';
|
|
8
|
+
import * as cheerio from 'cheerio';
|
|
9
|
+
import TurndownService from 'turndown';
|
|
10
|
+
import { DOCS_BASE_URL, DOCS_API_URL, JAMF_PRODUCTS, JAMF_TOPICS, REQUEST_CONFIG, SELECTORS, CONTENT_LIMITS, TOKEN_CONFIG, PAGINATION_CONFIG } from '../constants.js';
|
|
11
|
+
import { JamfDocsError, JamfDocsErrorCode } from '../types.js';
|
|
12
|
+
import { cache } from './cache.js';
|
|
13
|
+
import { estimateTokens, createTokenInfo, extractSections, extractSection, truncateToTokenLimit, calculatePagination } from './tokenizer.js';
|
|
14
|
+
// Initialize Turndown for HTML to Markdown conversion
|
|
15
|
+
const turndown = new TurndownService({
|
|
16
|
+
headingStyle: 'atx',
|
|
17
|
+
codeBlockStyle: 'fenced',
|
|
18
|
+
bulletListMarker: '-',
|
|
19
|
+
emDelimiter: '*',
|
|
20
|
+
strongDelimiter: '**'
|
|
21
|
+
});
|
|
22
|
+
// Custom Turndown rules
|
|
23
|
+
turndown.addRule('codeBlocks', {
|
|
24
|
+
filter: 'pre',
|
|
25
|
+
replacement: (content, node) => {
|
|
26
|
+
// Handle code element extraction safely
|
|
27
|
+
const nodeElement = node;
|
|
28
|
+
const codeElement = nodeElement.querySelector?.('code');
|
|
29
|
+
const language = codeElement?.className?.replace('language-', '') || '';
|
|
30
|
+
return `\n\`\`\`${language}\n${content.trim()}\n\`\`\`\n`;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
// Rate limiter
|
|
34
|
+
let lastRequestTime = 0;
|
|
35
|
+
async function throttle() {
|
|
36
|
+
const now = Date.now();
|
|
37
|
+
const elapsed = now - lastRequestTime;
|
|
38
|
+
if (elapsed < REQUEST_CONFIG.RATE_LIMIT_DELAY) {
|
|
39
|
+
await new Promise(resolve => setTimeout(resolve, REQUEST_CONFIG.RATE_LIMIT_DELAY - elapsed));
|
|
40
|
+
}
|
|
41
|
+
lastRequestTime = Date.now();
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Transform frontend URL to backend URL for content fetching
|
|
45
|
+
* learn.jamf.com -> learn-be.jamf.com
|
|
46
|
+
*/
|
|
47
|
+
function transformToBackendUrl(url) {
|
|
48
|
+
return url.replace('learn.jamf.com', 'learn-be.jamf.com');
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Transform backend URL to frontend URL for display
|
|
52
|
+
* learn-be.jamf.com -> learn.jamf.com
|
|
53
|
+
*/
|
|
54
|
+
function transformToFrontendUrl(url) {
|
|
55
|
+
return url.replace('learn-be.jamf.com', 'learn.jamf.com');
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Strip HTML tags from a string
|
|
59
|
+
*/
|
|
60
|
+
function stripHtml(html) {
|
|
61
|
+
return html
|
|
62
|
+
.replace(/<[^>]*>/g, '')
|
|
63
|
+
.replace(/ /g, ' ')
|
|
64
|
+
.replace(/&/g, '&')
|
|
65
|
+
.replace(/</g, '<')
|
|
66
|
+
.replace(/>/g, '>')
|
|
67
|
+
.replace(/"/g, '"')
|
|
68
|
+
.replace(/'/g, "'")
|
|
69
|
+
.replace(/\s+/g, ' ')
|
|
70
|
+
.trim();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Fetch JSON data from a URL with error handling
|
|
74
|
+
*/
|
|
75
|
+
async function fetchJson(url) {
|
|
76
|
+
await throttle();
|
|
77
|
+
try {
|
|
78
|
+
const response = await axios.get(url, {
|
|
79
|
+
timeout: REQUEST_CONFIG.TIMEOUT,
|
|
80
|
+
headers: {
|
|
81
|
+
'User-Agent': REQUEST_CONFIG.USER_AGENT,
|
|
82
|
+
'Accept': 'application/json',
|
|
83
|
+
'Accept-Language': 'en-US,en;q=0.9'
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
return response.data;
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
if (axios.isAxiosError(error)) {
|
|
90
|
+
const axiosError = error;
|
|
91
|
+
if (axiosError.response?.status === 404) {
|
|
92
|
+
throw new JamfDocsError(`Resource not found: ${url}`, JamfDocsErrorCode.NOT_FOUND, url, 404);
|
|
93
|
+
}
|
|
94
|
+
if (axiosError.response?.status === 429) {
|
|
95
|
+
throw new JamfDocsError('Rate limited. Please wait and try again.', JamfDocsErrorCode.RATE_LIMITED, url, 429);
|
|
96
|
+
}
|
|
97
|
+
if (axiosError.code === 'ECONNABORTED') {
|
|
98
|
+
throw new JamfDocsError('Request timed out', JamfDocsErrorCode.TIMEOUT, url);
|
|
99
|
+
}
|
|
100
|
+
throw new JamfDocsError(`Network error: ${axiosError.message}`, JamfDocsErrorCode.NETWORK_ERROR, url);
|
|
101
|
+
}
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Fetch HTML content from a URL with error handling
|
|
107
|
+
*/
|
|
108
|
+
async function fetchHtml(url) {
|
|
109
|
+
await throttle();
|
|
110
|
+
try {
|
|
111
|
+
const response = await axios.get(url, {
|
|
112
|
+
timeout: REQUEST_CONFIG.TIMEOUT,
|
|
113
|
+
headers: {
|
|
114
|
+
'User-Agent': REQUEST_CONFIG.USER_AGENT,
|
|
115
|
+
'Accept': 'text/html,application/xhtml+xml',
|
|
116
|
+
'Accept-Language': 'en-US,en;q=0.9'
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
return response.data;
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
if (axios.isAxiosError(error)) {
|
|
123
|
+
const axiosError = error;
|
|
124
|
+
if (axiosError.response?.status === 404) {
|
|
125
|
+
throw new JamfDocsError(`Article not found: ${url}`, JamfDocsErrorCode.NOT_FOUND, url, 404);
|
|
126
|
+
}
|
|
127
|
+
if (axiosError.response?.status === 429) {
|
|
128
|
+
throw new JamfDocsError('Rate limited. Please wait and try again.', JamfDocsErrorCode.RATE_LIMITED, url, 429);
|
|
129
|
+
}
|
|
130
|
+
if (axiosError.code === 'ECONNABORTED') {
|
|
131
|
+
throw new JamfDocsError('Request timed out', JamfDocsErrorCode.TIMEOUT, url);
|
|
132
|
+
}
|
|
133
|
+
throw new JamfDocsError(`Network error: ${axiosError.message}`, JamfDocsErrorCode.NETWORK_ERROR, url);
|
|
134
|
+
}
|
|
135
|
+
throw error;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Clean HTML content by removing unwanted elements
|
|
140
|
+
*/
|
|
141
|
+
function cleanHtml($) {
|
|
142
|
+
// Remove unwanted elements
|
|
143
|
+
$(SELECTORS.REMOVE).remove();
|
|
144
|
+
// Fix relative URLs
|
|
145
|
+
$('a[href^="/"]').each((_, el) => {
|
|
146
|
+
const href = $(el).attr('href');
|
|
147
|
+
if (href) {
|
|
148
|
+
$(el).attr('href', `${DOCS_BASE_URL}${href}`);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
$('img[src^="/"]').each((_, el) => {
|
|
152
|
+
const src = $(el).attr('src');
|
|
153
|
+
if (src) {
|
|
154
|
+
$(el).attr('src', `${DOCS_BASE_URL}${src}`);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Extract product and version from URL
|
|
160
|
+
* Supports both old docs.jamf.com and new learn.jamf.com URL structures
|
|
161
|
+
*/
|
|
162
|
+
function extractProductInfo(url) {
|
|
163
|
+
// learn.jamf.com structure: /en-US/bundle/{product}-documentation/page/{page}.html
|
|
164
|
+
const bundleMatch = url.match(/\/bundle\/([^/]+)-documentation\//);
|
|
165
|
+
if (bundleMatch) {
|
|
166
|
+
const bundleSlug = bundleMatch[1];
|
|
167
|
+
const product = Object.values(JAMF_PRODUCTS).find(p => p.bundleId.includes(bundleSlug ?? ''));
|
|
168
|
+
return { product: product?.name, version: 'current' };
|
|
169
|
+
}
|
|
170
|
+
// Legacy docs.jamf.com structure: /{version}/{product}/...
|
|
171
|
+
const urlObj = new URL(url);
|
|
172
|
+
const pathParts = urlObj.pathname.split('/').filter(Boolean);
|
|
173
|
+
// Check for versioned paths like /11.5.0/jamf-pro/...
|
|
174
|
+
const versionMatch = pathParts[0]?.match(/^\d+\.\d+(\.\d+)?$/);
|
|
175
|
+
if (versionMatch) {
|
|
176
|
+
const version = pathParts[0];
|
|
177
|
+
const productSlug = pathParts[1];
|
|
178
|
+
const product = Object.values(JAMF_PRODUCTS).find(p => p.urlPattern.includes(productSlug ?? ''));
|
|
179
|
+
return { product: product?.name, version };
|
|
180
|
+
}
|
|
181
|
+
// Check for unversioned paths like /jamf-connect/...
|
|
182
|
+
for (const [, product] of Object.entries(JAMF_PRODUCTS)) {
|
|
183
|
+
if (url.includes(product.bundleId) || url.includes(product.id)) {
|
|
184
|
+
return { product: product.name, version: 'current' };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return { product: undefined, version: undefined };
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Check if a search result matches a topic based on keywords
|
|
191
|
+
*/
|
|
192
|
+
function matchesTopic(result, topicId) {
|
|
193
|
+
const topic = JAMF_TOPICS[topicId];
|
|
194
|
+
const searchText = `${result.title} ${result.snippet}`.toLowerCase();
|
|
195
|
+
return topic.keywords.some(keyword => searchText.includes(keyword.toLowerCase()));
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Search Jamf documentation using Zoomin Search API
|
|
199
|
+
*/
|
|
200
|
+
export async function searchDocumentation(params) {
|
|
201
|
+
const page = params.page ?? PAGINATION_CONFIG.DEFAULT_PAGE;
|
|
202
|
+
const pageSize = params.limit ?? CONTENT_LIMITS.DEFAULT_SEARCH_RESULTS;
|
|
203
|
+
const maxTokens = params.maxTokens ?? TOKEN_CONFIG.DEFAULT_MAX_TOKENS;
|
|
204
|
+
const cacheKey = `search:${JSON.stringify({ ...params, page: 1 })}`; // Cache without page for full results
|
|
205
|
+
// Check cache for full results
|
|
206
|
+
let allResults = await cache.get(cacheKey);
|
|
207
|
+
if (!allResults) {
|
|
208
|
+
// Fetch more results to allow for filtering
|
|
209
|
+
const fetchLimit = CONTENT_LIMITS.MAX_SEARCH_RESULTS;
|
|
210
|
+
// Build API URL with query params
|
|
211
|
+
const apiUrl = new URL(`${DOCS_API_URL}/api/search`);
|
|
212
|
+
apiUrl.searchParams.set('q', params.query);
|
|
213
|
+
apiUrl.searchParams.set('rpp', fetchLimit.toString());
|
|
214
|
+
console.error(`[SEARCH] Query: "${params.query}", Product: ${params.product ?? 'all'}, Topic: ${params.topic ?? 'all'}, URL: ${apiUrl.toString()}`);
|
|
215
|
+
try {
|
|
216
|
+
const response = await fetchJson(apiUrl.toString());
|
|
217
|
+
// Transform Zoomin results to SearchResult format with metadata
|
|
218
|
+
allResults = response.Results
|
|
219
|
+
.filter(wrapper => wrapper.leading_result !== null)
|
|
220
|
+
.map(wrapper => {
|
|
221
|
+
const result = wrapper.leading_result;
|
|
222
|
+
// Extract product from bundle_id
|
|
223
|
+
const bundleId = result.bundle_id || '';
|
|
224
|
+
const bundleMatch = bundleId.match(/^(jamf-[a-z]+)-documentation/);
|
|
225
|
+
const bundleSlug = bundleMatch?.[1] ?? null;
|
|
226
|
+
const productEntry = bundleSlug
|
|
227
|
+
? Object.entries(JAMF_PRODUCTS).find(([id]) => id === bundleSlug)
|
|
228
|
+
: null;
|
|
229
|
+
const searchResult = {
|
|
230
|
+
title: result.title || 'Untitled',
|
|
231
|
+
url: transformToFrontendUrl(result.url || ''),
|
|
232
|
+
snippet: stripHtml(result.snippet || '').slice(0, CONTENT_LIMITS.MAX_SNIPPET_LENGTH),
|
|
233
|
+
product: productEntry ? productEntry[1].name : (result.publication_title || 'Jamf'),
|
|
234
|
+
version: 'current'
|
|
235
|
+
};
|
|
236
|
+
if (result.score !== undefined && result.score !== null) {
|
|
237
|
+
searchResult.relevance = result.score;
|
|
238
|
+
}
|
|
239
|
+
// Find matched topics
|
|
240
|
+
const matchedTopics = Object.keys(JAMF_TOPICS)
|
|
241
|
+
.filter(topicId => matchesTopic(searchResult, topicId));
|
|
242
|
+
return { result: searchResult, bundleSlug, matchedTopics };
|
|
243
|
+
});
|
|
244
|
+
// Cache full results
|
|
245
|
+
await cache.set(cacheKey, allResults);
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
console.error('[SEARCH] Error:', error);
|
|
249
|
+
if (error instanceof JamfDocsError) {
|
|
250
|
+
throw error;
|
|
251
|
+
}
|
|
252
|
+
// Return empty results on error
|
|
253
|
+
return {
|
|
254
|
+
results: [],
|
|
255
|
+
pagination: {
|
|
256
|
+
page: 1,
|
|
257
|
+
pageSize,
|
|
258
|
+
totalPages: 0,
|
|
259
|
+
totalItems: 0,
|
|
260
|
+
hasNext: false,
|
|
261
|
+
hasPrev: false
|
|
262
|
+
},
|
|
263
|
+
tokenInfo: createTokenInfo('', maxTokens)
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// Apply filters
|
|
268
|
+
let filteredResults = allResults;
|
|
269
|
+
// Product filter
|
|
270
|
+
if (params.product) {
|
|
271
|
+
filteredResults = filteredResults.filter(r => r.bundleSlug === params.product);
|
|
272
|
+
}
|
|
273
|
+
// Topic filter
|
|
274
|
+
if (params.topic) {
|
|
275
|
+
const topicFilter = params.topic;
|
|
276
|
+
filteredResults = filteredResults.filter(r => r.matchedTopics.includes(topicFilter));
|
|
277
|
+
}
|
|
278
|
+
// Calculate pagination
|
|
279
|
+
const paginationInfo = calculatePagination(filteredResults.length, page, pageSize);
|
|
280
|
+
// Get paginated results
|
|
281
|
+
const paginatedResults = filteredResults
|
|
282
|
+
.slice(paginationInfo.startIndex, paginationInfo.endIndex)
|
|
283
|
+
.map(r => r.result);
|
|
284
|
+
// Calculate token info
|
|
285
|
+
const resultText = paginatedResults.map(r => `${r.title}\n${r.snippet}\n${r.url}`).join('\n\n');
|
|
286
|
+
const tokenCount = estimateTokens(resultText);
|
|
287
|
+
// Check if we need to truncate
|
|
288
|
+
let finalResults = paginatedResults;
|
|
289
|
+
let truncated = false;
|
|
290
|
+
if (tokenCount > maxTokens) {
|
|
291
|
+
// Truncate results to fit token limit
|
|
292
|
+
let runningTokens = 0;
|
|
293
|
+
finalResults = [];
|
|
294
|
+
for (const result of paginatedResults) {
|
|
295
|
+
const resultTokens = estimateTokens(`${result.title}\n${result.snippet}\n${result.url}`);
|
|
296
|
+
if (runningTokens + resultTokens > maxTokens) {
|
|
297
|
+
truncated = true;
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
finalResults.push(result);
|
|
301
|
+
runningTokens += resultTokens;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return {
|
|
305
|
+
results: finalResults,
|
|
306
|
+
pagination: {
|
|
307
|
+
page: paginationInfo.page,
|
|
308
|
+
pageSize: paginationInfo.pageSize,
|
|
309
|
+
totalPages: paginationInfo.totalPages,
|
|
310
|
+
totalItems: filteredResults.length,
|
|
311
|
+
hasNext: paginationInfo.hasNext || truncated,
|
|
312
|
+
hasPrev: paginationInfo.hasPrev
|
|
313
|
+
},
|
|
314
|
+
tokenInfo: {
|
|
315
|
+
tokenCount: estimateTokens(finalResults.map(r => `${r.title}\n${r.snippet}\n${r.url}`).join('\n\n')),
|
|
316
|
+
truncated,
|
|
317
|
+
maxTokens
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Fetch and parse a documentation article
|
|
323
|
+
* Uses backend URL (learn-be.jamf.com) for pre-rendered content
|
|
324
|
+
*/
|
|
325
|
+
export async function fetchArticle(url, options = {}) {
|
|
326
|
+
const maxTokens = options.maxTokens ?? TOKEN_CONFIG.DEFAULT_MAX_TOKENS;
|
|
327
|
+
// Store original URL for display, use backend URL for fetching
|
|
328
|
+
const displayUrl = transformToFrontendUrl(url);
|
|
329
|
+
const fetchUrl = transformToBackendUrl(url);
|
|
330
|
+
const cacheKey = `article:${displayUrl}`;
|
|
331
|
+
// Check cache for raw article (without section/token processing)
|
|
332
|
+
let rawArticle = await cache.get(cacheKey);
|
|
333
|
+
if (!rawArticle) {
|
|
334
|
+
// Fetch HTML from backend URL (pre-rendered content, not SPA shell)
|
|
335
|
+
const html = await fetchHtml(fetchUrl);
|
|
336
|
+
const $ = cheerio.load(html);
|
|
337
|
+
// Clean content
|
|
338
|
+
cleanHtml($);
|
|
339
|
+
// Extract content
|
|
340
|
+
const contentHtml = $(SELECTORS.CONTENT).html() ?? '';
|
|
341
|
+
const title = $(SELECTORS.TITLE).first().text().trim() || 'Untitled';
|
|
342
|
+
// Convert to Markdown
|
|
343
|
+
const content = turndown.turndown(contentHtml);
|
|
344
|
+
// Extract breadcrumb
|
|
345
|
+
const breadcrumb = $(SELECTORS.BREADCRUMB)
|
|
346
|
+
.map((_, el) => $(el).text().trim())
|
|
347
|
+
.get()
|
|
348
|
+
.filter(Boolean);
|
|
349
|
+
// Extract related articles
|
|
350
|
+
const relatedArticles = options.includeRelated
|
|
351
|
+
? $(SELECTORS.RELATED).map((_, el) => ({
|
|
352
|
+
title: $(el).text().trim(),
|
|
353
|
+
url: $(el).attr('href') ?? ''
|
|
354
|
+
})).get().filter(r => r.title && r.url)
|
|
355
|
+
: undefined;
|
|
356
|
+
// Extract product info from URL
|
|
357
|
+
const { product, version } = extractProductInfo(displayUrl);
|
|
358
|
+
rawArticle = {
|
|
359
|
+
title,
|
|
360
|
+
content,
|
|
361
|
+
url: displayUrl,
|
|
362
|
+
product,
|
|
363
|
+
version,
|
|
364
|
+
breadcrumb: breadcrumb.length > 0 ? breadcrumb : undefined,
|
|
365
|
+
relatedArticles: relatedArticles && relatedArticles.length > 0 ? relatedArticles : undefined
|
|
366
|
+
};
|
|
367
|
+
// Cache raw article
|
|
368
|
+
await cache.set(cacheKey, rawArticle);
|
|
369
|
+
}
|
|
370
|
+
// Extract all sections
|
|
371
|
+
const allSections = extractSections(rawArticle.content);
|
|
372
|
+
// Handle section extraction if requested
|
|
373
|
+
let processedContent = rawArticle.content;
|
|
374
|
+
let tokenInfo;
|
|
375
|
+
if (options.section) {
|
|
376
|
+
// Extract specific section
|
|
377
|
+
const sectionResult = extractSection(rawArticle.content, options.section, maxTokens);
|
|
378
|
+
processedContent = sectionResult.content;
|
|
379
|
+
tokenInfo = sectionResult.tokenInfo;
|
|
380
|
+
if (!sectionResult.section) {
|
|
381
|
+
// Section not found, return error info
|
|
382
|
+
processedContent = `*Section "${options.section}" not found.*\n\n**Available sections:**\n${allSections.map(s => `- ${s.title}`).join('\n')}`;
|
|
383
|
+
tokenInfo = createTokenInfo(processedContent, maxTokens);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
// Apply token limit with smart truncation
|
|
388
|
+
const truncateResult = truncateToTokenLimit(rawArticle.content, maxTokens);
|
|
389
|
+
processedContent = truncateResult.content;
|
|
390
|
+
tokenInfo = truncateResult.tokenInfo;
|
|
391
|
+
}
|
|
392
|
+
return {
|
|
393
|
+
...rawArticle,
|
|
394
|
+
content: processedContent,
|
|
395
|
+
tokenInfo,
|
|
396
|
+
sections: allSections
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Discover the latest bundle version for a product via search API
|
|
401
|
+
*/
|
|
402
|
+
async function discoverLatestBundleId(product) {
|
|
403
|
+
const productInfo = JAMF_PRODUCTS[product];
|
|
404
|
+
const baseBundleId = productInfo.bundleId;
|
|
405
|
+
try {
|
|
406
|
+
// Search for any document from this product to discover the latest version
|
|
407
|
+
const apiUrl = `${DOCS_API_URL}/api/search?q=${encodeURIComponent(productInfo.name)}&rpp=10`;
|
|
408
|
+
const response = await fetchJson(apiUrl);
|
|
409
|
+
// Find a result with a matching bundle prefix
|
|
410
|
+
for (const wrapper of response.Results) {
|
|
411
|
+
const bundleId = wrapper.leading_result?.bundle_id;
|
|
412
|
+
if (bundleId && bundleId.startsWith(baseBundleId)) {
|
|
413
|
+
return bundleId;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
catch (error) {
|
|
418
|
+
console.error(`[TOC] Error discovering bundle version for ${product}:`, error);
|
|
419
|
+
}
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Parse TOC HTML from Zoomin backend
|
|
424
|
+
*/
|
|
425
|
+
function parseTocHtml(html) {
|
|
426
|
+
const $ = cheerio.load(html);
|
|
427
|
+
const toc = [];
|
|
428
|
+
// Parse the nested list structure
|
|
429
|
+
$('ul.list-links > li.toc').each((_, el) => {
|
|
430
|
+
const entry = parseTocEntry($, el);
|
|
431
|
+
if (entry) {
|
|
432
|
+
toc.push(entry);
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
return toc;
|
|
436
|
+
}
|
|
437
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
438
|
+
function parseTocEntry($, el) {
|
|
439
|
+
const $el = $(el);
|
|
440
|
+
const $link = $el.children('.inner').children('a').first();
|
|
441
|
+
const title = $link.text().trim();
|
|
442
|
+
let url = $link.attr('href') ?? '';
|
|
443
|
+
if (!title || !url) {
|
|
444
|
+
return null;
|
|
445
|
+
}
|
|
446
|
+
// Transform to frontend URL for display
|
|
447
|
+
url = transformToFrontendUrl(url);
|
|
448
|
+
const entry = { title, url };
|
|
449
|
+
// Check for children
|
|
450
|
+
const $children = $el.children('ul.list-links');
|
|
451
|
+
if ($children.length > 0) {
|
|
452
|
+
const children = [];
|
|
453
|
+
$children.children('li.toc').each((_, childEl) => {
|
|
454
|
+
const childEntry = parseTocEntry($, childEl);
|
|
455
|
+
if (childEntry) {
|
|
456
|
+
children.push(childEntry);
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
if (children.length > 0) {
|
|
460
|
+
entry.children = children;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return entry;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Convert TOC entry to string for token counting
|
|
467
|
+
*/
|
|
468
|
+
function tocEntryToString(entry, depth = 0) {
|
|
469
|
+
const indent = ' '.repeat(depth);
|
|
470
|
+
let result = `${indent}- ${entry.title}\n`;
|
|
471
|
+
if (entry.children) {
|
|
472
|
+
for (const child of entry.children) {
|
|
473
|
+
result += tocEntryToString(child, depth + 1);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return result;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Count total TOC entries including children
|
|
480
|
+
*/
|
|
481
|
+
function countTocEntries(entries) {
|
|
482
|
+
let count = entries.length;
|
|
483
|
+
for (const entry of entries) {
|
|
484
|
+
if (entry.children) {
|
|
485
|
+
count += countTocEntries(entry.children);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return count;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Fetch table of contents for a product
|
|
492
|
+
* Uses backend TOC endpoint (learn-be.jamf.com/bundle/{bundleId}/toc)
|
|
493
|
+
*/
|
|
494
|
+
export async function fetchTableOfContents(product, _version, // Version is not used for learn.jamf.com (always current)
|
|
495
|
+
options = {}) {
|
|
496
|
+
const page = options.page ?? PAGINATION_CONFIG.DEFAULT_PAGE;
|
|
497
|
+
const maxTokens = options.maxTokens ?? TOKEN_CONFIG.DEFAULT_MAX_TOKENS;
|
|
498
|
+
const cacheKey = `toc:${product}`;
|
|
499
|
+
// Check cache
|
|
500
|
+
let allToc = await cache.get(cacheKey);
|
|
501
|
+
if (!allToc) {
|
|
502
|
+
// Discover the latest bundle version
|
|
503
|
+
const bundleId = await discoverLatestBundleId(product);
|
|
504
|
+
if (!bundleId) {
|
|
505
|
+
throw new JamfDocsError(`Could not discover bundle version for ${product}`, JamfDocsErrorCode.NOT_FOUND);
|
|
506
|
+
}
|
|
507
|
+
// Fetch TOC from backend
|
|
508
|
+
const tocUrl = `${DOCS_API_URL}/bundle/${bundleId}/toc`;
|
|
509
|
+
console.error(`[TOC] Fetching TOC from: ${tocUrl}`);
|
|
510
|
+
const tocJson = await fetchJson(tocUrl);
|
|
511
|
+
// Parse TOC
|
|
512
|
+
allToc = [];
|
|
513
|
+
for (const [, html] of Object.entries(tocJson)) {
|
|
514
|
+
if (typeof html === 'string' && html.includes('<ul')) {
|
|
515
|
+
const entries = parseTocHtml(html);
|
|
516
|
+
allToc.push(...entries);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
// Cache result
|
|
520
|
+
await cache.set(cacheKey, allToc);
|
|
521
|
+
}
|
|
522
|
+
// Count total entries
|
|
523
|
+
const totalItems = countTocEntries(allToc);
|
|
524
|
+
// For TOC, we paginate at the top-level entries
|
|
525
|
+
const topLevelCount = allToc.length;
|
|
526
|
+
const pageSize = PAGINATION_CONFIG.DEFAULT_PAGE_SIZE;
|
|
527
|
+
const paginationInfo = calculatePagination(topLevelCount, page, pageSize);
|
|
528
|
+
// Get paginated top-level entries (with their children)
|
|
529
|
+
const paginatedToc = allToc.slice(paginationInfo.startIndex, paginationInfo.endIndex);
|
|
530
|
+
// Calculate tokens for paginated TOC
|
|
531
|
+
const tocText = paginatedToc.map(e => tocEntryToString(e)).join('');
|
|
532
|
+
let tokenCount = estimateTokens(tocText);
|
|
533
|
+
let truncated = false;
|
|
534
|
+
let finalToc = paginatedToc;
|
|
535
|
+
// Truncate if over token limit
|
|
536
|
+
if (tokenCount > maxTokens) {
|
|
537
|
+
truncated = true;
|
|
538
|
+
finalToc = [];
|
|
539
|
+
let runningTokens = 0;
|
|
540
|
+
for (const entry of paginatedToc) {
|
|
541
|
+
const entryText = tocEntryToString(entry);
|
|
542
|
+
const entryTokens = estimateTokens(entryText);
|
|
543
|
+
if (runningTokens + entryTokens > maxTokens) {
|
|
544
|
+
break;
|
|
545
|
+
}
|
|
546
|
+
finalToc.push(entry);
|
|
547
|
+
runningTokens += entryTokens;
|
|
548
|
+
}
|
|
549
|
+
tokenCount = runningTokens;
|
|
550
|
+
}
|
|
551
|
+
return {
|
|
552
|
+
toc: finalToc,
|
|
553
|
+
pagination: {
|
|
554
|
+
page: paginationInfo.page,
|
|
555
|
+
pageSize: paginationInfo.pageSize,
|
|
556
|
+
totalPages: paginationInfo.totalPages,
|
|
557
|
+
totalItems,
|
|
558
|
+
hasNext: paginationInfo.hasNext || truncated,
|
|
559
|
+
hasPrev: paginationInfo.hasPrev
|
|
560
|
+
},
|
|
561
|
+
tokenInfo: {
|
|
562
|
+
tokenCount,
|
|
563
|
+
truncated,
|
|
564
|
+
maxTokens
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
//# sourceMappingURL=scraper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scraper.js","sourceRoot":"","sources":["../../src/services/scraper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tokenizer service for Context7-style token management
|
|
3
|
+
*
|
|
4
|
+
* Provides token estimation, smart truncation, and section extraction
|
|
5
|
+
* for controlling response size in LLM contexts.
|
|
6
|
+
*/
|
|
7
|
+
import type { TokenInfo, ArticleSection } from '../types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Result of truncation operation
|
|
10
|
+
*/
|
|
11
|
+
export interface TruncateResult {
|
|
12
|
+
content: string;
|
|
13
|
+
tokenInfo: TokenInfo;
|
|
14
|
+
remainingSections?: ArticleSection[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Result of section extraction
|
|
18
|
+
*/
|
|
19
|
+
export interface ExtractSectionResult {
|
|
20
|
+
content: string;
|
|
21
|
+
section: ArticleSection | null;
|
|
22
|
+
tokenInfo: TokenInfo;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Estimate token count for a text string
|
|
26
|
+
* Uses different ratios for code blocks vs normal text
|
|
27
|
+
*/
|
|
28
|
+
export declare function estimateTokens(text: string): number;
|
|
29
|
+
/**
|
|
30
|
+
* Create a TokenInfo object
|
|
31
|
+
*/
|
|
32
|
+
export declare function createTokenInfo(content: string, maxTokens: number, truncated?: boolean): TokenInfo;
|
|
33
|
+
/**
|
|
34
|
+
* Extract sections (headings) from Markdown content
|
|
35
|
+
*/
|
|
36
|
+
export declare function extractSections(content: string): ArticleSection[];
|
|
37
|
+
/**
|
|
38
|
+
* Extract a specific section from Markdown content
|
|
39
|
+
*/
|
|
40
|
+
export declare function extractSection(content: string, sectionIdentifier: string, maxTokens?: number): ExtractSectionResult;
|
|
41
|
+
/**
|
|
42
|
+
* Smart truncation that preserves document structure
|
|
43
|
+
* - Preserves paragraph boundaries
|
|
44
|
+
* - Correctly closes code blocks
|
|
45
|
+
* - Lists remaining sections when truncated
|
|
46
|
+
*/
|
|
47
|
+
export declare function truncateToTokenLimit(content: string, maxTokens?: number): TruncateResult;
|
|
48
|
+
/**
|
|
49
|
+
* Calculate pagination info
|
|
50
|
+
*/
|
|
51
|
+
export declare function calculatePagination(totalItems: number, page: number, pageSize: number): {
|
|
52
|
+
page: number;
|
|
53
|
+
pageSize: number;
|
|
54
|
+
totalPages: number;
|
|
55
|
+
totalItems: number;
|
|
56
|
+
hasNext: boolean;
|
|
57
|
+
hasPrev: boolean;
|
|
58
|
+
startIndex: number;
|
|
59
|
+
endIndex: number;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Truncate an array of items to fit within token limit
|
|
63
|
+
* Returns items that fit and pagination info
|
|
64
|
+
*/
|
|
65
|
+
export declare function truncateItemsToTokenLimit<T>(items: T[], maxTokens: number, itemToString: (item: T) => string, page?: number, pageSize?: number): {
|
|
66
|
+
items: T[];
|
|
67
|
+
tokenInfo: TokenInfo;
|
|
68
|
+
pagination: {
|
|
69
|
+
page: number;
|
|
70
|
+
pageSize: number;
|
|
71
|
+
totalPages: number;
|
|
72
|
+
totalItems: number;
|
|
73
|
+
hasNext: boolean;
|
|
74
|
+
hasPrev: boolean;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=tokenizer.d.ts.map
|