@airoom/nextmin-node 2.0.2 → 2.0.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 +151 -0
- package/dist/api/apiRouter.d.ts +20 -0
- package/dist/api/apiRouter.js +122 -7
- package/dist/api/router/mountCrudRoutes.js +69 -18
- package/dist/api/router/setupAuthRoutes.js +475 -38
- package/dist/api/router/setupChatWidgetRoutes.d.ts +3 -0
- package/dist/api/router/setupChatWidgetRoutes.js +207 -0
- package/dist/api/router/setupFileRoutes.js +221 -16
- package/dist/api/router/utils.d.ts +2 -1
- package/dist/api/router/utils.js +8 -6
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +145 -64
- package/dist/database/DatabaseAdapter.d.ts +1 -0
- package/dist/database/NMAdapter.d.ts +6 -0
- package/dist/database/NMAdapter.js +437 -86
- package/dist/database/QueryEngine.js +7 -4
- package/dist/files/FileStorageAdapter.d.ts +1 -0
- package/dist/files/LocalFileStorageAdapter.d.ts +1 -0
- package/dist/files/LocalFileStorageAdapter.js +25 -3
- package/dist/files/S3FileStorageAdapter.d.ts +3 -1
- package/dist/files/S3FileStorageAdapter.js +72 -11
- package/dist/files/filename.js +6 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/models/BaseModel.d.ts +4 -0
- package/dist/policy/authorize.d.ts +1 -1
- package/dist/policy/authorize.js +64 -13
- package/dist/schemas/Users.json +20 -10
- package/dist/services/IndexingService.d.ts +24 -0
- package/dist/services/IndexingService.js +555 -0
- package/dist/services/LocalAIService.d.ts +34 -0
- package/dist/services/LocalAIService.js +471 -0
- package/dist/services/OpenAIService.d.ts +16 -0
- package/dist/services/OpenAIService.js +586 -0
- package/dist/utils/SchemaLoader.d.ts +1 -1
- package/dist/utils/SchemaLoader.js +40 -4
- package/package.json +12 -4
package/dist/cli.js
CHANGED
|
@@ -1,83 +1,164 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
2
36
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
37
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
38
|
};
|
|
5
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const NMAdapter_1 = require("./database/NMAdapter");
|
|
7
|
-
const SchemaLoader_1 = require("./utils/SchemaLoader");
|
|
8
40
|
const path_1 = __importDefault(require("path"));
|
|
41
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
42
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
43
|
+
// Simple helper to parse CLI arguments of format --key value or --key
|
|
44
|
+
function parseArgs(args) {
|
|
45
|
+
const parsed = {};
|
|
46
|
+
for (let i = 0; i < args.length; i++) {
|
|
47
|
+
const arg = args[i];
|
|
48
|
+
if (arg.startsWith('--')) {
|
|
49
|
+
const key = arg.slice(2);
|
|
50
|
+
const nextVal = args[i + 1];
|
|
51
|
+
if (nextVal && !nextVal.startsWith('--')) {
|
|
52
|
+
parsed[key] = nextVal;
|
|
53
|
+
i++;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
parsed[key] = 'true';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return parsed;
|
|
61
|
+
}
|
|
62
|
+
function findAndLoadEnv(customEnvPath) {
|
|
63
|
+
if (customEnvPath) {
|
|
64
|
+
const resolved = path_1.default.resolve(process.cwd(), customEnvPath);
|
|
65
|
+
if (fs_1.default.existsSync(resolved)) {
|
|
66
|
+
dotenv_1.default.config({ path: resolved });
|
|
67
|
+
console.log(`Loaded custom env file: ${resolved}`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
console.warn(`Custom env file not found: ${resolved}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
let dir = process.cwd();
|
|
75
|
+
let envLoaded = false;
|
|
76
|
+
let envLocalLoaded = false;
|
|
77
|
+
// Traverse up to 5 parent directories to look for .env or .env.local
|
|
78
|
+
for (let i = 0; i < 5; i++) {
|
|
79
|
+
const envLocalPath = path_1.default.join(dir, '.env.local');
|
|
80
|
+
const envPath = path_1.default.join(dir, '.env');
|
|
81
|
+
if (!envLocalLoaded && fs_1.default.existsSync(envLocalPath)) {
|
|
82
|
+
dotenv_1.default.config({ path: envLocalPath });
|
|
83
|
+
console.log(`Loaded environment from: ${envLocalPath}`);
|
|
84
|
+
envLocalLoaded = true;
|
|
85
|
+
}
|
|
86
|
+
if (!envLoaded && fs_1.default.existsSync(envPath)) {
|
|
87
|
+
dotenv_1.default.config({ path: envPath });
|
|
88
|
+
console.log(`Loaded environment from: ${envPath}`);
|
|
89
|
+
envLoaded = true;
|
|
90
|
+
}
|
|
91
|
+
if (envLoaded && envLocalLoaded)
|
|
92
|
+
break;
|
|
93
|
+
const parent = path_1.default.dirname(dir);
|
|
94
|
+
if (parent === dir)
|
|
95
|
+
break;
|
|
96
|
+
dir = parent;
|
|
18
97
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
useNewUrlParser: true,
|
|
28
|
-
useUnifiedTopology: true,
|
|
29
|
-
schemas: schemaDefs
|
|
30
|
-
});
|
|
98
|
+
}
|
|
99
|
+
const args = process.argv.slice(2);
|
|
100
|
+
const command = args[0];
|
|
101
|
+
const cliArgs = parseArgs(args.slice(1));
|
|
102
|
+
// Load env before using any of the settings
|
|
103
|
+
findAndLoadEnv(cliArgs['env']);
|
|
104
|
+
async function runReindex(cliArgs) {
|
|
105
|
+
let diskConfig = {};
|
|
31
106
|
try {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
console.log(`Checking ${name} (extends ${schema.extends})...`);
|
|
37
|
-
const items = await adapter.read(name, {});
|
|
38
|
-
const broken = items.filter(it => !it.baseId);
|
|
39
|
-
if (broken.length > 0) {
|
|
40
|
-
console.log(`Found ${broken.length} items missing baseId in ${name}. Attempting repair...`);
|
|
41
|
-
for (const item of broken) {
|
|
42
|
-
const searchVal = item.slug || item.username || item.name;
|
|
43
|
-
if (!searchVal)
|
|
44
|
-
continue;
|
|
45
|
-
// Try to find matching base record
|
|
46
|
-
const baseMatches = await adapter.read(schema.extends, {
|
|
47
|
-
$or: [
|
|
48
|
-
{ slug: searchVal },
|
|
49
|
-
{ username: searchVal },
|
|
50
|
-
{ name: searchVal }
|
|
51
|
-
]
|
|
52
|
-
});
|
|
53
|
-
if (baseMatches.length > 0) {
|
|
54
|
-
const baseId = baseMatches[0].id;
|
|
55
|
-
await adapter.update(name, item.id, { baseId });
|
|
56
|
-
console.log(` ✅ Repaired ${name} item '${searchVal}' -> baseId: ${baseId}`);
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
console.warn(` ❌ Could not find matching ${schema.extends} for ${name} item '${searchVal}'`);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
console.log(` No broken links found in ${name}.`);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
107
|
+
const configPath = path_1.default.join(process.cwd(), '.nextmin', 'config.json');
|
|
108
|
+
if (fs_1.default.existsSync(configPath)) {
|
|
109
|
+
diskConfig = JSON.parse(fs_1.default.readFileSync(configPath, 'utf-8'));
|
|
110
|
+
console.log(`Loaded chat widget config from: ${configPath}`);
|
|
67
111
|
}
|
|
68
|
-
console.log('Repair process completed.');
|
|
69
112
|
}
|
|
70
113
|
catch (err) {
|
|
71
|
-
console.
|
|
114
|
+
console.warn('Failed to read config from disk:', err);
|
|
115
|
+
}
|
|
116
|
+
const chatWidgetConfig = {
|
|
117
|
+
...diskConfig,
|
|
118
|
+
enabled: cliArgs['enabled'] !== 'false' && process.env.NEXTMIN_CHAT_ENABLED !== 'false' && diskConfig.enabled !== false,
|
|
119
|
+
localModelPath: cliArgs['model-path'] || process.env.NEXTMIN_CHAT_MODEL_PATH || diskConfig.localModelPath,
|
|
120
|
+
frontendBuildPath: cliArgs['build-path'] || process.env.NEXTMIN_CHAT_FRONTEND_PATH || diskConfig.frontendBuildPath || './.next',
|
|
121
|
+
siteUrl: cliArgs['site-url'] || process.env.NEXTMIN_CHAT_SITE_URL || process.env.FRONTEND_URL || diskConfig.siteUrl || `http://localhost:${process.env.PORT || 3000}`,
|
|
122
|
+
scrapePaths: (cliArgs['scrape-paths'] || process.env.NEXTMIN_CHAT_SCRAPE_PATHS)
|
|
123
|
+
? (cliArgs['scrape-paths'] || process.env.NEXTMIN_CHAT_SCRAPE_PATHS).split(',').map(s => s.trim())
|
|
124
|
+
: (diskConfig.scrapePaths || ['/']),
|
|
125
|
+
concurrency: parseInt(cliArgs['threads'] || cliArgs['concurrency'] || process.env.NEXTMIN_CHAT_CONCURRENCY || String(diskConfig.concurrency || 5), 10)
|
|
126
|
+
};
|
|
127
|
+
console.log('--- NextMin Reindex Tool (Local-Only) ---');
|
|
128
|
+
console.log(`Frontend Build Path: ${chatWidgetConfig.frontendBuildPath}`);
|
|
129
|
+
console.log(`Site Scrape URL: ${chatWidgetConfig.siteUrl}`);
|
|
130
|
+
console.log(`Scrape Paths: ${chatWidgetConfig.scrapePaths.join(', ')}`);
|
|
131
|
+
console.log(`Concurrency Threads: ${chatWidgetConfig.concurrency}`);
|
|
132
|
+
let hasError = false;
|
|
133
|
+
try {
|
|
134
|
+
const { reindex } = await Promise.resolve().then(() => __importStar(require('./services/IndexingService')));
|
|
135
|
+
await reindex({
|
|
136
|
+
chatWidget: chatWidgetConfig,
|
|
137
|
+
force: cliArgs['force'] === 'true'
|
|
138
|
+
});
|
|
139
|
+
console.log('Reindex completed successfully.');
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
console.error('Reindex failed:', err);
|
|
143
|
+
hasError = true;
|
|
72
144
|
}
|
|
73
145
|
finally {
|
|
74
|
-
|
|
146
|
+
if (hasError) {
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
75
149
|
}
|
|
76
150
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
repairMongo();
|
|
151
|
+
if (command === 'reindex') {
|
|
152
|
+
runReindex(cliArgs);
|
|
80
153
|
}
|
|
81
154
|
else {
|
|
82
|
-
console.log('Usage:
|
|
155
|
+
console.log('Usage: npx nextmin-node <command> [options]');
|
|
156
|
+
console.log('\nCommands:');
|
|
157
|
+
console.log(' reindex Index website files via scraping');
|
|
158
|
+
console.log('\nOptions:');
|
|
159
|
+
console.log(' --threads <count> Number of concurrent scraping threads (default: 5)');
|
|
160
|
+
console.log(' --site-url <url> Website URL to crawl');
|
|
161
|
+
console.log(' --build-path <path> Path to Next.js build directory (.next)');
|
|
162
|
+
console.log(' --force Force full reindexing and bypass manifest cache');
|
|
163
|
+
console.log(' --env <path> Path to a custom environment (.env) file');
|
|
83
164
|
}
|
|
@@ -19,4 +19,5 @@ export interface DatabaseAdapter {
|
|
|
19
19
|
syncIndexes?(modelName: string, desired: FieldIndexSpec): Promise<void>;
|
|
20
20
|
cleanupUnusedFields?(schemas: Record<string, Schema>): Promise<Record<string, string[]>>;
|
|
21
21
|
isExclusiveProjection(projection: Record<string, 0 | 1> | undefined, schema: Schema | undefined): boolean;
|
|
22
|
+
formatUrlForRead?(val: string): string;
|
|
22
23
|
}
|
|
@@ -11,14 +11,20 @@ export declare class NMAdapter implements DatabaseAdapter {
|
|
|
11
11
|
private entitySchemas;
|
|
12
12
|
private registeredSchemas;
|
|
13
13
|
private imageProxyOptions;
|
|
14
|
+
private queryCache;
|
|
14
15
|
constructor(options: any);
|
|
15
16
|
connect(): Promise<void>;
|
|
16
17
|
disconnect(): Promise<void>;
|
|
17
18
|
registerSchemas(schemas: Record<string, NextMinSchema>): Promise<void>;
|
|
19
|
+
private validateRefPathSchemas;
|
|
18
20
|
syncIndexes(modelName: string, spec: FieldIndexSpec): Promise<void>;
|
|
19
21
|
private buildEntitySchema;
|
|
20
22
|
private mapType;
|
|
21
23
|
private getRepository;
|
|
24
|
+
private getActiveBaseUrl;
|
|
25
|
+
private cleanUrlForStorage;
|
|
26
|
+
private cleanPayloadForStorage;
|
|
27
|
+
formatUrlForRead(val: string): string;
|
|
22
28
|
create(collection: string, data: any, schemaDefinition?: NextMinSchema): Promise<any>;
|
|
23
29
|
private coercePayloadForStorage;
|
|
24
30
|
read(collection: string, query: any, limit?: number, skip?: number, schemaDefinition?: NextMinSchema, includePrivateFields?: boolean, options?: ReadOptions): Promise<any[]>;
|