@cosmocoder/mcp-web-docs 2.0.20 → 2.0.22
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/build/config.d.ts +0 -19
- package/build/config.js +0 -50
- package/build/config.js.map +1 -1
- package/build/config.test.js +1 -31
- package/build/config.test.js.map +1 -1
- package/build/crawler/base.d.ts +1 -16
- package/build/crawler/base.js +4 -120
- package/build/crawler/base.js.map +1 -1
- package/build/crawler/base.test.js +2 -184
- package/build/crawler/base.test.js.map +1 -1
- package/build/crawler/crawlee-crawler.js +0 -1
- package/build/crawler/crawlee-crawler.js.map +1 -1
- package/build/crawler/crawlee-crawler.test.js +13 -0
- package/build/crawler/crawlee-crawler.test.js.map +1 -1
- package/build/crawler/docs-crawler.d.ts +4 -7
- package/build/crawler/docs-crawler.js +5 -12
- package/build/crawler/docs-crawler.js.map +1 -1
- package/build/crawler/docs-crawler.test.js +13 -51
- package/build/crawler/docs-crawler.test.js.map +1 -1
- package/build/crawler/github.d.ts +1 -1
- package/build/crawler/github.js +7 -7
- package/build/crawler/github.js.map +1 -1
- package/build/crawler/github.test.js +9 -39
- package/build/crawler/github.test.js.map +1 -1
- package/build/crawler/llms-txt.js +5 -3
- package/build/crawler/llms-txt.js.map +1 -1
- package/build/crawler/llms-txt.test.js +2 -0
- package/build/crawler/llms-txt.test.js.map +1 -1
- package/build/index.js +26 -1664
- package/build/index.js.map +1 -1
- package/build/index.test.js +267 -433
- package/build/index.test.js.map +1 -1
- package/build/indexing/queue-manager.d.ts +2 -0
- package/build/indexing/queue-manager.js +13 -18
- package/build/indexing/queue-manager.js.map +1 -1
- package/build/indexing/queue-manager.test.js +5 -12
- package/build/indexing/queue-manager.test.js.map +1 -1
- package/build/indexing/workflow.d.ts +38 -0
- package/build/indexing/workflow.js +223 -0
- package/build/indexing/workflow.js.map +1 -0
- package/build/indexing/workflow.test.d.ts +1 -0
- package/build/indexing/workflow.test.js +218 -0
- package/build/indexing/workflow.test.js.map +1 -0
- package/build/server.d.ts +88 -0
- package/build/server.js +1460 -0
- package/build/server.js.map +1 -0
- package/build/server.test.d.ts +1 -0
- package/build/server.test.js +27 -0
- package/build/server.test.js.map +1 -0
- package/build/storage/storage.js +1 -0
- package/build/storage/storage.js.map +1 -1
- package/build/storage/storage.test.js +25 -8
- package/build/storage/storage.test.js.map +1 -1
- package/build/types.d.ts +0 -15
- package/build/util/docs.js +1 -2
- package/build/util/docs.js.map +1 -1
- package/build/util/docs.test.js +8 -2
- package/build/util/docs.test.js.map +1 -1
- package/build/util/security.d.ts +1 -0
- package/build/util/security.js +6 -5
- package/build/util/security.js.map +1 -1
- package/build/util/security.test.js +7 -1
- package/build/util/security.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
2
|
+
import { detectPromptInjection, safeJsonParse, sanitizeErrorMessage, SessionExpiredError, StorageStateSchema, } from '../util/security.js';
|
|
3
|
+
import { logger } from '../util/logger.js';
|
|
4
|
+
export class IndexingWorkflow {
|
|
5
|
+
dependencies;
|
|
6
|
+
constructor(dependencies) {
|
|
7
|
+
this.dependencies = dependencies;
|
|
8
|
+
}
|
|
9
|
+
async run(request, signal) {
|
|
10
|
+
const { operationId, url, title, pathPrefix, authInfo, tags, version } = request;
|
|
11
|
+
const reIndex = request.reIndex ?? false;
|
|
12
|
+
const { store, processor, statusTracker, authManager } = this.dependencies;
|
|
13
|
+
const checkCancelled = () => {
|
|
14
|
+
if (signal.aborted) {
|
|
15
|
+
logger.info(`[IndexingWorkflow] Operation cancelled for ${url}`);
|
|
16
|
+
if (statusTracker.getStatus(operationId)?.status !== 'cancelled') {
|
|
17
|
+
statusTracker.cancelIndexing(operationId);
|
|
18
|
+
}
|
|
19
|
+
const error = new Error('Operation cancelled');
|
|
20
|
+
error.name = 'AbortError';
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
try {
|
|
25
|
+
logger.info(`[IndexingWorkflow] Starting indexing for ${url} (reIndex: ${reIndex})`);
|
|
26
|
+
checkCancelled();
|
|
27
|
+
logger.debug(`[IndexingWorkflow] Checking if document exists: ${url}`);
|
|
28
|
+
const existingDoc = await store.getDocument(url);
|
|
29
|
+
checkCancelled();
|
|
30
|
+
if (existingDoc) {
|
|
31
|
+
logger.debug(`[IndexingWorkflow] Document exists: ${url}`);
|
|
32
|
+
if (!reIndex) {
|
|
33
|
+
logger.info(`[IndexingWorkflow] Document ${url} already indexed and reIndex=false`);
|
|
34
|
+
statusTracker.completeIndexing(operationId);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
logger.info(`[IndexingWorkflow] Will reindex existing document: ${url}`);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
logger.debug(`[IndexingWorkflow] Document does not exist: ${url}`);
|
|
41
|
+
}
|
|
42
|
+
checkCancelled();
|
|
43
|
+
statusTracker.updateProgress(operationId, 0, 'Finding subpages');
|
|
44
|
+
logger.info(`[IndexingWorkflow] Starting crawl${pathPrefix ? ` with pathPrefix=${pathPrefix}` : ''}`);
|
|
45
|
+
const crawler = this.dependencies.createCrawler();
|
|
46
|
+
if (pathPrefix) {
|
|
47
|
+
crawler.setPathPrefix(pathPrefix);
|
|
48
|
+
}
|
|
49
|
+
const savedSession = await authManager.loadSession(url);
|
|
50
|
+
checkCancelled();
|
|
51
|
+
if (savedSession) {
|
|
52
|
+
try {
|
|
53
|
+
const validatedState = safeJsonParse(savedSession, StorageStateSchema);
|
|
54
|
+
crawler.setStorageState(validatedState);
|
|
55
|
+
logger.info(`[IndexingWorkflow] Using validated authentication session for ${url}`);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
logger.warn(`[IndexingWorkflow] Failed to parse or validate saved session:`, error);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const pages = [];
|
|
62
|
+
let processedPages = 0;
|
|
63
|
+
let estimatedProgress = 0;
|
|
64
|
+
logger.info(`[IndexingWorkflow] Starting page crawl for ${url}`);
|
|
65
|
+
const abortCrawler = () => crawler.abort();
|
|
66
|
+
signal.addEventListener('abort', abortCrawler, { once: true });
|
|
67
|
+
if (signal.aborted) {
|
|
68
|
+
abortCrawler();
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
for await (const page of crawler.crawl(url)) {
|
|
72
|
+
checkCancelled();
|
|
73
|
+
logger.debug(`[IndexingWorkflow] Found page ${processedPages + 1}: ${page.path}`);
|
|
74
|
+
processedPages++;
|
|
75
|
+
estimatedProgress += 1 / 2 ** processedPages;
|
|
76
|
+
statusTracker.updateProgress(operationId, 0.15 * estimatedProgress + Math.min(0.35, (0.35 * processedPages) / 500), `Finding subpages (${page.path})`);
|
|
77
|
+
statusTracker.updateStats(operationId, { pagesFound: processedPages });
|
|
78
|
+
pages.push(page);
|
|
79
|
+
await delay(50, undefined, { signal });
|
|
80
|
+
checkCancelled();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (signal.aborted) {
|
|
85
|
+
checkCancelled();
|
|
86
|
+
}
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
signal.removeEventListener('abort', abortCrawler);
|
|
91
|
+
}
|
|
92
|
+
checkCancelled();
|
|
93
|
+
if (pages.length === 0) {
|
|
94
|
+
logger.warn('[IndexingWorkflow] No pages found during crawl');
|
|
95
|
+
throw new Error('No pages found to index');
|
|
96
|
+
}
|
|
97
|
+
logger.info(`[IndexingWorkflow] Found ${pages.length} pages to process`);
|
|
98
|
+
logger.info('[IndexingWorkflow] Starting content processing and embedding generation');
|
|
99
|
+
statusTracker.updateStats(operationId, { pagesFound: pages.length });
|
|
100
|
+
checkCancelled();
|
|
101
|
+
const chunks = [];
|
|
102
|
+
for (let i = 0; i < pages.length; i++) {
|
|
103
|
+
checkCancelled();
|
|
104
|
+
const page = pages[i];
|
|
105
|
+
logger.debug(`[IndexingWorkflow] Processing page ${i + 1}/${pages.length}: ${page.path}`);
|
|
106
|
+
statusTracker.updateProgress(operationId, 0.5 + 0.3 * (i / pages.length), `Creating embeddings (${i + 1}/${pages.length})`);
|
|
107
|
+
try {
|
|
108
|
+
const processed = await processor.process(page);
|
|
109
|
+
logger.debug(`[IndexingWorkflow] Created ${processed.chunks.length} chunks for ${page.path}`);
|
|
110
|
+
chunks.push(...processed.chunks);
|
|
111
|
+
statusTracker.updateStats(operationId, {
|
|
112
|
+
pagesProcessed: i + 1,
|
|
113
|
+
chunksCreated: chunks.length,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
if (signal.aborted) {
|
|
118
|
+
checkCancelled();
|
|
119
|
+
}
|
|
120
|
+
logger.error(`[IndexingWorkflow] Error processing page ${page.path}:`, error);
|
|
121
|
+
throw new Error(sanitizeErrorMessage(`Failed to process ${page.path}: ${sanitizeErrorMessage(error)}`));
|
|
122
|
+
}
|
|
123
|
+
checkCancelled();
|
|
124
|
+
await delay(20, undefined, { signal });
|
|
125
|
+
checkCancelled();
|
|
126
|
+
}
|
|
127
|
+
logger.info(`[IndexingWorkflow] Total chunks created: ${chunks.length}`);
|
|
128
|
+
let injectionWarnings = 0;
|
|
129
|
+
for (const chunk of chunks) {
|
|
130
|
+
const injectionResult = detectPromptInjection(chunk.content);
|
|
131
|
+
if (injectionResult.hasInjection) {
|
|
132
|
+
injectionWarnings++;
|
|
133
|
+
if (injectionResult.maxSeverity === 'high') {
|
|
134
|
+
logger.debug(`[Security] Prompt injection pattern detected in ${chunk.path || 'unknown'}: ${injectionResult.detections[0]?.description}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (injectionWarnings > 0) {
|
|
139
|
+
logger.debug(`[Security] Detected ${injectionWarnings} chunks with potential prompt injection patterns in ${url}. Content will be marked when returned in search results.`);
|
|
140
|
+
}
|
|
141
|
+
checkCancelled();
|
|
142
|
+
if (chunks.length === 0) {
|
|
143
|
+
logger.warn(`[IndexingWorkflow] No content was extracted from ${url}`);
|
|
144
|
+
logger.warn(`[IndexingWorkflow] Pages found: ${pages.length}`);
|
|
145
|
+
logger.warn(`[IndexingWorkflow] Chunks created: ${chunks.length}`);
|
|
146
|
+
statusTracker.failIndexing(operationId, 'No content was extracted from the pages');
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
checkCancelled();
|
|
150
|
+
const favicon = await this.dependencies.fetchFavicon(new URL(url));
|
|
151
|
+
checkCancelled();
|
|
152
|
+
statusTracker.updateProgress(operationId, 0.9, `Storing ${chunks.length} chunks`);
|
|
153
|
+
await this.addDocumentWithRetry({
|
|
154
|
+
metadata: {
|
|
155
|
+
url,
|
|
156
|
+
title,
|
|
157
|
+
favicon: favicon ?? undefined,
|
|
158
|
+
lastIndexed: new Date(),
|
|
159
|
+
requiresAuth: authInfo?.requiresAuth,
|
|
160
|
+
authDomain: authInfo?.authDomain,
|
|
161
|
+
version,
|
|
162
|
+
pathPrefix,
|
|
163
|
+
},
|
|
164
|
+
chunks,
|
|
165
|
+
}, signal, tags);
|
|
166
|
+
checkCancelled();
|
|
167
|
+
if (tags && tags.length > 0) {
|
|
168
|
+
logger.info(`[IndexingWorkflow] Tags set for ${url}:`, tags);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
logger.debug(`[IndexingWorkflow] Tags cleared for ${url}`);
|
|
172
|
+
}
|
|
173
|
+
logger.info(`[IndexingWorkflow] Successfully indexed ${url}`);
|
|
174
|
+
logger.info(`[IndexingWorkflow] Pages processed: ${pages.length}`);
|
|
175
|
+
logger.info(`[IndexingWorkflow] Chunks stored: ${chunks.length}`);
|
|
176
|
+
statusTracker.updateStats(operationId, { chunksCreated: chunks.length });
|
|
177
|
+
statusTracker.completeIndexing(operationId);
|
|
178
|
+
store.optimize().catch((error) => {
|
|
179
|
+
logger.warn('[IndexingWorkflow] Background optimization failed:', error);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
if (signal.aborted || (error instanceof Error && error.name === 'AbortError')) {
|
|
184
|
+
if (signal.aborted && statusTracker.getStatus(operationId)?.status !== 'cancelled') {
|
|
185
|
+
statusTracker.cancelIndexing(operationId);
|
|
186
|
+
}
|
|
187
|
+
logger.info(`[IndexingWorkflow] Indexing cancelled for ${url}`);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (error instanceof SessionExpiredError) {
|
|
191
|
+
logger.warn(`[IndexingWorkflow] Session expired during crawl of ${url}: ${error.message}`);
|
|
192
|
+
logger.warn(`[IndexingWorkflow] Expected URL: ${error.expectedUrl}, Detected URL: ${error.detectedUrl}`);
|
|
193
|
+
await authManager.clearSession(url);
|
|
194
|
+
checkCancelled();
|
|
195
|
+
logger.info(`[IndexingWorkflow] Cleared expired session for ${url}`);
|
|
196
|
+
statusTracker.failIndexing(operationId, `Authentication session has expired. The crawler was redirected to a login page. Please use the 'authenticate' tool to log in again before re-indexing.`);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
logger.error('[IndexingWorkflow] Error during indexing:', error);
|
|
200
|
+
logger.error('[IndexingWorkflow] Error details:', error instanceof Error ? error.stack : error);
|
|
201
|
+
statusTracker.failIndexing(operationId, error instanceof Error ? error.message : 'Unknown error');
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
async addDocumentWithRetry(doc, signal, tags, maxRetries = 3) {
|
|
205
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
206
|
+
signal.throwIfAborted();
|
|
207
|
+
try {
|
|
208
|
+
await this.dependencies.store.addDocument(doc, { signal, tags: tags ?? [] });
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
const isRetryable = error instanceof Error && (error.message.includes('Commit conflict') || error.message.startsWith('Replacement lease lost for '));
|
|
213
|
+
if (isRetryable && attempt < maxRetries) {
|
|
214
|
+
logger.warn(`[IndexingWorkflow] Storage conflict, retrying (${attempt}/${maxRetries})...`);
|
|
215
|
+
await delay(1000 * attempt, undefined, { signal });
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
throw error;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=workflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.js","sourceRoot":"","sources":["../../src/indexing/workflow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { SessionExpiredError } from '../util/security.js';
|
|
2
|
+
import { DocsCrawler } from '../crawler/docs-crawler.js';
|
|
3
|
+
import { IndexingWorkflow } from './workflow.js';
|
|
4
|
+
const request = {
|
|
5
|
+
operationId: 'operation-1',
|
|
6
|
+
url: 'https://docs.example.com',
|
|
7
|
+
title: 'Example Docs',
|
|
8
|
+
};
|
|
9
|
+
const page = {
|
|
10
|
+
url: request.url,
|
|
11
|
+
path: '/',
|
|
12
|
+
content: '<h1>Example</h1>',
|
|
13
|
+
contentFormat: 'text',
|
|
14
|
+
title: request.title,
|
|
15
|
+
};
|
|
16
|
+
const chunk = {
|
|
17
|
+
content: 'Example content',
|
|
18
|
+
url: request.url,
|
|
19
|
+
title: request.title,
|
|
20
|
+
path: '/',
|
|
21
|
+
startLine: 0,
|
|
22
|
+
endLine: 0,
|
|
23
|
+
vector: [0.1, 0.2],
|
|
24
|
+
metadata: { type: 'overview' },
|
|
25
|
+
};
|
|
26
|
+
function createHarness(options = {}) {
|
|
27
|
+
const addDocument = vi.fn().mockResolvedValue(undefined);
|
|
28
|
+
const store = {
|
|
29
|
+
addDocument,
|
|
30
|
+
getDocument: vi.fn().mockResolvedValue(options.existingDocument ?? null),
|
|
31
|
+
optimize: vi.fn().mockResolvedValue({ compacted: false, cleanedUp: false }),
|
|
32
|
+
};
|
|
33
|
+
const statusTracker = {
|
|
34
|
+
cancelIndexing: vi.fn(),
|
|
35
|
+
completeIndexing: vi.fn(),
|
|
36
|
+
failIndexing: vi.fn(),
|
|
37
|
+
getStatus: vi.fn(),
|
|
38
|
+
updateProgress: vi.fn(),
|
|
39
|
+
updateStats: vi.fn(),
|
|
40
|
+
};
|
|
41
|
+
const authManager = {
|
|
42
|
+
clearSession: vi.fn().mockResolvedValue(undefined),
|
|
43
|
+
loadSession: vi.fn().mockResolvedValue(options.savedSession ?? null),
|
|
44
|
+
};
|
|
45
|
+
const crawler = {
|
|
46
|
+
abort: vi.fn(),
|
|
47
|
+
crawl: options.crawl ??
|
|
48
|
+
async function* () {
|
|
49
|
+
yield page;
|
|
50
|
+
},
|
|
51
|
+
setPathPrefix: vi.fn(),
|
|
52
|
+
setStorageState: vi.fn(),
|
|
53
|
+
};
|
|
54
|
+
const process = vi.fn(options.process ??
|
|
55
|
+
(async () => ({
|
|
56
|
+
metadata: { url: page.url, title: page.title, lastIndexed: new Date() },
|
|
57
|
+
chunks: [chunk],
|
|
58
|
+
})));
|
|
59
|
+
const processor = { process };
|
|
60
|
+
const createCrawler = vi.fn(options.createCrawler ?? (() => crawler));
|
|
61
|
+
const fetchFavicon = vi.fn().mockResolvedValue('data:image/x-icon;base64,AA==');
|
|
62
|
+
const workflow = new IndexingWorkflow({ store, processor, statusTracker, authManager, createCrawler, fetchFavicon });
|
|
63
|
+
return { workflow, store, statusTracker, authManager, crawler, createCrawler, fetchFavicon, addDocument, process };
|
|
64
|
+
}
|
|
65
|
+
const runWorkflow = (workflow, indexingRequest, signal = new AbortController().signal) => workflow.run(indexingRequest, signal);
|
|
66
|
+
describe('IndexingWorkflow', () => {
|
|
67
|
+
it('crawls, processes, stores, tags, completes, and optimizes a document', async () => {
|
|
68
|
+
const harness = createHarness();
|
|
69
|
+
await runWorkflow(harness.workflow, { ...request, pathPrefix: '/guide', tags: ['guide'], version: '2' });
|
|
70
|
+
expect(harness.createCrawler).toHaveBeenCalledWith();
|
|
71
|
+
expect(harness.crawler.setPathPrefix).toHaveBeenCalledWith('/guide');
|
|
72
|
+
expect(harness.addDocument).toHaveBeenCalledWith({
|
|
73
|
+
metadata: expect.objectContaining({
|
|
74
|
+
url: request.url,
|
|
75
|
+
title: request.title,
|
|
76
|
+
favicon: 'data:image/x-icon;base64,AA==',
|
|
77
|
+
version: '2',
|
|
78
|
+
pathPrefix: '/guide',
|
|
79
|
+
}),
|
|
80
|
+
chunks: [chunk],
|
|
81
|
+
}, { signal: expect.any(AbortSignal), tags: ['guide'] });
|
|
82
|
+
expect(harness.statusTracker.completeIndexing).toHaveBeenCalledWith(request.operationId);
|
|
83
|
+
expect(harness.store.optimize).toHaveBeenCalledOnce();
|
|
84
|
+
const progressStages = harness.statusTracker.updateProgress.mock.calls.map((call) => call[2]);
|
|
85
|
+
expect(progressStages).toEqual(expect.arrayContaining(['Finding subpages', 'Finding subpages (/)', 'Creating embeddings (1/1)', 'Storing 1 chunks']));
|
|
86
|
+
expect(progressStages.indexOf('Finding subpages')).toBeLessThan(progressStages.indexOf('Creating embeddings (1/1)'));
|
|
87
|
+
expect(progressStages.indexOf('Creating embeddings (1/1)')).toBeLessThan(progressStages.indexOf('Storing 1 chunks'));
|
|
88
|
+
expect(harness.statusTracker.updateStats).toHaveBeenCalledWith(request.operationId, { pagesFound: 1 });
|
|
89
|
+
expect(harness.statusTracker.updateStats).toHaveBeenCalledWith(request.operationId, { pagesProcessed: 1, chunksCreated: 1 });
|
|
90
|
+
expect(harness.statusTracker.updateStats).toHaveBeenCalledWith(request.operationId, { chunksCreated: 1 });
|
|
91
|
+
});
|
|
92
|
+
it('reindexes only after processing and finishes metadata after the replacement write', async () => {
|
|
93
|
+
const harness = createHarness({
|
|
94
|
+
existingDocument: { url: request.url, title: request.title, lastIndexed: new Date() },
|
|
95
|
+
});
|
|
96
|
+
await runWorkflow(harness.workflow, { ...request, reIndex: true, tags: ['existing'] });
|
|
97
|
+
const processOrder = harness.process.mock.invocationCallOrder[0];
|
|
98
|
+
const addOrder = harness.addDocument.mock.invocationCallOrder[0];
|
|
99
|
+
expect(processOrder).toBeLessThan(addOrder);
|
|
100
|
+
expect(addOrder).toBeLessThan(harness.statusTracker.completeIndexing.mock.invocationCallOrder[0]);
|
|
101
|
+
const progressStages = harness.statusTracker.updateProgress.mock.calls.map((call) => call[2]);
|
|
102
|
+
expect(progressStages.indexOf('Creating embeddings (1/1)')).toBeLessThan(progressStages.indexOf('Storing 1 chunks'));
|
|
103
|
+
expect(harness.statusTracker.updateStats).toHaveBeenCalledWith(request.operationId, {
|
|
104
|
+
pagesProcessed: 1,
|
|
105
|
+
chunksCreated: 1,
|
|
106
|
+
});
|
|
107
|
+
const failedWrite = createHarness({
|
|
108
|
+
existingDocument: { url: request.url, title: request.title, lastIndexed: new Date() },
|
|
109
|
+
});
|
|
110
|
+
failedWrite.addDocument.mockRejectedValue(new Error('write failed'));
|
|
111
|
+
await runWorkflow(failedWrite.workflow, { ...request, reIndex: true, tags: ['existing'] });
|
|
112
|
+
expect(failedWrite.addDocument).toHaveBeenCalledOnce();
|
|
113
|
+
expect(failedWrite.statusTracker.completeIndexing).not.toHaveBeenCalled();
|
|
114
|
+
expect(failedWrite.statusTracker.failIndexing).toHaveBeenCalledWith(request.operationId, 'write failed');
|
|
115
|
+
});
|
|
116
|
+
it('completes an existing add without crawling or writing', async () => {
|
|
117
|
+
const harness = createHarness({
|
|
118
|
+
existingDocument: { url: request.url, title: request.title, lastIndexed: new Date() },
|
|
119
|
+
});
|
|
120
|
+
await runWorkflow(harness.workflow, request);
|
|
121
|
+
expect(harness.statusTracker.completeIndexing).toHaveBeenCalledWith(request.operationId);
|
|
122
|
+
expect(harness.createCrawler).not.toHaveBeenCalled();
|
|
123
|
+
expect(harness.addDocument).not.toHaveBeenCalled();
|
|
124
|
+
});
|
|
125
|
+
it('fails without writing when processing produces no chunks', async () => {
|
|
126
|
+
const harness = createHarness({
|
|
127
|
+
existingDocument: { url: request.url, title: request.title, lastIndexed: new Date() },
|
|
128
|
+
process: vi.fn().mockResolvedValue({
|
|
129
|
+
metadata: { url: page.url, title: page.title, lastIndexed: new Date() },
|
|
130
|
+
chunks: [],
|
|
131
|
+
}),
|
|
132
|
+
});
|
|
133
|
+
await runWorkflow(harness.workflow, { ...request, reIndex: true });
|
|
134
|
+
expect(harness.statusTracker.failIndexing).toHaveBeenCalledWith(request.operationId, 'No content was extracted from the pages');
|
|
135
|
+
expect(harness.addDocument).not.toHaveBeenCalled();
|
|
136
|
+
});
|
|
137
|
+
it.each([
|
|
138
|
+
['valid', JSON.stringify({ cookies: [] }), { cookies: [] }],
|
|
139
|
+
['malformed', '{not json', undefined],
|
|
140
|
+
])('continues crawling with a %s saved session', async (_label, savedSession, expectedState) => {
|
|
141
|
+
const harness = createHarness({ savedSession });
|
|
142
|
+
await runWorkflow(harness.workflow, request);
|
|
143
|
+
if (expectedState) {
|
|
144
|
+
expect(harness.crawler.setStorageState).toHaveBeenCalledWith(expectedState);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
expect(harness.crawler.setStorageState).not.toHaveBeenCalled();
|
|
148
|
+
}
|
|
149
|
+
expect(harness.addDocument).toHaveBeenCalledOnce();
|
|
150
|
+
expect(harness.statusTracker.completeIndexing).toHaveBeenCalledWith(request.operationId);
|
|
151
|
+
});
|
|
152
|
+
it('aborts an in-progress crawl without writing', async () => {
|
|
153
|
+
const controller = new AbortController();
|
|
154
|
+
const harness = createHarness({
|
|
155
|
+
crawl: async function* () {
|
|
156
|
+
yield page;
|
|
157
|
+
controller.abort();
|
|
158
|
+
yield { ...page, path: '/second' };
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
await runWorkflow(harness.workflow, request, controller.signal);
|
|
162
|
+
expect(harness.crawler.abort).toHaveBeenCalledOnce();
|
|
163
|
+
expect(harness.statusTracker.cancelIndexing).toHaveBeenCalledWith(request.operationId);
|
|
164
|
+
expect(harness.addDocument).not.toHaveBeenCalled();
|
|
165
|
+
});
|
|
166
|
+
it('clears an expired session and reports the friendly authentication failure', async () => {
|
|
167
|
+
const harness = createHarness({
|
|
168
|
+
crawl: async function* () {
|
|
169
|
+
yield* [];
|
|
170
|
+
throw new SessionExpiredError('redirected', request.url, 'https://docs.example.com/login', {
|
|
171
|
+
isLoginPage: true,
|
|
172
|
+
confidence: 1,
|
|
173
|
+
reasons: ['login URL'],
|
|
174
|
+
});
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
await runWorkflow(harness.workflow, request);
|
|
178
|
+
expect(harness.authManager.clearSession).toHaveBeenCalledWith(request.url);
|
|
179
|
+
expect(harness.statusTracker.failIndexing).toHaveBeenCalledWith(request.operationId, expect.stringContaining("Please use the 'authenticate' tool"));
|
|
180
|
+
expect(harness.addDocument).not.toHaveBeenCalled();
|
|
181
|
+
});
|
|
182
|
+
it('consumes generic failures and marks the operation failed', async () => {
|
|
183
|
+
const harness = createHarness({
|
|
184
|
+
crawl: async function* () {
|
|
185
|
+
yield* [];
|
|
186
|
+
throw new Error('crawl failed');
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
await expect(runWorkflow(harness.workflow, request)).resolves.toBeUndefined();
|
|
190
|
+
expect(harness.statusTracker.failIndexing).toHaveBeenCalledWith(request.operationId, 'crawl failed');
|
|
191
|
+
expect(harness.addDocument).not.toHaveBeenCalled();
|
|
192
|
+
});
|
|
193
|
+
it('surfaces unsupported GitHub blob URLs through indexing status', async () => {
|
|
194
|
+
const harness = createHarness({ createCrawler: () => new DocsCrawler() });
|
|
195
|
+
const blobUrl = 'https://github.com/owner/repo/blob/main/README.md';
|
|
196
|
+
await runWorkflow(harness.workflow, { ...request, url: blobUrl });
|
|
197
|
+
expect(harness.statusTracker.failIndexing).toHaveBeenCalledWith(request.operationId, `Unsupported GitHub URL: ${blobUrl}. Use a repository root or /tree/<branch>[/path] URL.`);
|
|
198
|
+
expect(fetchMock).not.toHaveBeenCalled();
|
|
199
|
+
expect(harness.fetchFavicon).not.toHaveBeenCalled();
|
|
200
|
+
expect(harness.addDocument).not.toHaveBeenCalled();
|
|
201
|
+
});
|
|
202
|
+
it('retries transient commit conflicts before succeeding', async () => {
|
|
203
|
+
vi.useFakeTimers();
|
|
204
|
+
const harness = createHarness();
|
|
205
|
+
harness.addDocument.mockRejectedValueOnce(new Error('Commit conflict')).mockResolvedValueOnce(undefined);
|
|
206
|
+
const run = runWorkflow(harness.workflow, request);
|
|
207
|
+
await vi.runAllTimersAsync();
|
|
208
|
+
await run;
|
|
209
|
+
expect(harness.addDocument).toHaveBeenCalledTimes(2);
|
|
210
|
+
expect(harness.addDocument).toHaveBeenLastCalledWith(expect.any(Object), {
|
|
211
|
+
signal: expect.any(AbortSignal),
|
|
212
|
+
tags: [],
|
|
213
|
+
});
|
|
214
|
+
expect(harness.statusTracker.completeIndexing).toHaveBeenCalledWith(request.operationId);
|
|
215
|
+
vi.useRealTimers();
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
//# sourceMappingURL=workflow.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.test.js","sourceRoot":"","sources":["../../src/indexing/workflow.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export declare class WebDocsServer {
|
|
2
|
+
private server;
|
|
3
|
+
private config;
|
|
4
|
+
private store;
|
|
5
|
+
private processor;
|
|
6
|
+
private statusTracker;
|
|
7
|
+
private indexingQueue;
|
|
8
|
+
private authManager;
|
|
9
|
+
private indexingWorkflow;
|
|
10
|
+
private runPromise?;
|
|
11
|
+
private closePromise?;
|
|
12
|
+
private activeToolCalls;
|
|
13
|
+
/** Maps operation ID to progress token for MCP notifications */
|
|
14
|
+
private progressTokens;
|
|
15
|
+
/** Tracks last notified progress to throttle notifications */
|
|
16
|
+
private lastNotifiedProgress;
|
|
17
|
+
constructor();
|
|
18
|
+
/**
|
|
19
|
+
* Send MCP progress notification to client.
|
|
20
|
+
* Only sends if the client provided a progressToken in the original request.
|
|
21
|
+
* Throttled to avoid flooding - sends on 5% increments or status changes.
|
|
22
|
+
*/
|
|
23
|
+
private sendProgressNotification;
|
|
24
|
+
private initialize;
|
|
25
|
+
private setupToolHandlers;
|
|
26
|
+
private handleAddDocumentation;
|
|
27
|
+
private handleListDocumentation;
|
|
28
|
+
private handleSearchDocumentation;
|
|
29
|
+
private handleReindexDocumentation;
|
|
30
|
+
private handleGetIndexingStatus;
|
|
31
|
+
/**
|
|
32
|
+
* Handle interactive authentication request.
|
|
33
|
+
* Opens a visible browser for the user to login manually.
|
|
34
|
+
*/
|
|
35
|
+
private handleAuthenticate;
|
|
36
|
+
/**
|
|
37
|
+
* Handle clearing saved authentication for a domain
|
|
38
|
+
*/
|
|
39
|
+
private handleClearAuth;
|
|
40
|
+
/**
|
|
41
|
+
* Handle deleting an indexed documentation site and all its data
|
|
42
|
+
*/
|
|
43
|
+
private handleDeleteDocumentation;
|
|
44
|
+
/**
|
|
45
|
+
* Handle setting tags for a documentation site
|
|
46
|
+
*/
|
|
47
|
+
private handleSetTags;
|
|
48
|
+
/**
|
|
49
|
+
* Handle listing all tags with usage counts
|
|
50
|
+
*/
|
|
51
|
+
private handleListTags;
|
|
52
|
+
/**
|
|
53
|
+
* Handle creating a new collection
|
|
54
|
+
*/
|
|
55
|
+
private handleCreateCollection;
|
|
56
|
+
/**
|
|
57
|
+
* Handle deleting a collection
|
|
58
|
+
*/
|
|
59
|
+
private handleDeleteCollection;
|
|
60
|
+
/**
|
|
61
|
+
* Handle updating a collection's metadata
|
|
62
|
+
*/
|
|
63
|
+
private handleUpdateCollection;
|
|
64
|
+
/**
|
|
65
|
+
* Handle listing all collections
|
|
66
|
+
*/
|
|
67
|
+
private handleListCollections;
|
|
68
|
+
/**
|
|
69
|
+
* Handle getting a specific collection with its documents
|
|
70
|
+
*/
|
|
71
|
+
private handleGetCollection;
|
|
72
|
+
/**
|
|
73
|
+
* Handle adding documents to a collection
|
|
74
|
+
*/
|
|
75
|
+
private handleAddToCollection;
|
|
76
|
+
/**
|
|
77
|
+
* Handle removing documents from a collection
|
|
78
|
+
*/
|
|
79
|
+
private handleRemoveFromCollection;
|
|
80
|
+
/**
|
|
81
|
+
* Handle searching within a collection
|
|
82
|
+
*/
|
|
83
|
+
private handleSearchCollection;
|
|
84
|
+
run(): Promise<void>;
|
|
85
|
+
private start;
|
|
86
|
+
close(): Promise<void>;
|
|
87
|
+
private closeResources;
|
|
88
|
+
}
|