@mostajs/setup 1.0.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.
- package/LICENSE +21 -0
- package/README.md +79 -0
- package/dist/api/install.route.d.ts +17 -0
- package/dist/api/install.route.js +23 -0
- package/dist/api/status.route.d.ts +11 -0
- package/dist/api/status.route.js +18 -0
- package/dist/api/test-db.route.d.ts +14 -0
- package/dist/api/test-db.route.js +34 -0
- package/dist/data/dialects.d.ts +3 -0
- package/dist/data/dialects.js +136 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +26 -0
- package/dist/lib/compose-uri.d.ts +5 -0
- package/dist/lib/compose-uri.js +42 -0
- package/dist/lib/db-test.d.ts +10 -0
- package/dist/lib/db-test.js +74 -0
- package/dist/lib/env-writer.d.ts +14 -0
- package/dist/lib/env-writer.js +114 -0
- package/dist/lib/setup.d.ts +22 -0
- package/dist/lib/setup.js +117 -0
- package/dist/types/index.d.ts +61 -0
- package/dist/types/index.js +4 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Dr Hamid MADANI <drmdh@msn.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# @mostajs/setup
|
|
2
|
+
|
|
3
|
+
> Reusable setup wizard module — multi-dialect DB configuration, .env.local writer, seed runner.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@mostajs/setup)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
Part of the [@mosta suite](https://mostajs.dev).
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @mostajs/setup @mostajs/orm
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
### 1. Create setup config
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import type { MostaSetupConfig } from '@mostajs/setup'
|
|
24
|
+
|
|
25
|
+
export const setupConfig: MostaSetupConfig = {
|
|
26
|
+
appName: 'MyApp',
|
|
27
|
+
defaultPort: 3000,
|
|
28
|
+
seedRBAC: async () => { /* seed roles & permissions */ },
|
|
29
|
+
createAdmin: async ({ email, hashedPassword, firstName, lastName }) => { /* create admin user */ },
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2. API routes
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// app/api/setup/status/route.ts
|
|
37
|
+
import { createStatusHandler, needsSetup } from '@mostajs/setup'
|
|
38
|
+
export const { GET } = createStatusHandler(() => needsSetup(countUsers))
|
|
39
|
+
|
|
40
|
+
// app/api/setup/test-db/route.ts
|
|
41
|
+
import { createTestDbHandler } from '@mostajs/setup'
|
|
42
|
+
export const { POST } = createTestDbHandler(() => needsSetup(countUsers))
|
|
43
|
+
|
|
44
|
+
// app/api/setup/install/route.ts
|
|
45
|
+
import { createInstallHandler } from '@mostajs/setup'
|
|
46
|
+
export const { POST } = createInstallHandler(() => needsSetup(countUsers), setupConfig)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Features
|
|
50
|
+
|
|
51
|
+
- **13 database dialects** — all dialects supported by @mostajs/orm
|
|
52
|
+
- **Connection testing** — test DB connection before saving
|
|
53
|
+
- **URI composition** — auto-build connection URI from form fields
|
|
54
|
+
- **.env.local writer** — persist DB config to disk
|
|
55
|
+
- **Seed runner** — RBAC + admin user creation
|
|
56
|
+
- **Dialect metadata** — names, icons, default ports, categories
|
|
57
|
+
|
|
58
|
+
## API Reference
|
|
59
|
+
|
|
60
|
+
| Export | Description |
|
|
61
|
+
|--------|-------------|
|
|
62
|
+
| `needsSetup(countFn)` | Check if app needs initial setup |
|
|
63
|
+
| `runInstall(config)` | Full installation flow |
|
|
64
|
+
| `testDbConnection(config)` | Test DB connection |
|
|
65
|
+
| `composeDbUri(config)` | Build connection URI |
|
|
66
|
+
| `writeEnvLocal(vars)` | Write/update .env.local |
|
|
67
|
+
| `DIALECT_INFO` / `ALL_DIALECTS` | Dialect metadata |
|
|
68
|
+
| `createStatusHandler()` | GET /setup/status factory |
|
|
69
|
+
| `createTestDbHandler()` | POST /setup/test-db factory |
|
|
70
|
+
| `createInstallHandler()` | POST /setup/install factory |
|
|
71
|
+
|
|
72
|
+
## Related Packages
|
|
73
|
+
|
|
74
|
+
- [@mostajs/orm](https://www.npmjs.com/package/@mostajs/orm) — Multi-dialect ORM (required)
|
|
75
|
+
- [@mostajs/auth](https://www.npmjs.com/package/@mostajs/auth) — Authentication (for RBAC seeding)
|
|
76
|
+
|
|
77
|
+
## License
|
|
78
|
+
|
|
79
|
+
MIT — © 2025 Dr Hamid MADANI <drmdh@msn.com>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import type { MostaSetupConfig } from '../types';
|
|
3
|
+
type NeedsSetupFn = () => Promise<boolean>;
|
|
4
|
+
/**
|
|
5
|
+
* Creates a POST handler for running the installation.
|
|
6
|
+
*/
|
|
7
|
+
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
|
+
}>>;
|
|
16
|
+
};
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// @mosta/setup — API Route template for install
|
|
3
|
+
// Author: Dr Hamid MADANI drmdh@msn.com
|
|
4
|
+
//
|
|
5
|
+
// 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");
|
|
10
|
+
/**
|
|
11
|
+
* Creates a POST handler for running the installation.
|
|
12
|
+
*/
|
|
13
|
+
function createInstallHandler(needsSetup, setupConfig) {
|
|
14
|
+
async function POST(req) {
|
|
15
|
+
if (!(await needsSetup())) {
|
|
16
|
+
return server_1.NextResponse.json({ error: 'Already installed' }, { status: 400 });
|
|
17
|
+
}
|
|
18
|
+
const body = await req.json();
|
|
19
|
+
const result = await (0, setup_1.runInstall)(body, setupConfig);
|
|
20
|
+
return server_1.NextResponse.json(result);
|
|
21
|
+
}
|
|
22
|
+
return { POST };
|
|
23
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
type NeedsSetupFn = () => Promise<boolean>;
|
|
3
|
+
/**
|
|
4
|
+
* Creates a GET handler for checking setup status.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createStatusHandler(needsSetup: NeedsSetupFn): {
|
|
7
|
+
GET: () => Promise<NextResponse<{
|
|
8
|
+
needsSetup: boolean;
|
|
9
|
+
}>>;
|
|
10
|
+
};
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// @mosta/setup — API Route template for status check
|
|
3
|
+
// Author: Dr Hamid MADANI drmdh@msn.com
|
|
4
|
+
//
|
|
5
|
+
// 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
|
+
/**
|
|
10
|
+
* Creates a GET handler for checking setup status.
|
|
11
|
+
*/
|
|
12
|
+
function createStatusHandler(needsSetup) {
|
|
13
|
+
async function GET() {
|
|
14
|
+
const needed = await needsSetup();
|
|
15
|
+
return server_1.NextResponse.json({ needsSetup: needed });
|
|
16
|
+
}
|
|
17
|
+
return { GET };
|
|
18
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
type NeedsSetupFn = () => Promise<boolean>;
|
|
3
|
+
/**
|
|
4
|
+
* Creates a POST handler for testing DB connections.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createTestDbHandler(needsSetup: NeedsSetupFn): {
|
|
7
|
+
POST: (req: Request) => Promise<NextResponse<{
|
|
8
|
+
error: string;
|
|
9
|
+
}> | NextResponse<{
|
|
10
|
+
ok: boolean;
|
|
11
|
+
error?: string;
|
|
12
|
+
}>>;
|
|
13
|
+
};
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// @mosta/setup — API Route template for test-db
|
|
3
|
+
// Author: Dr Hamid MADANI drmdh@msn.com
|
|
4
|
+
//
|
|
5
|
+
// 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");
|
|
10
|
+
/**
|
|
11
|
+
* Creates a POST handler for testing DB connections.
|
|
12
|
+
*/
|
|
13
|
+
function createTestDbHandler(needsSetup) {
|
|
14
|
+
async function POST(req) {
|
|
15
|
+
if (!(await needsSetup())) {
|
|
16
|
+
return server_1.NextResponse.json({ error: 'Already installed' }, { status: 400 });
|
|
17
|
+
}
|
|
18
|
+
const body = await req.json();
|
|
19
|
+
const { dialect, host, port, name, user, password } = body;
|
|
20
|
+
if (!dialect || !name) {
|
|
21
|
+
return server_1.NextResponse.json({ error: 'Missing required fields' }, { status: 400 });
|
|
22
|
+
}
|
|
23
|
+
const result = await (0, db_test_1.testDbConnection)({
|
|
24
|
+
dialect: dialect,
|
|
25
|
+
host: host || 'localhost',
|
|
26
|
+
port: port || 27017,
|
|
27
|
+
name,
|
|
28
|
+
user: user || '',
|
|
29
|
+
password: password || '',
|
|
30
|
+
});
|
|
31
|
+
return server_1.NextResponse.json(result);
|
|
32
|
+
}
|
|
33
|
+
return { POST };
|
|
34
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ALL_DIALECTS = exports.DIALECT_INFO = void 0;
|
|
4
|
+
exports.DIALECT_INFO = {
|
|
5
|
+
mongodb: {
|
|
6
|
+
name: 'MongoDB',
|
|
7
|
+
icon: '🍃',
|
|
8
|
+
defaultPort: 27017,
|
|
9
|
+
defaultUser: '',
|
|
10
|
+
defaultHost: 'localhost',
|
|
11
|
+
driverHint: null,
|
|
12
|
+
requiresAuth: false,
|
|
13
|
+
category: 'document',
|
|
14
|
+
},
|
|
15
|
+
sqlite: {
|
|
16
|
+
name: 'SQLite',
|
|
17
|
+
icon: '📄',
|
|
18
|
+
defaultPort: 0,
|
|
19
|
+
defaultUser: '',
|
|
20
|
+
defaultHost: '',
|
|
21
|
+
driverHint: null,
|
|
22
|
+
requiresAuth: false,
|
|
23
|
+
category: 'file',
|
|
24
|
+
},
|
|
25
|
+
postgres: {
|
|
26
|
+
name: 'PostgreSQL',
|
|
27
|
+
icon: '🐘',
|
|
28
|
+
defaultPort: 5432,
|
|
29
|
+
defaultUser: 'postgres',
|
|
30
|
+
defaultHost: 'localhost',
|
|
31
|
+
driverHint: 'npm install pg',
|
|
32
|
+
requiresAuth: true,
|
|
33
|
+
category: 'sql',
|
|
34
|
+
},
|
|
35
|
+
mysql: {
|
|
36
|
+
name: 'MySQL',
|
|
37
|
+
icon: '🐬',
|
|
38
|
+
defaultPort: 3306,
|
|
39
|
+
defaultUser: 'root',
|
|
40
|
+
defaultHost: 'localhost',
|
|
41
|
+
driverHint: 'npm install mysql2',
|
|
42
|
+
requiresAuth: true,
|
|
43
|
+
category: 'sql',
|
|
44
|
+
},
|
|
45
|
+
mariadb: {
|
|
46
|
+
name: 'MariaDB',
|
|
47
|
+
icon: '🦭',
|
|
48
|
+
defaultPort: 3306,
|
|
49
|
+
defaultUser: 'root',
|
|
50
|
+
defaultHost: 'localhost',
|
|
51
|
+
driverHint: 'npm install mariadb',
|
|
52
|
+
requiresAuth: true,
|
|
53
|
+
category: 'sql',
|
|
54
|
+
},
|
|
55
|
+
oracle: {
|
|
56
|
+
name: 'Oracle',
|
|
57
|
+
icon: '🔴',
|
|
58
|
+
defaultPort: 1521,
|
|
59
|
+
defaultUser: 'system',
|
|
60
|
+
defaultHost: 'localhost',
|
|
61
|
+
driverHint: 'npm install oracledb',
|
|
62
|
+
requiresAuth: true,
|
|
63
|
+
category: 'enterprise',
|
|
64
|
+
},
|
|
65
|
+
mssql: {
|
|
66
|
+
name: 'Microsoft SQL Server',
|
|
67
|
+
icon: '🟦',
|
|
68
|
+
defaultPort: 1433,
|
|
69
|
+
defaultUser: 'sa',
|
|
70
|
+
defaultHost: 'localhost',
|
|
71
|
+
driverHint: 'npm install tedious',
|
|
72
|
+
requiresAuth: true,
|
|
73
|
+
category: 'enterprise',
|
|
74
|
+
},
|
|
75
|
+
cockroachdb: {
|
|
76
|
+
name: 'CockroachDB',
|
|
77
|
+
icon: '🪳',
|
|
78
|
+
defaultPort: 26257,
|
|
79
|
+
defaultUser: 'root',
|
|
80
|
+
defaultHost: 'localhost',
|
|
81
|
+
driverHint: 'npm install pg',
|
|
82
|
+
requiresAuth: true,
|
|
83
|
+
category: 'distributed',
|
|
84
|
+
},
|
|
85
|
+
db2: {
|
|
86
|
+
name: 'IBM DB2',
|
|
87
|
+
icon: '🏢',
|
|
88
|
+
defaultPort: 50000,
|
|
89
|
+
defaultUser: 'db2inst1',
|
|
90
|
+
defaultHost: 'localhost',
|
|
91
|
+
driverHint: 'npm install ibm_db',
|
|
92
|
+
requiresAuth: true,
|
|
93
|
+
category: 'enterprise',
|
|
94
|
+
},
|
|
95
|
+
hana: {
|
|
96
|
+
name: 'SAP HANA',
|
|
97
|
+
icon: '💎',
|
|
98
|
+
defaultPort: 39013,
|
|
99
|
+
defaultUser: 'SYSTEM',
|
|
100
|
+
defaultHost: 'localhost',
|
|
101
|
+
driverHint: 'npm install @sap/hana-client',
|
|
102
|
+
requiresAuth: true,
|
|
103
|
+
category: 'enterprise',
|
|
104
|
+
},
|
|
105
|
+
hsqldb: {
|
|
106
|
+
name: 'HyperSQL',
|
|
107
|
+
icon: '⚡',
|
|
108
|
+
defaultPort: 9001,
|
|
109
|
+
defaultUser: 'SA',
|
|
110
|
+
defaultHost: 'localhost',
|
|
111
|
+
driverHint: null,
|
|
112
|
+
requiresAuth: false,
|
|
113
|
+
category: 'legacy',
|
|
114
|
+
},
|
|
115
|
+
spanner: {
|
|
116
|
+
name: 'Google Cloud Spanner',
|
|
117
|
+
icon: '☁️',
|
|
118
|
+
defaultPort: 0,
|
|
119
|
+
defaultUser: '',
|
|
120
|
+
defaultHost: '',
|
|
121
|
+
driverHint: 'npm install @google-cloud/spanner',
|
|
122
|
+
requiresAuth: false,
|
|
123
|
+
category: 'distributed',
|
|
124
|
+
},
|
|
125
|
+
sybase: {
|
|
126
|
+
name: 'Sybase ASE',
|
|
127
|
+
icon: '🔷',
|
|
128
|
+
defaultPort: 5000,
|
|
129
|
+
defaultUser: 'sa',
|
|
130
|
+
defaultHost: 'localhost',
|
|
131
|
+
driverHint: 'npm install sybase',
|
|
132
|
+
requiresAuth: true,
|
|
133
|
+
category: 'legacy',
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
exports.ALL_DIALECTS = Object.keys(exports.DIALECT_INFO);
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { needsSetup, runInstall } from './lib/setup';
|
|
2
|
+
export { testDbConnection } from './lib/db-test';
|
|
3
|
+
export { composeDbUri } from './lib/compose-uri';
|
|
4
|
+
export { writeEnvLocal } from './lib/env-writer';
|
|
5
|
+
export { DIALECT_INFO, ALL_DIALECTS } from './data/dialects';
|
|
6
|
+
export { createTestDbHandler } from './api/test-db.route';
|
|
7
|
+
export { createInstallHandler } from './api/install.route';
|
|
8
|
+
export { createStatusHandler } from './api/status.route';
|
|
9
|
+
export type { DialectType, DialectInfo, DbConfig, InstallConfig, SeedOptions, SeedDefinition, MostaSetupConfig, } from './types';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// @mosta/setup — Barrel exports
|
|
3
|
+
// 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
|
+
// 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; } });
|
|
16
|
+
// 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; } });
|
|
20
|
+
// 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; } });
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.composeDbUri = composeDbUri;
|
|
4
|
+
/**
|
|
5
|
+
* Compose a database connection URI from individual fields.
|
|
6
|
+
*/
|
|
7
|
+
function composeDbUri(dialect, config) {
|
|
8
|
+
const { host, port, name, user, password } = config;
|
|
9
|
+
const eu = encodeURIComponent(user);
|
|
10
|
+
const ep = encodeURIComponent(password);
|
|
11
|
+
switch (dialect) {
|
|
12
|
+
case 'mongodb':
|
|
13
|
+
if (user && password)
|
|
14
|
+
return `mongodb://${eu}:${ep}@${host}:${port}/${name}`;
|
|
15
|
+
return `mongodb://${host}:${port}/${name}`;
|
|
16
|
+
case 'sqlite':
|
|
17
|
+
return `./data/${name}.db`;
|
|
18
|
+
case 'postgres':
|
|
19
|
+
case 'cockroachdb':
|
|
20
|
+
return `postgresql://${eu}:${ep}@${host}:${port}/${name}`;
|
|
21
|
+
case 'mysql':
|
|
22
|
+
return `mysql://${eu}:${ep}@${host}:${port}/${name}`;
|
|
23
|
+
case 'mariadb':
|
|
24
|
+
return `mariadb://${eu}:${ep}@${host}:${port}/${name}`;
|
|
25
|
+
case 'oracle':
|
|
26
|
+
return `oracle://${eu}:${ep}@${host}:${port}/${name}`;
|
|
27
|
+
case 'mssql':
|
|
28
|
+
return `mssql://${eu}:${ep}@${host}:${port}/${name}`;
|
|
29
|
+
case 'db2':
|
|
30
|
+
return `db2://${eu}:${ep}@${host}:${port}/${name}`;
|
|
31
|
+
case 'hana':
|
|
32
|
+
return `hana://${eu}:${ep}@${host}:${port}`;
|
|
33
|
+
case 'hsqldb':
|
|
34
|
+
return `hsqldb:hsql://${host}:${port}/${name}`;
|
|
35
|
+
case 'spanner':
|
|
36
|
+
return `spanner://projects/${name}`;
|
|
37
|
+
case 'sybase':
|
|
38
|
+
return `sybase://${eu}:${ep}@${host}:${port}/${name}`;
|
|
39
|
+
default:
|
|
40
|
+
return `mongodb://${host}:${port}/${name}`;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DialectType, DbConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Test a database connection without affecting the global dialect singleton.
|
|
4
|
+
*/
|
|
5
|
+
export declare function testDbConnection(params: {
|
|
6
|
+
dialect: DialectType;
|
|
7
|
+
} & DbConfig): Promise<{
|
|
8
|
+
ok: boolean;
|
|
9
|
+
error?: string;
|
|
10
|
+
}>;
|
|
@@ -0,0 +1,74 @@
|
|
|
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");
|
|
38
|
+
/**
|
|
39
|
+
* Test a database connection without affecting the global dialect singleton.
|
|
40
|
+
*/
|
|
41
|
+
async function testDbConnection(params) {
|
|
42
|
+
const { dialect, ...dbConfig } = params;
|
|
43
|
+
try {
|
|
44
|
+
switch (dialect) {
|
|
45
|
+
case 'mongodb': {
|
|
46
|
+
const uri = (0, compose_uri_1.composeDbUri)('mongodb', dbConfig);
|
|
47
|
+
const mongoose = await Promise.resolve().then(() => __importStar(require('mongoose')));
|
|
48
|
+
const conn = mongoose.default.createConnection(uri, {
|
|
49
|
+
serverSelectionTimeoutMS: 5000,
|
|
50
|
+
connectTimeoutMS: 5000,
|
|
51
|
+
});
|
|
52
|
+
try {
|
|
53
|
+
await conn.asPromise();
|
|
54
|
+
return { ok: conn.readyState === 1 };
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
await conn.close().catch(() => { });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
case 'sqlite':
|
|
61
|
+
return { ok: true };
|
|
62
|
+
default: {
|
|
63
|
+
const uri = (0, compose_uri_1.composeDbUri)(dialect, dbConfig);
|
|
64
|
+
const { testConnection } = await Promise.resolve().then(() => __importStar(require('@mostajs/orm')));
|
|
65
|
+
const ok = await testConnection({ dialect, uri, schemaStrategy: 'none' });
|
|
66
|
+
return { ok };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
const message = err instanceof Error ? err.message : 'Connexion echouee';
|
|
72
|
+
return { ok: false, error: message };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DialectType } from '../types';
|
|
2
|
+
export interface EnvWriterOptions {
|
|
3
|
+
dialect: DialectType;
|
|
4
|
+
uri: string;
|
|
5
|
+
/** Extra variables to write (e.g. STRIPE_KEY, SMTP_HOST) */
|
|
6
|
+
extraVars?: Record<string, string>;
|
|
7
|
+
/** Default app port (default: 3000) */
|
|
8
|
+
port?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Write or update .env.local with DB_DIALECT + SGBD_URI.
|
|
12
|
+
* Preserves commented lines. Returns true if dialect changed (needs restart).
|
|
13
|
+
*/
|
|
14
|
+
export declare function writeEnvLocal(options: EnvWriterOptions): Promise<boolean>;
|
|
@@ -0,0 +1,114 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.writeEnvLocal = writeEnvLocal;
|
|
40
|
+
// @mosta/setup — Write/update .env.local
|
|
41
|
+
// Author: Dr Hamid MADANI drmdh@msn.com
|
|
42
|
+
const fs_1 = __importDefault(require("fs"));
|
|
43
|
+
const path_1 = __importDefault(require("path"));
|
|
44
|
+
/**
|
|
45
|
+
* Write or update .env.local with DB_DIALECT + SGBD_URI.
|
|
46
|
+
* Preserves commented lines. Returns true if dialect changed (needs restart).
|
|
47
|
+
*/
|
|
48
|
+
async function writeEnvLocal(options) {
|
|
49
|
+
const { dialect, uri, extraVars, port = 3000 } = options;
|
|
50
|
+
const envPath = path_1.default.resolve(process.cwd(), '.env.local');
|
|
51
|
+
let content = '';
|
|
52
|
+
let previousDialect = null;
|
|
53
|
+
try {
|
|
54
|
+
content = fs_1.default.readFileSync(envPath, 'utf-8');
|
|
55
|
+
const match = content.match(/^DB_DIALECT=(.+)$/m);
|
|
56
|
+
if (match)
|
|
57
|
+
previousDialect = match[1].trim();
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// .env.local doesn't exist yet
|
|
61
|
+
}
|
|
62
|
+
const schemaValue = dialect !== 'mongodb' ? 'update' : undefined;
|
|
63
|
+
if (content) {
|
|
64
|
+
// Replace only active (uncommented) lines
|
|
65
|
+
content = upsertEnvLine(content, 'DB_DIALECT', dialect);
|
|
66
|
+
content = upsertEnvLine(content, 'SGBD_URI', uri);
|
|
67
|
+
if (schemaValue) {
|
|
68
|
+
content = upsertEnvLine(content, 'DB_SCHEMA_STRATEGY', schemaValue);
|
|
69
|
+
}
|
|
70
|
+
else if (/^DB_SCHEMA_STRATEGY=/m.test(content)) {
|
|
71
|
+
content = content.replace(/^DB_SCHEMA_STRATEGY=.*$/m, '#DB_SCHEMA_STRATEGY=update');
|
|
72
|
+
}
|
|
73
|
+
// Write extra vars
|
|
74
|
+
if (extraVars) {
|
|
75
|
+
for (const [key, val] of Object.entries(extraVars)) {
|
|
76
|
+
content = upsertEnvLine(content, key, val);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
// Fresh .env.local
|
|
82
|
+
const { randomBytes } = await Promise.resolve().then(() => __importStar(require('crypto')));
|
|
83
|
+
const secret = randomBytes(32).toString('base64');
|
|
84
|
+
const lines = [
|
|
85
|
+
`DB_DIALECT=${dialect}`,
|
|
86
|
+
`SGBD_URI=${uri}`,
|
|
87
|
+
...(schemaValue ? [`DB_SCHEMA_STRATEGY=${schemaValue}`] : []),
|
|
88
|
+
'',
|
|
89
|
+
'# NextAuth Configuration',
|
|
90
|
+
`NEXTAUTH_URL=http://localhost:${port}`,
|
|
91
|
+
`NEXTAUTH_SECRET=${secret}`,
|
|
92
|
+
`AUTH_SECRET=${secret}`,
|
|
93
|
+
`NEXT_PUBLIC_APP_URL=http://localhost:${port}`,
|
|
94
|
+
'',
|
|
95
|
+
'# Environment',
|
|
96
|
+
'NODE_ENV=development',
|
|
97
|
+
`PORT=${port}`,
|
|
98
|
+
'',
|
|
99
|
+
...(extraVars
|
|
100
|
+
? ['# App Configuration', ...Object.entries(extraVars).map(([k, v]) => `${k}=${v}`), '']
|
|
101
|
+
: []),
|
|
102
|
+
];
|
|
103
|
+
content = lines.join('\n') + '\n';
|
|
104
|
+
}
|
|
105
|
+
fs_1.default.writeFileSync(envPath, content, 'utf-8');
|
|
106
|
+
return previousDialect !== null && previousDialect !== dialect;
|
|
107
|
+
}
|
|
108
|
+
function upsertEnvLine(content, key, value) {
|
|
109
|
+
const regex = new RegExp(`^${key}=.*$`, 'm');
|
|
110
|
+
if (regex.test(content)) {
|
|
111
|
+
return content.replace(regex, `${key}=${value}`);
|
|
112
|
+
}
|
|
113
|
+
return content.trimEnd() + `\n${key}=${value}\n`;
|
|
114
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { InstallConfig, MostaSetupConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Check if the app needs initial setup (0 users in DB).
|
|
4
|
+
* Provide a countUsers function from your app.
|
|
5
|
+
*/
|
|
6
|
+
export declare function needsSetup(countUsers: () => Promise<number>): Promise<boolean>;
|
|
7
|
+
/**
|
|
8
|
+
* Run the complete installation flow.
|
|
9
|
+
*
|
|
10
|
+
* 1. Compose URI and write .env.local
|
|
11
|
+
* 2. Set process.env in-memory
|
|
12
|
+
* 3. Disconnect existing dialect singleton
|
|
13
|
+
* 4. Seed RBAC (via config.seedRBAC callback)
|
|
14
|
+
* 5. Create first admin user
|
|
15
|
+
* 6. Run optional seeds
|
|
16
|
+
*/
|
|
17
|
+
export declare function runInstall(installConfig: InstallConfig, setupConfig: MostaSetupConfig): Promise<{
|
|
18
|
+
ok: boolean;
|
|
19
|
+
error?: string;
|
|
20
|
+
needsRestart: boolean;
|
|
21
|
+
seeded?: string[];
|
|
22
|
+
}>;
|
|
@@ -0,0 +1,117 @@
|
|
|
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.needsSetup = needsSetup;
|
|
37
|
+
exports.runInstall = runInstall;
|
|
38
|
+
// @mosta/setup — Core setup logic
|
|
39
|
+
// Author: Dr Hamid MADANI drmdh@msn.com
|
|
40
|
+
const compose_uri_1 = require("./compose-uri");
|
|
41
|
+
const env_writer_1 = require("./env-writer");
|
|
42
|
+
/**
|
|
43
|
+
* Check if the app needs initial setup (0 users in DB).
|
|
44
|
+
* Provide a countUsers function from your app.
|
|
45
|
+
*/
|
|
46
|
+
async function needsSetup(countUsers) {
|
|
47
|
+
try {
|
|
48
|
+
const count = await countUsers();
|
|
49
|
+
return count === 0;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Run the complete installation flow.
|
|
57
|
+
*
|
|
58
|
+
* 1. Compose URI and write .env.local
|
|
59
|
+
* 2. Set process.env in-memory
|
|
60
|
+
* 3. Disconnect existing dialect singleton
|
|
61
|
+
* 4. Seed RBAC (via config.seedRBAC callback)
|
|
62
|
+
* 5. Create first admin user
|
|
63
|
+
* 6. Run optional seeds
|
|
64
|
+
*/
|
|
65
|
+
async function runInstall(installConfig, setupConfig) {
|
|
66
|
+
try {
|
|
67
|
+
// 1. Compose URI and write .env.local
|
|
68
|
+
const uri = (0, compose_uri_1.composeDbUri)(installConfig.dialect, installConfig.db);
|
|
69
|
+
const needsRestart = await (0, env_writer_1.writeEnvLocal)({
|
|
70
|
+
dialect: installConfig.dialect,
|
|
71
|
+
uri,
|
|
72
|
+
extraVars: setupConfig.extraEnvVars,
|
|
73
|
+
port: setupConfig.defaultPort,
|
|
74
|
+
});
|
|
75
|
+
// 2. Set process.env in-memory
|
|
76
|
+
process.env.DB_DIALECT = installConfig.dialect;
|
|
77
|
+
process.env.SGBD_URI = uri;
|
|
78
|
+
if (installConfig.dialect !== 'mongodb') {
|
|
79
|
+
process.env.DB_SCHEMA_STRATEGY = 'update';
|
|
80
|
+
}
|
|
81
|
+
// 3. Disconnect existing dialect singleton
|
|
82
|
+
const { disconnectDialect } = await Promise.resolve().then(() => __importStar(require('@mostajs/orm')));
|
|
83
|
+
await disconnectDialect();
|
|
84
|
+
// 4. Seed RBAC
|
|
85
|
+
const seeded = [];
|
|
86
|
+
if (setupConfig.seedRBAC) {
|
|
87
|
+
await setupConfig.seedRBAC();
|
|
88
|
+
seeded.push('categories', 'permissions', 'roles');
|
|
89
|
+
}
|
|
90
|
+
// 5. Create admin user
|
|
91
|
+
if (setupConfig.createAdmin) {
|
|
92
|
+
const bcrypt = await Promise.resolve().then(() => __importStar(require('bcryptjs')));
|
|
93
|
+
const hashedPassword = await bcrypt.hash(installConfig.admin.password, 12);
|
|
94
|
+
await setupConfig.createAdmin({
|
|
95
|
+
email: installConfig.admin.email,
|
|
96
|
+
hashedPassword,
|
|
97
|
+
firstName: installConfig.admin.firstName,
|
|
98
|
+
lastName: installConfig.admin.lastName,
|
|
99
|
+
});
|
|
100
|
+
seeded.push('admin');
|
|
101
|
+
}
|
|
102
|
+
// 6. Optional seeds
|
|
103
|
+
if (setupConfig.optionalSeeds && installConfig.seed) {
|
|
104
|
+
for (const seedDef of setupConfig.optionalSeeds) {
|
|
105
|
+
if (installConfig.seed[seedDef.key]) {
|
|
106
|
+
await seedDef.run({});
|
|
107
|
+
seeded.push(seedDef.key);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return { ok: true, needsRestart, seeded };
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
const message = err instanceof Error ? err.message : 'Erreur installation';
|
|
115
|
+
return { ok: false, error: message, needsRestart: false };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export type DialectType = 'mongodb' | 'sqlite' | 'postgres' | 'mysql' | 'mariadb' | 'oracle' | 'mssql' | 'cockroachdb' | 'db2' | 'hana' | 'hsqldb' | 'spanner' | 'sybase';
|
|
2
|
+
export interface DialectInfo {
|
|
3
|
+
name: string;
|
|
4
|
+
icon: string;
|
|
5
|
+
defaultPort: number;
|
|
6
|
+
defaultUser: string;
|
|
7
|
+
defaultHost: string;
|
|
8
|
+
driverHint: string | null;
|
|
9
|
+
requiresAuth: boolean;
|
|
10
|
+
category: 'document' | 'file' | 'sql' | 'enterprise' | 'distributed' | 'legacy';
|
|
11
|
+
}
|
|
12
|
+
export interface DbConfig {
|
|
13
|
+
host: string;
|
|
14
|
+
port: number;
|
|
15
|
+
name: string;
|
|
16
|
+
user: string;
|
|
17
|
+
password: string;
|
|
18
|
+
}
|
|
19
|
+
export interface InstallConfig {
|
|
20
|
+
dialect: DialectType;
|
|
21
|
+
db: DbConfig;
|
|
22
|
+
admin: {
|
|
23
|
+
email: string;
|
|
24
|
+
password: string;
|
|
25
|
+
firstName: string;
|
|
26
|
+
lastName: string;
|
|
27
|
+
};
|
|
28
|
+
seed?: SeedOptions;
|
|
29
|
+
}
|
|
30
|
+
export interface SeedOptions {
|
|
31
|
+
[key: string]: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface SeedDefinition {
|
|
34
|
+
key: string;
|
|
35
|
+
label: string;
|
|
36
|
+
description: string;
|
|
37
|
+
icon?: string;
|
|
38
|
+
default?: boolean;
|
|
39
|
+
run: (repos: any) => Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
export interface MostaSetupConfig {
|
|
42
|
+
/** Application name (shown in wizard) */
|
|
43
|
+
appName: string;
|
|
44
|
+
/** Default port (default: 3000) */
|
|
45
|
+
defaultPort?: number;
|
|
46
|
+
/** Enabled dialects (default: all 13) */
|
|
47
|
+
enabledDialects?: DialectType[];
|
|
48
|
+
/** Callback to seed RBAC (permissions, roles, categories) */
|
|
49
|
+
seedRBAC?: () => Promise<void>;
|
|
50
|
+
/** Create first admin user — called with hashed password */
|
|
51
|
+
createAdmin?: (admin: {
|
|
52
|
+
email: string;
|
|
53
|
+
hashedPassword: string;
|
|
54
|
+
firstName: string;
|
|
55
|
+
lastName: string;
|
|
56
|
+
}) => Promise<void>;
|
|
57
|
+
/** Optional seeds shown in the wizard */
|
|
58
|
+
optionalSeeds?: SeedDefinition[];
|
|
59
|
+
/** Extra env vars to write to .env.local */
|
|
60
|
+
extraEnvVars?: Record<string, string>;
|
|
61
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mostajs/setup",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Reusable setup wizard module — multi-dialect DB configuration, .env.local writer, seed runner",
|
|
5
|
+
"author": "Dr Hamid MADANI <drmdh@msn.com>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.js",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"LICENSE",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"keywords": [
|
|
23
|
+
"setup",
|
|
24
|
+
"wizard",
|
|
25
|
+
"installer",
|
|
26
|
+
"database",
|
|
27
|
+
"multi-dialect",
|
|
28
|
+
"nextjs",
|
|
29
|
+
"mosta"
|
|
30
|
+
],
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/apolocine/mosta-setup"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://mostajs.dev/packages/setup",
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18.0.0"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsc",
|
|
41
|
+
"prepublishOnly": "npm run build"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@mostajs/orm": "^1.0.0",
|
|
45
|
+
"bcryptjs": "^2.4.3"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"next": ">=14",
|
|
49
|
+
"react": ">=18"
|
|
50
|
+
},
|
|
51
|
+
"peerDependenciesMeta": {
|
|
52
|
+
"next": {
|
|
53
|
+
"optional": true
|
|
54
|
+
},
|
|
55
|
+
"react": {
|
|
56
|
+
"optional": true
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"optionalDependencies": {
|
|
60
|
+
"mongoose": "^8.0.0"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@types/bcryptjs": "^2.4.0",
|
|
64
|
+
"@types/node": "^25.3.3",
|
|
65
|
+
"@types/react": "^19.0.0",
|
|
66
|
+
"next": "^15.0.0",
|
|
67
|
+
"react": "^19.0.0",
|
|
68
|
+
"typescript": "^5.6.0"
|
|
69
|
+
}
|
|
70
|
+
}
|