speedly 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +280 -0
  2. package/dist/cjs/auth/auth.js +86 -0
  3. package/dist/cjs/db/db.d.ts +181 -0
  4. package/dist/cjs/db/db.js +485 -0
  5. package/dist/cjs/index.d.ts +5 -0
  6. package/dist/cjs/index.js +44 -0
  7. package/dist/cjs/model/translation.d.ts +59 -0
  8. package/dist/cjs/model/translation.js +13 -0
  9. package/dist/{modules/auth.d.ts → cjs/uploader/uploader.d.ts} +1 -1
  10. package/dist/cjs/uploader/uploader.js +150 -0
  11. package/dist/cjs/util/getConfig.d.ts +4 -0
  12. package/dist/cjs/util/getConfig.js +21 -0
  13. package/dist/cjs/util/strToObj.d.ts +2 -0
  14. package/dist/cjs/util/strToObj.js +9 -0
  15. package/dist/cjs/util/translator.d.ts +2 -0
  16. package/dist/cjs/util/translator.js +67 -0
  17. package/dist/cjs/validator/validator.d.ts +9 -0
  18. package/dist/cjs/validator/validator.js +32 -0
  19. package/dist/esm/auth/auth.js +86 -0
  20. package/dist/esm/db/db.d.ts +181 -0
  21. package/dist/esm/db/db.js +485 -0
  22. package/dist/esm/index.d.ts +5 -0
  23. package/dist/esm/index.js +44 -0
  24. package/dist/esm/model/translation.d.ts +59 -0
  25. package/dist/esm/model/translation.js +13 -0
  26. package/dist/{modules/db.d.ts → esm/uploader/uploader.d.ts} +1 -1
  27. package/dist/esm/uploader/uploader.js +150 -0
  28. package/dist/esm/util/getConfig.d.ts +4 -0
  29. package/dist/esm/util/getConfig.js +21 -0
  30. package/dist/esm/util/strToObj.d.ts +2 -0
  31. package/dist/esm/util/strToObj.js +9 -0
  32. package/dist/esm/util/translator.d.ts +2 -0
  33. package/dist/esm/util/translator.js +67 -0
  34. package/dist/esm/validator/validator.d.ts +9 -0
  35. package/dist/esm/validator/validator.js +32 -0
  36. package/package.json +28 -15
  37. package/dist/index.d.ts +0 -0
  38. package/dist/index.js +0 -1
  39. package/dist/modules/auth.js +0 -68
  40. package/dist/modules/db/aggregation.d.ts +0 -0
  41. package/dist/modules/db/aggregation.js +0 -1
  42. package/dist/modules/db/aggregation.types.d.ts +0 -56
  43. package/dist/modules/db/aggregation.types.js +0 -2
  44. package/dist/modules/db/db.d.ts +0 -0
  45. package/dist/modules/db/db.js +0 -1
  46. package/dist/modules/db/db.type.js +0 -2
  47. package/dist/modules/db.js +0 -228
  48. package/dist/modules/types/db.d.ts +0 -38
  49. package/dist/modules/types/db.js +0 -1
  50. package/dist/modules/uploader.js +0 -57
  51. package/dist/modules/utils.d.ts +0 -0
  52. package/dist/modules/utils.js +0 -1
  53. package/dist/modules/validator.d.ts +0 -1
  54. package/dist/modules/validator.js +0 -47
  55. package/dist/utils/strToObj.d.ts +0 -0
  56. package/dist/utils/strToObj.js +0 -8
  57. /package/dist/{modules/db/db.type.d.ts → cjs/auth/auth.d.ts} +0 -0
  58. /package/dist/{modules/uploader.d.ts → esm/auth/auth.d.ts} +0 -0
package/README.md ADDED
@@ -0,0 +1,280 @@
1
+ # Speedly
2
+
3
+ A powerful Node.js/TypeScript utility library that provides essential modules for rapid web application development, including authentication, database operations, file uploading, validation, and translation services.
4
+
5
+ ## Features
6
+
7
+ - 🔐 **Authentication System** - JWT-based authentication with role-based access control
8
+ - 🗄️ **Database Management** - MongoDB/Mongoose integration with advanced query building
9
+ - 📤 **File Upload Handler** - Multer-based file upload with automatic directory management
10
+ - ✅ **Request Validation** - Yup-based schema validation for requests
11
+ - 🌐 **Translation Service** - Multi-provider translation with caching support
12
+ - 📦 **Dual Module Support** - Both CommonJS and ES Module exports
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install speedly
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ```typescript
23
+ import { auth, db, uploader, validator } from 'speedly';
24
+
25
+ // Initialize your Express app with Speedly modules
26
+ ```
27
+
28
+ ## Modules
29
+
30
+ ### 🔐 Authentication (`auth`)
31
+
32
+ Provides JWT-based authentication with customizable role management and middleware support.
33
+
34
+ ```typescript
35
+ import { auth } from 'speedly';
36
+
37
+ // Configure authentication
38
+ const authConfig = {
39
+ admin: {
40
+ role: 'ADMIN',
41
+ model: '../models/admin'
42
+ },
43
+ jwtSecretEnv: 'JWT_KEY',
44
+ customValidator: (req, key) => {
45
+ // Custom validation logic
46
+ return true;
47
+ }
48
+ };
49
+
50
+ const authMiddleware = auth(authConfig);
51
+
52
+ // Use in Express routes
53
+ app.use('/admin', authMiddleware.useAuth);
54
+ ```
55
+
56
+ ### 🗄️ Database (`db`)
57
+
58
+ Advanced MongoDB operations with query building, pagination, and pipeline support.
59
+
60
+ ```typescript
61
+ import { db } from 'speedly';
62
+
63
+ // Configure database
64
+ const dbConfig = {
65
+ dbType: "mongodb",
66
+ path: "../models",
67
+ dbEnv: "DB_URL",
68
+ pagination: {
69
+ quantity: 10,
70
+ detailed: true
71
+ }
72
+ };
73
+
74
+ // Use database operations
75
+ // Supports complex queries, aggregation pipelines, and automatic pagination
76
+ ```
77
+
78
+ ### 📤 File Upload (`uploader`)
79
+
80
+ Multer-based file upload system with automatic directory creation and validation.
81
+
82
+ ```typescript
83
+ import { uploader } from 'speedly';
84
+
85
+ // Configure uploader
86
+ const uploadConfig = {
87
+ saveInDb: false,
88
+ prefix: "img_",
89
+ limit: 5,
90
+ format: /png|jpg|webp|jpeg/i
91
+ };
92
+
93
+ const upload = uploader("/uploads/images", uploadConfig);
94
+
95
+ // Use in Express routes
96
+ app.post('/upload', upload.single('file'), (req, res) => {
97
+ // File uploaded successfully
98
+ res.json({ mediaId: req.mediaId });
99
+ });
100
+ ```
101
+
102
+ ### ✅ Validation (`validator`)
103
+
104
+ Type-safe request validation using Yup schemas.
105
+
106
+ ```typescript
107
+ import { validator } from 'speedly';
108
+ import * as yup from 'yup';
109
+
110
+ // Define validation schema
111
+ const userSchema = {
112
+ body: yup.object({
113
+ name: yup.string().required(),
114
+ email: yup.string().email().required(),
115
+ age: yup.number().min(18)
116
+ }),
117
+ params: yup.object({
118
+ id: yup.string().required()
119
+ }),
120
+ query: yup.object({
121
+ page: yup.number().default(1)
122
+ })
123
+ };
124
+
125
+ // Use validation middleware
126
+ app.post('/users/:id', validator(userSchema), (req, res) => {
127
+ // req.body, req.params, req.query are now validated and typed
128
+ });
129
+ ```
130
+
131
+ ## Configuration
132
+
133
+ Speedly uses a configuration system that allows you to customize each module. Create configuration files or use environment variables:
134
+
135
+ ### Environment Variables
136
+
137
+ ```bash
138
+ # Database
139
+ DB_URL=mongodb://localhost:27017/myapp
140
+
141
+ # JWT Secret
142
+ JWT_KEY=your-secret-key
143
+
144
+ # Translation API (optional)
145
+ ONE_API_TOKEN=your-translation-api-token
146
+ ```
147
+
148
+ ### Configuration Files
149
+
150
+ Create module-specific configuration by using the `getConfig` utility:
151
+
152
+ ```typescript
153
+ // Example configuration structure
154
+ const config = {
155
+ auth: {
156
+ jwtSecretEnv: 'JWT_KEY',
157
+ admin: { role: 'ADMIN' }
158
+ },
159
+ db: {
160
+ dbType: 'mongodb',
161
+ pagination: { quantity: 20 }
162
+ },
163
+ uploader: {
164
+ limit: 10,
165
+ format: /png|jpg|jpeg|webp|gif/i
166
+ },
167
+ translate: {
168
+ one_api_token: process.env.ONE_API_TOKEN
169
+ }
170
+ };
171
+ ```
172
+
173
+ ## Advanced Usage
174
+
175
+ ### Database Queries with Pipelines
176
+
177
+ ```typescript
178
+ // Complex aggregation pipeline example
179
+ const queryState = {
180
+ action: 'aggregate',
181
+ match: { status: 'active' },
182
+ pipeline: [
183
+ { $lookup: { from: 'users', localField: 'userId', foreignField: '_id', as: 'user' } },
184
+ { $unwind: '$user' },
185
+ { $sort: { createdAt: -1 } }
186
+ ]
187
+ };
188
+ ```
189
+
190
+ ### Translation with Caching
191
+
192
+ The translation module automatically caches translations and supports multiple providers:
193
+
194
+ ```typescript
195
+ import { translator } from 'speedly/dist/util/translator';
196
+
197
+ // Translate text with automatic caching
198
+ const translatedText = await translator("Hello World", "fa");
199
+ ```
200
+
201
+ ## API Reference
202
+
203
+ ### Authentication Module
204
+
205
+ - `auth(config)` - Creates authentication middleware
206
+ - `useAuth` - Express middleware for route protection
207
+
208
+ ### Database Module
209
+
210
+ - Supports MongoDB operations with Mongoose
211
+ - Built-in pagination and query building
212
+ - Aggregation pipeline support
213
+
214
+ ### Uploader Module
215
+
216
+ - `uploader(destination, config)` - Creates multer upload middleware
217
+ - Automatic directory creation
218
+ - File format validation
219
+
220
+ ### Validator Module
221
+
222
+ - `validator(schemas)` - Creates validation middleware
223
+ - Type-safe validation with Yup
224
+ - Supports body, params, and query validation
225
+
226
+ ## Dependencies
227
+
228
+ - **Express.js** - Web framework
229
+ - **Mongoose** - MongoDB object modeling
230
+ - **Multer** - File upload handling
231
+ - **Yup** - Schema validation
232
+ - **jsonwebtoken** - JWT authentication
233
+ - **axios** - HTTP client
234
+ - **translate** - Translation services
235
+
236
+ ## Development
237
+
238
+ ### Building the Project
239
+
240
+ ```bash
241
+ # Build both CommonJS and ES modules
242
+ npm run build
243
+
244
+ # Build CommonJS only
245
+ npm run build:cjs
246
+
247
+ # Build ES modules only
248
+ npm run build:esm
249
+
250
+ # Development mode
251
+ npm run dev
252
+ ```
253
+
254
+ ### Project Structure
255
+
256
+ ```
257
+ src/
258
+ ├── auth/ # Authentication module
259
+ ├── db/ # Database operations
260
+ ├── uploader/ # File upload handling
261
+ ├── validator/ # Request validation
262
+ ├── util/ # Utility functions
263
+ └── model/ # Data models
264
+ ```
265
+
266
+ ## TypeScript Support
267
+
268
+ Speedly is written in TypeScript and provides full type definitions. The package exports both CommonJS and ES modules for maximum compatibility.
269
+
270
+ ## License
271
+
272
+ MIT © MAHSERIN
273
+
274
+ ## Contributing
275
+
276
+ Contributions are welcome! Please feel free to submit a Pull Request.
277
+
278
+ ## Support
279
+
280
+ For questions and support, please open an issue on the GitHub repository.
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const getConfig_1 = __importDefault(require("../util/getConfig"));
7
+ const gConfig = { admin: { role: 'ADMIN', model: '../models/admin' }, jwtSecretEnv: 'JWT_KEY', customValidator: (req, key) => { return true; }, ...(0, getConfig_1.default)('auth') };
8
+ const auth = (config = gConfig) => {
9
+ // const adminModel = require('../models/admin')
10
+ let handlerState = {};
11
+ const useAuth = async (req, res, next) => {
12
+ try {
13
+ const nextFunc = (handlers, index = 0) => (errorMessage = '') => {
14
+ if (errorMessage)
15
+ return next(errorMessage);
16
+ if (!handlers.length || !handlers[index + 1])
17
+ return next();
18
+ handlers[index + 1](req, res, nextFunc(handlers, index + 1));
19
+ };
20
+ const keys = Object.keys(handlerState);
21
+ for (let i = 0; i < keys.length; i++) {
22
+ const key = keys[i];
23
+ if (!handlerState[key]?.handlers?.length)
24
+ continue;
25
+ if (await gConfig?.customValidator?.(req, key)) {
26
+ return await handlerState[key].handlers[0](req, res, nextFunc(handlerState[key].handlers));
27
+ }
28
+ else if (await gConfig?.customValidator?.(req, key) == null) {
29
+ return next({ status: 401, json: { message: 'unauthorized' } });
30
+ }
31
+ else if (i === keys.length - 1) {
32
+ next({ status: 405, json: { message: 'you don\'t have access to this section' } });
33
+ }
34
+ else
35
+ continue;
36
+ }
37
+ // اینجا اگر i === keys.length - 1 باشد یعنی آخرین آیتم هستی
38
+ // }else if (!req.cookies.AT_SECRET) {
39
+ // if (!handlerState.user || !handlerState.user?.handlers?.length) return res.status(403).json({ message: 'you dont have access for this section' })
40
+ // handlerState.user.handlers[0](req ,res , nextFunc(handlerState.user.handlers))
41
+ // }else {
42
+ // if(!handlerState.admin || !handlerState.admin?.handlers?.length) {
43
+ // if (!handlerState.user || !handlerState.user?.handlers?.length) return res.status(404).json({ message: 'route not found :(' })
44
+ // handlerState.user.handlers[0](req ,res , nextFunc(handlerState.user.handlers))
45
+ // } else {
46
+ // const tokenPayload = jwt.verify(req.cookies.AT_SECRET , process.env[gConfig.jwtSecretEnv])
47
+ // const adminDoc = await adminModel.findById(tokenPayload.id)
48
+ // if(!adminDoc)return res.status(403).json({ message: 'you don\'t have access for this section' })
49
+ // if(adminDoc.role !='OWNER' && adminDoc.role != config?.admin?.role ) return res.status(403).json({ message: 'you dont have access for this section' })
50
+ // req.admin = adminDoc
51
+ // handlerState.admin.handlers[0](req , res , nextFunc(handlerState.admin.handlers))
52
+ // }
53
+ // }
54
+ }
55
+ catch (error) {
56
+ console.log('auth', 42, error);
57
+ next({ status: 403, json: { message: (error instanceof Error ? error.message : 'error on authentication please login again') } });
58
+ }
59
+ };
60
+ useAuth.admin = (...handlers) => {
61
+ if (!Array.isArray(handlers))
62
+ throw new Error('handlers must be an array');
63
+ const hasConfig = typeof handlers[0] === 'object' && 'permission' in handlers[0];
64
+ const configObj = hasConfig ? handlers[0] : undefined;
65
+ const handlerFns = hasConfig ? handlers.slice(1) : handlers;
66
+ handlerState[`admin${configObj?.permission ? `:${configObj.permission}` : ''}`] = {
67
+ ...(configObj ? { config: configObj } : {}),
68
+ handlers: handlerFns
69
+ };
70
+ return useAuth;
71
+ };
72
+ useAuth.user = (...handlers) => {
73
+ if (!Array.isArray(handlers))
74
+ throw new Error('handlers must be an array');
75
+ handlerState.user = { handlers };
76
+ return useAuth;
77
+ };
78
+ useAuth.any = (...handlers) => {
79
+ if (!Array.isArray(handlers))
80
+ throw new Error('handlers must be an array');
81
+ handlerState.any = { handlers };
82
+ return useAuth;
83
+ };
84
+ return useAuth;
85
+ };
86
+ module.exports = auth;
@@ -0,0 +1,181 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ declare module 'express-serve-static-core' {
3
+ interface Request {
4
+ document?: any;
5
+ user?: any;
6
+ }
7
+ interface Response {
8
+ logger?: (message: string, details?: any) => void;
9
+ success?: (statusCode: number, body: any) => void;
10
+ }
11
+ }
12
+ type ConfigsType = {
13
+ dbType?: string;
14
+ path?: string;
15
+ dbEnv?: string;
16
+ pagination?: {
17
+ quantity?: number;
18
+ detailed?: boolean;
19
+ [key: string]: unknown;
20
+ };
21
+ [key: string]: unknown;
22
+ };
23
+ declare const db: (collectionName: string, config?: ConfigsType) => {
24
+ find: (match?: {}) => {
25
+ (req: Request, res: Response, next: NextFunction): Promise<void>;
26
+ select(value: string | {
27
+ [key: string]: -1 | 1;
28
+ }): /*elided*/ any;
29
+ sort(value: string | {
30
+ [key: string]: -1 | 1;
31
+ }): /*elided*/ any;
32
+ skip(value: number): /*elided*/ any;
33
+ limit(value: number): /*elided*/ any;
34
+ populate(value: string | object | (string | object)[]): /*elided*/ any;
35
+ };
36
+ create: (body?: {}) => {
37
+ (req: Request, res: Response, next: NextFunction): Promise<void>;
38
+ select(value: string | {
39
+ [key: string]: -1 | 1;
40
+ }): /*elided*/ any;
41
+ sort(value: string | {
42
+ [key: string]: -1 | 1;
43
+ }): /*elided*/ any;
44
+ skip(value: number): /*elided*/ any;
45
+ limit(value: number): /*elided*/ any;
46
+ populate(value: string | object | (string | object)[]): /*elided*/ any;
47
+ };
48
+ updateOne: (match?: {}, body?: {}) => {
49
+ (req: Request, res: Response, next: NextFunction): Promise<void>;
50
+ select(value: string | {
51
+ [key: string]: -1 | 1;
52
+ }): /*elided*/ any;
53
+ sort(value: string | {
54
+ [key: string]: -1 | 1;
55
+ }): /*elided*/ any;
56
+ skip(value: number): /*elided*/ any;
57
+ limit(value: number): /*elided*/ any;
58
+ populate(value: string | object | (string | object)[]): /*elided*/ any;
59
+ };
60
+ updateMany: (match?: {}, body?: {}) => {
61
+ (req: Request, res: Response, next: NextFunction): Promise<void>;
62
+ select(value: string | {
63
+ [key: string]: -1 | 1;
64
+ }): /*elided*/ any;
65
+ sort(value: string | {
66
+ [key: string]: -1 | 1;
67
+ }): /*elided*/ any;
68
+ skip(value: number): /*elided*/ any;
69
+ limit(value: number): /*elided*/ any;
70
+ populate(value: string | object | (string | object)[]): /*elided*/ any;
71
+ };
72
+ deleteOne: (match?: {}) => {
73
+ (req: Request, res: Response, next: NextFunction): Promise<void>;
74
+ select(value: string | {
75
+ [key: string]: -1 | 1;
76
+ }): /*elided*/ any;
77
+ sort(value: string | {
78
+ [key: string]: -1 | 1;
79
+ }): /*elided*/ any;
80
+ skip(value: number): /*elided*/ any;
81
+ limit(value: number): /*elided*/ any;
82
+ populate(value: string | object | (string | object)[]): /*elided*/ any;
83
+ };
84
+ deleteMany: (match?: {}) => {
85
+ (req: Request, res: Response, next: NextFunction): Promise<void>;
86
+ select(value: string | {
87
+ [key: string]: -1 | 1;
88
+ }): /*elided*/ any;
89
+ sort(value: string | {
90
+ [key: string]: -1 | 1;
91
+ }): /*elided*/ any;
92
+ skip(value: number): /*elided*/ any;
93
+ limit(value: number): /*elided*/ any;
94
+ populate(value: string | object | (string | object)[]): /*elided*/ any;
95
+ };
96
+ findOne: (match?: {}) => {
97
+ (req: Request, res: Response, next: NextFunction): Promise<void>;
98
+ select(value: string | {
99
+ [key: string]: -1 | 1;
100
+ }): /*elided*/ any;
101
+ sort(value: string | {
102
+ [key: string]: -1 | 1;
103
+ }): /*elided*/ any;
104
+ skip(value: number): /*elided*/ any;
105
+ limit(value: number): /*elided*/ any;
106
+ populate(value: string | object | (string | object)[]): /*elided*/ any;
107
+ };
108
+ findOneAndUpdate: (match?: {}, body?: {}) => {
109
+ (req: Request, res: Response, next: NextFunction): Promise<void>;
110
+ select(value: string | {
111
+ [key: string]: -1 | 1;
112
+ }): /*elided*/ any;
113
+ sort(value: string | {
114
+ [key: string]: -1 | 1;
115
+ }): /*elided*/ any;
116
+ skip(value: number): /*elided*/ any;
117
+ limit(value: number): /*elided*/ any;
118
+ populate(value: string | object | (string | object)[]): /*elided*/ any;
119
+ };
120
+ aggregate: (pipeline?: never[]) => {
121
+ (req: Request, res: Response, next: NextFunction): Promise<void>;
122
+ select(value: string | {
123
+ [key: string]: -1 | 1;
124
+ }): /*elided*/ any;
125
+ sort(value: string | {
126
+ [key: string]: -1 | 1;
127
+ }): /*elided*/ any;
128
+ skip(value: number): /*elided*/ any;
129
+ limit(value: number): /*elided*/ any;
130
+ populate(value: string | object | (string | object)[]): /*elided*/ any;
131
+ };
132
+ findOneAndDelete: (match?: {}) => {
133
+ (req: Request, res: Response, next: NextFunction): Promise<void>;
134
+ select(value: string | {
135
+ [key: string]: -1 | 1;
136
+ }): /*elided*/ any;
137
+ sort(value: string | {
138
+ [key: string]: -1 | 1;
139
+ }): /*elided*/ any;
140
+ skip(value: number): /*elided*/ any;
141
+ limit(value: number): /*elided*/ any;
142
+ populate(value: string | object | (string | object)[]): /*elided*/ any;
143
+ };
144
+ findById: (id?: string) => {
145
+ (req: Request, res: Response, next: NextFunction): Promise<void>;
146
+ select(value: string | {
147
+ [key: string]: -1 | 1;
148
+ }): /*elided*/ any;
149
+ sort(value: string | {
150
+ [key: string]: -1 | 1;
151
+ }): /*elided*/ any;
152
+ skip(value: number): /*elided*/ any;
153
+ limit(value: number): /*elided*/ any;
154
+ populate(value: string | object | (string | object)[]): /*elided*/ any;
155
+ };
156
+ findByIdAndUpdate: (id?: string, body?: {}) => {
157
+ (req: Request, res: Response, next: NextFunction): Promise<void>;
158
+ select(value: string | {
159
+ [key: string]: -1 | 1;
160
+ }): /*elided*/ any;
161
+ sort(value: string | {
162
+ [key: string]: -1 | 1;
163
+ }): /*elided*/ any;
164
+ skip(value: number): /*elided*/ any;
165
+ limit(value: number): /*elided*/ any;
166
+ populate(value: string | object | (string | object)[]): /*elided*/ any;
167
+ };
168
+ findByIdAndDelete: (id?: string) => {
169
+ (req: Request, res: Response, next: NextFunction): Promise<void>;
170
+ select(value: string | {
171
+ [key: string]: -1 | 1;
172
+ }): /*elided*/ any;
173
+ sort(value: string | {
174
+ [key: string]: -1 | 1;
175
+ }): /*elided*/ any;
176
+ skip(value: number): /*elided*/ any;
177
+ limit(value: number): /*elided*/ any;
178
+ populate(value: string | object | (string | object)[]): /*elided*/ any;
179
+ };
180
+ } | undefined;
181
+ export default db;