@robthepcguy/rag-vault 1.5.1 → 1.5.3
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/README.md +12 -4
- package/dist/vectordb/index.d.ts +24 -0
- package/dist/vectordb/index.js +110 -2
- package/dist/web/http-server.js +11 -3
- package/dist/web/index.js +11 -1
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -430,6 +430,12 @@ pnpm dev
|
|
|
430
430
|
|
|
431
431
|
# Run web server locally
|
|
432
432
|
pnpm web:dev
|
|
433
|
+
|
|
434
|
+
# Release to npm (local, guarded)
|
|
435
|
+
pnpm release:patch
|
|
436
|
+
pnpm release:minor
|
|
437
|
+
pnpm release:major
|
|
438
|
+
pnpm release:dry
|
|
433
439
|
```
|
|
434
440
|
|
|
435
441
|
|
|
@@ -440,11 +446,13 @@ pnpm web:dev
|
|
|
440
446
|
|
|
441
447
|
Use `RUN_EMBEDDING_INTEGRATION=1` to explicitly opt into network/model-dependent suites.
|
|
442
448
|
|
|
443
|
-
###
|
|
449
|
+
### Release Strategy
|
|
444
450
|
|
|
445
|
-
-
|
|
446
|
-
-
|
|
447
|
-
-
|
|
451
|
+
- Releases are local and scripted via `scripts/release-npm.sh`.
|
|
452
|
+
- Supported bumps: `patch`, `minor`, `major`.
|
|
453
|
+
- The script runs dependency installs, `pnpm check:all`, and `pnpm ui:build` before touching version files.
|
|
454
|
+
- `package.json` and `server.json` versions are updated only after checks pass, and auto-restored if any later step fails.
|
|
455
|
+
- `pnpm release:dry` performs the full gate plus npm dry-run publish and always restores version files.
|
|
448
456
|
|
|
449
457
|
### Project Structure
|
|
450
458
|
|
package/dist/vectordb/index.d.ts
CHANGED
|
@@ -149,6 +149,30 @@ export declare class VectorStore {
|
|
|
149
149
|
* Record FTS success (resets circuit breaker)
|
|
150
150
|
*/
|
|
151
151
|
private recordFtsSuccess;
|
|
152
|
+
/**
|
|
153
|
+
* Extract unsupported custom metadata field from LanceDB schema mismatch errors.
|
|
154
|
+
*
|
|
155
|
+
* Returns:
|
|
156
|
+
* - specific key (e.g., "character") for metadata.custom.character mismatch
|
|
157
|
+
* - CUSTOM_METADATA_ALL_FIELDS when metadata.custom itself is unsupported
|
|
158
|
+
* - null when error is unrelated
|
|
159
|
+
*/
|
|
160
|
+
private extractUnsupportedCustomMetadataField;
|
|
161
|
+
/**
|
|
162
|
+
* Remove unsupported custom metadata field from chunks for schema compatibility.
|
|
163
|
+
*
|
|
164
|
+
* @param chunks - Source chunks
|
|
165
|
+
* @param field - Unsupported field name, or CUSTOM_METADATA_ALL_FIELDS to drop all custom metadata
|
|
166
|
+
* @returns Sanitized chunks and whether any changes were applied
|
|
167
|
+
*/
|
|
168
|
+
private stripUnsupportedCustomMetadata;
|
|
169
|
+
/**
|
|
170
|
+
* Add chunks to existing table with automatic fallback for custom metadata schema mismatches.
|
|
171
|
+
*
|
|
172
|
+
* LanceDB infers struct fields from early inserts, so later custom metadata keys may fail.
|
|
173
|
+
* This method retries by stripping only unsupported custom fields when needed.
|
|
174
|
+
*/
|
|
175
|
+
private addChunksWithSchemaFallback;
|
|
152
176
|
/**
|
|
153
177
|
* Initialize LanceDB and create table
|
|
154
178
|
*/
|
package/dist/vectordb/index.js
CHANGED
|
@@ -74,6 +74,13 @@ const DELETE_IGNORABLE_PATTERNS = [
|
|
|
74
74
|
'no rows',
|
|
75
75
|
'empty result',
|
|
76
76
|
];
|
|
77
|
+
/**
|
|
78
|
+
* LanceDB schema mismatch pattern for custom metadata fields.
|
|
79
|
+
* Example: "Found field not in schema: metadata.custom.character at row 0"
|
|
80
|
+
*/
|
|
81
|
+
const CUSTOM_METADATA_SCHEMA_MISMATCH_REGEX = /Found field not in schema:\s*metadata\.custom(?:\.([A-Za-z0-9_-]+))?/i;
|
|
82
|
+
/** Sentinel for "metadata.custom itself is not in schema" */
|
|
83
|
+
const CUSTOM_METADATA_ALL_FIELDS = '__all__';
|
|
77
84
|
/**
|
|
78
85
|
* Regex for validating file paths before use in queries.
|
|
79
86
|
* Allows alphanumeric characters, slashes, dots, underscores, hyphens, colons (Windows), and spaces.
|
|
@@ -311,6 +318,108 @@ class VectorStore {
|
|
|
311
318
|
this.ftsLastFailure = null;
|
|
312
319
|
}
|
|
313
320
|
}
|
|
321
|
+
/**
|
|
322
|
+
* Extract unsupported custom metadata field from LanceDB schema mismatch errors.
|
|
323
|
+
*
|
|
324
|
+
* Returns:
|
|
325
|
+
* - specific key (e.g., "character") for metadata.custom.character mismatch
|
|
326
|
+
* - CUSTOM_METADATA_ALL_FIELDS when metadata.custom itself is unsupported
|
|
327
|
+
* - null when error is unrelated
|
|
328
|
+
*/
|
|
329
|
+
extractUnsupportedCustomMetadataField(error) {
|
|
330
|
+
const message = error instanceof Error ? error.message : typeof error === 'string' ? error : String(error);
|
|
331
|
+
const match = CUSTOM_METADATA_SCHEMA_MISMATCH_REGEX.exec(message);
|
|
332
|
+
if (!match)
|
|
333
|
+
return null;
|
|
334
|
+
return match[1] || CUSTOM_METADATA_ALL_FIELDS;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Remove unsupported custom metadata field from chunks for schema compatibility.
|
|
338
|
+
*
|
|
339
|
+
* @param chunks - Source chunks
|
|
340
|
+
* @param field - Unsupported field name, or CUSTOM_METADATA_ALL_FIELDS to drop all custom metadata
|
|
341
|
+
* @returns Sanitized chunks and whether any changes were applied
|
|
342
|
+
*/
|
|
343
|
+
stripUnsupportedCustomMetadata(chunks, field) {
|
|
344
|
+
let changed = false;
|
|
345
|
+
const sanitizedChunks = chunks.map((chunk) => {
|
|
346
|
+
const custom = chunk.metadata.custom;
|
|
347
|
+
if (!custom)
|
|
348
|
+
return chunk;
|
|
349
|
+
// Entire custom object is unsupported by table schema
|
|
350
|
+
if (field === CUSTOM_METADATA_ALL_FIELDS) {
|
|
351
|
+
changed = true;
|
|
352
|
+
const metadataWithoutCustom = { ...chunk.metadata };
|
|
353
|
+
delete metadataWithoutCustom.custom;
|
|
354
|
+
return {
|
|
355
|
+
...chunk,
|
|
356
|
+
metadata: metadataWithoutCustom,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
// Specific custom key is unsupported by table schema
|
|
360
|
+
if (!(field in custom)) {
|
|
361
|
+
return chunk;
|
|
362
|
+
}
|
|
363
|
+
changed = true;
|
|
364
|
+
const filteredCustom = Object.fromEntries(Object.entries(custom).filter(([key]) => key !== field));
|
|
365
|
+
if (Object.keys(filteredCustom).length === 0) {
|
|
366
|
+
const metadataWithoutCustom = { ...chunk.metadata };
|
|
367
|
+
delete metadataWithoutCustom.custom;
|
|
368
|
+
return {
|
|
369
|
+
...chunk,
|
|
370
|
+
metadata: metadataWithoutCustom,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
return {
|
|
374
|
+
...chunk,
|
|
375
|
+
metadata: {
|
|
376
|
+
...chunk.metadata,
|
|
377
|
+
custom: filteredCustom,
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
});
|
|
381
|
+
return { chunks: sanitizedChunks, changed };
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Add chunks to existing table with automatic fallback for custom metadata schema mismatches.
|
|
385
|
+
*
|
|
386
|
+
* LanceDB infers struct fields from early inserts, so later custom metadata keys may fail.
|
|
387
|
+
* This method retries by stripping only unsupported custom fields when needed.
|
|
388
|
+
*/
|
|
389
|
+
async addChunksWithSchemaFallback(chunks) {
|
|
390
|
+
if (!this.table) {
|
|
391
|
+
throw new index_js_1.DatabaseError('VectorStore is not initialized. Call initialize() first.');
|
|
392
|
+
}
|
|
393
|
+
let chunksToInsert = chunks;
|
|
394
|
+
const removedFields = new Set();
|
|
395
|
+
// Multiple unknown keys can surface one-by-one; allow bounded retries.
|
|
396
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
397
|
+
try {
|
|
398
|
+
const records = chunksToInsert.map(toDbRecord);
|
|
399
|
+
await this.table.add(records);
|
|
400
|
+
if (removedFields.size > 0) {
|
|
401
|
+
const removed = Array.from(removedFields)
|
|
402
|
+
.map((field) => (field === CUSTOM_METADATA_ALL_FIELDS ? 'metadata.custom' : field))
|
|
403
|
+
.join(', ');
|
|
404
|
+
console.warn(`VectorStore: Removed unsupported custom metadata field(s) for schema compatibility: ${removed}`);
|
|
405
|
+
}
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
catch (error) {
|
|
409
|
+
const unsupportedField = this.extractUnsupportedCustomMetadataField(error);
|
|
410
|
+
if (!unsupportedField) {
|
|
411
|
+
throw error;
|
|
412
|
+
}
|
|
413
|
+
const { chunks: strippedChunks, changed } = this.stripUnsupportedCustomMetadata(chunksToInsert, unsupportedField);
|
|
414
|
+
if (!changed) {
|
|
415
|
+
throw error;
|
|
416
|
+
}
|
|
417
|
+
removedFields.add(unsupportedField);
|
|
418
|
+
chunksToInsert = strippedChunks;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
throw new index_js_1.DatabaseError('Failed to insert chunks after schema fallback retries');
|
|
422
|
+
}
|
|
314
423
|
/**
|
|
315
424
|
* Initialize LanceDB and create table
|
|
316
425
|
*/
|
|
@@ -450,8 +559,7 @@ class VectorStore {
|
|
|
450
559
|
}
|
|
451
560
|
}
|
|
452
561
|
// Add data to existing table
|
|
453
|
-
|
|
454
|
-
await this.table.add(records);
|
|
562
|
+
await this.addChunksWithSchemaFallback(chunksWithFingerprints);
|
|
455
563
|
// Rebuild FTS index after adding new data
|
|
456
564
|
await this.rebuildFtsIndex();
|
|
457
565
|
console.error(`VectorStore: Inserted ${chunks.length} chunks`);
|
package/dist/web/http-server.js
CHANGED
|
@@ -327,11 +327,19 @@ async function createHttpServerInternal(serverAccessor, config, configRouter) {
|
|
|
327
327
|
* Start HTTP server
|
|
328
328
|
*/
|
|
329
329
|
function startServer(app, port) {
|
|
330
|
-
return new Promise((resolve) => {
|
|
331
|
-
app.listen(port
|
|
330
|
+
return new Promise((resolve, reject) => {
|
|
331
|
+
const server = app.listen(port);
|
|
332
|
+
const onError = (error) => {
|
|
333
|
+
server.off('listening', onListening);
|
|
334
|
+
reject(error);
|
|
335
|
+
};
|
|
336
|
+
const onListening = () => {
|
|
337
|
+
server.off('error', onError);
|
|
332
338
|
console.log(`Web server running at http://localhost:${port}`);
|
|
333
339
|
resolve();
|
|
334
|
-
}
|
|
340
|
+
};
|
|
341
|
+
server.once('error', onError);
|
|
342
|
+
server.once('listening', onListening);
|
|
335
343
|
});
|
|
336
344
|
}
|
|
337
345
|
//# sourceMappingURL=http-server.js.map
|
package/dist/web/index.js
CHANGED
|
@@ -52,17 +52,23 @@ const index_js_1 = require("./middleware/index.js");
|
|
|
52
52
|
console.error('Cleaning up rate limiter...');
|
|
53
53
|
(0, index_js_1.stopRateLimiterCleanup)();
|
|
54
54
|
});
|
|
55
|
+
function isErrnoException(error) {
|
|
56
|
+
return (typeof error === 'object' &&
|
|
57
|
+
error !== null &&
|
|
58
|
+
'code' in error &&
|
|
59
|
+
typeof error.code === 'string');
|
|
60
|
+
}
|
|
55
61
|
/**
|
|
56
62
|
* Entry point - Start RAG Web Server
|
|
57
63
|
*/
|
|
58
64
|
async function main() {
|
|
65
|
+
const port = Number.parseInt(process.env['WEB_PORT'] || '3000', 10);
|
|
59
66
|
try {
|
|
60
67
|
// Dynamic imports to avoid loading heavy modules at CLI parse time
|
|
61
68
|
const { RAGServer } = await Promise.resolve().then(() => __importStar(require('../server/index.js')));
|
|
62
69
|
const { createHttpServerWithManager, startServer } = await Promise.resolve().then(() => __importStar(require('./http-server.js')));
|
|
63
70
|
const { DatabaseManager } = await Promise.resolve().then(() => __importStar(require('./database-manager.js')));
|
|
64
71
|
// Configuration from environment
|
|
65
|
-
const port = Number.parseInt(process.env['WEB_PORT'] || '3000', 10);
|
|
66
72
|
const uploadDir = process.env['UPLOAD_DIR'] || './uploads/';
|
|
67
73
|
// Determine static files directory
|
|
68
74
|
// Check multiple locations: cwd for dev, package dir for npx/global install
|
|
@@ -113,6 +119,10 @@ async function main() {
|
|
|
113
119
|
}
|
|
114
120
|
}
|
|
115
121
|
catch (error) {
|
|
122
|
+
if (isErrnoException(error) && error.code === 'EADDRINUSE') {
|
|
123
|
+
console.error(`Port ${port} is already in use. Close the other RAG Vault web server or run with a different port (example: WEB_PORT=3001 npx @robthepcguy/rag-vault web).`);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
116
126
|
console.error('Failed to start RAG Web Server:', error);
|
|
117
127
|
process.exit(1);
|
|
118
128
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robthepcguy/rag-vault",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.3",
|
|
4
4
|
"description": "Local RAG MCP Server - Easy-to-setup document search with minimal configuration",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -116,6 +116,11 @@
|
|
|
116
116
|
"web": "tsx src/web/index.ts",
|
|
117
117
|
"test:unit": "vitest run --project backend-unit --project web-ui",
|
|
118
118
|
"test:integration": "RUN_EMBEDDING_INTEGRATION=1 vitest run --project backend-integration",
|
|
119
|
-
"hooks:install": "git config core.hooksPath .githooks"
|
|
119
|
+
"hooks:install": "git config core.hooksPath .githooks",
|
|
120
|
+
"release:patch": "bash ./scripts/release-npm.sh --bump patch",
|
|
121
|
+
"release:minor": "bash ./scripts/release-npm.sh --bump minor",
|
|
122
|
+
"release:major": "bash ./scripts/release-npm.sh --bump major",
|
|
123
|
+
"release:dry": "bash ./scripts/release-npm.sh --bump patch --dry-run",
|
|
124
|
+
"release:publish": "bash ./scripts/release-npm.sh --bump patch"
|
|
120
125
|
}
|
|
121
126
|
}
|