@codenokami/node-api-master 1.4.1 → 1.5.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/dist/AppError-ByGDb4IL.d.mts +20 -0
- package/dist/AppError-ByGDb4IL.d.ts +20 -0
- package/dist/chunk-B3SAPWGT.mjs +1 -0
- package/dist/chunk-ZJQTZFDU.js +1 -0
- package/dist/index.d.mts +5 -183
- package/dist/index.d.ts +5 -183
- package/dist/index.js +1 -415
- package/dist/index.mjs +1 -372
- package/dist/socket.d.mts +55 -0
- package/dist/socket.d.ts +55 -0
- package/dist/socket.js +1 -0
- package/dist/socket.mjs +1 -0
- package/dist/validation.d.mts +101 -0
- package/dist/validation.d.ts +101 -0
- package/dist/validation.js +1 -0
- package/dist/validation.mjs +1 -0
- package/package.json +15 -15
package/dist/index.mjs
CHANGED
|
@@ -1,372 +1 @@
|
|
|
1
|
-
var
|
|
2
|
-
var __export = (target, all) => {
|
|
3
|
-
for (var name in all)
|
|
4
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
// src/index.js
|
|
8
|
-
import Joi3 from "joi";
|
|
9
|
-
|
|
10
|
-
// src/db/connection.js
|
|
11
|
-
import mongoose from "mongoose";
|
|
12
|
-
var connectDB = async (url) => {
|
|
13
|
-
if (!url) {
|
|
14
|
-
console.error(
|
|
15
|
-
"\u274C Error: MongoDB URL is required to connect to the database."
|
|
16
|
-
);
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
try {
|
|
20
|
-
const conn = await mongoose.connect(url);
|
|
21
|
-
console.log(`\u2705 MongoDB Connected: ${conn.connection.host}`);
|
|
22
|
-
} catch (error) {
|
|
23
|
-
console.error(`\u274C Error: ${error.message}`);
|
|
24
|
-
process.exit(1);
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
var connection_default = connectDB;
|
|
28
|
-
|
|
29
|
-
// src/middleware/auth.js
|
|
30
|
-
import jwt from "jsonwebtoken";
|
|
31
|
-
|
|
32
|
-
// src/utils/AppError.js
|
|
33
|
-
var AppError = class extends Error {
|
|
34
|
-
constructor(message, statusCode) {
|
|
35
|
-
super(message);
|
|
36
|
-
this.statusCode = statusCode;
|
|
37
|
-
this.status = `${statusCode}`.startsWith("4") ? "fail" : "error";
|
|
38
|
-
this.isOperational = true;
|
|
39
|
-
Error.captureStackTrace(this, this.constructor);
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
var AppError_default = AppError;
|
|
43
|
-
|
|
44
|
-
// src/utils/catchAsync.js
|
|
45
|
-
var catchAsync = (fn) => {
|
|
46
|
-
return (req, res, next) => {
|
|
47
|
-
fn(req, res, next).catch(next);
|
|
48
|
-
};
|
|
49
|
-
};
|
|
50
|
-
var catchAsync_default = catchAsync;
|
|
51
|
-
|
|
52
|
-
// src/middleware/auth.js
|
|
53
|
-
var auth = (secret = process.env.JWT_SECRET) => catchAsync_default(async (req, res, next) => {
|
|
54
|
-
let token;
|
|
55
|
-
if (req.headers.authorization && req.headers.authorization.startsWith("Bearer")) {
|
|
56
|
-
token = req.headers.authorization.split(" ")[1];
|
|
57
|
-
} else if (req.cookies && req.cookies.jwt) {
|
|
58
|
-
token = req.cookies.jwt;
|
|
59
|
-
}
|
|
60
|
-
if (!secret) {
|
|
61
|
-
return next(
|
|
62
|
-
new AppError_default("JWT Secret is not defined in environment variables", 500)
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
if (!token) {
|
|
66
|
-
return next(
|
|
67
|
-
new AppError_default(
|
|
68
|
-
"You are not logged in! Please log in to get access.",
|
|
69
|
-
401
|
|
70
|
-
)
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
try {
|
|
74
|
-
const decoded = jwt.verify(token, secret);
|
|
75
|
-
req.user = decoded;
|
|
76
|
-
next();
|
|
77
|
-
} catch (error) {
|
|
78
|
-
return next(
|
|
79
|
-
new AppError_default("Invalid token or expired. Please log in again.", 401)
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
var admin = (req, res, next) => {
|
|
84
|
-
if (req.user && req.user.role === "admin") {
|
|
85
|
-
next();
|
|
86
|
-
} else {
|
|
87
|
-
return next(
|
|
88
|
-
new AppError_default("You do not have permission to perform this action", 403)
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
// src/middleware/validate.js
|
|
94
|
-
var validate = (schema) => (req, res, next) => {
|
|
95
|
-
const { error, value } = schema.validate(req.body, {
|
|
96
|
-
abortEarly: false,
|
|
97
|
-
// Error အားလုံးကို တစ်ခါတည်း ပြရန်
|
|
98
|
-
allowUnknown: true,
|
|
99
|
-
// Schema ထဲမပါတဲ့ field တွေပါလာရင် လက်ခံရန်
|
|
100
|
-
stripUnknown: true
|
|
101
|
-
// Schema ထဲမပါတဲ့ field တွေကို ဖယ်ထုတ်ပစ်ရန်
|
|
102
|
-
});
|
|
103
|
-
if (error) {
|
|
104
|
-
const errorMessage = error.details.map((detail) => detail.message.replace(/"/g, "")).join(", ");
|
|
105
|
-
return next(new AppError_default(errorMessage, 400));
|
|
106
|
-
}
|
|
107
|
-
req.body = value;
|
|
108
|
-
next();
|
|
109
|
-
};
|
|
110
|
-
var validate_default = validate;
|
|
111
|
-
|
|
112
|
-
// src/utils/constants.js
|
|
113
|
-
var PORT = process.env.PORT || 5e3;
|
|
114
|
-
var STATUS_CODES = {
|
|
115
|
-
// --- 2xx Success ---
|
|
116
|
-
OK: 200,
|
|
117
|
-
// Request အောင်မြင်သည်
|
|
118
|
-
CREATED: 201,
|
|
119
|
-
// Data အသစ် တည်ဆောက်မှု အောင်မြင်သည်
|
|
120
|
-
ACCEPTED: 202,
|
|
121
|
-
// လက်ခံရရှိသည် (နောက်မှ အလုပ်လုပ်မည်)
|
|
122
|
-
NO_CONTENT: 204,
|
|
123
|
-
// အောင်မြင်သည်၊ သို့သော် ပြစရာ Data မရှိ (ဥပမာ- Delete လုပ်ပြီးချိန်)
|
|
124
|
-
// --- 3xx Redirection ---
|
|
125
|
-
MOVED_PERMANENTLY: 301,
|
|
126
|
-
FOUND: 302,
|
|
127
|
-
// --- 4xx Client Errors ---
|
|
128
|
-
BAD_REQUEST: 400,
|
|
129
|
-
// ပေးပို့လိုက်သော Data Format မှားနေသည် (Validation error)
|
|
130
|
-
UNAUTHORIZED: 401,
|
|
131
|
-
// Login ဝင်ရန် လိုအပ်သည် (သို့မဟုတ် Token မှားသည်)
|
|
132
|
-
FORBIDDEN: 403,
|
|
133
|
-
// လုပ်ပိုင်ခွင့်မရှိ (ဥပမာ- Admin မဟုတ်ဘဲ Admin panel ဝင်ခြင်း)
|
|
134
|
-
NOT_FOUND: 404,
|
|
135
|
-
// ရှာဖွေနေသော Resource မရှိပါ
|
|
136
|
-
METHOD_NOT_ALLOWED: 405,
|
|
137
|
-
// API Method (GET, POST, etc.) မှားနေသည်
|
|
138
|
-
CONFLICT: 409,
|
|
139
|
-
// Data ထပ်နေသည် (ဥပမာ- ရှိပြီးသား Email နဲ့ Register လုပ်ခြင်း)
|
|
140
|
-
UNPROCESSABLE_ENTITY: 422,
|
|
141
|
-
// Validation Error များအတွက် အသုံးများသည်
|
|
142
|
-
TOO_MANY_REQUESTS: 429,
|
|
143
|
-
// API ကို ခဏခဏ ဆက်တိုက်ခေါ်ခြင်း (Rate limiting)
|
|
144
|
-
// --- 5xx Server Errors ---
|
|
145
|
-
INTERNAL_SERVER_ERROR: 500,
|
|
146
|
-
// Server ထဲတွင် Code မှားယွင်းခြင်း
|
|
147
|
-
NOT_IMPLEMENTED: 501,
|
|
148
|
-
BAD_GATEWAY: 502,
|
|
149
|
-
SERVICE_UNAVAILABLE: 503,
|
|
150
|
-
// Server ခေတ္တပိတ်ထားသည်
|
|
151
|
-
GATEWAY_TIMEOUT: 504,
|
|
152
|
-
PORT
|
|
153
|
-
};
|
|
154
|
-
var constants_default = STATUS_CODES;
|
|
155
|
-
|
|
156
|
-
// src/middleware/errorMiddleware.js
|
|
157
|
-
var errorMiddleware = (err, req, res, next) => {
|
|
158
|
-
err.statusCode = err.statusCode || constants_default.INTERNAL_SERVER_ERROR;
|
|
159
|
-
err.status = err.status || "error";
|
|
160
|
-
if (process.env.NODE_ENV === "development") {
|
|
161
|
-
res.status(err.statusCode).json({
|
|
162
|
-
status: err.status,
|
|
163
|
-
error: err,
|
|
164
|
-
message: err.message,
|
|
165
|
-
stack: err.stack
|
|
166
|
-
});
|
|
167
|
-
} else {
|
|
168
|
-
if (err.isOperational) {
|
|
169
|
-
res.status(err.statusCode).json({
|
|
170
|
-
status: err.status,
|
|
171
|
-
message: err.message
|
|
172
|
-
});
|
|
173
|
-
} else {
|
|
174
|
-
console.error("ERROR \u{1F4A5}", err);
|
|
175
|
-
res.status(constants_default.INTERNAL_SERVER_ERROR).json({
|
|
176
|
-
status: "error",
|
|
177
|
-
message: "Something went very wrong!"
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
};
|
|
182
|
-
var errorMiddleware_default = errorMiddleware;
|
|
183
|
-
|
|
184
|
-
// src/utils/response.js
|
|
185
|
-
var response_exports = {};
|
|
186
|
-
__export(response_exports, {
|
|
187
|
-
default: () => response_default
|
|
188
|
-
});
|
|
189
|
-
var apiResponse = {
|
|
190
|
-
// အောင်မြင်တဲ့ response ပေးပို့ရန်
|
|
191
|
-
success: (res, data, message = "Success", statusCode = constants_default.OK) => {
|
|
192
|
-
return res.status(statusCode).json({
|
|
193
|
-
status: "success",
|
|
194
|
-
message,
|
|
195
|
-
data
|
|
196
|
-
});
|
|
197
|
-
},
|
|
198
|
-
// Error response ပေးပို့ရန် (Operational error များအတွက်)
|
|
199
|
-
error: (res, message = "Internal Server Error", statusCode = constants_default.INTERNAL_SERVER_ERROR) => {
|
|
200
|
-
return res.status(statusCode).json({
|
|
201
|
-
status: "error",
|
|
202
|
-
message
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
var response_default = apiResponse;
|
|
207
|
-
|
|
208
|
-
// src/utils/authHelper.js
|
|
209
|
-
import bcrypt from "bcryptjs";
|
|
210
|
-
import jwt2 from "jsonwebtoken";
|
|
211
|
-
var hashPassword = async (password) => {
|
|
212
|
-
const salt = await bcrypt.genSalt(10);
|
|
213
|
-
return await bcrypt.hash(password, salt);
|
|
214
|
-
};
|
|
215
|
-
var comparePassword = async (password, hashedPassword) => {
|
|
216
|
-
return await bcrypt.compare(password, hashedPassword);
|
|
217
|
-
};
|
|
218
|
-
var generateToken = (payload, res, options = {}) => {
|
|
219
|
-
const secret = options.secret || process.env.JWT_SECRET;
|
|
220
|
-
const expiresIn = options.expiresIn || "30d";
|
|
221
|
-
const cookieName = options.cookieName || "jwt";
|
|
222
|
-
const token = jwt2.sign(payload, secret, {
|
|
223
|
-
expiresIn
|
|
224
|
-
});
|
|
225
|
-
const cookieOptions = {
|
|
226
|
-
maxAge: options.maxAge || 30 * 24 * 60 * 60 * 1e3,
|
|
227
|
-
// Default 30 days
|
|
228
|
-
httpOnly: true,
|
|
229
|
-
// JavaScript မှ ဖတ်မရအောင် (Prevent XSS)
|
|
230
|
-
sameSite: process.env.NODE_ENV === "production" ? "none" : "lax",
|
|
231
|
-
// CSRF Protection
|
|
232
|
-
secure: process.env.NODE_ENV === "production",
|
|
233
|
-
// Production တွင် HTTPS သုံးမှသာ အလုပ်လုပ်မည်
|
|
234
|
-
...options.extraCookieOptions
|
|
235
|
-
// တခြား အပို options များရှိလျှင် ထည့်ရန်
|
|
236
|
-
};
|
|
237
|
-
res.cookie(cookieName, token, cookieOptions);
|
|
238
|
-
return token;
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
// src/utils/uuid.js
|
|
242
|
-
import crypto from "crypto";
|
|
243
|
-
var generateUUID = () => {
|
|
244
|
-
if (typeof crypto.randomUUID === "function") {
|
|
245
|
-
return crypto.randomUUID();
|
|
246
|
-
}
|
|
247
|
-
return ("10000000-1000-4000-8000" + -1e11).replace(
|
|
248
|
-
/[018]/g,
|
|
249
|
-
(c) => (c ^ crypto.randomBytes(1).readUInt8() & 15 >> c / 4).toString(16)
|
|
250
|
-
);
|
|
251
|
-
};
|
|
252
|
-
var uuid_default = generateUUID;
|
|
253
|
-
|
|
254
|
-
// src/validations/user.schema.js
|
|
255
|
-
import Joi from "joi";
|
|
256
|
-
var userSchema = {
|
|
257
|
-
// Standard Register Schema
|
|
258
|
-
register: Joi.object({
|
|
259
|
-
username: Joi.string().alphanum().min(3).max(30).required().messages({
|
|
260
|
-
"string.min": "Username must be at least 3 characters long",
|
|
261
|
-
"any.required": "Username is a required field"
|
|
262
|
-
}),
|
|
263
|
-
email: Joi.string().email({ minDomainSegments: 2, tlds: { allow: ["com", "net", "org"] } }).required().messages({
|
|
264
|
-
"string.email": "Please provide a valid email address"
|
|
265
|
-
}),
|
|
266
|
-
password: Joi.string().min(8).required().messages({
|
|
267
|
-
"string.min": "Password must be at least 8 characters long"
|
|
268
|
-
}),
|
|
269
|
-
confirmPassword: Joi.any().equal(Joi.ref("password")).required().messages({ "any.only": "Passwords do not match" }),
|
|
270
|
-
role: Joi.string().valid("user", "admin").default("user")
|
|
271
|
-
}),
|
|
272
|
-
// Login Schema
|
|
273
|
-
login: Joi.object({
|
|
274
|
-
email: Joi.string().email().required(),
|
|
275
|
-
password: Joi.string().required()
|
|
276
|
-
}),
|
|
277
|
-
// Password Update Schema
|
|
278
|
-
updatePassword: Joi.object({
|
|
279
|
-
currentPassword: Joi.string().required(),
|
|
280
|
-
newPassword: Joi.string().min(8).required()
|
|
281
|
-
}),
|
|
282
|
-
/**
|
|
283
|
-
* စိတ်ကြိုက် schema အသစ်ဆောက်ချင်ရင် သုံးရန် (Dynamic Flexibility)
|
|
284
|
-
* @param {Object} schemaDefinition - Joi object definition
|
|
285
|
-
*/
|
|
286
|
-
custom: (schemaDefinition) => Joi.object(schemaDefinition)
|
|
287
|
-
};
|
|
288
|
-
var user_schema_default = userSchema;
|
|
289
|
-
|
|
290
|
-
// src/validations/common.schema.js
|
|
291
|
-
import Joi2 from "joi";
|
|
292
|
-
var commonSchema = {
|
|
293
|
-
// MongoDB ObjectId စစ်ဆေးရန် (24 hex characters)
|
|
294
|
-
objectId: Joi2.string().regex(/^[0-9a-fA-F]{24}$/).messages({
|
|
295
|
-
"string.pattern.base": "Invalid ID format. Must be a valid ObjectId."
|
|
296
|
-
}),
|
|
297
|
-
// Pagination အတွက် (Query strings)
|
|
298
|
-
pagination: Joi2.object({
|
|
299
|
-
page: Joi2.number().integer().min(1).default(1),
|
|
300
|
-
limit: Joi2.number().integer().min(1).max(100).default(10),
|
|
301
|
-
sort: Joi2.string().optional(),
|
|
302
|
-
fields: Joi2.string().optional()
|
|
303
|
-
})
|
|
304
|
-
};
|
|
305
|
-
var common_schema_default = commonSchema;
|
|
306
|
-
|
|
307
|
-
// src/validations/index.js
|
|
308
|
-
var schemas = {
|
|
309
|
-
user: user_schema_default,
|
|
310
|
-
common: common_schema_default
|
|
311
|
-
};
|
|
312
|
-
var validations_default = schemas;
|
|
313
|
-
|
|
314
|
-
// src/socket/index.js
|
|
315
|
-
var socket_exports = {};
|
|
316
|
-
__export(socket_exports, {
|
|
317
|
-
getIO: () => getIO,
|
|
318
|
-
initSocket: () => initSocket
|
|
319
|
-
});
|
|
320
|
-
import { Server } from "socket.io";
|
|
321
|
-
import jwt3 from "jsonwebtoken";
|
|
322
|
-
var io;
|
|
323
|
-
var socketAuth = (secret) => {
|
|
324
|
-
return (socket, next) => {
|
|
325
|
-
var _a, _b;
|
|
326
|
-
const token = ((_a = socket.handshake.auth) == null ? void 0 : _a.token) || ((_b = socket.handshake.headers) == null ? void 0 : _b.token);
|
|
327
|
-
if (!token) {
|
|
328
|
-
return next(new Error("Authentication error: Token missing"));
|
|
329
|
-
}
|
|
330
|
-
try {
|
|
331
|
-
const decoded = jwt3.verify(token, secret || process.env.JWT_SECRET);
|
|
332
|
-
socket.user = decoded;
|
|
333
|
-
next();
|
|
334
|
-
} catch (err) {
|
|
335
|
-
next(new Error("Authentication error: Invalid token"));
|
|
336
|
-
}
|
|
337
|
-
};
|
|
338
|
-
};
|
|
339
|
-
var initSocket = (server, options = {}) => {
|
|
340
|
-
io = new Server(server, {
|
|
341
|
-
cors: {
|
|
342
|
-
origin: options.origin || "*"
|
|
343
|
-
},
|
|
344
|
-
...options
|
|
345
|
-
});
|
|
346
|
-
if (options.authRequired) {
|
|
347
|
-
io.use(socketAuth(options.jwtSecret));
|
|
348
|
-
}
|
|
349
|
-
return io;
|
|
350
|
-
};
|
|
351
|
-
var getIO = () => {
|
|
352
|
-
if (!io) throw new Error("Socket.io not initialized!");
|
|
353
|
-
return io;
|
|
354
|
-
};
|
|
355
|
-
export {
|
|
356
|
-
AppError_default as AppError,
|
|
357
|
-
Joi3 as Joi,
|
|
358
|
-
constants_default as STATUS_CODES,
|
|
359
|
-
admin,
|
|
360
|
-
response_exports as apiResponse,
|
|
361
|
-
auth,
|
|
362
|
-
catchAsync_default as catchAsync,
|
|
363
|
-
comparePassword,
|
|
364
|
-
connection_default as connectDB,
|
|
365
|
-
errorMiddleware_default as errorMiddleware,
|
|
366
|
-
generateToken,
|
|
367
|
-
uuid_default as generateUUID,
|
|
368
|
-
hashPassword,
|
|
369
|
-
validations_default as schemas,
|
|
370
|
-
socket_exports as socket,
|
|
371
|
-
validate_default as validate
|
|
372
|
-
};
|
|
1
|
+
import{a as c}from"./chunk-B3SAPWGT.mjs";import d from"mongoose";var R=async e=>{e||(console.error("\u274C Error: MongoDB URL is required to connect to the database."),process.exit(1));try{let t=await d.connect(e);console.log(`\u2705 MongoDB Connected: ${t.connection.host}`)}catch(t){console.error(`\u274C Error: ${t.message}`),process.exit(1)}},T=R;import O from"jsonwebtoken";var f=e=>(t,o,r)=>{e(t,o,r).catch(r)},m=f;var N=(e=process.env.JWT_SECRET,t={})=>m(async(o,r,n)=>{let a;if(o.headers.authorization&&o.headers.authorization.startsWith("Bearer")?a=o.headers.authorization.split(" ")[1]:o.cookies&&o.cookies[t.cookieName||"jwt"]&&(a=o.cookies[t.cookieName||"jwt"]),!e)return n(new c("JWT Secret is not defined in environment variables",500));if(!a)return n(new c("You are not logged in! Please log in to get access.",401));try{let i=O.verify(a,e);o.user=i,n()}catch{return n(new c("Invalid token or expired. Please log in again.",401))}}),l=(e,t,o)=>{if(e.user&&e.user.role==="admin")o();else return o(new c("You do not have permission to perform this action",403))};var A=process.env.PORT||5e3,S={OK:200,CREATED:201,ACCEPTED:202,NO_CONTENT:204,MOVED_PERMANENTLY:301,FOUND:302,BAD_REQUEST:400,UNAUTHORIZED:401,FORBIDDEN:403,NOT_FOUND:404,METHOD_NOT_ALLOWED:405,CONFLICT:409,UNPROCESSABLE_ENTITY:422,TOO_MANY_REQUESTS:429,INTERNAL_SERVER_ERROR:500,NOT_IMPLEMENTED:501,BAD_GATEWAY:502,SERVICE_UNAVAILABLE:503,GATEWAY_TIMEOUT:504,PORT:A},s=S;var _=(e,t,o,r)=>{e.statusCode=e.statusCode||s.INTERNAL_SERVER_ERROR,e.status=e.status||"error",process.env.NODE_ENV==="development"?o.status(e.statusCode).json({status:e.status,error:e,message:e.message,stack:e.stack}):e.isOperational?o.status(e.statusCode).json({status:e.status,message:e.message}):(console.error("ERROR \u{1F4A5}",e),o.status(s.INTERNAL_SERVER_ERROR).json({status:"error",message:"Something went very wrong!"}))},g=_;var D={success:(e,t,o="Success",r=s.OK)=>e.status(r).json({status:"success",message:o,data:t}),error:(e,t="Internal Server Error",o=s.INTERNAL_SERVER_ERROR)=>e.status(o).json({status:"error",message:t})},h=D;import E from"bcryptjs";import U from"jsonwebtoken";var I=async e=>{let t=await E.genSalt(10);return await E.hash(e,t)},w=async(e,t)=>await E.compare(e,t),C=(e,t,o={})=>{let r=o.secret||process.env.JWT_SECRET,n=o.expiresIn||"30d",a=o.cookieName||"jwt",i=U.sign(e,r,{expiresIn:n}),u={maxAge:o.maxAge||720*60*60*1e3,httpOnly:!0,sameSite:process.env.NODE_ENV==="production"?"none":"lax",secure:process.env.NODE_ENV==="production",...o.extraCookieOptions};return t.cookie(a,i,u),i};import p from"crypto";var x=()=>typeof p.randomUUID=="function"?p.randomUUID():("10000000-1000-4000-8000"+-1e11).replace(/[018]/g,e=>(e^p.randomBytes(1).readUInt8()&15>>e/4).toString(16)),k=x;export{c as AppError,s as STATUS_CODES,l as admin,h as apiResponse,N as auth,m as catchAsync,w as comparePassword,T as connectDB,g as errorMiddleware,C as generateToken,k as generateUUID,I as hashPassword};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Server } from 'socket.io';
|
|
2
|
+
import jwt from 'jsonwebtoken';
|
|
3
|
+
|
|
4
|
+
let io;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Socket Authentication Middleware
|
|
8
|
+
*/
|
|
9
|
+
const socketAuth = (secret) => {
|
|
10
|
+
return (socket, next) => {
|
|
11
|
+
const token =
|
|
12
|
+
socket.handshake.auth?.token || socket.handshake.headers?.token;
|
|
13
|
+
|
|
14
|
+
if (!token) {
|
|
15
|
+
return next(new Error("Authentication error: Token missing"));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const decoded = jwt.verify(token, secret || process.env.JWT_SECRET);
|
|
20
|
+
socket.user = decoded; // socket ထဲမှာ user data သိမ်းထားမယ်
|
|
21
|
+
next();
|
|
22
|
+
} catch (err) {
|
|
23
|
+
next(new Error("Authentication error: Invalid token"));
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Socket Initialize လုပ်ခြင်း
|
|
30
|
+
*/
|
|
31
|
+
const initSocket = (server, options = {}) => {
|
|
32
|
+
io = new Server(server, {
|
|
33
|
+
cors: {
|
|
34
|
+
origin: options.origin || "*",
|
|
35
|
+
},
|
|
36
|
+
...options,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// JWT Middleware ကို အသုံးပြုခြင်း
|
|
40
|
+
if (options.authRequired) {
|
|
41
|
+
io.use(socketAuth(options.jwtSecret));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return io;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Initialize ပြီးသား IO object ကို ပြန်ယူခြင်း
|
|
49
|
+
*/
|
|
50
|
+
const getIO = () => {
|
|
51
|
+
if (!io) throw new Error("Socket.io not initialized!");
|
|
52
|
+
return io;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export { getIO, initSocket };
|
package/dist/socket.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Server } from 'socket.io';
|
|
2
|
+
import jwt from 'jsonwebtoken';
|
|
3
|
+
|
|
4
|
+
let io;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Socket Authentication Middleware
|
|
8
|
+
*/
|
|
9
|
+
const socketAuth = (secret) => {
|
|
10
|
+
return (socket, next) => {
|
|
11
|
+
const token =
|
|
12
|
+
socket.handshake.auth?.token || socket.handshake.headers?.token;
|
|
13
|
+
|
|
14
|
+
if (!token) {
|
|
15
|
+
return next(new Error("Authentication error: Token missing"));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const decoded = jwt.verify(token, secret || process.env.JWT_SECRET);
|
|
20
|
+
socket.user = decoded; // socket ထဲမှာ user data သိမ်းထားမယ်
|
|
21
|
+
next();
|
|
22
|
+
} catch (err) {
|
|
23
|
+
next(new Error("Authentication error: Invalid token"));
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Socket Initialize လုပ်ခြင်း
|
|
30
|
+
*/
|
|
31
|
+
const initSocket = (server, options = {}) => {
|
|
32
|
+
io = new Server(server, {
|
|
33
|
+
cors: {
|
|
34
|
+
origin: options.origin || "*",
|
|
35
|
+
},
|
|
36
|
+
...options,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// JWT Middleware ကို အသုံးပြုခြင်း
|
|
40
|
+
if (options.authRequired) {
|
|
41
|
+
io.use(socketAuth(options.jwtSecret));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return io;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Initialize ပြီးသား IO object ကို ပြန်ယူခြင်း
|
|
49
|
+
*/
|
|
50
|
+
const getIO = () => {
|
|
51
|
+
if (!io) throw new Error("Socket.io not initialized!");
|
|
52
|
+
return io;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export { getIO, initSocket };
|
package/dist/socket.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var _socketio = require('socket.io');var _jsonwebtoken = require('jsonwebtoken'); var _jsonwebtoken2 = _interopRequireDefault(_jsonwebtoken);var e,s=t=>(r,o)=>{var i,c;let n=((i=r.handshake.auth)==null?void 0:i.token)||((c=r.handshake.headers)==null?void 0:c.token);if(!n)return o(new Error("Authentication error: Token missing"));try{let a=_jsonwebtoken2.default.verify(n,t||process.env.JWT_SECRET);r.user=a,o()}catch (e2){o(new Error("Authentication error: Invalid token"))}},f= exports.initSocket =(t,r={})=>(e=new (0, _socketio.Server)(t,{cors:{origin:r.origin||"*"},...r}),r.authRequired&&e.use(s(r.jwtSecret)),e),w= exports.getIO =()=>{if(!e)throw new Error("Socket.io not initialized!");return e};exports.getIO = w; exports.initSocket = f;
|
package/dist/socket.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Server as h}from"socket.io";import u from"jsonwebtoken";var e,s=t=>(r,o)=>{var i,c;let n=((i=r.handshake.auth)==null?void 0:i.token)||((c=r.handshake.headers)==null?void 0:c.token);if(!n)return o(new Error("Authentication error: Token missing"));try{let a=u.verify(n,t||process.env.JWT_SECRET);r.user=a,o()}catch{o(new Error("Authentication error: Invalid token"))}},f=(t,r={})=>(e=new h(t,{cors:{origin:r.origin||"*"},...r}),r.authRequired&&e.use(s(r.jwtSecret)),e),w=()=>{if(!e)throw new Error("Socket.io not initialized!");return e};export{w as getIO,f as initSocket};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import Joi from 'joi';
|
|
2
|
+
export { default as Joi } from 'joi';
|
|
3
|
+
import { A as AppError } from './AppError-ByGDb4IL.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Joi Schema Validation Middleware
|
|
7
|
+
* @param {Object} schema - Joi validation schema
|
|
8
|
+
*/
|
|
9
|
+
const validate = (schema) => (req, res, next) => {
|
|
10
|
+
// body, query, params အားလုံးကို စစ်လို့ရအောင် req object တစ်ခုလုံးကို schema နဲ့ တိုက်စစ်မယ်
|
|
11
|
+
const { error, value } = schema.validate(req.body, {
|
|
12
|
+
abortEarly: false, // Error အားလုံးကို တစ်ခါတည်း ပြရန်
|
|
13
|
+
allowUnknown: true, // Schema ထဲမပါတဲ့ field တွေပါလာရင် လက်ခံရန်
|
|
14
|
+
stripUnknown: true, // Schema ထဲမပါတဲ့ field တွေကို ဖယ်ထုတ်ပစ်ရန်
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
if (error) {
|
|
18
|
+
// Error message တွေကို စုစည်းပြီး format လုပ်မယ်
|
|
19
|
+
const errorMessage = error.details
|
|
20
|
+
.map((detail) => detail.message.replace(/"/g, ""))
|
|
21
|
+
.join(", ");
|
|
22
|
+
|
|
23
|
+
return next(new AppError(errorMessage, 400));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// စစ်ဆေးပြီးသား data (sanitized data) ကို req.body ထဲ ပြန်ထည့်မယ်
|
|
27
|
+
req.body = value;
|
|
28
|
+
next();
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* User Validation Schemas
|
|
33
|
+
*/
|
|
34
|
+
const userSchema = {
|
|
35
|
+
// Standard Register Schema
|
|
36
|
+
register: Joi.object({
|
|
37
|
+
username: Joi.string().alphanum().min(3).max(30).required().messages({
|
|
38
|
+
"string.min": "Username must be at least 3 characters long",
|
|
39
|
+
"any.required": "Username is a required field",
|
|
40
|
+
}),
|
|
41
|
+
email: Joi.string()
|
|
42
|
+
.email({ minDomainSegments: 2, tlds: { allow: ["com", "net", "org"] } })
|
|
43
|
+
.required()
|
|
44
|
+
.messages({
|
|
45
|
+
"string.email": "Please provide a valid email address",
|
|
46
|
+
}),
|
|
47
|
+
password: Joi.string().min(8).required().messages({
|
|
48
|
+
"string.min": "Password must be at least 8 characters long",
|
|
49
|
+
}),
|
|
50
|
+
confirmPassword: Joi.any()
|
|
51
|
+
.equal(Joi.ref("password"))
|
|
52
|
+
.required()
|
|
53
|
+
.messages({ "any.only": "Passwords do not match" }),
|
|
54
|
+
role: Joi.string().valid("user", "admin").default("user"),
|
|
55
|
+
}),
|
|
56
|
+
|
|
57
|
+
// Login Schema
|
|
58
|
+
login: Joi.object({
|
|
59
|
+
email: Joi.string().email().required(),
|
|
60
|
+
password: Joi.string().required(),
|
|
61
|
+
}),
|
|
62
|
+
|
|
63
|
+
// Password Update Schema
|
|
64
|
+
updatePassword: Joi.object({
|
|
65
|
+
currentPassword: Joi.string().required(),
|
|
66
|
+
newPassword: Joi.string().min(8).required(),
|
|
67
|
+
}),
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* စိတ်ကြိုက် schema အသစ်ဆောက်ချင်ရင် သုံးရန် (Dynamic Flexibility)
|
|
71
|
+
* @param {Object} schemaDefinition - Joi object definition
|
|
72
|
+
*/
|
|
73
|
+
custom: (schemaDefinition) => Joi.object(schemaDefinition),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Common Joi Schemas
|
|
78
|
+
*/
|
|
79
|
+
const commonSchema = {
|
|
80
|
+
// MongoDB ObjectId စစ်ဆေးရန် (24 hex characters)
|
|
81
|
+
objectId: Joi.string()
|
|
82
|
+
.regex(/^[0-9a-fA-F]{24}$/)
|
|
83
|
+
.messages({
|
|
84
|
+
"string.pattern.base": "Invalid ID format. Must be a valid ObjectId.",
|
|
85
|
+
}),
|
|
86
|
+
|
|
87
|
+
// Pagination အတွက် (Query strings)
|
|
88
|
+
pagination: Joi.object({
|
|
89
|
+
page: Joi.number().integer().min(1).default(1),
|
|
90
|
+
limit: Joi.number().integer().min(1).max(100).default(10),
|
|
91
|
+
sort: Joi.string().optional(),
|
|
92
|
+
fields: Joi.string().optional(),
|
|
93
|
+
}),
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const schemas = {
|
|
97
|
+
user: userSchema,
|
|
98
|
+
common: commonSchema,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export { schemas as default, schemas, validate };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import Joi from 'joi';
|
|
2
|
+
export { default as Joi } from 'joi';
|
|
3
|
+
import { A as AppError } from './AppError-ByGDb4IL.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Joi Schema Validation Middleware
|
|
7
|
+
* @param {Object} schema - Joi validation schema
|
|
8
|
+
*/
|
|
9
|
+
const validate = (schema) => (req, res, next) => {
|
|
10
|
+
// body, query, params အားလုံးကို စစ်လို့ရအောင် req object တစ်ခုလုံးကို schema နဲ့ တိုက်စစ်မယ်
|
|
11
|
+
const { error, value } = schema.validate(req.body, {
|
|
12
|
+
abortEarly: false, // Error အားလုံးကို တစ်ခါတည်း ပြရန်
|
|
13
|
+
allowUnknown: true, // Schema ထဲမပါတဲ့ field တွေပါလာရင် လက်ခံရန်
|
|
14
|
+
stripUnknown: true, // Schema ထဲမပါတဲ့ field တွေကို ဖယ်ထုတ်ပစ်ရန်
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
if (error) {
|
|
18
|
+
// Error message တွေကို စုစည်းပြီး format လုပ်မယ်
|
|
19
|
+
const errorMessage = error.details
|
|
20
|
+
.map((detail) => detail.message.replace(/"/g, ""))
|
|
21
|
+
.join(", ");
|
|
22
|
+
|
|
23
|
+
return next(new AppError(errorMessage, 400));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// စစ်ဆေးပြီးသား data (sanitized data) ကို req.body ထဲ ပြန်ထည့်မယ်
|
|
27
|
+
req.body = value;
|
|
28
|
+
next();
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* User Validation Schemas
|
|
33
|
+
*/
|
|
34
|
+
const userSchema = {
|
|
35
|
+
// Standard Register Schema
|
|
36
|
+
register: Joi.object({
|
|
37
|
+
username: Joi.string().alphanum().min(3).max(30).required().messages({
|
|
38
|
+
"string.min": "Username must be at least 3 characters long",
|
|
39
|
+
"any.required": "Username is a required field",
|
|
40
|
+
}),
|
|
41
|
+
email: Joi.string()
|
|
42
|
+
.email({ minDomainSegments: 2, tlds: { allow: ["com", "net", "org"] } })
|
|
43
|
+
.required()
|
|
44
|
+
.messages({
|
|
45
|
+
"string.email": "Please provide a valid email address",
|
|
46
|
+
}),
|
|
47
|
+
password: Joi.string().min(8).required().messages({
|
|
48
|
+
"string.min": "Password must be at least 8 characters long",
|
|
49
|
+
}),
|
|
50
|
+
confirmPassword: Joi.any()
|
|
51
|
+
.equal(Joi.ref("password"))
|
|
52
|
+
.required()
|
|
53
|
+
.messages({ "any.only": "Passwords do not match" }),
|
|
54
|
+
role: Joi.string().valid("user", "admin").default("user"),
|
|
55
|
+
}),
|
|
56
|
+
|
|
57
|
+
// Login Schema
|
|
58
|
+
login: Joi.object({
|
|
59
|
+
email: Joi.string().email().required(),
|
|
60
|
+
password: Joi.string().required(),
|
|
61
|
+
}),
|
|
62
|
+
|
|
63
|
+
// Password Update Schema
|
|
64
|
+
updatePassword: Joi.object({
|
|
65
|
+
currentPassword: Joi.string().required(),
|
|
66
|
+
newPassword: Joi.string().min(8).required(),
|
|
67
|
+
}),
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* စိတ်ကြိုက် schema အသစ်ဆောက်ချင်ရင် သုံးရန် (Dynamic Flexibility)
|
|
71
|
+
* @param {Object} schemaDefinition - Joi object definition
|
|
72
|
+
*/
|
|
73
|
+
custom: (schemaDefinition) => Joi.object(schemaDefinition),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Common Joi Schemas
|
|
78
|
+
*/
|
|
79
|
+
const commonSchema = {
|
|
80
|
+
// MongoDB ObjectId စစ်ဆေးရန် (24 hex characters)
|
|
81
|
+
objectId: Joi.string()
|
|
82
|
+
.regex(/^[0-9a-fA-F]{24}$/)
|
|
83
|
+
.messages({
|
|
84
|
+
"string.pattern.base": "Invalid ID format. Must be a valid ObjectId.",
|
|
85
|
+
}),
|
|
86
|
+
|
|
87
|
+
// Pagination အတွက် (Query strings)
|
|
88
|
+
pagination: Joi.object({
|
|
89
|
+
page: Joi.number().integer().min(1).default(1),
|
|
90
|
+
limit: Joi.number().integer().min(1).max(100).default(10),
|
|
91
|
+
sort: Joi.string().optional(),
|
|
92
|
+
fields: Joi.string().optional(),
|
|
93
|
+
}),
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const schemas = {
|
|
97
|
+
user: userSchema,
|
|
98
|
+
common: commonSchema,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export { schemas as default, schemas, validate };
|