dolphin-server-modules 2.11.1 โ 2.11.2
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/TUTORIAL_NEPALI.md +181 -0
- package/dist/adapters/mongoose/index.test.d.ts +1 -0
- package/dist/adapters/mongoose/index.test.js +145 -0
- package/dist/adapters/mongoose/index.test.js.map +1 -0
- package/dist/adapters/mongoose/integration.test.d.ts +5 -0
- package/dist/adapters/mongoose/integration.test.js +217 -0
- package/dist/adapters/mongoose/integration.test.js.map +1 -0
- package/dist/ai/dolphin-agent/agent.d.ts +5 -0
- package/dist/ai/dolphin-agent/agent.js +93 -46
- package/dist/ai/dolphin-agent/agent.js.map +1 -1
- package/dist/ai/dolphin-agent/config.js +19 -23
- package/dist/ai/dolphin-agent/config.js.map +1 -1
- package/dist/auth/auth.test.d.ts +1 -0
- package/dist/auth/auth.test.js +286 -0
- package/dist/auth/auth.test.js.map +1 -0
- package/dist/authController/authController.js +1 -1
- package/dist/authController/authController.js.map +1 -1
- package/dist/authController/authController.test.d.ts +1 -0
- package/dist/authController/authController.test.js +359 -0
- package/dist/authController/authController.test.js.map +1 -0
- package/dist/bin/cli.js +494 -131
- package/dist/bin/cli.js.map +1 -1
- package/dist/client.test.d.ts +22 -0
- package/dist/client.test.js +573 -0
- package/dist/client.test.js.map +1 -0
- package/dist/controller/controller.test.d.ts +1 -0
- package/dist/controller/controller.test.js +37 -0
- package/dist/controller/controller.test.js.map +1 -0
- package/dist/curd/crud.test.d.ts +1 -0
- package/dist/curd/crud.test.js +104 -0
- package/dist/curd/crud.test.js.map +1 -0
- package/dist/demo-server.d.ts +1 -0
- package/dist/demo-server.js +191 -0
- package/dist/demo-server.js.map +1 -0
- package/dist/djson/djson.test.d.ts +1 -0
- package/dist/djson/djson.test.js +200 -0
- package/dist/djson/djson.test.js.map +1 -0
- package/dist/dolphin-bench.d.ts +1 -0
- package/dist/dolphin-bench.js +63 -0
- package/dist/dolphin-bench.js.map +1 -0
- package/dist/hard-performance-test.d.ts +1 -0
- package/dist/hard-performance-test.js +97 -0
- package/dist/hard-performance-test.js.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/middleware/zod.test.d.ts +1 -0
- package/dist/middleware/zod.test.js +74 -0
- package/dist/middleware/zod.test.js.map +1 -0
- package/dist/performance-test.d.ts +1 -0
- package/dist/performance-test.js +92 -0
- package/dist/performance-test.js.map +1 -0
- package/dist/real-test-mongoose.d.ts +1 -0
- package/dist/real-test-mongoose.js +104 -0
- package/dist/real-test-mongoose.js.map +1 -0
- package/dist/realtime/camera.d.ts +119 -0
- package/dist/realtime/camera.js +299 -0
- package/dist/realtime/camera.js.map +1 -0
- package/dist/realtime/camera.test.d.ts +1 -0
- package/dist/realtime/camera.test.js +345 -0
- package/dist/realtime/camera.test.js.map +1 -0
- package/dist/realtime/core.d.ts +5 -5
- package/dist/realtime/core.js +6 -6
- package/dist/realtime/core.js.map +1 -1
- package/dist/realtime/index.d.ts +6 -4
- package/dist/realtime/index.js +6 -4
- package/dist/realtime/index.js.map +1 -1
- package/dist/realtime/realtime.test.d.ts +1 -0
- package/dist/realtime/realtime.test.js +623 -0
- package/dist/realtime/realtime.test.js.map +1 -0
- package/dist/realtime/rtsp.d.ts +65 -0
- package/dist/realtime/rtsp.js +410 -0
- package/dist/realtime/rtsp.js.map +1 -0
- package/dist/realtime/rtsp.test.d.ts +1 -0
- package/dist/realtime/rtsp.test.js +361 -0
- package/dist/realtime/rtsp.test.js.map +1 -0
- package/dist/router/router.test.d.ts +1 -0
- package/dist/router/router.test.js +45 -0
- package/dist/router/router.test.js.map +1 -0
- package/dist/server/server.d.ts +8 -8
- package/dist/server/server.js +2 -11
- package/dist/server/server.js.map +1 -1
- package/dist/server/server.test.d.ts +1 -0
- package/dist/server/server.test.js +299 -0
- package/dist/server/server.test.js.map +1 -0
- package/dist/services/ai-service.js +22 -11
- package/dist/services/ai-service.js.map +1 -1
- package/dist/signaling/index.d.ts +1 -1
- package/dist/signaling/signaling.test.d.ts +1 -0
- package/dist/signaling/signaling.test.js +112 -0
- package/dist/signaling/signaling.test.js.map +1 -0
- package/dist/swagger/swagger.test.d.ts +1 -0
- package/dist/swagger/swagger.test.js +38 -0
- package/dist/swagger/swagger.test.js.map +1 -0
- package/dist/templates/index.d.ts +6 -0
- package/dist/templates/index.js +247 -70
- package/dist/templates/index.js.map +1 -1
- package/dist/test-2fa-real.d.ts +1 -0
- package/dist/test-2fa-real.js +105 -0
- package/dist/test-2fa-real.js.map +1 -0
- package/dist/test-dolphin.d.ts +1 -0
- package/dist/test-dolphin.js +98 -0
- package/dist/test-dolphin.js.map +1 -0
- package/dist/utils/ctx.d.ts +50 -0
- package/dist/utils/ctx.js +82 -0
- package/dist/utils/ctx.js.map +1 -0
- package/package.json +156 -65
- package/scripts/client.js +838 -703
- package/scripts/benchmark.js +0 -12
- package/scripts/benchmark.ts +0 -12
- package/scripts/list-models.js +0 -34
- package/scripts/run-real-ai-test.js +0 -79
- package/scripts/test-ai-logic.js +0 -44
- package/scripts/test-client.js +0 -105
- package/scripts/test-dolphin.js +0 -36
package/dist/templates/index.js
CHANGED
|
@@ -2,111 +2,288 @@ export const TEMPLATES = {
|
|
|
2
2
|
app: `import { createDolphinServer } from 'dolphin-server-modules/server';
|
|
3
3
|
import { createMongooseAdapter } from 'dolphin-server-modules/adapters/mongoose';
|
|
4
4
|
import { createDolphinAuthController } from 'dolphin-server-modules/auth-controller';
|
|
5
|
+
import { connectDB } from './config/db.js';
|
|
6
|
+
import { User, RefreshToken } from './models/User.js';
|
|
5
7
|
|
|
6
8
|
const app = createDolphinServer();
|
|
7
9
|
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
+
// Global Error Handler โ server crash เคฌเคพเค เคฌเคเคพเคเคเค
|
|
11
|
+
app.use(async (ctx, next) => {
|
|
12
|
+
try { if (next) await next(); }
|
|
13
|
+
catch (error) {
|
|
14
|
+
console.error('๐ฅ ERROR:', error.message);
|
|
15
|
+
ctx.status(500).json({ success: false, message: 'Internal Server Error' });
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// DB connect
|
|
20
|
+
connectDB(process.env.MONGO_URI || 'mongodb://localhost:27017/dolphin_db');
|
|
10
21
|
|
|
11
|
-
//
|
|
22
|
+
// Mongoose Adapter
|
|
23
|
+
const db = createMongooseAdapter({ User, RefreshToken });
|
|
24
|
+
|
|
25
|
+
// Auth
|
|
12
26
|
const auth = createDolphinAuthController({
|
|
13
|
-
|
|
14
|
-
|
|
27
|
+
adapter: db,
|
|
28
|
+
jwtSecret: process.env.JWT_SECRET || 'change_in_production',
|
|
15
29
|
});
|
|
16
30
|
|
|
17
31
|
app.post('/api/auth/register', auth.register);
|
|
18
|
-
app.post('/api/auth/login',
|
|
32
|
+
app.post('/api/auth/login', auth.login);
|
|
33
|
+
app.post('/api/auth/refresh', auth.refresh);
|
|
34
|
+
app.post('/api/auth/logout', auth.middleware(), auth.logout);
|
|
35
|
+
|
|
36
|
+
app.get('/health', (ctx) => ({ status: 'ok', ts: new Date().toISOString() }));
|
|
19
37
|
|
|
20
|
-
|
|
38
|
+
const PORT = parseInt(process.env.PORT || '3000');
|
|
39
|
+
app.listen(PORT, () => console.log(\`๐ฌ Dolphin Server swimming on port \${PORT}\`));
|
|
21
40
|
`,
|
|
22
41
|
mongoose: `import mongoose from 'mongoose';
|
|
42
|
+
|
|
23
43
|
export const connectDB = async (uri) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
44
|
+
try {
|
|
45
|
+
await mongoose.connect(uri, { serverSelectionTimeoutMS: 5000 });
|
|
46
|
+
console.log('โ
MongoDB Connected:', mongoose.connection.host);
|
|
47
|
+
} catch (e) {
|
|
48
|
+
console.error('โ MongoDB Error:', e.message);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
mongoose.connection.on('disconnected', () => console.warn('โ ๏ธ MongoDB disconnected'));
|
|
54
|
+
mongoose.connection.on('error', (err) => console.error('โ MongoDB:', err.message));
|
|
55
|
+
`,
|
|
31
56
|
sequelize: `import { Sequelize } from 'sequelize';
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
57
|
+
|
|
58
|
+
export const sequelize = new Sequelize(
|
|
59
|
+
process.env.DB_NAME || 'dolphin_db',
|
|
60
|
+
process.env.DB_USER || 'root',
|
|
61
|
+
process.env.DB_PASS || '',
|
|
62
|
+
{
|
|
63
|
+
host: process.env.DB_HOST || 'localhost',
|
|
64
|
+
dialect: process.env.DB_DIALECT || 'mysql',
|
|
65
|
+
logging: process.env.NODE_ENV === 'development' ? console.log : false,
|
|
66
|
+
pool: { max: 10, min: 0, acquire: 30000, idle: 10000 },
|
|
67
|
+
}
|
|
68
|
+
);
|
|
37
69
|
|
|
38
70
|
export const connectDB = async () => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
71
|
+
try {
|
|
72
|
+
await sequelize.authenticate();
|
|
73
|
+
console.log('โ
Sequelize Connected:', process.env.DB_HOST || 'localhost');
|
|
74
|
+
await sequelize.sync({ alter: process.env.NODE_ENV === 'development' });
|
|
75
|
+
} catch (e) {
|
|
76
|
+
console.error('โ Sequelize Error:', e.message); process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
`,
|
|
80
|
+
redis: `import { createClient } from 'redis';
|
|
81
|
+
|
|
82
|
+
const REDIS_URL = process.env.REDIS_URL || 'redis://localhost:6379';
|
|
83
|
+
|
|
84
|
+
export const redisClient = createClient({ url: REDIS_URL });
|
|
85
|
+
redisClient.on('error', (err) => console.error('โ Redis:', err.message));
|
|
86
|
+
redisClient.on('connect', () => console.log('โ
Redis Connected:', REDIS_URL));
|
|
87
|
+
redisClient.on('reconnecting',() => console.warn('โ ๏ธ Redis reconnecting...'));
|
|
88
|
+
|
|
89
|
+
export const connectRedis = async () => {
|
|
90
|
+
await redisClient.connect().catch(e => { console.error('โ Redis:', e.message); process.exit(1); });
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const cache = {
|
|
94
|
+
set: (key, value, ttl = 3600) => redisClient.setEx(key, ttl, JSON.stringify(value)),
|
|
95
|
+
get: async (key) => { const v = await redisClient.get(key); return v ? JSON.parse(v) : null; },
|
|
96
|
+
del: (key) => redisClient.del(key),
|
|
97
|
+
exists: async (key) => (await redisClient.exists(key)) === 1,
|
|
98
|
+
};
|
|
99
|
+
`,
|
|
46
100
|
auth: `import { createDolphinAuthController } from 'dolphin-server-modules/auth-controller';
|
|
47
|
-
import {
|
|
101
|
+
import { db } from './adapter.js'; // เคคเคชเคพเคเคเคเฅ createMongooseAdapter instance
|
|
48
102
|
|
|
49
|
-
// This is a production-ready Auth Controller using Dolphin Modules
|
|
50
103
|
export const auth = createDolphinAuthController({
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
104
|
+
adapter: db,
|
|
105
|
+
jwtSecret: process.env.JWT_SECRET || 'change_in_production',
|
|
106
|
+
accessTokenExpiry: '15m',
|
|
107
|
+
refreshTokenExpiry: '7d',
|
|
54
108
|
});
|
|
55
109
|
|
|
56
|
-
export const register = auth
|
|
57
|
-
export const login = auth.login;
|
|
110
|
+
export const { register, login, refresh, logout, middleware } = auth;
|
|
58
111
|
`,
|
|
59
112
|
crud: (name) => `import { createCrudController } from 'dolphin-server-modules/crud';
|
|
60
|
-
import {
|
|
113
|
+
import { db } from '../config/adapter.js';
|
|
61
114
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
{ softDelete: true, enforceOwnership: true }
|
|
67
|
-
);
|
|
115
|
+
const ctrl = createCrudController(db, '${name}', {
|
|
116
|
+
softDelete: true,
|
|
117
|
+
enforceOwnership: false,
|
|
118
|
+
});
|
|
68
119
|
|
|
69
|
-
export const getAll =
|
|
70
|
-
export const
|
|
71
|
-
export const create = ${name.toLowerCase()}Controller.create;
|
|
72
|
-
export const update = ${name.toLowerCase()}Controller.update;
|
|
73
|
-
export const remove = ${name.toLowerCase()}Controller.delete;
|
|
120
|
+
export const { getAll, getOne, create, update } = ctrl;
|
|
121
|
+
export const remove = ctrl.delete;
|
|
74
122
|
`,
|
|
75
123
|
crudModel: (name) => `import mongoose from 'mongoose';
|
|
76
124
|
|
|
77
|
-
const ${name.toLowerCase()}Schema = new mongoose.Schema(
|
|
78
|
-
|
|
79
|
-
title:
|
|
80
|
-
description: { type: String },
|
|
81
|
-
status:
|
|
82
|
-
|
|
125
|
+
const ${name.toLowerCase()}Schema = new mongoose.Schema(
|
|
126
|
+
{
|
|
127
|
+
title: { type: String, required: true, trim: true },
|
|
128
|
+
description: { type: String, default: '' },
|
|
129
|
+
status: { type: String, enum: ['active','inactive'], default: 'active' },
|
|
130
|
+
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
|
|
131
|
+
},
|
|
132
|
+
{ timestamps: true, versionKey: false }
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
${name.toLowerCase()}Schema.index({ userId: 1, status: 1 });
|
|
136
|
+
${name.toLowerCase()}Schema.index({ createdAt: -1 });
|
|
83
137
|
|
|
84
138
|
export const ${name} = mongoose.model('${name}', ${name.toLowerCase()}Schema);
|
|
85
139
|
`,
|
|
86
140
|
authModel: `import mongoose from 'mongoose';
|
|
87
141
|
|
|
88
|
-
const userSchema = new mongoose.Schema(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
142
|
+
const userSchema = new mongoose.Schema(
|
|
143
|
+
{
|
|
144
|
+
email: { type: String, required: true, unique: true, lowercase: true, trim: true },
|
|
145
|
+
password: { type: String, required: true },
|
|
146
|
+
role: { type: String, enum: ['user','admin','moderator'], default: 'user' },
|
|
147
|
+
twoFactorEnabled: { type: Boolean, default: false },
|
|
148
|
+
twoFactorSecret: { type: String, default: null },
|
|
149
|
+
pending2FASecret: { type: String, default: null },
|
|
150
|
+
recoveryCodes: { type: [String], default: [] },
|
|
151
|
+
isActive: { type: Boolean, default: true },
|
|
152
|
+
lastLoginAt: { type: Date, default: null },
|
|
153
|
+
},
|
|
154
|
+
{ timestamps: true, versionKey: false }
|
|
155
|
+
);
|
|
156
|
+
userSchema.index({ email: 1 });
|
|
98
157
|
export const User = mongoose.model('User', userSchema);
|
|
99
158
|
|
|
100
|
-
const refreshTokenSchema = new mongoose.Schema(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
159
|
+
const refreshTokenSchema = new mongoose.Schema(
|
|
160
|
+
{
|
|
161
|
+
token: { type: String, required: true, unique: true, index: true },
|
|
162
|
+
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
|
|
163
|
+
expiresAt: { type: Date, required: true },
|
|
164
|
+
twoFactorVerified: { type: Boolean, default: false },
|
|
165
|
+
userAgent: { type: String, default: null },
|
|
166
|
+
ip: { type: String, default: null },
|
|
167
|
+
},
|
|
168
|
+
{ timestamps: true, versionKey: false }
|
|
169
|
+
);
|
|
170
|
+
refreshTokenSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });
|
|
171
|
+
export const RefreshToken = mongoose.model('RefreshToken', refreshTokenSchema);
|
|
172
|
+
`,
|
|
173
|
+
model: (name) => `import mongoose from 'mongoose';
|
|
106
174
|
|
|
107
|
-
|
|
175
|
+
const ${name.toLowerCase()}Schema = new mongoose.Schema(
|
|
176
|
+
{
|
|
177
|
+
name: { type: String, required: true, trim: true, maxlength: 200 },
|
|
178
|
+
description: { type: String, default: '', maxlength: 2000 },
|
|
179
|
+
isActive: { type: Boolean, default: true },
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
timestamps: true,
|
|
183
|
+
versionKey: false,
|
|
184
|
+
toJSON: {
|
|
185
|
+
transform: (_, ret) => { ret.id = ret._id?.toString(); delete ret._id; return ret; }
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
);
|
|
108
189
|
|
|
109
|
-
|
|
110
|
-
|
|
190
|
+
${name.toLowerCase()}Schema.index({ name: 1 });
|
|
191
|
+
${name.toLowerCase()}Schema.index({ isActive: 1, createdAt: -1 });
|
|
192
|
+
|
|
193
|
+
export const ${name} = mongoose.model('${name}', ${name.toLowerCase()}Schema);
|
|
194
|
+
`,
|
|
195
|
+
middleware: (name) => `/**
|
|
196
|
+
* ${name} Middleware
|
|
197
|
+
* Usage: app.use(${name.toLowerCase()}Middleware) เคตเคพ app.get('/route', ${name.toLowerCase()}Middleware, handler)
|
|
198
|
+
*/
|
|
199
|
+
export const ${name.toLowerCase()}Middleware = async (ctx, next) => {
|
|
200
|
+
// TODO: เคคเคชเคพเคเคเคเฅ logic เคฏเคนเคพเค เคฒเฅเคเฅเคจเฅเคนเฅเคธเฅ
|
|
201
|
+
console.log(\`[${name}] \${ctx.req.method} \${ctx.req.url}\`);
|
|
202
|
+
if (next) await next();
|
|
203
|
+
};
|
|
204
|
+
`,
|
|
205
|
+
route: (name) => `import { createDolphinRouter } from 'dolphin-server-modules/router';
|
|
206
|
+
|
|
207
|
+
const router = createDolphinRouter();
|
|
208
|
+
const base = '/${name.toLowerCase()}s';
|
|
209
|
+
|
|
210
|
+
router.get(base, async (ctx) => {
|
|
211
|
+
return { success: true, data: [], message: '${name} list' };
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
router.get(\`\${base}/:id\`, async (ctx) => {
|
|
215
|
+
return { success: true, data: { id: ctx.params.id } };
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
router.post(base, async (ctx) => {
|
|
219
|
+
return ctx.status(201).json({ success: true, data: ctx.body });
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
router.put(\`\${base}/:id\`, async (ctx) => {
|
|
223
|
+
return { success: true, data: { id: ctx.params.id, ...ctx.body } };
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
router.delete(\`\${base}/:id\`, async (ctx) => {
|
|
227
|
+
return { success: true, data: { id: ctx.params.id, deleted: true } };
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
export const ${name.toLowerCase()}Router = router;
|
|
231
|
+
`,
|
|
232
|
+
service: (name) => `/**
|
|
233
|
+
* ${name}Service โ Business logic layer
|
|
234
|
+
* Controller เคฐ Database เคเฅ เคฌเฅเคเคเฅ layer
|
|
235
|
+
*/
|
|
236
|
+
export class ${name}Service {
|
|
237
|
+
|
|
238
|
+
static async getAll(filter = {}) {
|
|
239
|
+
// TODO: DB query
|
|
240
|
+
return [];
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
static async getById(id) {
|
|
244
|
+
// TODO: DB findById
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
static async create(data) {
|
|
249
|
+
// TODO: DB create
|
|
250
|
+
return { id: Date.now().toString(), ...data, createdAt: new Date() };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
static async update(id, data) {
|
|
254
|
+
// TODO: DB update
|
|
255
|
+
return { id, ...data, updatedAt: new Date() };
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
static async delete(id) {
|
|
259
|
+
// TODO: DB delete
|
|
260
|
+
return { id, deleted: true };
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
`,
|
|
264
|
+
env: `# ๐ฌ Dolphin Framework โ Environment Variables
|
|
265
|
+
# โ ๏ธ เคฏเฅ file .gitignore เคฎเคพ เคฐเคพเคเฅเคจเฅเคนเฅเคธเฅ โ production เคฎเคพ NEVER commit!
|
|
266
|
+
|
|
267
|
+
NODE_ENV=development
|
|
268
|
+
PORT=3000
|
|
269
|
+
|
|
270
|
+
# MongoDB
|
|
271
|
+
MONGO_URI=mongodb://localhost:27017/dolphin_db
|
|
272
|
+
|
|
273
|
+
# JWT Secret (เคเคฎเฅเคคเฅเคฎเคพ 32 chars)
|
|
274
|
+
JWT_SECRET=change_this_ultra_secret_key_in_production_32chars
|
|
275
|
+
|
|
276
|
+
# Redis (optional โ realtime scaling)
|
|
277
|
+
# REDIS_URL=redis://localhost:6379
|
|
278
|
+
|
|
279
|
+
# AI Keys (dolphin chat/generate เคเฅ เคฒเคพเคเคฟ)
|
|
280
|
+
# GEMINI_API_KEY=your_key_here
|
|
281
|
+
# GROQ_API_KEY=your_key_here
|
|
282
|
+
# OPENAI_API_KEY=your_key_here
|
|
283
|
+
|
|
284
|
+
# Local Ollama (optional)
|
|
285
|
+
# USE_OLLAMA=true
|
|
286
|
+
# OLLAMA_MODEL=gemma3:latest
|
|
287
|
+
`,
|
|
111
288
|
};
|
|
112
289
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG;IAErB,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCR;IAEG,QAAQ,EAAE;;;;;;;;;;;;;;CAcb;IAEG,SAAS,EAAE;;;;;;;;;;;;;;;;;;;;;;;CAuBd;IAEG,KAAK,EAAE;;;;;;;;;;;;;;;;;;;CAmBV;IAEG,IAAI,EAAE;;;;;;;;;;;CAWT;IAEG,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC;;;yCAGa,IAAI;;;;;;;CAO5C;IAEG,SAAS,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC;;QAEzB,IAAI,CAAC,WAAW,EAAE;;;;;;;;;;EAUxB,IAAI,CAAC,WAAW,EAAE;EAClB,IAAI,CAAC,WAAW,EAAE;;eAEL,IAAI,sBAAsB,IAAI,MAAM,IAAI,CAAC,WAAW,EAAE;CACpE;IAEG,SAAS,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCd;IAEG,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC;;QAErB,IAAI,CAAC,WAAW,EAAE;;;;;;;;;;;;;;;EAexB,IAAI,CAAC,WAAW,EAAE;EAClB,IAAI,CAAC,WAAW,EAAE;;eAEL,IAAI,sBAAsB,IAAI,MAAM,IAAI,CAAC,WAAW,EAAE;CACpE;IAEG,UAAU,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC;KAC7B,IAAI;oBACW,IAAI,CAAC,WAAW,EAAE,sCAAsC,IAAI,CAAC,WAAW,EAAE;;eAE/E,IAAI,CAAC,WAAW,EAAE;;mBAEd,IAAI;;;CAGtB;IAEG,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC;;;iBAGZ,IAAI,CAAC,WAAW,EAAE;;;gDAGa,IAAI;;;;;;;;;;;;;;;;;;;eAmBrC,IAAI,CAAC,WAAW,EAAE;CAChC;IAEG,OAAO,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC;KAC1B,IAAI;;;eAGM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BlB;IAEG,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;;;;CAuBR;CACA,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// test-2fa-real.ts
|
|
2
|
+
import { createAuth } from "./auth/auth";
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
import argon2 from "argon2";
|
|
5
|
+
// Helper to simulate a TOTP app (reusing logic from auth.ts)
|
|
6
|
+
const BASE32_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
|
7
|
+
const base32Decode = (str) => {
|
|
8
|
+
str = str.replace(/=/g, '').toUpperCase();
|
|
9
|
+
let bits = 0, value = 0;
|
|
10
|
+
const bytes = [];
|
|
11
|
+
for (let i = 0; i < str.length; i++) {
|
|
12
|
+
const idx = BASE32_CHARS.indexOf(str[i]);
|
|
13
|
+
value = (value << 5) | idx;
|
|
14
|
+
bits += 5;
|
|
15
|
+
if (bits >= 8) {
|
|
16
|
+
bytes.push((value >>> (bits - 8)) & 255);
|
|
17
|
+
bits -= 8;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return Buffer.from(bytes);
|
|
21
|
+
};
|
|
22
|
+
const generateTOTP = (secretBase32, timestamp = Date.now()) => {
|
|
23
|
+
const counter = Math.floor(timestamp / 30000);
|
|
24
|
+
const counterBuf = Buffer.alloc(8);
|
|
25
|
+
counterBuf.writeBigInt64BE(BigInt(counter), 0);
|
|
26
|
+
const secret = base32Decode(secretBase32);
|
|
27
|
+
const hmac = crypto.createHmac('sha1', secret);
|
|
28
|
+
hmac.update(counterBuf);
|
|
29
|
+
const hash = hmac.digest();
|
|
30
|
+
const offset = hash[hash.length - 1] & 0xf;
|
|
31
|
+
const code = (hash.readUInt32BE(offset) & 0x7fffffff) % 1000000;
|
|
32
|
+
return code.toString().padStart(6, '0');
|
|
33
|
+
};
|
|
34
|
+
async function run2FATest() {
|
|
35
|
+
console.log("๐ Starting 'Real' 2FA Flow Test...\n");
|
|
36
|
+
const auth = createAuth({ secret: 'test-secret' });
|
|
37
|
+
// 1. Mock DB state
|
|
38
|
+
let mockUser = {
|
|
39
|
+
id: "user123",
|
|
40
|
+
email: "test@example.com",
|
|
41
|
+
password: await argon2.hash("password123"),
|
|
42
|
+
twoFactorEnabled: false,
|
|
43
|
+
twoFactorSecret: null,
|
|
44
|
+
pending2FASecret: null,
|
|
45
|
+
recoveryCodes: []
|
|
46
|
+
};
|
|
47
|
+
const db = {
|
|
48
|
+
findUserById: async () => mockUser,
|
|
49
|
+
findUserByEmail: async () => mockUser,
|
|
50
|
+
updateUser: async (id, data) => {
|
|
51
|
+
mockUser = { ...mockUser, ...data };
|
|
52
|
+
return mockUser;
|
|
53
|
+
},
|
|
54
|
+
saveRefreshToken: async () => { },
|
|
55
|
+
findRefreshToken: async () => null,
|
|
56
|
+
deleteRefreshToken: async () => { }
|
|
57
|
+
};
|
|
58
|
+
// --- STEP 1: Enable 2FA ---
|
|
59
|
+
console.log("Step 1: Enabling 2FA (Generating Secret)...");
|
|
60
|
+
const setup = await auth.enable2FA(db, mockUser.id);
|
|
61
|
+
console.log("โ
Secret Generated:", setup.secret);
|
|
62
|
+
console.log("โ
URI:", setup.uri);
|
|
63
|
+
// --- STEP 2: Verify 2FA ---
|
|
64
|
+
console.log("\nStep 2: Verifying 2FA with TOTP Token...");
|
|
65
|
+
const realToken = generateTOTP(setup.secret);
|
|
66
|
+
console.log("๐ฑ Simulated App Token:", realToken);
|
|
67
|
+
const verifyResult = await auth.verify2FA(db, mockUser.id, realToken);
|
|
68
|
+
console.log("โ
2FA Verified! Recovery Codes:", verifyResult.recoveryCodes);
|
|
69
|
+
console.log("โ
User 2FA Status:", mockUser.twoFactorEnabled ? "ENABLED" : "FAILED");
|
|
70
|
+
// --- STEP 3: Login without TOTP (Should fail) ---
|
|
71
|
+
console.log("\nStep 3: Attempting Login WITHOUT TOTP...");
|
|
72
|
+
try {
|
|
73
|
+
await auth.login(db, { email: mockUser.email, password: "password123" });
|
|
74
|
+
console.log("โ FAILED: Login succeeded without TOTP!");
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
console.log("โ
SUCCESS: Login denied as expected:", err.message);
|
|
78
|
+
}
|
|
79
|
+
// --- STEP 4: Login with correct TOTP ---
|
|
80
|
+
console.log("\nStep 4: Attempting Login WITH correct TOTP...");
|
|
81
|
+
const loginToken = generateTOTP(setup.secret);
|
|
82
|
+
const loginResult = await auth.login(db, { email: mockUser.email, password: "password123", totp: loginToken });
|
|
83
|
+
console.log("โ
SUCCESS: Logged in! Access Token length:", loginResult.accessToken.length);
|
|
84
|
+
// --- STEP 5: Test Recovery Codes ---
|
|
85
|
+
console.log("\nStep 5: Testing Recovery Code Login...");
|
|
86
|
+
const backupCode = verifyResult.recoveryCodes[0];
|
|
87
|
+
const recoveryResult = await auth.login(db, {
|
|
88
|
+
email: mockUser.email,
|
|
89
|
+
password: "password123",
|
|
90
|
+
recovery: backupCode
|
|
91
|
+
});
|
|
92
|
+
console.log("โ
SUCCESS: Logged in using recovery code!");
|
|
93
|
+
console.log("โ
Remaining recovery codes count:", mockUser.recoveryCodes.length);
|
|
94
|
+
// --- STEP 6: Disable 2FA ---
|
|
95
|
+
console.log("\nStep 6: Disabling 2FA...");
|
|
96
|
+
const disableToken = generateTOTP(setup.secret);
|
|
97
|
+
await auth.disable2FA(db, mockUser.id, disableToken);
|
|
98
|
+
console.log("โ
SUCCESS: 2FA Disabled. Status:", mockUser.twoFactorEnabled ? "ENABLED (Error)" : "DISABLED");
|
|
99
|
+
console.log("\n๐ ALL 2FA FLOWS COMPLETED SUCCESSFULLY! ๐");
|
|
100
|
+
}
|
|
101
|
+
run2FATest().catch(err => {
|
|
102
|
+
console.error("โ TEST FAILED:", err);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
});
|
|
105
|
+
//# sourceMappingURL=test-2fa-real.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-2fa-real.js","sourceRoot":"","sources":["../src/test-2fa-real.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// test-dolphin.ts
|
|
2
|
+
import { createDolphinServer } from "./server/server";
|
|
3
|
+
import { createDolphinController } from "./controller/controller";
|
|
4
|
+
import { createDolphinAuthController } from "./authController/authController";
|
|
5
|
+
// Mock Database Connection (Replacing ./config.js)
|
|
6
|
+
const dbConnect = async () => {
|
|
7
|
+
console.log("๐ ๏ธ Mock Database Connected");
|
|
8
|
+
};
|
|
9
|
+
// Mock Database Interface (Replacing ./auth/model.js)
|
|
10
|
+
const db = {
|
|
11
|
+
createUser: async (data) => ({ id: "123", ...data }),
|
|
12
|
+
findUserByEmail: async (email) => ({ id: "123", email, password: "hashed_password", role: "admin" }),
|
|
13
|
+
findUserById: async (id) => ({ id, email: "user@example.com", role: "admin" }),
|
|
14
|
+
updateUser: async (id, data) => ({ id, ...data }),
|
|
15
|
+
saveRefreshToken: async () => { },
|
|
16
|
+
findRefreshToken: async () => ({ userId: "123", expiresAt: new Date(Date.now() + 10000) }),
|
|
17
|
+
deleteRefreshToken: async () => { },
|
|
18
|
+
// For CRUD
|
|
19
|
+
read: async () => [{ id: "123", name: "John Doe" }],
|
|
20
|
+
create: async (data) => ({ id: "456", ...data }),
|
|
21
|
+
update: async (id, data) => ({ id, ...data }),
|
|
22
|
+
delete: async (id) => ({ id })
|
|
23
|
+
};
|
|
24
|
+
async function main() {
|
|
25
|
+
const app = createDolphinServer();
|
|
26
|
+
await dbConnect();
|
|
27
|
+
// ============ SETUP AUTH ============
|
|
28
|
+
const auth = createDolphinAuthController(db, {
|
|
29
|
+
secret: process.env.JWT_SECRET || 'my-super-secret-key',
|
|
30
|
+
cookieMaxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
31
|
+
issuer: 'MyApp'
|
|
32
|
+
});
|
|
33
|
+
// ============ CRUD CONTROLLER ============
|
|
34
|
+
const userController = createDolphinController(db, "User");
|
|
35
|
+
// ============ PUBLIC ROUTES (No Auth) ============
|
|
36
|
+
app.post("/auth/register", async (ctx) => {
|
|
37
|
+
const result = await auth.register(ctx);
|
|
38
|
+
return result; // Using the new auto-reply feature!
|
|
39
|
+
});
|
|
40
|
+
app.post("/auth/login", async (ctx) => {
|
|
41
|
+
return await auth.login(ctx);
|
|
42
|
+
});
|
|
43
|
+
app.post("/auth/refresh", async (ctx) => {
|
|
44
|
+
return await auth.refresh(ctx);
|
|
45
|
+
});
|
|
46
|
+
// ============ PROTECTED ROUTES (Auth Required) ============
|
|
47
|
+
// โ
NOW SUPPORTED: Multiple handlers (middleware + final handler)
|
|
48
|
+
app.get("/auth/me", auth.requireAuth, async (ctx) => {
|
|
49
|
+
const result = await auth.me(ctx);
|
|
50
|
+
return result;
|
|
51
|
+
});
|
|
52
|
+
app.post("/auth/logout", auth.requireAuth, async (ctx) => {
|
|
53
|
+
return await auth.logout(ctx);
|
|
54
|
+
});
|
|
55
|
+
// ============ PROTECTED CRUD ROUTES (Auth Required) ============
|
|
56
|
+
app.get("/user", auth.requireAuth, async (ctx) => {
|
|
57
|
+
const users = await userController.list(ctx, ctx.req.user?.id);
|
|
58
|
+
return users.map((user) => auth.sanitize(user));
|
|
59
|
+
});
|
|
60
|
+
app.post("/user", auth.requireAuth, async (ctx) => {
|
|
61
|
+
const user = await userController.create(ctx, ctx.req.user?.id);
|
|
62
|
+
return auth.sanitize(user);
|
|
63
|
+
});
|
|
64
|
+
// ============ ADMIN ROUTES ============
|
|
65
|
+
app.get("/admin/users", auth.requireAdmin, async (ctx) => {
|
|
66
|
+
const users = await userController.list(ctx);
|
|
67
|
+
return users.map(auth.sanitize);
|
|
68
|
+
});
|
|
69
|
+
// ============ START SERVER ============
|
|
70
|
+
const PORT = 3000;
|
|
71
|
+
app.listen(PORT, () => {
|
|
72
|
+
console.log(`
|
|
73
|
+
๐ Dolphin Server running on port ${PORT}
|
|
74
|
+
|
|
75
|
+
๐ Available Routes:
|
|
76
|
+
|
|
77
|
+
๐ PUBLIC ROUTES:
|
|
78
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
79
|
+
โ POST /auth/register โ
|
|
80
|
+
โ POST /auth/login โ
|
|
81
|
+
โ POST /auth/refresh โ
|
|
82
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
|
83
|
+
โ ๐ PROTECTED ROUTES (Auth Required): โ
|
|
84
|
+
โ GET /auth/me โ
|
|
85
|
+
โ POST /auth/logout โ
|
|
86
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
|
87
|
+
โ ๐ค USER CRUD (Protected): โ
|
|
88
|
+
โ GET /user โ
|
|
89
|
+
โ POST /user โ
|
|
90
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
|
91
|
+
โ ๐ ADMIN ROUTES: โ
|
|
92
|
+
โ GET /admin/users โ
|
|
93
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
94
|
+
`);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
main().catch(console.error);
|
|
98
|
+
//# sourceMappingURL=test-dolphin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-dolphin.js","sourceRoot":"","sources":["../src/test-dolphin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dolphin Universal Context Builder
|
|
3
|
+
*
|
|
4
|
+
* Dolphin modules (auth-controller, crud, router) เคฒเฅ ctx object use เคเคฐเฅเคเคจเฅเฅค
|
|
5
|
+
* เคฏเฅ helper เคฒเฅ เคเฅเคจเฅ เคชเคจเคฟ framework เคเฅ req/res เคฌเคพเค ctx เคฌเคจเคพเคเคเคเฅค
|
|
6
|
+
*
|
|
7
|
+
* โโโ Express โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
8
|
+
* import { createCtx } from 'dolphin-server-modules/utils/ctx';
|
|
9
|
+
* app.post('/login', (req, res) => auth.login(createCtx(req, res)));
|
|
10
|
+
*
|
|
11
|
+
* โโโ Fastify โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
12
|
+
* fastify.post('/login', (req, reply) =>
|
|
13
|
+
* auth.login(createCtx(req.raw, reply.raw, req.body, req.params, req.query))
|
|
14
|
+
* );
|
|
15
|
+
*
|
|
16
|
+
* โโโ Next.js API Route โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
17
|
+
* export default async function handler(req, res) {
|
|
18
|
+
* return auth.login(createCtx(req, res));
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* โโโ Hono โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
22
|
+
* app.post('/login', async (c) => {
|
|
23
|
+
* const ctx = createCtx(c.req.raw, c.res, await c.req.json(), c.req.param());
|
|
24
|
+
* return auth.login(ctx);
|
|
25
|
+
* });
|
|
26
|
+
*/
|
|
27
|
+
export interface DolphinCtx {
|
|
28
|
+
req: any;
|
|
29
|
+
res: any;
|
|
30
|
+
params: Record<string, string>;
|
|
31
|
+
query: Record<string, string>;
|
|
32
|
+
body: any;
|
|
33
|
+
state: Record<string, any>;
|
|
34
|
+
json: (data: any, status?: number) => DolphinCtx;
|
|
35
|
+
text: (data: any, status?: number) => DolphinCtx;
|
|
36
|
+
html: (data: any, status?: number) => DolphinCtx;
|
|
37
|
+
status: (code: number) => DolphinCtx;
|
|
38
|
+
setHeader: (name: string, value: string) => DolphinCtx;
|
|
39
|
+
getHeader: (name: string) => string | undefined;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* เคเฅเคจเฅ เคชเคจเคฟ framework เคเฅ req/res เคฌเคพเค Dolphin ctx เคฌเคจเคพเคเคจเฅ
|
|
43
|
+
* @param req - Express req / Fastify request.raw / Next.js req / Node.js IncomingMessage
|
|
44
|
+
* @param res - Express res / Fastify reply.raw / Next.js res / Node.js ServerResponse
|
|
45
|
+
* @param body - parsed body (req.body เคตเคพ await req.json())
|
|
46
|
+
* @param params - route params ({ id: '123' })
|
|
47
|
+
* @param query - query string params
|
|
48
|
+
*/
|
|
49
|
+
export declare function createCtx(req: any, res: any, body?: any, params?: Record<string, string>, query?: Record<string, string>): DolphinCtx;
|
|
50
|
+
export default createCtx;
|