@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.
Files changed (37) hide show
  1. package/README.md +151 -0
  2. package/dist/api/apiRouter.d.ts +20 -0
  3. package/dist/api/apiRouter.js +122 -7
  4. package/dist/api/router/mountCrudRoutes.js +69 -18
  5. package/dist/api/router/setupAuthRoutes.js +475 -38
  6. package/dist/api/router/setupChatWidgetRoutes.d.ts +3 -0
  7. package/dist/api/router/setupChatWidgetRoutes.js +207 -0
  8. package/dist/api/router/setupFileRoutes.js +221 -16
  9. package/dist/api/router/utils.d.ts +2 -1
  10. package/dist/api/router/utils.js +8 -6
  11. package/dist/cli.d.ts +1 -0
  12. package/dist/cli.js +145 -64
  13. package/dist/database/DatabaseAdapter.d.ts +1 -0
  14. package/dist/database/NMAdapter.d.ts +6 -0
  15. package/dist/database/NMAdapter.js +437 -86
  16. package/dist/database/QueryEngine.js +7 -4
  17. package/dist/files/FileStorageAdapter.d.ts +1 -0
  18. package/dist/files/LocalFileStorageAdapter.d.ts +1 -0
  19. package/dist/files/LocalFileStorageAdapter.js +25 -3
  20. package/dist/files/S3FileStorageAdapter.d.ts +3 -1
  21. package/dist/files/S3FileStorageAdapter.js +72 -11
  22. package/dist/files/filename.js +6 -4
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.js +3 -1
  25. package/dist/models/BaseModel.d.ts +4 -0
  26. package/dist/policy/authorize.d.ts +1 -1
  27. package/dist/policy/authorize.js +64 -13
  28. package/dist/schemas/Users.json +20 -10
  29. package/dist/services/IndexingService.d.ts +24 -0
  30. package/dist/services/IndexingService.js +555 -0
  31. package/dist/services/LocalAIService.d.ts +34 -0
  32. package/dist/services/LocalAIService.js +471 -0
  33. package/dist/services/OpenAIService.d.ts +16 -0
  34. package/dist/services/OpenAIService.js +586 -0
  35. package/dist/utils/SchemaLoader.d.ts +1 -1
  36. package/dist/utils/SchemaLoader.js +40 -4
  37. 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
- dotenv_1.default.config();
11
- async function repairMongo() {
12
- const mongoUri = process.env.MONGODB_URI;
13
- const dbName = process.env.DB_NAME || 'test';
14
- const schemasDir = process.env.SCHEMAS_DIR || path_1.default.join(process.cwd(), 'schemas');
15
- if (!mongoUri) {
16
- console.error('MONGODB_URI is required in .env');
17
- process.exit(1);
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
- console.log('--- NextMin MongoDB Repair Tool ---');
20
- console.log(`Connecting to: ${mongoUri}`);
21
- const loader = SchemaLoader_1.SchemaLoader.getInstance();
22
- const schemaDefs = loader.getSchemas();
23
- const adapter = new NMAdapter_1.NMAdapter({
24
- type: 'mongodb',
25
- url: mongoUri,
26
- database: dbName,
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
- await adapter.connect();
33
- await adapter.registerSchemas(schemaDefs);
34
- for (const [name, schema] of Object.entries(schemaDefs)) {
35
- if (schema.extends) {
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.error('Repair failed:', err);
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
- await adapter.disconnect();
146
+ if (hasError) {
147
+ process.exit(1);
148
+ }
75
149
  }
76
150
  }
77
- const command = process.argv[2];
78
- if (command === 'repair-mongo') {
79
- repairMongo();
151
+ if (command === 'reindex') {
152
+ runReindex(cliArgs);
80
153
  }
81
154
  else {
82
- console.log('Usage: ts-node src/cli.ts repair-mongo');
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[]>;