@mostajs/setup 1.0.0 → 1.1.0

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.
@@ -0,0 +1,3 @@
1
+ export declare function createDetectModulesHandler(): {
2
+ GET: () => Promise<Response>;
3
+ };
@@ -0,0 +1,10 @@
1
+ // @mosta/setup — Detect modules API route factory
2
+ // Author: Dr Hamid MADANI drmdh@msn.com
3
+ import { discoverNpmModules } from '../lib/discover-modules';
4
+ export function createDetectModulesHandler() {
5
+ async function GET() {
6
+ const result = await discoverNpmModules();
7
+ return Response.json(result);
8
+ }
9
+ return { GET };
10
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Factory for POST /api/setup/install-modules
3
+ * @param needsSetup - async function checking if app still needs setup
4
+ */
5
+ export declare function createInstallModulesHandler(needsSetup: () => Promise<boolean>): {
6
+ POST: (req: Request) => Promise<Response>;
7
+ };
@@ -0,0 +1,112 @@
1
+ // @mosta/setup — Install modules API route factory
2
+ // Author: Dr Hamid MADANI drmdh@msn.com
3
+ import { exec } from 'child_process';
4
+ import { promisify } from 'util';
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import { MODULES, resolveModuleDependencies } from '../data/module-definitions';
8
+ const execAsync = promisify(exec);
9
+ /**
10
+ * Factory for POST /api/setup/install-modules
11
+ * @param needsSetup - async function checking if app still needs setup
12
+ */
13
+ export function createInstallModulesHandler(needsSetup) {
14
+ async function POST(req) {
15
+ const setupNeeded = await needsSetup();
16
+ if (!setupNeeded) {
17
+ return Response.json({ error: { code: 'FORBIDDEN', message: 'Installation deja effectuee' } }, { status: 403 });
18
+ }
19
+ let body;
20
+ try {
21
+ body = await req.json();
22
+ }
23
+ catch {
24
+ return Response.json({ error: { code: 'VALIDATION_ERROR', message: 'JSON invalide' } }, { status: 400 });
25
+ }
26
+ if (!body.modules || !Array.isArray(body.modules) || body.modules.length === 0) {
27
+ return Response.json({ error: { code: 'VALIDATION_ERROR', message: 'modules[] requis' } }, { status: 400 });
28
+ }
29
+ // Resolve dependencies
30
+ const allModules = resolveModuleDependencies(body.modules);
31
+ const moduleMap = new Map(MODULES.map((m) => [m.key, m]));
32
+ const packagesDir = path.resolve(process.cwd(), 'packages');
33
+ const results = [];
34
+ // Build install specifiers — hybrid: local file: if dir exists, npm registry otherwise
35
+ // Skip packages already installed in node_modules/ to avoid triggering Next.js hot-reload
36
+ const nodeModulesBase = path.resolve(process.cwd(), 'node_modules', '@mostajs');
37
+ const toInstall = [];
38
+ for (const key of allModules) {
39
+ const mod = moduleMap.get(key);
40
+ const npmSubdir = (mod?.packageName || `@mostajs/${key}`).replace('@mostajs/', '');
41
+ // Already in node_modules? Skip to avoid unnecessary npm install
42
+ if (fs.existsSync(path.join(nodeModulesBase, npmSubdir))) {
43
+ results.push({ key, ok: true });
44
+ continue;
45
+ }
46
+ if (mod?.localDir) {
47
+ const localPath = path.join(packagesDir, mod.localDir);
48
+ if (fs.existsSync(localPath)) {
49
+ toInstall.push(`file:./packages/${mod.localDir}`);
50
+ continue;
51
+ }
52
+ }
53
+ // Fallback to npm registry (published or discovered package)
54
+ const packageName = mod?.packageName || `@mostajs/${key}`;
55
+ toInstall.push(packageName);
56
+ }
57
+ if (toInstall.length > 0) {
58
+ try {
59
+ const cmd = `npm install ${toInstall.join(' ')} --save`;
60
+ await execAsync(cmd, { cwd: process.cwd(), timeout: 120_000 });
61
+ // Mark all remaining modules as ok
62
+ for (const key of allModules) {
63
+ if (!results.some((r) => r.key === key)) {
64
+ results.push({ key, ok: true });
65
+ }
66
+ }
67
+ }
68
+ catch (err) {
69
+ const message = err instanceof Error ? err.message : 'npm install failed';
70
+ for (const key of allModules) {
71
+ if (!results.some((r) => r.key === key)) {
72
+ results.push({ key, ok: false, error: message });
73
+ }
74
+ }
75
+ return Response.json({ error: { code: 'INSTALL_ERROR', message }, results }, { status: 500 });
76
+ }
77
+ }
78
+ else {
79
+ // All already installed — fill results for any missing
80
+ for (const key of allModules) {
81
+ if (!results.some((r) => r.key === key)) {
82
+ results.push({ key, ok: true });
83
+ }
84
+ }
85
+ }
86
+ // Write MOSTAJS_MODULES to .env.local
87
+ try {
88
+ const envPath = path.resolve(process.cwd(), '.env.local');
89
+ let content = '';
90
+ try {
91
+ content = fs.readFileSync(envPath, 'utf-8');
92
+ }
93
+ catch { /* file doesn't exist yet */ }
94
+ const modulesValue = allModules.join(',');
95
+ const regex = /^MOSTAJS_MODULES=.*$/m;
96
+ if (regex.test(content)) {
97
+ content = content.replace(regex, `MOSTAJS_MODULES=${modulesValue}`);
98
+ }
99
+ else {
100
+ content = content.trimEnd() + `\n\n# Modules actives\nMOSTAJS_MODULES=${modulesValue}\n`;
101
+ }
102
+ fs.writeFileSync(envPath, content, 'utf-8');
103
+ }
104
+ catch {
105
+ // Non-fatal: env write can fail at this stage if .env.local not yet created
106
+ }
107
+ return Response.json({
108
+ data: { ok: true, modules: allModules, results },
109
+ });
110
+ }
111
+ return { POST };
112
+ }
@@ -1,17 +1,9 @@
1
- import { NextResponse } from 'next/server';
2
- import type { MostaSetupConfig } from '../types';
1
+ import type { MostaSetupConfig } from '../types/index';
3
2
  type NeedsSetupFn = () => Promise<boolean>;
4
3
  /**
5
4
  * Creates a POST handler for running the installation.
6
5
  */
7
6
  export declare function createInstallHandler(needsSetup: NeedsSetupFn, setupConfig: MostaSetupConfig): {
8
- POST: (req: Request) => Promise<NextResponse<{
9
- error: string;
10
- }> | NextResponse<{
11
- ok: boolean;
12
- error?: string;
13
- needsRestart: boolean;
14
- seeded?: string[];
15
- }>>;
7
+ POST: (req: Request) => Promise<Response>;
16
8
  };
17
9
  export {};
@@ -1,23 +1,19 @@
1
- "use strict";
2
1
  // @mosta/setup — API Route template for install
3
2
  // Author: Dr Hamid MADANI drmdh@msn.com
4
3
  //
5
4
  // Copy to: src/app/api/setup/install/route.ts
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.createInstallHandler = createInstallHandler;
8
- const server_1 = require("next/server");
9
- const setup_1 = require("../lib/setup");
5
+ import { runInstall } from '../lib/setup';
10
6
  /**
11
7
  * Creates a POST handler for running the installation.
12
8
  */
13
- function createInstallHandler(needsSetup, setupConfig) {
9
+ export function createInstallHandler(needsSetup, setupConfig) {
14
10
  async function POST(req) {
15
11
  if (!(await needsSetup())) {
16
- return server_1.NextResponse.json({ error: 'Already installed' }, { status: 400 });
12
+ return Response.json({ error: 'Already installed' }, { status: 400 });
17
13
  }
18
14
  const body = await req.json();
19
- const result = await (0, setup_1.runInstall)(body, setupConfig);
20
- return server_1.NextResponse.json(result);
15
+ const result = await runInstall(body, setupConfig);
16
+ return Response.json(result);
21
17
  }
22
18
  return { POST };
23
19
  }
@@ -1,11 +1,8 @@
1
- import { NextResponse } from 'next/server';
2
1
  type NeedsSetupFn = () => Promise<boolean>;
3
2
  /**
4
3
  * Creates a GET handler for checking setup status.
5
4
  */
6
5
  export declare function createStatusHandler(needsSetup: NeedsSetupFn): {
7
- GET: () => Promise<NextResponse<{
8
- needsSetup: boolean;
9
- }>>;
6
+ GET: () => Promise<Response>;
10
7
  };
11
8
  export {};
@@ -1,18 +1,14 @@
1
- "use strict";
2
1
  // @mosta/setup — API Route template for status check
3
2
  // Author: Dr Hamid MADANI drmdh@msn.com
4
3
  //
5
4
  // Copy to: src/app/api/setup/status/route.ts
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.createStatusHandler = createStatusHandler;
8
- const server_1 = require("next/server");
9
5
  /**
10
6
  * Creates a GET handler for checking setup status.
11
7
  */
12
- function createStatusHandler(needsSetup) {
8
+ export function createStatusHandler(needsSetup) {
13
9
  async function GET() {
14
10
  const needed = await needsSetup();
15
- return server_1.NextResponse.json({ needsSetup: needed });
11
+ return Response.json({ needsSetup: needed });
16
12
  }
17
13
  return { GET };
18
14
  }
@@ -1,14 +1,8 @@
1
- import { NextResponse } from 'next/server';
2
1
  type NeedsSetupFn = () => Promise<boolean>;
3
2
  /**
4
3
  * Creates a POST handler for testing DB connections.
5
4
  */
6
5
  export declare function createTestDbHandler(needsSetup: NeedsSetupFn): {
7
- POST: (req: Request) => Promise<NextResponse<{
8
- error: string;
9
- }> | NextResponse<{
10
- ok: boolean;
11
- error?: string;
12
- }>>;
6
+ POST: (req: Request) => Promise<Response>;
13
7
  };
14
8
  export {};
@@ -1,26 +1,22 @@
1
- "use strict";
2
1
  // @mosta/setup — API Route template for test-db
3
2
  // Author: Dr Hamid MADANI drmdh@msn.com
4
3
  //
5
4
  // Copy to: src/app/api/setup/test-db/route.ts
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.createTestDbHandler = createTestDbHandler;
8
- const server_1 = require("next/server");
9
- const db_test_1 = require("../lib/db-test");
5
+ import { testDbConnection } from '../lib/db-test';
10
6
  /**
11
7
  * Creates a POST handler for testing DB connections.
12
8
  */
13
- function createTestDbHandler(needsSetup) {
9
+ export function createTestDbHandler(needsSetup) {
14
10
  async function POST(req) {
15
11
  if (!(await needsSetup())) {
16
- return server_1.NextResponse.json({ error: 'Already installed' }, { status: 400 });
12
+ return Response.json({ error: 'Already installed' }, { status: 400 });
17
13
  }
18
14
  const body = await req.json();
19
15
  const { dialect, host, port, name, user, password } = body;
20
16
  if (!dialect || !name) {
21
- return server_1.NextResponse.json({ error: 'Missing required fields' }, { status: 400 });
17
+ return Response.json({ error: 'Missing required fields' }, { status: 400 });
22
18
  }
23
- const result = await (0, db_test_1.testDbConnection)({
19
+ const result = await testDbConnection({
24
20
  dialect: dialect,
25
21
  host: host || 'localhost',
26
22
  port: port || 27017,
@@ -28,7 +24,7 @@ function createTestDbHandler(needsSetup) {
28
24
  user: user || '',
29
25
  password: password || '',
30
26
  });
31
- return server_1.NextResponse.json(result);
27
+ return Response.json(result);
32
28
  }
33
29
  return { POST };
34
30
  }
@@ -1,3 +1,3 @@
1
- import type { DialectType, DialectInfo } from '../types';
1
+ import type { DialectType, DialectInfo } from '../types/index';
2
2
  export declare const DIALECT_INFO: Record<DialectType, DialectInfo>;
3
3
  export declare const ALL_DIALECTS: DialectType[];
@@ -1,7 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ALL_DIALECTS = exports.DIALECT_INFO = void 0;
4
- exports.DIALECT_INFO = {
1
+ export const DIALECT_INFO = {
5
2
  mongodb: {
6
3
  name: 'MongoDB',
7
4
  icon: '🍃',
@@ -133,4 +130,4 @@ exports.DIALECT_INFO = {
133
130
  category: 'legacy',
134
131
  },
135
132
  };
136
- exports.ALL_DIALECTS = Object.keys(exports.DIALECT_INFO);
133
+ export const ALL_DIALECTS = Object.keys(DIALECT_INFO);
@@ -0,0 +1,18 @@
1
+ export interface ModuleDefinition {
2
+ key: string;
3
+ packageName: string;
4
+ localDir?: string;
5
+ label: string;
6
+ description: string;
7
+ icon: string;
8
+ required?: boolean;
9
+ default?: boolean;
10
+ dependsOn?: string[];
11
+ discovered?: boolean;
12
+ }
13
+ export declare const MODULES: ModuleDefinition[];
14
+ /**
15
+ * Given a set of selected module keys, returns the full set including
16
+ * all transitive dependencies. Works with both static and discovered modules.
17
+ */
18
+ export declare function resolveModuleDependencies(selected: string[], modules?: ModuleDefinition[]): string[];
@@ -0,0 +1,105 @@
1
+ // @mosta/setup — Module definitions registry
2
+ // Author: Dr Hamid MADANI drmdh@msn.com
3
+ export const MODULES = [
4
+ {
5
+ key: 'orm',
6
+ packageName: '@mostajs/orm',
7
+ localDir: 'mosta-orm',
8
+ label: 'ORM (Data Access Layer)',
9
+ description: 'Couche d\'acces aux donnees multi-dialecte',
10
+ icon: '🗄️',
11
+ required: true,
12
+ default: true,
13
+ },
14
+ {
15
+ key: 'auth',
16
+ packageName: '@mostajs/auth',
17
+ localDir: 'mosta-auth',
18
+ label: 'Authentification',
19
+ description: 'NextAuth, sessions, gestion des mots de passe',
20
+ icon: '🔐',
21
+ required: true,
22
+ default: true,
23
+ dependsOn: ['orm'],
24
+ },
25
+ {
26
+ key: 'audit',
27
+ packageName: '@mostajs/audit',
28
+ localDir: 'mosta-audit',
29
+ label: 'Audit & Logs',
30
+ description: 'Journalisation des actions, tracabilite',
31
+ icon: '📋',
32
+ default: true,
33
+ dependsOn: ['orm'],
34
+ },
35
+ {
36
+ key: 'rbac',
37
+ packageName: '@mostajs/rbac',
38
+ localDir: 'mosta-rbac',
39
+ label: 'Roles & Permissions',
40
+ description: 'Gestion RBAC : roles, permissions, matrice',
41
+ icon: '🛡️',
42
+ default: true,
43
+ dependsOn: ['auth', 'audit'],
44
+ },
45
+ {
46
+ key: 'settings',
47
+ packageName: '@mostajs/settings',
48
+ localDir: 'mosta-settings',
49
+ label: 'Parametres',
50
+ description: 'Parametres cle-valeur, formulaire auto, provider React',
51
+ icon: '⚙️',
52
+ default: true,
53
+ dependsOn: ['orm'],
54
+ },
55
+ {
56
+ key: 'face',
57
+ packageName: '@mostajs/face',
58
+ localDir: 'mosta-face',
59
+ label: 'Reconnaissance faciale',
60
+ description: 'Detection de visage, extraction descripteurs, matching 1:N',
61
+ icon: '👤',
62
+ default: false,
63
+ },
64
+ {
65
+ key: 'setup',
66
+ packageName: '@mostajs/setup',
67
+ localDir: 'mosta-setup',
68
+ label: 'Setup Wizard',
69
+ description: 'Assistant d\'installation, test connexion, seed DB',
70
+ icon: '🧙',
71
+ required: true,
72
+ default: true,
73
+ dependsOn: ['orm'],
74
+ },
75
+ ];
76
+ /**
77
+ * Given a set of selected module keys, returns the full set including
78
+ * all transitive dependencies. Works with both static and discovered modules.
79
+ */
80
+ export function resolveModuleDependencies(selected, modules = MODULES) {
81
+ const resolved = new Set(selected);
82
+ const moduleMap = new Map(modules.map((m) => [m.key, m]));
83
+ let changed = true;
84
+ while (changed) {
85
+ changed = false;
86
+ for (const key of resolved) {
87
+ const mod = moduleMap.get(key);
88
+ if (mod?.dependsOn) {
89
+ for (const dep of mod.dependsOn) {
90
+ if (!resolved.has(dep)) {
91
+ resolved.add(dep);
92
+ changed = true;
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }
98
+ // Always include required modules
99
+ for (const mod of modules) {
100
+ if (mod.required && !resolved.has(mod.key)) {
101
+ resolved.add(mod.key);
102
+ }
103
+ }
104
+ return Array.from(resolved);
105
+ }
package/dist/index.d.ts CHANGED
@@ -3,7 +3,11 @@ export { testDbConnection } from './lib/db-test';
3
3
  export { composeDbUri } from './lib/compose-uri';
4
4
  export { writeEnvLocal } from './lib/env-writer';
5
5
  export { DIALECT_INFO, ALL_DIALECTS } from './data/dialects';
6
+ export { MODULES, resolveModuleDependencies } from './data/module-definitions';
7
+ export { discoverNpmModules } from './lib/discover-modules';
6
8
  export { createTestDbHandler } from './api/test-db.route';
7
9
  export { createInstallHandler } from './api/install.route';
8
10
  export { createStatusHandler } from './api/status.route';
9
- export type { DialectType, DialectInfo, DbConfig, InstallConfig, SeedOptions, SeedDefinition, MostaSetupConfig, } from './types';
11
+ export { createDetectModulesHandler } from './api/detect-modules.route';
12
+ export { createInstallModulesHandler } from './api/install-modules.route';
13
+ export type { DialectType, DialectInfo, DbConfig, InstallConfig, SeedOptions, SeedDefinition, MostaSetupConfig, ModuleDefinition, } from './types/index';
package/dist/index.js CHANGED
@@ -1,26 +1,18 @@
1
- "use strict";
2
1
  // @mosta/setup — Barrel exports
3
2
  // Author: Dr Hamid MADANI drmdh@msn.com
4
- Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.createStatusHandler = exports.createInstallHandler = exports.createTestDbHandler = exports.ALL_DIALECTS = exports.DIALECT_INFO = exports.writeEnvLocal = exports.composeDbUri = exports.testDbConnection = exports.runInstall = exports.needsSetup = void 0;
6
3
  // Core
7
- var setup_1 = require("./lib/setup");
8
- Object.defineProperty(exports, "needsSetup", { enumerable: true, get: function () { return setup_1.needsSetup; } });
9
- Object.defineProperty(exports, "runInstall", { enumerable: true, get: function () { return setup_1.runInstall; } });
10
- var db_test_1 = require("./lib/db-test");
11
- Object.defineProperty(exports, "testDbConnection", { enumerable: true, get: function () { return db_test_1.testDbConnection; } });
12
- var compose_uri_1 = require("./lib/compose-uri");
13
- Object.defineProperty(exports, "composeDbUri", { enumerable: true, get: function () { return compose_uri_1.composeDbUri; } });
14
- var env_writer_1 = require("./lib/env-writer");
15
- Object.defineProperty(exports, "writeEnvLocal", { enumerable: true, get: function () { return env_writer_1.writeEnvLocal; } });
4
+ export { needsSetup, runInstall } from './lib/setup';
5
+ export { testDbConnection } from './lib/db-test';
6
+ export { composeDbUri } from './lib/compose-uri';
7
+ export { writeEnvLocal } from './lib/env-writer';
16
8
  // Data
17
- var dialects_1 = require("./data/dialects");
18
- Object.defineProperty(exports, "DIALECT_INFO", { enumerable: true, get: function () { return dialects_1.DIALECT_INFO; } });
19
- Object.defineProperty(exports, "ALL_DIALECTS", { enumerable: true, get: function () { return dialects_1.ALL_DIALECTS; } });
9
+ export { DIALECT_INFO, ALL_DIALECTS } from './data/dialects';
10
+ export { MODULES, resolveModuleDependencies } from './data/module-definitions';
11
+ // Lib
12
+ export { discoverNpmModules } from './lib/discover-modules';
20
13
  // API route factories
21
- var test_db_route_1 = require("./api/test-db.route");
22
- Object.defineProperty(exports, "createTestDbHandler", { enumerable: true, get: function () { return test_db_route_1.createTestDbHandler; } });
23
- var install_route_1 = require("./api/install.route");
24
- Object.defineProperty(exports, "createInstallHandler", { enumerable: true, get: function () { return install_route_1.createInstallHandler; } });
25
- var status_route_1 = require("./api/status.route");
26
- Object.defineProperty(exports, "createStatusHandler", { enumerable: true, get: function () { return status_route_1.createStatusHandler; } });
14
+ export { createTestDbHandler } from './api/test-db.route';
15
+ export { createInstallHandler } from './api/install.route';
16
+ export { createStatusHandler } from './api/status.route';
17
+ export { createDetectModulesHandler } from './api/detect-modules.route';
18
+ export { createInstallModulesHandler } from './api/install-modules.route';
@@ -1,4 +1,4 @@
1
- import type { DialectType, DbConfig } from '../types';
1
+ import type { DialectType, DbConfig } from '../types/index';
2
2
  /**
3
3
  * Compose a database connection URI from individual fields.
4
4
  */
@@ -1,10 +1,7 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.composeDbUri = composeDbUri;
4
1
  /**
5
2
  * Compose a database connection URI from individual fields.
6
3
  */
7
- function composeDbUri(dialect, config) {
4
+ export function composeDbUri(dialect, config) {
8
5
  const { host, port, name, user, password } = config;
9
6
  const eu = encodeURIComponent(user);
10
7
  const ep = encodeURIComponent(password);
@@ -1,4 +1,4 @@
1
- import type { DialectType, DbConfig } from '../types';
1
+ import type { DialectType, DbConfig } from '../types/index';
2
2
  /**
3
3
  * Test a database connection without affecting the global dialect singleton.
4
4
  */
@@ -1,50 +1,14 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.testDbConnection = testDbConnection;
37
- const compose_uri_1 = require("./compose-uri");
1
+ import { composeDbUri } from './compose-uri';
38
2
  /**
39
3
  * Test a database connection without affecting the global dialect singleton.
40
4
  */
41
- async function testDbConnection(params) {
5
+ export async function testDbConnection(params) {
42
6
  const { dialect, ...dbConfig } = params;
43
7
  try {
44
8
  switch (dialect) {
45
9
  case 'mongodb': {
46
- const uri = (0, compose_uri_1.composeDbUri)('mongodb', dbConfig);
47
- const mongoose = await Promise.resolve().then(() => __importStar(require('mongoose')));
10
+ const uri = composeDbUri('mongodb', dbConfig);
11
+ const mongoose = await import('mongoose');
48
12
  const conn = mongoose.default.createConnection(uri, {
49
13
  serverSelectionTimeoutMS: 5000,
50
14
  connectTimeoutMS: 5000,
@@ -60,8 +24,8 @@ async function testDbConnection(params) {
60
24
  case 'sqlite':
61
25
  return { ok: true };
62
26
  default: {
63
- const uri = (0, compose_uri_1.composeDbUri)(dialect, dbConfig);
64
- const { testConnection } = await Promise.resolve().then(() => __importStar(require('@mostajs/orm')));
27
+ const uri = composeDbUri(dialect, dbConfig);
28
+ const { testConnection } = await import('@mostajs/orm');
65
29
  const ok = await testConnection({ dialect, uri, schemaStrategy: 'none' });
66
30
  return { ok };
67
31
  }
@@ -0,0 +1,13 @@
1
+ import { type ModuleDefinition } from '../data/module-definitions';
2
+ /**
3
+ * Discover @mostajs packages from npm registry and merge with static list.
4
+ *
5
+ * - Known modules keep their rich metadata (required, dependsOn, icon)
6
+ * - New packages found on npm are added with `discovered: true`
7
+ * - Detects which packages are already installed in node_modules/
8
+ * - Falls back to static list if npm search fails (offline, timeout)
9
+ */
10
+ export declare function discoverNpmModules(): Promise<{
11
+ modules: ModuleDefinition[];
12
+ installed: string[];
13
+ }>;