@cosmocoder/mcp-web-docs 2.0.11 → 2.0.13

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.
@@ -1,257 +1,167 @@
1
+ import { setImmediate as nextTurn } from 'node:timers/promises';
1
2
  import { IndexingQueueManager } from './queue-manager.js';
2
3
  describe('IndexingQueueManager', () => {
3
- let queue;
4
- beforeEach(() => {
5
- queue = new IndexingQueueManager();
4
+ it('registers before running and removes the same completed operation', async () => {
5
+ const queue = new IndexingQueueManager();
6
+ const started = Promise.withResolvers();
7
+ const released = Promise.withResolvers();
8
+ const handle = await queue.runLatest('https://example.com/', async () => {
9
+ started.resolve();
10
+ await released.promise;
11
+ });
12
+ await started.promise;
13
+ expect(handle.replacedExisting).toBe(false);
14
+ released.resolve();
15
+ await handle.completion;
6
16
  });
7
- describe('startOperation', () => {
8
- it('should return an AbortController for new operations', async () => {
9
- const controller = await queue.startOperation('https://example.com');
10
- expect(controller).toBeDefined();
11
- expect(controller).toBeInstanceOf(AbortController);
12
- expect(controller.signal.aborted).toBe(false);
13
- });
14
- it('should normalize URLs when starting operations', async () => {
15
- const controller = await queue.startOperation('https://example.com/');
16
- // Register the operation to verify normalization works
17
- const mockPromise = new Promise((resolve) => setTimeout(resolve, 100));
18
- queue.registerOperation('https://example.com/', controller, mockPromise);
19
- // Should find it with or without trailing slash
20
- expect(queue.isIndexing('https://example.com')).toBe(true);
21
- expect(queue.isIndexing('https://example.com/')).toBe(true);
22
- queue.completeOperation('https://example.com');
23
- });
24
- it('should cancel existing operation when starting new one for same URL', async () => {
25
- // Start first operation
26
- const controller1 = await queue.startOperation('https://example.com');
27
- const mockPromise1 = new Promise((_resolve, reject) => {
28
- controller1.signal.addEventListener('abort', () => reject(new Error('Aborted')));
29
- });
30
- queue.registerOperation('https://example.com', controller1, mockPromise1);
31
- // Start second operation for same URL - should cancel first
32
- const controller2 = await queue.startOperation('https://example.com');
33
- expect(controller1.signal.aborted).toBe(true);
34
- expect(controller2.signal.aborted).toBe(false);
35
- queue.completeOperation('https://example.com');
36
- });
37
- it('should not affect operations for different URLs', async () => {
38
- const controller1 = await queue.startOperation('https://example.com');
39
- const mockPromise1 = new Promise((resolve) => setTimeout(resolve, 1000));
40
- queue.registerOperation('https://example.com', controller1, mockPromise1);
41
- const controller2 = await queue.startOperation('https://other.com');
42
- const mockPromise2 = new Promise((resolve) => setTimeout(resolve, 1000));
43
- queue.registerOperation('https://other.com', controller2, mockPromise2);
44
- // Both should be active
45
- expect(controller1.signal.aborted).toBe(false);
46
- expect(controller2.signal.aborted).toBe(false);
47
- expect(queue.isIndexing('https://example.com')).toBe(true);
48
- expect(queue.isIndexing('https://other.com')).toBe(true);
49
- queue.completeOperation('https://example.com');
50
- queue.completeOperation('https://other.com');
51
- });
52
- it('should handle cancellation timeout gracefully', async () => {
53
- vi.useFakeTimers();
54
- // Start operation that never resolves
55
- const controller1 = await queue.startOperation('https://example.com');
56
- const neverResolves = new Promise(() => {
57
- // This promise never resolves
58
- });
59
- queue.registerOperation('https://example.com', controller1, neverResolves);
60
- // Start new operation - should timeout waiting for cancellation
61
- const startPromise = queue.startOperation('https://example.com');
62
- // Advance timers past the 5000ms timeout
63
- await vi.advanceTimersByTimeAsync(5100);
64
- const controller2 = await startPromise;
65
- // Should have returned a new controller after timeout
66
- expect(controller2).toBeDefined();
67
- expect(controller2.signal.aborted).toBe(false);
68
- queue.completeOperation('https://example.com');
69
- vi.useRealTimers();
70
- });
17
+ it('rejects a replacement when its aborted predecessor does not stop in time', async () => {
18
+ const queue = new IndexingQueueManager(10);
19
+ const firstStarted = Promise.withResolvers();
20
+ const firstReleased = Promise.withResolvers();
21
+ let firstSignal;
22
+ let replacementStarted = false;
23
+ const first = await queue.runLatest('https://example.com', async (signal) => {
24
+ firstSignal = signal;
25
+ firstStarted.resolve();
26
+ await firstReleased.promise;
27
+ });
28
+ await firstStarted.promise;
29
+ await expect(queue.runLatest('https://example.com/', async () => {
30
+ replacementStarted = true;
31
+ })).rejects.toThrow('Timed out cancelling');
32
+ expect(firstSignal.aborted).toBe(true);
33
+ expect(replacementStarted).toBe(false);
34
+ firstReleased.resolve();
35
+ await first.completion;
71
36
  });
72
- describe('registerOperation', () => {
73
- it('should register an operation', async () => {
74
- const controller = await queue.startOperation('https://example.com');
75
- const mockPromise = new Promise((resolve) => setTimeout(resolve, 100));
76
- queue.registerOperation('https://example.com', controller, mockPromise);
77
- expect(queue.isIndexing('https://example.com')).toBe(true);
78
- queue.completeOperation('https://example.com');
79
- });
80
- it('should store operation with correct metadata', async () => {
81
- const controller = await queue.startOperation('https://example.com');
82
- const mockPromise = new Promise((resolve) => setTimeout(resolve, 100));
83
- const beforeRegister = new Date();
84
- queue.registerOperation('https://example.com', controller, mockPromise);
85
- const afterRegister = new Date();
86
- const operations = queue.getActiveOperations();
87
- expect(operations).toHaveLength(1);
88
- expect(operations[0].url).toBe('https://example.com');
89
- expect(operations[0].startedAt.getTime()).toBeGreaterThanOrEqual(beforeRegister.getTime());
90
- expect(operations[0].startedAt.getTime()).toBeLessThanOrEqual(afterRegister.getTime());
91
- queue.completeOperation('https://example.com');
92
- });
93
- it('should normalize URL when registering', async () => {
94
- const controller = await queue.startOperation('https://example.com/');
95
- const mockPromise = new Promise((resolve) => setTimeout(resolve, 100));
96
- queue.registerOperation('https://example.com/', controller, mockPromise);
97
- // Should be findable with normalized URL
98
- expect(queue.isIndexing('https://example.com')).toBe(true);
99
- queue.completeOperation('https://example.com');
100
- });
37
+ it('keeps same-URL transitions ordered while a different URL starts independently', async () => {
38
+ const queue = new IndexingQueueManager(1_000);
39
+ const firstStarted = Promise.withResolvers();
40
+ const firstReleased = Promise.withResolvers();
41
+ const secondStarted = Promise.withResolvers();
42
+ const secondReleased = Promise.withResolvers();
43
+ const thirdStarted = Promise.withResolvers();
44
+ const thirdReleased = Promise.withResolvers();
45
+ const otherStarted = Promise.withResolvers();
46
+ const otherReleased = Promise.withResolvers();
47
+ const order = [];
48
+ let firstSignal;
49
+ let secondSignal;
50
+ const first = await queue.runLatest('https://example.com', async (signal) => {
51
+ firstSignal = signal;
52
+ order.push('first');
53
+ firstStarted.resolve();
54
+ await firstReleased.promise;
55
+ });
56
+ await firstStarted.promise;
57
+ const secondStart = queue.runLatest('https://example.com', async (signal) => {
58
+ secondSignal = signal;
59
+ order.push('second');
60
+ secondStarted.resolve();
61
+ await secondReleased.promise;
62
+ });
63
+ const thirdStart = queue.runLatest('https://example.com', async () => {
64
+ order.push('third');
65
+ thirdStarted.resolve();
66
+ await thirdReleased.promise;
67
+ });
68
+ const other = await queue.runLatest('https://other.com', async () => {
69
+ order.push('other');
70
+ otherStarted.resolve();
71
+ await otherReleased.promise;
72
+ });
73
+ await otherStarted.promise;
74
+ expect(order).toEqual(['first', 'other']);
75
+ expect(firstSignal.aborted).toBe(true);
76
+ firstReleased.resolve();
77
+ const second = await secondStart;
78
+ await secondStarted.promise;
79
+ await first.completion;
80
+ await nextTurn();
81
+ expect(secondSignal.aborted).toBe(true);
82
+ expect(order).toEqual(['first', 'other', 'second']);
83
+ secondReleased.resolve();
84
+ const third = await thirdStart;
85
+ await thirdStarted.promise;
86
+ expect(order).toEqual(['first', 'other', 'second', 'third']);
87
+ thirdReleased.resolve();
88
+ otherReleased.resolve();
89
+ await Promise.all([second.completion, third.completion, other.completion]);
101
90
  });
102
- describe('completeOperation', () => {
103
- it('should remove operation from active map', async () => {
104
- const controller = await queue.startOperation('https://example.com');
105
- const mockPromise = new Promise((resolve) => setTimeout(resolve, 100));
106
- queue.registerOperation('https://example.com', controller, mockPromise);
107
- expect(queue.isIndexing('https://example.com')).toBe(true);
108
- queue.completeOperation('https://example.com');
109
- expect(queue.isIndexing('https://example.com')).toBe(false);
110
- });
111
- it('should handle completing non-existent operation gracefully', () => {
112
- // Should not throw
113
- expect(() => queue.completeOperation('https://nonexistent.com')).not.toThrow();
114
- });
115
- it('should normalize URL when completing', async () => {
116
- const controller = await queue.startOperation('https://example.com');
117
- const mockPromise = new Promise((resolve) => setTimeout(resolve, 100));
118
- queue.registerOperation('https://example.com', controller, mockPromise);
119
- // Complete with trailing slash
120
- queue.completeOperation('https://example.com/');
121
- expect(queue.isIndexing('https://example.com')).toBe(false);
122
- });
123
- });
124
- describe('cancelAll', () => {
125
- it('should cancel all active operations', async () => {
126
- const controller1 = await queue.startOperation('https://example1.com');
127
- const mockPromise1 = new Promise((resolve) => {
128
- controller1.signal.addEventListener('abort', () => resolve());
129
- });
130
- queue.registerOperation('https://example1.com', controller1, mockPromise1);
131
- const controller2 = await queue.startOperation('https://example2.com');
132
- const mockPromise2 = new Promise((resolve) => {
133
- controller2.signal.addEventListener('abort', () => resolve());
91
+ it('continues after a cancelled predecessor rejects', async () => {
92
+ const queue = new IndexingQueueManager();
93
+ const firstStarted = Promise.withResolvers();
94
+ const first = await queue.runLatest('https://example.com', async (signal) => {
95
+ firstStarted.resolve();
96
+ await new Promise((_resolve, reject) => {
97
+ signal.addEventListener('abort', () => reject(new Error('cancelled')), { once: true });
134
98
  });
135
- queue.registerOperation('https://example2.com', controller2, mockPromise2);
136
- expect(queue.getActiveOperations()).toHaveLength(2);
137
- await queue.cancelAll();
138
- expect(controller1.signal.aborted).toBe(true);
139
- expect(controller2.signal.aborted).toBe(true);
140
- expect(queue.getActiveOperations()).toHaveLength(0);
141
- });
142
- it('should handle empty queue', async () => {
143
- await expect(queue.cancelAll()).resolves.not.toThrow();
144
- expect(queue.getActiveOperations()).toHaveLength(0);
145
- });
146
- it('should handle operations that reject on cancel', async () => {
147
- const controller = await queue.startOperation('https://example.com');
148
- const mockPromise = new Promise((_, reject) => {
149
- controller.signal.addEventListener('abort', () => reject(new Error('Cancelled')));
150
- });
151
- queue.registerOperation('https://example.com', controller, mockPromise);
152
- // Should not throw even if promises reject
153
- await expect(queue.cancelAll()).resolves.not.toThrow();
154
- expect(queue.getActiveOperations()).toHaveLength(0);
155
- });
156
- });
157
- describe('isIndexing', () => {
158
- it('should return false for URLs not being indexed', () => {
159
- expect(queue.isIndexing('https://example.com')).toBe(false);
160
- });
161
- it('should return true for URLs being indexed', async () => {
162
- const controller = await queue.startOperation('https://example.com');
163
- const mockPromise = new Promise((resolve) => setTimeout(resolve, 100));
164
- queue.registerOperation('https://example.com', controller, mockPromise);
165
- expect(queue.isIndexing('https://example.com')).toBe(true);
166
- queue.completeOperation('https://example.com');
167
- });
168
- it('should return false after operation completes', async () => {
169
- const controller = await queue.startOperation('https://example.com');
170
- const mockPromise = new Promise((resolve) => setTimeout(resolve, 100));
171
- queue.registerOperation('https://example.com', controller, mockPromise);
172
- queue.completeOperation('https://example.com');
173
- expect(queue.isIndexing('https://example.com')).toBe(false);
174
- });
175
- it('should normalize URL when checking', async () => {
176
- const controller = await queue.startOperation('https://example.com');
177
- const mockPromise = new Promise((resolve) => setTimeout(resolve, 100));
178
- queue.registerOperation('https://example.com', controller, mockPromise);
179
- // Check with trailing slash
180
- expect(queue.isIndexing('https://example.com/')).toBe(true);
181
- queue.completeOperation('https://example.com');
182
99
  });
100
+ const firstCompletion = first.completion.catch(() => { });
101
+ await firstStarted.promise;
102
+ const second = await queue.runLatest('https://example.com', async () => { });
103
+ expect(second.replacedExisting).toBe(true);
104
+ await Promise.all([firstCompletion, second.completion]);
183
105
  });
184
- describe('getActiveOperations', () => {
185
- it('should return empty array when no operations', () => {
186
- expect(queue.getActiveOperations()).toEqual([]);
187
- });
188
- it('should return all active operations', async () => {
189
- const controller1 = await queue.startOperation('https://example1.com');
190
- const mockPromise1 = new Promise((resolve) => setTimeout(resolve, 100));
191
- queue.registerOperation('https://example1.com', controller1, mockPromise1);
192
- const controller2 = await queue.startOperation('https://example2.com');
193
- const mockPromise2 = new Promise((resolve) => setTimeout(resolve, 100));
194
- queue.registerOperation('https://example2.com', controller2, mockPromise2);
195
- const operations = queue.getActiveOperations();
196
- expect(operations).toHaveLength(2);
197
- const urls = operations.map((op) => op.url);
198
- expect(urls).toContain('https://example1.com');
199
- expect(urls).toContain('https://example2.com');
200
- queue.completeOperation('https://example1.com');
201
- queue.completeOperation('https://example2.com');
202
- });
203
- it('should return operation metadata', async () => {
204
- const controller = await queue.startOperation('https://example.com');
205
- const mockPromise = new Promise((resolve) => setTimeout(resolve, 100));
206
- queue.registerOperation('https://example.com', controller, mockPromise);
207
- const operations = queue.getActiveOperations();
208
- expect(operations[0]).toHaveProperty('url');
209
- expect(operations[0]).toHaveProperty('startedAt');
210
- expect(operations[0].startedAt).toBeInstanceOf(Date);
211
- queue.completeOperation('https://example.com');
212
- });
213
- it('should not include completed operations', async () => {
214
- const controller = await queue.startOperation('https://example.com');
215
- const mockPromise = new Promise((resolve) => setTimeout(resolve, 100));
216
- queue.registerOperation('https://example.com', controller, mockPromise);
217
- queue.completeOperation('https://example.com');
218
- expect(queue.getActiveOperations()).toHaveLength(0);
219
- });
106
+ it('cancelAll drains pending transitions and rejects starts until its shared barrier completes', async () => {
107
+ const queue = new IndexingQueueManager();
108
+ const firstStarted = Promise.withResolvers();
109
+ const firstReleased = Promise.withResolvers();
110
+ let firstSignal;
111
+ let secondStarted = false;
112
+ const first = await queue.runLatest('https://example.com', async (signal) => {
113
+ firstSignal = signal;
114
+ firstStarted.resolve();
115
+ await firstReleased.promise;
116
+ });
117
+ await firstStarted.promise;
118
+ const secondStart = queue.runLatest('https://example.com', async () => {
119
+ secondStarted = true;
120
+ });
121
+ const secondResult = expect(secondStart).rejects.toThrow('being cancelled');
122
+ await nextTurn();
123
+ let cancellationFinished = false;
124
+ const cancellation = queue.cancelAll();
125
+ expect(queue.cancelAll()).toBe(cancellation);
126
+ void cancellation.then(() => {
127
+ cancellationFinished = true;
128
+ });
129
+ let duringCancellationStarted = false;
130
+ await expect(queue.runLatest('https://other.com', async () => {
131
+ duringCancellationStarted = true;
132
+ })).rejects.toThrow('being cancelled');
133
+ await nextTurn();
134
+ expect(firstSignal.aborted).toBe(true);
135
+ expect(duringCancellationStarted).toBe(false);
136
+ expect(cancellationFinished).toBe(false);
137
+ firstReleased.resolve();
138
+ await Promise.all([first.completion, secondResult, cancellation]);
139
+ expect(secondStarted).toBe(false);
140
+ expect(cancellationFinished).toBe(true);
141
+ let afterCancellationStarted = false;
142
+ const afterCancellation = await queue.runLatest('https://example.com', async () => {
143
+ afterCancellationStarted = true;
144
+ });
145
+ await afterCancellation.completion;
146
+ expect(afterCancellationStarted).toBe(true);
220
147
  });
221
- describe('concurrent operations', () => {
222
- it('should handle multiple concurrent operations for different URLs', async () => {
223
- const urls = ['https://a.com', 'https://b.com', 'https://c.com'];
224
- const controllers = [];
225
- for (const url of urls) {
226
- const controller = await queue.startOperation(url);
227
- const mockPromise = new Promise((resolve) => setTimeout(resolve, 100));
228
- queue.registerOperation(url, controller, mockPromise);
229
- controllers.push(controller);
230
- }
231
- expect(queue.getActiveOperations()).toHaveLength(3);
232
- // All should be active
233
- for (const controller of controllers) {
234
- expect(controller.signal.aborted).toBe(false);
235
- }
236
- // Complete one
237
- queue.completeOperation('https://b.com');
238
- expect(queue.getActiveOperations()).toHaveLength(2);
239
- expect(queue.isIndexing('https://a.com')).toBe(true);
240
- expect(queue.isIndexing('https://b.com')).toBe(false);
241
- expect(queue.isIndexing('https://c.com')).toBe(true);
242
- queue.completeOperation('https://a.com');
243
- queue.completeOperation('https://c.com');
244
- });
245
- it('should handle rapid start/complete cycles', async () => {
246
- for (let i = 0; i < 10; i++) {
247
- const controller = await queue.startOperation('https://example.com');
248
- const mockPromise = Promise.resolve();
249
- queue.registerOperation('https://example.com', controller, mockPromise);
250
- queue.completeOperation('https://example.com');
251
- }
252
- expect(queue.isIndexing('https://example.com')).toBe(false);
253
- expect(queue.getActiveOperations()).toHaveLength(0);
254
- });
148
+ it('bounds cancelAll when an operation ignores cancellation', async () => {
149
+ const queue = new IndexingQueueManager(10);
150
+ const started = Promise.withResolvers();
151
+ const released = Promise.withResolvers();
152
+ let signal;
153
+ const operation = await queue.runLatest('https://example.com', async (operationSignal) => {
154
+ signal = operationSignal;
155
+ started.resolve();
156
+ await released.promise;
157
+ });
158
+ await started.promise;
159
+ await expect(queue.cancelAll()).rejects.toThrow('Timed out cancelling all indexing operations');
160
+ expect(signal.aborted).toBe(true);
161
+ const next = await queue.runLatest('https://other.com', async () => { });
162
+ await next.completion;
163
+ released.resolve();
164
+ await operation.completion;
255
165
  });
256
166
  });
257
167
  //# sourceMappingURL=queue-manager.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"queue-manager.test.js","sourceRoot":"","sources":["../../src/indexing/queue-manager.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"queue-manager.test.js","sourceRoot":"","sources":["../../src/indexing/queue-manager.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,IAAI,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,MAAM,KAAK,GAAG,IAAI,oBAAoB,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QAE/C,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;YACtE,OAAO,CAAC,OAAO,EAAE,CAAC;YAClB,MAAM,QAAQ,CAAC,OAAO,CAAC;QACzB,CAAC,CAAC,CAAC;QACH,MAAM,OAAO,CAAC,OAAO,CAAC;QAEtB,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5C,QAAQ,CAAC,OAAO,EAAE,CAAC;QACnB,MAAM,MAAM,CAAC,UAAU,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QACxF,MAAM,KAAK,GAAG,IAAI,oBAAoB,CAAC,EAAE,CAAC,CAAC;QAC3C,MAAM,YAAY,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QACnD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QACpD,IAAI,WAAyB,CAAC;QAC9B,IAAI,kBAAkB,GAAG,KAAK,CAAC;QAC/B,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,qBAAqB,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YAC1E,WAAW,GAAG,MAAM,CAAC;YACrB,YAAY,CAAC,OAAO,EAAE,CAAC;YACvB,MAAM,aAAa,CAAC,OAAO,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,MAAM,YAAY,CAAC,OAAO,CAAC;QAE3B,MAAM,MAAM,CACV,KAAK,CAAC,SAAS,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;YACjD,kBAAkB,GAAG,IAAI,CAAC;QAC5B,CAAC,CAAC,CACH,CAAC,OAAO,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;QAE1C,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,aAAa,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,KAAK,CAAC,UAAU,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+EAA+E,EAAE,KAAK,IAAI,EAAE;QAC7F,MAAM,KAAK,GAAG,IAAI,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,YAAY,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QACnD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QACpD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QACpD,MAAM,cAAc,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QACrD,MAAM,YAAY,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QACnD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QACpD,MAAM,YAAY,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QACnD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QACpD,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,IAAI,WAAyB,CAAC;QAC9B,IAAI,YAA0B,CAAC;QAE/B,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,qBAAqB,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YAC1E,WAAW,GAAG,MAAM,CAAC;YACrB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpB,YAAY,CAAC,OAAO,EAAE,CAAC;YACvB,MAAM,aAAa,CAAC,OAAO,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,MAAM,YAAY,CAAC,OAAO,CAAC;QAE3B,MAAM,WAAW,GAAG,KAAK,CAAC,SAAS,CAAC,qBAAqB,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YAC1E,YAAY,GAAG,MAAM,CAAC;YACtB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACrB,aAAa,CAAC,OAAO,EAAE,CAAC;YACxB,MAAM,cAAc,CAAC,OAAO,CAAC;QAC/B,CAAC,CAAC,CAAC;QACH,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC,qBAAqB,EAAE,KAAK,IAAI,EAAE;YACnE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpB,YAAY,CAAC,OAAO,EAAE,CAAC;YACvB,MAAM,aAAa,CAAC,OAAO,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;YAClE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpB,YAAY,CAAC,OAAO,EAAE,CAAC;YACvB,MAAM,aAAa,CAAC,OAAO,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,MAAM,YAAY,CAAC,OAAO,CAAC;QAE3B,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,aAAa,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC;QACjC,MAAM,aAAa,CAAC,OAAO,CAAC;QAC5B,MAAM,KAAK,CAAC,UAAU,CAAC;QACvB,MAAM,QAAQ,EAAE,CAAC;QACjB,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;QAEpD,cAAc,CAAC,OAAO,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC;QAC/B,MAAM,YAAY,CAAC,OAAO,CAAC;QAC3B,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;QAE7D,aAAa,CAAC,OAAO,EAAE,CAAC;QACxB,aAAa,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,KAAK,GAAG,IAAI,oBAAoB,EAAE,CAAC;QACzC,MAAM,YAAY,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QACnD,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,qBAAqB,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YAC1E,YAAY,CAAC,OAAO,EAAE,CAAC;YACvB,MAAM,IAAI,OAAO,CAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE;gBAC3C,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACzF,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,MAAM,eAAe,GAAG,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACzD,MAAM,YAAY,CAAC,OAAO,CAAC;QAE3B,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,qBAAqB,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,CAAC,CAAC;QAC5E,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,eAAe,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4FAA4F,EAAE,KAAK,IAAI,EAAE;QAC1G,MAAM,KAAK,GAAG,IAAI,oBAAoB,EAAE,CAAC;QACzC,MAAM,YAAY,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QACnD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QACpD,IAAI,WAAyB,CAAC;QAC9B,IAAI,aAAa,GAAG,KAAK,CAAC;QAE1B,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,qBAAqB,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YAC1E,WAAW,GAAG,MAAM,CAAC;YACrB,YAAY,CAAC,OAAO,EAAE,CAAC;YACvB,MAAM,aAAa,CAAC,OAAO,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,MAAM,YAAY,CAAC,OAAO,CAAC;QAE3B,MAAM,WAAW,GAAG,KAAK,CAAC,SAAS,CAAC,qBAAqB,EAAE,KAAK,IAAI,EAAE;YACpE,aAAa,GAAG,IAAI,CAAC;QACvB,CAAC,CAAC,CAAC;QACH,MAAM,YAAY,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAC5E,MAAM,QAAQ,EAAE,CAAC;QAEjB,IAAI,oBAAoB,GAAG,KAAK,CAAC;QACjC,MAAM,YAAY,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7C,KAAK,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE;YAC1B,oBAAoB,GAAG,IAAI,CAAC;QAC9B,CAAC,CAAC,CAAC;QAEH,IAAI,yBAAyB,GAAG,KAAK,CAAC;QACtC,MAAM,MAAM,CACV,KAAK,CAAC,SAAS,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;YAC9C,yBAAyB,GAAG,IAAI,CAAC;QACnC,CAAC,CAAC,CACH,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACrC,MAAM,QAAQ,EAAE,CAAC;QAEjB,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,CAAC,yBAAyB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEzC,aAAa,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,UAAU,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;QAElE,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClC,MAAM,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAExC,IAAI,wBAAwB,GAAG,KAAK,CAAC;QACrC,MAAM,iBAAiB,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,qBAAqB,EAAE,KAAK,IAAI,EAAE;YAChF,wBAAwB,GAAG,IAAI,CAAC;QAClC,CAAC,CAAC,CAAC;QACH,MAAM,iBAAiB,CAAC,UAAU,CAAC;QACnC,MAAM,CAAC,wBAAwB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACvE,MAAM,KAAK,GAAG,IAAI,oBAAoB,CAAC,EAAE,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QAC/C,IAAI,MAAoB,CAAC;QACzB,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,qBAAqB,EAAE,KAAK,EAAE,eAAe,EAAE,EAAE;YACvF,MAAM,GAAG,eAAe,CAAC;YACzB,OAAO,CAAC,OAAO,EAAE,CAAC;YAClB,MAAM,QAAQ,CAAC,OAAO,CAAC;QACzB,CAAC,CAAC,CAAC;QACH,MAAM,OAAO,CAAC,OAAO,CAAC;QAEtB,MAAM,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,8CAA8C,CAAC,CAAC;QAChG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAElC,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,CAAC,CAAC;QACxE,MAAM,IAAI,CAAC,UAAU,CAAC;QAEtB,QAAQ,CAAC,OAAO,EAAE,CAAC;QACnB,MAAM,SAAS,CAAC,UAAU,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -328,6 +328,13 @@ export class DocumentStore {
328
328
  );
329
329
  `,
330
330
  },
331
+ {
332
+ version: 6,
333
+ description: 'Persist crawl path prefix',
334
+ sql: `
335
+ ALTER TABLE documents ADD COLUMN path_prefix TEXT;
336
+ `,
337
+ },
331
338
  ];
332
339
  /**
333
340
  * Run pending database migrations.
@@ -609,15 +616,16 @@ export class DocumentStore {
609
616
  if (!this.sqliteDb) {
610
617
  throw new Error('Storage not initialized');
611
618
  }
612
- await this.sqliteDb.run(`INSERT INTO documents (url, title, favicon, last_indexed, requires_auth, auth_domain, version)
613
- VALUES (?, ?, ?, ?, ?, ?, ?)
619
+ await this.sqliteDb.run(`INSERT INTO documents (url, title, favicon, last_indexed, requires_auth, auth_domain, version, path_prefix)
620
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
614
621
  ON CONFLICT(url) DO UPDATE SET
615
622
  title = excluded.title,
616
623
  favicon = excluded.favicon,
617
624
  last_indexed = excluded.last_indexed,
618
625
  requires_auth = excluded.requires_auth,
619
626
  auth_domain = excluded.auth_domain,
620
- version = excluded.version`, [
627
+ version = excluded.version,
628
+ path_prefix = excluded.path_prefix`, [
621
629
  metadata.url,
622
630
  metadata.title,
623
631
  metadata.favicon ?? null,
@@ -625,6 +633,7 @@ export class DocumentStore {
625
633
  metadata.requiresAuth ? 1 : 0,
626
634
  metadata.authDomain ?? null,
627
635
  metadata.version ?? null,
636
+ metadata.pathPrefix ?? null,
628
637
  ]);
629
638
  }
630
639
  async recoverDocumentReplacements() {
@@ -1141,7 +1150,7 @@ export class DocumentStore {
1141
1150
  }
1142
1151
  logger.debug(`[DocumentStore] Listing documents`);
1143
1152
  try {
1144
- const rows = await this.sqliteReadDb.all(`SELECT d.url, d.title, d.favicon, d.last_indexed, d.requires_auth, d.auth_domain, d.version,
1153
+ const rows = await this.sqliteReadDb.all(`SELECT d.url, d.title, d.favicon, d.last_indexed, d.requires_auth, d.auth_domain, d.version, d.path_prefix,
1145
1154
  COALESCE((SELECT json_group_array(dt.tag) FROM document_tags dt WHERE dt.url = d.url), '[]') AS tags_json
1146
1155
  FROM documents d
1147
1156
  ORDER BY d.last_indexed DESC`);
@@ -1155,6 +1164,7 @@ export class DocumentStore {
1155
1164
  authDomain: row.auth_domain ?? undefined,
1156
1165
  tags: this.parseDocumentTags(row.tags_json),
1157
1166
  version: row.version ?? undefined,
1167
+ pathPrefix: row.path_prefix ?? undefined,
1158
1168
  }));
1159
1169
  }
1160
1170
  catch (error) {
@@ -1230,7 +1240,7 @@ export class DocumentStore {
1230
1240
  try {
1231
1241
  // Log the query being executed
1232
1242
  logger.debug(`[DocumentStore] Executing SQLite query for URL: ${url}`);
1233
- const row = await this.sqliteReadDb.get(`SELECT d.url, d.title, d.favicon, d.last_indexed, d.requires_auth, d.auth_domain, d.version,
1243
+ const row = await this.sqliteReadDb.get(`SELECT d.url, d.title, d.favicon, d.last_indexed, d.requires_auth, d.auth_domain, d.version, d.path_prefix,
1234
1244
  COALESCE((SELECT json_group_array(dt.tag) FROM document_tags dt WHERE dt.url = d.url), '[]') AS tags_json
1235
1245
  FROM documents d
1236
1246
  WHERE d.url = ?`, [url]);
@@ -1253,6 +1263,7 @@ export class DocumentStore {
1253
1263
  authDomain: row.auth_domain ?? undefined,
1254
1264
  tags: this.parseDocumentTags(row.tags_json),
1255
1265
  version: row.version ?? undefined,
1266
+ pathPrefix: row.path_prefix ?? undefined,
1256
1267
  };
1257
1268
  }
1258
1269
  catch (error) {
@@ -1554,7 +1565,7 @@ export class DocumentStore {
1554
1565
  }
1555
1566
  // Get documents in the collection
1556
1567
  const docRows = await this.sqliteReadDb.all(`
1557
- SELECT d.url, d.title, d.favicon, d.last_indexed, d.requires_auth, d.auth_domain, d.version,
1568
+ SELECT d.url, d.title, d.favicon, d.last_indexed, d.requires_auth, d.auth_domain, d.version, d.path_prefix,
1558
1569
  COALESCE((SELECT json_group_array(dt.tag) FROM document_tags dt WHERE dt.url = d.url), '[]') AS tags_json
1559
1570
  FROM documents d
1560
1571
  INNER JOIN collection_documents cd ON d.url = cd.url
@@ -1570,6 +1581,7 @@ export class DocumentStore {
1570
1581
  authDomain: doc.auth_domain ?? undefined,
1571
1582
  tags: this.parseDocumentTags(doc.tags_json),
1572
1583
  version: doc.version ?? undefined,
1584
+ pathPrefix: doc.path_prefix ?? undefined,
1573
1585
  }));
1574
1586
  logger.debug(`[DocumentStore] Collection "${normalizedName}" has ${documents.length} documents`);
1575
1587
  return {