90dc-core 1.10.20 → 1.11.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.
- package/README.md +360 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/Errors/AppError.d.ts +47 -0
- package/dist/lib/Errors/AppError.d.ts.map +1 -0
- package/dist/lib/Errors/AppError.js +104 -0
- package/dist/lib/Errors/AppError.js.map +1 -0
- package/dist/lib/classes/Redis.d.ts +13 -0
- package/dist/lib/classes/Redis.d.ts.map +1 -0
- package/dist/lib/classes/Redis.js +63 -0
- package/dist/lib/classes/Redis.js.map +1 -0
- package/dist/lib/config/ConfigValidator.d.ts +88 -0
- package/dist/lib/config/ConfigValidator.d.ts.map +1 -0
- package/dist/lib/config/ConfigValidator.js +138 -0
- package/dist/lib/config/ConfigValidator.js.map +1 -0
- package/dist/lib/middlewares/ErrorMiddleware.d.ts +19 -0
- package/dist/lib/middlewares/ErrorMiddleware.d.ts.map +1 -0
- package/dist/lib/middlewares/ErrorMiddleware.js +98 -0
- package/dist/lib/middlewares/ErrorMiddleware.js.map +1 -0
- package/dist/lib/utils/AuthenticationUtil.d.ts +1 -46
- package/dist/lib/utils/AuthenticationUtil.d.ts.map +1 -1
- package/dist/lib/utils/AuthenticationUtil.js +24 -57
- package/dist/lib/utils/AuthenticationUtil.js.map +1 -1
- package/dist/lib/utils/Logger.d.ts +17 -0
- package/dist/lib/utils/Logger.d.ts.map +1 -0
- package/dist/lib/utils/Logger.js +203 -0
- package/dist/lib/utils/Logger.js.map +1 -0
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -1,2 +1,361 @@
|
|
|
1
1
|
# 90dc-core
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
Shared utilities, models, and middleware for 90 Day Challenge microservices.
|
|
4
|
+
|
|
5
|
+
## Version 1.11.0 - NEW Features ✨
|
|
6
|
+
|
|
7
|
+
This version adds **configuration validation** and **error handling middleware** to improve code quality across all services.
|
|
8
|
+
|
|
9
|
+
### What's New
|
|
10
|
+
|
|
11
|
+
- ✅ **Type-safe configuration** with Zod validation
|
|
12
|
+
- ✅ **Consistent error handling** across all services
|
|
13
|
+
- ✅ **Request validation middleware** with Zod
|
|
14
|
+
- ✅ **Comprehensive error classes** (404, 400, 401, 403, 500, etc.)
|
|
15
|
+
- ✅ **Fail-fast validation** on startup
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install 90dc-core@latest zod
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
### 1. Configuration Validation
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { BaseConfigSchema, ConfigValidator } from '90dc-core';
|
|
33
|
+
import { z } from 'zod';
|
|
34
|
+
|
|
35
|
+
// Extend base config with service-specific settings
|
|
36
|
+
const ConfigSchema = BaseConfigSchema.extend({
|
|
37
|
+
GOOGLE_CLIENT_ID: z.string().min(1),
|
|
38
|
+
APPLE_TEAM_ID: z.string().min(1),
|
|
39
|
+
MOLLIE_API_KEY: z.string().min(1)
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Create validated config (fails fast on startup if invalid)
|
|
43
|
+
const config = new ConfigValidator(ConfigSchema);
|
|
44
|
+
|
|
45
|
+
// Use with type safety
|
|
46
|
+
const port = config.get('PORT'); // Type: number
|
|
47
|
+
const jwtSecret = config.get('JWT_SECRET'); // Type: string
|
|
48
|
+
const googleClientId = config.get('GOOGLE_CLIENT_ID'); // Type: string
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2. Error Handling Middleware
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import Koa from 'koa';
|
|
55
|
+
import { createErrorMiddleware } from '90dc-core';
|
|
56
|
+
|
|
57
|
+
const app = new Koa();
|
|
58
|
+
|
|
59
|
+
// Add error middleware FIRST
|
|
60
|
+
app.use(createErrorMiddleware({
|
|
61
|
+
exposeErrorDetails: config.isDevelopment()
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
// Add your routes
|
|
65
|
+
app.use(router.routes());
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 3. Throwing Errors
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import {
|
|
72
|
+
NotFoundError,
|
|
73
|
+
ValidationError,
|
|
74
|
+
ForbiddenError,
|
|
75
|
+
AuthenticationError
|
|
76
|
+
} from '90dc-core';
|
|
77
|
+
|
|
78
|
+
class UserController {
|
|
79
|
+
async getUser(ctx: Context) {
|
|
80
|
+
const user = await User.findByPk(ctx.params.id);
|
|
81
|
+
|
|
82
|
+
if (!user) {
|
|
83
|
+
throw new NotFoundError('User'); // Returns 404 with consistent format
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
ctx.body = { user };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async createUser(ctx: Context) {
|
|
90
|
+
const existing = await User.findOne({ where: { email } });
|
|
91
|
+
|
|
92
|
+
if (existing) {
|
|
93
|
+
throw new ConflictError('Email already registered'); // Returns 409
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ... create user
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 4. Request Validation
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import { validateRequest } from '90dc-core';
|
|
105
|
+
import { z } from 'zod';
|
|
106
|
+
|
|
107
|
+
const CreateUserSchema = z.object({
|
|
108
|
+
email: z.string().email(),
|
|
109
|
+
password: z.string().min(8),
|
|
110
|
+
firstName: z.string().min(1).max(100)
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
router.post('/users',
|
|
114
|
+
validateRequest({ body: CreateUserSchema }),
|
|
115
|
+
async (ctx) => {
|
|
116
|
+
// ctx.request.body is now validated and typed
|
|
117
|
+
const user = await User.create(ctx.request.body);
|
|
118
|
+
ctx.body = { user };
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Error Response Format
|
|
126
|
+
|
|
127
|
+
All errors return consistent JSON:
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"success": false,
|
|
132
|
+
"error": {
|
|
133
|
+
"code": "NOT_FOUND",
|
|
134
|
+
"message": "User not found"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
With details for validation errors:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"success": false,
|
|
144
|
+
"error": {
|
|
145
|
+
"code": "VALIDATION_ERROR",
|
|
146
|
+
"message": "Request validation failed",
|
|
147
|
+
"details": {
|
|
148
|
+
"validationErrors": [
|
|
149
|
+
{
|
|
150
|
+
"path": "email",
|
|
151
|
+
"message": "Invalid email",
|
|
152
|
+
"code": "invalid_string"
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Available Error Types
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import {
|
|
166
|
+
ValidationError, // 400 - Invalid data
|
|
167
|
+
AuthenticationError, // 401 - Not authenticated
|
|
168
|
+
ForbiddenError, // 403 - No permission
|
|
169
|
+
NotFoundError, // 404 - Resource not found
|
|
170
|
+
ConflictError, // 409 - Resource conflict
|
|
171
|
+
UnprocessableEntityError,// 422 - Semantic error
|
|
172
|
+
RateLimitError, // 429 - Too many requests
|
|
173
|
+
InternalServerError, // 500 - Server error
|
|
174
|
+
ServiceUnavailableError, // 503 - Service down
|
|
175
|
+
DatabaseError, // 500 - Database issue
|
|
176
|
+
ExternalAPIError, // 502 - External API failed
|
|
177
|
+
} from '90dc-core';
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Common Config Schemas
|
|
183
|
+
|
|
184
|
+
Reusable schemas for common configurations:
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
import { CommonSchemas } from '90dc-core';
|
|
188
|
+
|
|
189
|
+
const ConfigSchema = BaseConfigSchema
|
|
190
|
+
.extend(CommonSchemas.redis.shape)
|
|
191
|
+
.extend(CommonSchemas.jwt.shape)
|
|
192
|
+
.extend(CommonSchemas.googleOAuth.shape);
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Available common schemas:
|
|
196
|
+
- `CommonSchemas.database` - PostgreSQL configuration
|
|
197
|
+
- `CommonSchemas.redis` - Redis configuration
|
|
198
|
+
- `CommonSchemas.jwt` - JWT authentication
|
|
199
|
+
- `CommonSchemas.googleOAuth` - Google OAuth
|
|
200
|
+
- `CommonSchemas.appleOAuth` - Apple OAuth
|
|
201
|
+
- `CommonSchemas.serviceUrls` - Inter-service URLs
|
|
202
|
+
- `CommonSchemas.featureFlags` - Feature flags
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Full Documentation
|
|
207
|
+
|
|
208
|
+
See **[USAGE_EXAMPLES.md](./USAGE_EXAMPLES.md)** for:
|
|
209
|
+
- Complete usage examples
|
|
210
|
+
- Migration guide from old code
|
|
211
|
+
- Best practices
|
|
212
|
+
- Testing examples
|
|
213
|
+
- All available features
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Exports
|
|
218
|
+
|
|
219
|
+
### Configuration
|
|
220
|
+
```typescript
|
|
221
|
+
import {
|
|
222
|
+
ConfigValidator,
|
|
223
|
+
BaseConfigSchema,
|
|
224
|
+
CommonSchemas,
|
|
225
|
+
createConfig,
|
|
226
|
+
ConfigurationError
|
|
227
|
+
} from '90dc-core';
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Errors
|
|
231
|
+
```typescript
|
|
232
|
+
import {
|
|
233
|
+
AppError,
|
|
234
|
+
ValidationError,
|
|
235
|
+
AuthenticationError,
|
|
236
|
+
ForbiddenError,
|
|
237
|
+
NotFoundError,
|
|
238
|
+
ConflictError,
|
|
239
|
+
UnprocessableEntityError,
|
|
240
|
+
RateLimitError,
|
|
241
|
+
InternalServerError,
|
|
242
|
+
ServiceUnavailableError,
|
|
243
|
+
DatabaseError,
|
|
244
|
+
ExternalAPIError,
|
|
245
|
+
isAppError,
|
|
246
|
+
isOperationalError,
|
|
247
|
+
toAppError
|
|
248
|
+
} from '90dc-core';
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Middleware
|
|
252
|
+
```typescript
|
|
253
|
+
import {
|
|
254
|
+
createErrorMiddleware,
|
|
255
|
+
validateRequest,
|
|
256
|
+
asyncHandler,
|
|
257
|
+
type ErrorMiddlewareConfig
|
|
258
|
+
} from '90dc-core';
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Database Models
|
|
262
|
+
```typescript
|
|
263
|
+
import {
|
|
264
|
+
PersistedUser,
|
|
265
|
+
Program,
|
|
266
|
+
Workout,
|
|
267
|
+
Exercise,
|
|
268
|
+
Badge,
|
|
269
|
+
// ... many more
|
|
270
|
+
} from '90dc-core';
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Utilities
|
|
274
|
+
```typescript
|
|
275
|
+
import {
|
|
276
|
+
AuthenticationUtil,
|
|
277
|
+
NotificationsUtil,
|
|
278
|
+
NotificationClient
|
|
279
|
+
} from '90dc-core';
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Migration Steps
|
|
285
|
+
|
|
286
|
+
1. **Install dependencies**:
|
|
287
|
+
```bash
|
|
288
|
+
npm install 90dc-core@latest zod
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
2. **Add config validation**:
|
|
292
|
+
```typescript
|
|
293
|
+
import { BaseConfigSchema, ConfigValidator } from '90dc-core';
|
|
294
|
+
const config = new ConfigValidator(BaseConfigSchema);
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
3. **Add error middleware**:
|
|
298
|
+
```typescript
|
|
299
|
+
import { createErrorMiddleware } from '90dc-core';
|
|
300
|
+
app.use(createErrorMiddleware());
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
4. **Replace error handling**:
|
|
304
|
+
```typescript
|
|
305
|
+
// Before
|
|
306
|
+
if (!user) {
|
|
307
|
+
ctx.status = 404;
|
|
308
|
+
ctx.body = { message: 'Not found' };
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// After
|
|
313
|
+
import { NotFoundError } from '90dc-core';
|
|
314
|
+
if (!user) {
|
|
315
|
+
throw new NotFoundError('User');
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
5. **Add request validation**:
|
|
320
|
+
```typescript
|
|
321
|
+
import { validateRequest } from '90dc-core';
|
|
322
|
+
router.post('/users',
|
|
323
|
+
validateRequest({ body: CreateUserSchema }),
|
|
324
|
+
handler
|
|
325
|
+
);
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
See **[USAGE_EXAMPLES.md](./USAGE_EXAMPLES.md)** for detailed migration guide.
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Building & Publishing
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
# Install dependencies
|
|
336
|
+
npm install
|
|
337
|
+
|
|
338
|
+
# Build
|
|
339
|
+
npm run build
|
|
340
|
+
|
|
341
|
+
# Publish to npm
|
|
342
|
+
npm run publish:build
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## Changelog
|
|
348
|
+
|
|
349
|
+
See **[CHANGELOG.md](./CHANGELOG.md)** for version history.
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## License
|
|
354
|
+
|
|
355
|
+
ISC
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## Contributing
|
|
360
|
+
|
|
361
|
+
This is part of the 90 Day Challenge microservices architecture. See the main refactor plan for contribution guidelines.
|
package/dist/index.d.ts
CHANGED
|
@@ -23,4 +23,9 @@ export * from "./lib/dbmodels/nonconsprogram/UserNonConsumableProgram.js";
|
|
|
23
23
|
export { AuthenticationUtil } from "./lib/utils/AuthenticationUtil.js";
|
|
24
24
|
export { NotificationsUtil } from "./lib/utils/NotificationsUtil.js";
|
|
25
25
|
export { NotificationClient } from "./lib/utils/NotificationClient.js";
|
|
26
|
+
export { Log } from "./lib/utils/Logger.js";
|
|
27
|
+
export { ConfigValidator, BaseConfigSchema, CommonSchemas, createConfig, ConfigurationError, type BaseConfig } from "./lib/config/ConfigValidator.js";
|
|
28
|
+
export { AppError, ValidationError, AuthenticationError, ForbiddenError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, ServiceUnavailableError, DatabaseError, ExternalAPIError, isAppError, isOperationalError, toAppError } from "./lib/Errors/AppError.js";
|
|
29
|
+
export { createErrorMiddleware, type ErrorMiddlewareConfig } from "./lib/middlewares/ErrorMiddleware.js";
|
|
30
|
+
export { RedisClient } from "./lib/classes/Redis.js";
|
|
26
31
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wCAAwC,CAAC;AAGvD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,8BAA8B,CAAA;AAC5C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,yBAAyB,CAAA;AACvC,cAAc,mCAAmC,CAAA;AACjD,cAAc,mCAAmC,CAAA;AACjD,cAAc,oCAAoC,CAAA;AAClD,cAAc,0CAA0C,CAAA;AACxD,cAAc,oCAAoC,CAAA;AAClD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,mCAAmC,CAAA;AACjD,cAAc,uDAAuD,CAAA;AACrE,cAAc,2EAA2E,CAAA;AACzF,cAAc,8DAA8D,CAAA;AAC5E,cAAc,iEAAiE,CAAA;AAC/E,cAAc,2DAA2D,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wCAAwC,CAAC;AAGvD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,8BAA8B,CAAA;AAC5C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,yBAAyB,CAAA;AACvC,cAAc,mCAAmC,CAAA;AACjD,cAAc,mCAAmC,CAAA;AACjD,cAAc,oCAAoC,CAAA;AAClD,cAAc,0CAA0C,CAAA;AACxD,cAAc,oCAAoC,CAAA;AAClD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,mCAAmC,CAAA;AACjD,cAAc,uDAAuD,CAAA;AACrE,cAAc,2EAA2E,CAAA;AACzF,cAAc,8DAA8D,CAAA;AAC5E,cAAc,iEAAiE,CAAA;AAC/E,cAAc,2DAA2D,CAAA;AAGzE,OAAO,EAAC,kBAAkB,EAAC,MAAM,mCAAmC,CAAA;AACpE,OAAO,EAAC,iBAAiB,EAAC,MAAM,kCAAkC,CAAA;AAClE,OAAO,EAAC,kBAAkB,EAAC,MAAM,mCAAmC,CAAA;AACpE,OAAO,EAAC,GAAG,EAAC,MAAM,uBAAuB,CAAA;AAGzC,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,KAAK,UAAU,EAChB,MAAM,iCAAiC,CAAA;AAGxC,OAAO,EACL,QAAQ,EACR,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,aAAa,EACb,wBAAwB,EACxB,cAAc,EACd,mBAAmB,EACnB,uBAAuB,EACvB,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,UAAU,EACX,MAAM,0BAA0B,CAAA;AAGjC,OAAO,EACL,qBAAqB,EACrB,KAAK,qBAAqB,EAC3B,MAAM,sCAAsC,CAAA;AAG7C,OAAO,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -26,5 +26,13 @@ export * from "./lib/dbmodels/nonconsprogram/UserNonConsumableProgram.js";
|
|
|
26
26
|
export { AuthenticationUtil } from "./lib/utils/AuthenticationUtil.js";
|
|
27
27
|
export { NotificationsUtil } from "./lib/utils/NotificationsUtil.js";
|
|
28
28
|
export { NotificationClient } from "./lib/utils/NotificationClient.js";
|
|
29
|
+
export { Log } from "./lib/utils/Logger.js";
|
|
30
|
+
//Config
|
|
31
|
+
export { ConfigValidator, BaseConfigSchema, CommonSchemas, createConfig, ConfigurationError } from "./lib/config/ConfigValidator.js";
|
|
32
|
+
//Errors
|
|
33
|
+
export { AppError, ValidationError, AuthenticationError, ForbiddenError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, ServiceUnavailableError, DatabaseError, ExternalAPIError, isAppError, isOperationalError, toAppError } from "./lib/Errors/AppError.js";
|
|
34
|
+
//Middlewares
|
|
35
|
+
export { createErrorMiddleware } from "./lib/middlewares/ErrorMiddleware.js";
|
|
36
|
+
export { RedisClient } from "./lib/classes/Redis.js";
|
|
29
37
|
|
|
30
38
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["//Interfaces\nexport * from \"./lib/models/ProgramInterfaces.js\";\nexport * from \"./lib/models/ExerciseInterfaces.js\";\nexport * from \"./lib/models/WorkoutInterfaces.js\";\nexport * from \"./lib/models/UserInterfaces.js\";\nexport * from \"./lib/models/NotificationInterfaces.js\";\n\n//DB Models\nexport * from \"./lib/dbmodels/UsersFriends.js\"\nexport * from \"./lib/dbmodels/PersistedUser.js\"\nexport * from \"./lib/dbmodels/UserBadges.js\"\nexport * from \"./lib/dbmodels/UserStreaks.js\"\nexport * from \"./lib/dbmodels/Badge.js\"\nexport * from \"./lib/dbmodels/program/Program.js\"\nexport * from \"./lib/dbmodels/program/Workout.js\"\nexport * from \"./lib/dbmodels/program/Exercise.js\"\nexport * from \"./lib/dbmodels/program/ExerciseModels.js\"\nexport * from \"./lib/dbmodels/program/Superset.js\"\nexport * from \"./lib/dbmodels/Subscription.js\"\nexport * from \"./lib/dbmodels/SubscriptionLog.js\"\nexport * from \"./lib/dbmodels/nonconsprogram/NonConsumableProgram.js\"\nexport * from \"./lib/dbmodels/nonconsprogram/TranslatedNonConsumableProgramWebContent.js\"\nexport * from \"./lib/dbmodels/nonconsprogram/TranslatedConsumableProgram.js\"\nexport * from \"./lib/dbmodels/nonconsprogram/NonConsumableProgramWebContent.js\"\nexport * from \"./lib/dbmodels/nonconsprogram/UserNonConsumableProgram.js\"\n\n
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["//Interfaces\nexport * from \"./lib/models/ProgramInterfaces.js\";\nexport * from \"./lib/models/ExerciseInterfaces.js\";\nexport * from \"./lib/models/WorkoutInterfaces.js\";\nexport * from \"./lib/models/UserInterfaces.js\";\nexport * from \"./lib/models/NotificationInterfaces.js\";\n\n//DB Models\nexport * from \"./lib/dbmodels/UsersFriends.js\"\nexport * from \"./lib/dbmodels/PersistedUser.js\"\nexport * from \"./lib/dbmodels/UserBadges.js\"\nexport * from \"./lib/dbmodels/UserStreaks.js\"\nexport * from \"./lib/dbmodels/Badge.js\"\nexport * from \"./lib/dbmodels/program/Program.js\"\nexport * from \"./lib/dbmodels/program/Workout.js\"\nexport * from \"./lib/dbmodels/program/Exercise.js\"\nexport * from \"./lib/dbmodels/program/ExerciseModels.js\"\nexport * from \"./lib/dbmodels/program/Superset.js\"\nexport * from \"./lib/dbmodels/Subscription.js\"\nexport * from \"./lib/dbmodels/SubscriptionLog.js\"\nexport * from \"./lib/dbmodels/nonconsprogram/NonConsumableProgram.js\"\nexport * from \"./lib/dbmodels/nonconsprogram/TranslatedNonConsumableProgramWebContent.js\"\nexport * from \"./lib/dbmodels/nonconsprogram/TranslatedConsumableProgram.js\"\nexport * from \"./lib/dbmodels/nonconsprogram/NonConsumableProgramWebContent.js\"\nexport * from \"./lib/dbmodels/nonconsprogram/UserNonConsumableProgram.js\"\n\n//Utils\nexport {AuthenticationUtil} from \"./lib/utils/AuthenticationUtil.js\"\nexport {NotificationsUtil} from \"./lib/utils/NotificationsUtil.js\"\nexport {NotificationClient} from \"./lib/utils/NotificationClient.js\"\nexport {Log} from \"./lib/utils/Logger.js\"\n\n//Config\nexport {\n ConfigValidator,\n BaseConfigSchema,\n CommonSchemas,\n createConfig,\n ConfigurationError,\n type BaseConfig\n} from \"./lib/config/ConfigValidator.js\"\n\n//Errors\nexport {\n AppError,\n ValidationError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n UnprocessableEntityError,\n RateLimitError,\n InternalServerError,\n ServiceUnavailableError,\n DatabaseError,\n ExternalAPIError,\n isAppError,\n isOperationalError,\n toAppError\n} from \"./lib/Errors/AppError.js\"\n\n//Middlewares\nexport {\n createErrorMiddleware,\n type ErrorMiddlewareConfig\n} from \"./lib/middlewares/ErrorMiddleware.js\"\n\n\nexport {RedisClient} from \"./lib/classes/Redis.js\""],"names":["AuthenticationUtil","NotificationsUtil","NotificationClient","Log","ConfigValidator","BaseConfigSchema","CommonSchemas","createConfig","ConfigurationError","AppError","ValidationError","AuthenticationError","ForbiddenError","NotFoundError","ConflictError","UnprocessableEntityError","RateLimitError","InternalServerError","ServiceUnavailableError","DatabaseError","ExternalAPIError","isAppError","isOperationalError","toAppError","createErrorMiddleware","RedisClient"],"mappings":"AAAA,YAAY;AACZ,cAAc,oCAAoC;AAClD,cAAc,qCAAqC;AACnD,cAAc,oCAAoC;AAClD,cAAc,iCAAiC;AAC/C,cAAc,yCAAyC;AAEvD,WAAW;AACX,cAAc,iCAAgC;AAC9C,cAAc,kCAAiC;AAC/C,cAAc,+BAA8B;AAC5C,cAAc,gCAA+B;AAC7C,cAAc,0BAAyB;AACvC,cAAc,oCAAmC;AACjD,cAAc,oCAAmC;AACjD,cAAc,qCAAoC;AAClD,cAAc,2CAA0C;AACxD,cAAc,qCAAoC;AAClD,cAAc,iCAAgC;AAC9C,cAAc,oCAAmC;AACjD,cAAc,wDAAuD;AACrE,cAAc,4EAA2E;AACzF,cAAc,+DAA8D;AAC5E,cAAc,kEAAiE;AAC/E,cAAc,4DAA2D;AAEzE,OAAO;AACP,SAAQA,kBAAkB,QAAO,oCAAmC;AACpE,SAAQC,iBAAiB,QAAO,mCAAkC;AAClE,SAAQC,kBAAkB,QAAO,oCAAmC;AACpE,SAAQC,GAAG,QAAO,wBAAuB;AAEzC,QAAQ;AACR,SACEC,eAAe,EACfC,gBAAgB,EAChBC,aAAa,EACbC,YAAY,EACZC,kBAAkB,QAEb,kCAAiC;AAExC,QAAQ;AACR,SACEC,QAAQ,EACRC,eAAe,EACfC,mBAAmB,EACnBC,cAAc,EACdC,aAAa,EACbC,aAAa,EACbC,wBAAwB,EACxBC,cAAc,EACdC,mBAAmB,EACnBC,uBAAuB,EACvBC,aAAa,EACbC,gBAAgB,EAChBC,UAAU,EACVC,kBAAkB,EAClBC,UAAU,QACL,2BAA0B;AAEjC,aAAa;AACb,SACEC,qBAAqB,QAEhB,uCAAsC;AAG7C,SAAQC,WAAW,QAAO,yBAAwB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export declare class AppError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
readonly statusCode: number;
|
|
4
|
+
readonly details?: unknown | undefined;
|
|
5
|
+
readonly isOperational: boolean;
|
|
6
|
+
constructor(code: string, message: string, statusCode: number, details?: unknown | undefined, isOperational?: boolean);
|
|
7
|
+
toJSON(): {
|
|
8
|
+
error: Record<string, unknown>;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export declare class ValidationError extends AppError {
|
|
12
|
+
constructor(message: string, details?: unknown);
|
|
13
|
+
}
|
|
14
|
+
export declare class AuthenticationError extends AppError {
|
|
15
|
+
constructor(message?: string);
|
|
16
|
+
}
|
|
17
|
+
export declare class ForbiddenError extends AppError {
|
|
18
|
+
constructor(message?: string);
|
|
19
|
+
}
|
|
20
|
+
export declare class NotFoundError extends AppError {
|
|
21
|
+
constructor(resource?: string);
|
|
22
|
+
}
|
|
23
|
+
export declare class ConflictError extends AppError {
|
|
24
|
+
constructor(message: string, details?: unknown);
|
|
25
|
+
}
|
|
26
|
+
export declare class UnprocessableEntityError extends AppError {
|
|
27
|
+
constructor(message: string, details?: unknown);
|
|
28
|
+
}
|
|
29
|
+
export declare class RateLimitError extends AppError {
|
|
30
|
+
constructor(message?: string);
|
|
31
|
+
}
|
|
32
|
+
export declare class InternalServerError extends AppError {
|
|
33
|
+
constructor(message?: string, details?: unknown);
|
|
34
|
+
}
|
|
35
|
+
export declare class ServiceUnavailableError extends AppError {
|
|
36
|
+
constructor(service?: string);
|
|
37
|
+
}
|
|
38
|
+
export declare class DatabaseError extends AppError {
|
|
39
|
+
constructor(message: string, details?: unknown);
|
|
40
|
+
}
|
|
41
|
+
export declare class ExternalAPIError extends AppError {
|
|
42
|
+
constructor(service: string, message: string, statusCode?: number, details?: unknown);
|
|
43
|
+
}
|
|
44
|
+
export declare function isAppError(error: unknown): error is AppError;
|
|
45
|
+
export declare function isOperationalError(error: unknown): boolean;
|
|
46
|
+
export declare function toAppError(error: unknown): AppError;
|
|
47
|
+
//# sourceMappingURL=AppError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppError.d.ts","sourceRoot":"","sources":["../../../src/lib/Errors/AppError.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAS,SAAQ,KAAK;aAIb,IAAI,EAAE,MAAM;aAEZ,UAAU,EAAE,MAAM;aAClB,OAAO,CAAC,EAAE,OAAO;IANrC,SAAgB,aAAa,EAAE,OAAO,CAAC;gBAGnB,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM,EACC,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,OAAO,YAAA,EACjC,aAAa,UAAO;IAQxB,MAAM;;;CAYP;AAGD,qBAAa,eAAgB,SAAQ,QAAQ;gBAC/B,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;CAG/C;AAGD,qBAAa,mBAAoB,SAAQ,QAAQ;gBACnC,OAAO,GAAE,MAAkC;CAGxD;AAGD,qBAAa,cAAe,SAAQ,QAAQ;gBAC9B,OAAO,GAAE,MAA2B;CAGjD;AAGD,qBAAa,aAAc,SAAQ,QAAQ;gBAC7B,QAAQ,GAAE,MAAmB;CAG1C;AAGD,qBAAa,aAAc,SAAQ,QAAQ;gBAC7B,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;CAG/C;AAGD,qBAAa,wBAAyB,SAAQ,QAAQ;gBACxC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;CAG/C;AAED,qBAAa,cAAe,SAAQ,QAAQ;gBAC9B,OAAO,GAAE,MAAoD;CAG1E;AAGD,qBAAa,mBAAoB,SAAQ,QAAQ;gBACnC,OAAO,GAAE,MAAgC,EAAE,OAAO,CAAC,EAAE,OAAO;CAGzE;AAGD,qBAAa,uBAAwB,SAAQ,QAAQ;gBACvC,OAAO,GAAE,MAAkB;CAGxC;AAGD,qBAAa,aAAc,SAAQ,QAAQ;gBAC7B,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;CAG/C;AAGD,qBAAa,gBAAiB,SAAQ,QAAQ;gBAE1C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,UAAU,GAAE,MAAY,EACxB,OAAO,CAAC,EAAE,OAAO;CASpB;AAGD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D;AAGD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAK1D;AAGD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAenD"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
export class AppError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
statusCode;
|
|
4
|
+
details;
|
|
5
|
+
isOperational;
|
|
6
|
+
constructor(code, message, statusCode, details, isOperational = true){
|
|
7
|
+
super(message), this.code = code, this.statusCode = statusCode, this.details = details;
|
|
8
|
+
this.name = new.target.name;
|
|
9
|
+
this.isOperational = isOperational;
|
|
10
|
+
Error.captureStackTrace?.(this, new.target);
|
|
11
|
+
}
|
|
12
|
+
toJSON() {
|
|
13
|
+
const error = {
|
|
14
|
+
code: this.code,
|
|
15
|
+
message: this.message
|
|
16
|
+
};
|
|
17
|
+
if (this.details !== undefined) {
|
|
18
|
+
error.details = this.details;
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
error
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export class ValidationError extends AppError {
|
|
26
|
+
constructor(message, details){
|
|
27
|
+
super('VALIDATION_ERROR', message, 400, details);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export class AuthenticationError extends AppError {
|
|
31
|
+
constructor(message = 'Authentication required'){
|
|
32
|
+
super('AUTHENTICATION_ERROR', message, 401);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export class ForbiddenError extends AppError {
|
|
36
|
+
constructor(message = 'Access forbidden'){
|
|
37
|
+
super('FORBIDDEN', message, 403);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export class NotFoundError extends AppError {
|
|
41
|
+
constructor(resource = 'Resource'){
|
|
42
|
+
super('NOT_FOUND', `${resource} not found`, 404);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export class ConflictError extends AppError {
|
|
46
|
+
constructor(message, details){
|
|
47
|
+
super('CONFLICT', message, 409, details);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export class UnprocessableEntityError extends AppError {
|
|
51
|
+
constructor(message, details){
|
|
52
|
+
super('UNPROCESSABLE_ENTITY', message, 422, details);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export class RateLimitError extends AppError {
|
|
56
|
+
constructor(message = 'Too many requests, please try again later'){
|
|
57
|
+
super('RATE_LIMIT_EXCEEDED', message, 429);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export class InternalServerError extends AppError {
|
|
61
|
+
constructor(message = 'Internal server error', details){
|
|
62
|
+
super('INTERNAL_ERROR', message, 500, details, false);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export class ServiceUnavailableError extends AppError {
|
|
66
|
+
constructor(service = 'Service'){
|
|
67
|
+
super('SERVICE_UNAVAILABLE', `${service} is temporarily unavailable`, 503);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export class DatabaseError extends AppError {
|
|
71
|
+
constructor(message, details){
|
|
72
|
+
super('DATABASE_ERROR', message, 500, details, false);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export class ExternalAPIError extends AppError {
|
|
76
|
+
constructor(service, message, statusCode = 502, details){
|
|
77
|
+
super('EXTERNAL_API_ERROR', `${service}: ${message}`, statusCode, details);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export function isAppError(error) {
|
|
81
|
+
return error instanceof AppError;
|
|
82
|
+
}
|
|
83
|
+
export function isOperationalError(error) {
|
|
84
|
+
if (error instanceof AppError) {
|
|
85
|
+
return error.isOperational;
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
export function toAppError(error) {
|
|
90
|
+
if (error instanceof AppError) {
|
|
91
|
+
return error;
|
|
92
|
+
}
|
|
93
|
+
if (error instanceof Error) {
|
|
94
|
+
return new InternalServerError(error.message, {
|
|
95
|
+
originalError: error.name,
|
|
96
|
+
stack: error.stack
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return new InternalServerError('An unexpected error occurred', {
|
|
100
|
+
error: String(error)
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
//# sourceMappingURL=AppError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/Errors/AppError.ts"],"sourcesContent":["export class AppError extends Error {\n public readonly isOperational: boolean;\n\n constructor(\n public readonly code: string,\n message: string,\n public readonly statusCode: number,\n public readonly details?: unknown,\n isOperational = true\n ) {\n super(message);\n this.name = new.target.name;\n this.isOperational = isOperational;\n Error.captureStackTrace?.(this, new.target);\n }\n\n toJSON() {\n const error: Record<string, unknown> = {\n code: this.code,\n message: this.message,\n };\n\n if (this.details !== undefined) {\n error.details = this.details;\n }\n\n return { error };\n }\n}\n\n\nexport class ValidationError extends AppError {\n constructor(message: string, details?: unknown) {\n super('VALIDATION_ERROR', message, 400, details);\n }\n}\n\n\nexport class AuthenticationError extends AppError {\n constructor(message: string = 'Authentication required') {\n super('AUTHENTICATION_ERROR', message, 401);\n }\n}\n\n\nexport class ForbiddenError extends AppError {\n constructor(message: string = 'Access forbidden') {\n super('FORBIDDEN', message, 403);\n }\n}\n\n\nexport class NotFoundError extends AppError {\n constructor(resource: string = 'Resource') {\n super('NOT_FOUND', `${resource} not found`, 404);\n }\n}\n\n\nexport class ConflictError extends AppError {\n constructor(message: string, details?: unknown) {\n super('CONFLICT', message, 409, details);\n }\n}\n\n\nexport class UnprocessableEntityError extends AppError {\n constructor(message: string, details?: unknown) {\n super('UNPROCESSABLE_ENTITY', message, 422, details);\n }\n}\n\nexport class RateLimitError extends AppError {\n constructor(message: string = 'Too many requests, please try again later') {\n super('RATE_LIMIT_EXCEEDED', message, 429);\n }\n}\n\n\nexport class InternalServerError extends AppError {\n constructor(message: string = 'Internal server error', details?: unknown) {\n super('INTERNAL_ERROR', message, 500, details, false);\n }\n}\n\n\nexport class ServiceUnavailableError extends AppError {\n constructor(service: string = 'Service') {\n super('SERVICE_UNAVAILABLE', `${service} is temporarily unavailable`, 503);\n }\n}\n\n\nexport class DatabaseError extends AppError {\n constructor(message: string, details?: unknown) {\n super('DATABASE_ERROR', message, 500, details, false);\n }\n}\n\n\nexport class ExternalAPIError extends AppError {\n constructor(\n service: string,\n message: string,\n statusCode: number = 502,\n details?: unknown\n ) {\n super(\n 'EXTERNAL_API_ERROR',\n `${service}: ${message}`,\n statusCode,\n details\n );\n }\n}\n\n\nexport function isAppError(error: unknown): error is AppError {\n return error instanceof AppError;\n}\n\n\nexport function isOperationalError(error: unknown): boolean {\n if (error instanceof AppError) {\n return error.isOperational;\n }\n return false;\n}\n\n\nexport function toAppError(error: unknown): AppError {\n if (error instanceof AppError) {\n return error;\n }\n\n if (error instanceof Error) {\n return new InternalServerError(error.message, {\n originalError: error.name,\n stack: error.stack,\n });\n }\n\n return new InternalServerError('An unexpected error occurred', {\n error: String(error),\n });\n}\n"],"names":["AppError","Error","isOperational","code","message","statusCode","details","name","captureStackTrace","toJSON","error","undefined","ValidationError","AuthenticationError","ForbiddenError","NotFoundError","resource","ConflictError","UnprocessableEntityError","RateLimitError","InternalServerError","ServiceUnavailableError","service","DatabaseError","ExternalAPIError","isAppError","isOperationalError","toAppError","originalError","stack","String"],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Redis } from "ioredis";
|
|
2
|
+
export declare class RedisClient {
|
|
3
|
+
private static instance;
|
|
4
|
+
private constructor();
|
|
5
|
+
static getInstance(): Redis;
|
|
6
|
+
static get(key: string): Promise<string | null>;
|
|
7
|
+
static set(key: string, value: string, expirySeconds?: number): Promise<string>;
|
|
8
|
+
static del(key: string): Promise<number>;
|
|
9
|
+
static getJSON<T>(key: string): Promise<T | null>;
|
|
10
|
+
static setJSON(key: string, value: any, expirySeconds?: number): Promise<string>;
|
|
11
|
+
static waitForFill<T>(key: string, timeoutMs?: number, pollMs?: number): Promise<T | null>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=Redis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Redis.d.ts","sourceRoot":"","sources":["../../../src/lib/classes/Redis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAMhC,qBAAa,WAAW;IACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAQ;IAE/B,OAAO;WAEO,WAAW,IAAI,KAAK;WA2Bd,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;WAKxC,GAAG,CACnB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,aAAa,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC;WAQE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;WAKjC,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;WAK1C,OAAO,CACvB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,GAAG,EACV,aAAa,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC;WAKE,WAAW,CAAC,CAAC,EAC7B,GAAG,EAAE,MAAM,EACX,SAAS,SAAO,EAChB,MAAM,SAAM,GACb,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;CASvB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Redis } from "ioredis";
|
|
2
|
+
import { Log } from "../utils/Logger.js";
|
|
3
|
+
const logger = Log.getInstance().extend("redis-client");
|
|
4
|
+
export class RedisClient {
|
|
5
|
+
static instance;
|
|
6
|
+
constructor(){}
|
|
7
|
+
static getInstance() {
|
|
8
|
+
if (!RedisClient.instance) {
|
|
9
|
+
const REDIS_HOST = process.env.REDIS_HOST || "localhost";
|
|
10
|
+
const REDIS_PORT = process.env.REDIS_PORT || 6379;
|
|
11
|
+
const options = {
|
|
12
|
+
host: REDIS_HOST,
|
|
13
|
+
port: Number(REDIS_PORT),
|
|
14
|
+
maxRetriesPerRequest: null,
|
|
15
|
+
enableAutoPipelining: true,
|
|
16
|
+
connectTimeout: 5000,
|
|
17
|
+
lazyConnect: false
|
|
18
|
+
};
|
|
19
|
+
RedisClient.instance = new Redis(options);
|
|
20
|
+
RedisClient.instance.on("connect", ()=>{
|
|
21
|
+
logger.info("Connected to Redis");
|
|
22
|
+
});
|
|
23
|
+
RedisClient.instance.on("error", (err)=>{
|
|
24
|
+
logger.error("Redis error:", err);
|
|
25
|
+
});
|
|
26
|
+
logger.info(`Redis status: ${RedisClient.instance.status}`);
|
|
27
|
+
}
|
|
28
|
+
return RedisClient.instance;
|
|
29
|
+
}
|
|
30
|
+
static async get(key) {
|
|
31
|
+
const client = this.getInstance();
|
|
32
|
+
return client.get(key);
|
|
33
|
+
}
|
|
34
|
+
static async set(key, value, expirySeconds) {
|
|
35
|
+
const client = this.getInstance();
|
|
36
|
+
if (expirySeconds) {
|
|
37
|
+
return client.set(key, value, "EX", expirySeconds);
|
|
38
|
+
}
|
|
39
|
+
return client.set(key, value);
|
|
40
|
+
}
|
|
41
|
+
static async del(key) {
|
|
42
|
+
const client = this.getInstance();
|
|
43
|
+
return client.del(key);
|
|
44
|
+
}
|
|
45
|
+
static async getJSON(key) {
|
|
46
|
+
const raw = await this.get(key);
|
|
47
|
+
return raw ? JSON.parse(raw) : null;
|
|
48
|
+
}
|
|
49
|
+
static async setJSON(key, value, expirySeconds) {
|
|
50
|
+
return this.set(key, JSON.stringify(value), expirySeconds);
|
|
51
|
+
}
|
|
52
|
+
static async waitForFill(key, timeoutMs = 8000, pollMs = 150) {
|
|
53
|
+
const start = Date.now();
|
|
54
|
+
while(Date.now() - start < timeoutMs){
|
|
55
|
+
const v = await this.getJSON(key);
|
|
56
|
+
if (v) return v;
|
|
57
|
+
await new Promise((r)=>setTimeout(r, pollMs));
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=Redis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/classes/Redis.ts"],"sourcesContent":["import { Redis } from \"ioredis\";\nimport type { RedisOptions } from \"ioredis\";\nimport {Log} from \"../utils/Logger.js\";\n\nconst logger: Log = Log.getInstance().extend(\"redis-client\");\n\nexport class RedisClient {\n private static instance: Redis;\n\n private constructor() {}\n\n public static getInstance(): Redis {\n if (!RedisClient.instance) {\n const REDIS_HOST = process.env.REDIS_HOST || \"localhost\";\n const REDIS_PORT = process.env.REDIS_PORT || 6379;\n\n const options: RedisOptions = {\n host: REDIS_HOST,\n port: Number(REDIS_PORT),\n maxRetriesPerRequest: null,\n enableAutoPipelining: true,\n connectTimeout: 5000,\n lazyConnect: false,\n };\n\n RedisClient.instance = new Redis(options);\n\n RedisClient.instance.on(\"connect\", () => {\n logger.info(\"Connected to Redis\");\n });\n RedisClient.instance.on(\"error\", (err) => {\n logger.error(\"Redis error:\", err);\n });\n logger.info(`Redis status: ${RedisClient.instance.status}`);\n }\n return RedisClient.instance;\n }\n\n public static async get(key: string): Promise<string | null> {\n const client = this.getInstance();\n return client.get(key);\n }\n\n public static async set(\n key: string,\n value: string,\n expirySeconds?: number,\n ): Promise<string> {\n const client = this.getInstance();\n if (expirySeconds) {\n return client.set(key, value, \"EX\", expirySeconds);\n }\n return client.set(key, value);\n }\n\n public static async del(key: string): Promise<number> {\n const client = this.getInstance();\n return client.del(key);\n }\n\n public static async getJSON<T>(key: string): Promise<T | null> {\n const raw = await this.get(key);\n return raw ? (JSON.parse(raw) as T) : null;\n }\n\n public static async setJSON(\n key: string,\n value: any,\n expirySeconds?: number,\n ): Promise<string> {\n return this.set(key, JSON.stringify(value), expirySeconds);\n }\n\n\n public static async waitForFill<T>(\n key: string,\n timeoutMs = 8000,\n pollMs = 150,\n ): Promise<T | null> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n const v = await this.getJSON<T>(key);\n if (v) return v;\n await new Promise((r) => setTimeout(r, pollMs));\n }\n return null;\n }\n}"],"names":["Redis","Log","logger","getInstance","extend","RedisClient","instance","REDIS_HOST","process","env","REDIS_PORT","options","host","port","Number","maxRetriesPerRequest","enableAutoPipelining","connectTimeout","lazyConnect","on","info","err","error","status","get","key","client","set","value","expirySeconds","del","getJSON","raw","JSON","parse","setJSON","stringify","waitForFill","timeoutMs","pollMs","start","Date","now","v","Promise","r","setTimeout"],"mappings":"AAAA,SAASA,KAAK,QAAQ,UAAU;AAEhC,SAAQC,GAAG,QAAO,qBAAqB;AAEvC,MAAMC,SAAcD,IAAIE,WAAW,GAAGC,MAAM,CAAC;AAE7C,OAAO,MAAMC;IACT,OAAeC,SAAgB;IAE/B,aAAsB,CAAC;IAEvB,OAAcH,cAAqB;QAC/B,IAAI,CAACE,YAAYC,QAAQ,EAAE;YACvB,MAAMC,aAAaC,QAAQC,GAAG,CAACF,UAAU,IAAI;YAC7C,MAAMG,aAAaF,QAAQC,GAAG,CAACC,UAAU,IAAI;YAE7C,MAAMC,UAAwB;gBAC1BC,MAAML;gBACNM,MAAMC,OAAOJ;gBACbK,sBAAsB;gBACtBC,sBAAsB;gBACtBC,gBAAgB;gBAChBC,aAAa;YACjB;YAEAb,YAAYC,QAAQ,GAAG,IAAIN,MAAMW;YAEjCN,YAAYC,QAAQ,CAACa,EAAE,CAAC,WAAW;gBAC/BjB,OAAOkB,IAAI,CAAC;YAChB;YACAf,YAAYC,QAAQ,CAACa,EAAE,CAAC,SAAS,CAACE;gBAC9BnB,OAAOoB,KAAK,CAAC,gBAAgBD;YACjC;YACAnB,OAAOkB,IAAI,CAAC,CAAC,cAAc,EAAEf,YAAYC,QAAQ,CAACiB,MAAM,EAAE;QAC9D;QACA,OAAOlB,YAAYC,QAAQ;IAC/B;IAEA,aAAoBkB,IAAIC,GAAW,EAA0B;QACzD,MAAMC,SAAS,IAAI,CAACvB,WAAW;QAC/B,OAAOuB,OAAOF,GAAG,CAACC;IACtB;IAEA,aAAoBE,IAChBF,GAAW,EACXG,KAAa,EACbC,aAAsB,EACP;QACf,MAAMH,SAAS,IAAI,CAACvB,WAAW;QAC/B,IAAI0B,eAAe;YACf,OAAOH,OAAOC,GAAG,CAACF,KAAKG,OAAO,MAAMC;QACxC;QACA,OAAOH,OAAOC,GAAG,CAACF,KAAKG;IAC3B;IAEA,aAAoBE,IAAIL,GAAW,EAAmB;QAClD,MAAMC,SAAS,IAAI,CAACvB,WAAW;QAC/B,OAAOuB,OAAOI,GAAG,CAACL;IACtB;IAEA,aAAoBM,QAAWN,GAAW,EAAqB;QAC3D,MAAMO,MAAM,MAAM,IAAI,CAACR,GAAG,CAACC;QAC3B,OAAOO,MAAOC,KAAKC,KAAK,CAACF,OAAa;IAC1C;IAEA,aAAoBG,QAChBV,GAAW,EACXG,KAAU,EACVC,aAAsB,EACP;QACf,OAAO,IAAI,CAACF,GAAG,CAACF,KAAKQ,KAAKG,SAAS,CAACR,QAAQC;IAChD;IAGA,aAAoBQ,YAChBZ,GAAW,EACXa,YAAY,IAAI,EAChBC,SAAS,GAAG,EACK;QACjB,MAAMC,QAAQC,KAAKC,GAAG;QACtB,MAAOD,KAAKC,GAAG,KAAKF,QAAQF,UAAW;YACnC,MAAMK,IAAI,MAAM,IAAI,CAACZ,OAAO,CAAIN;YAChC,IAAIkB,GAAG,OAAOA;YACd,MAAM,IAAIC,QAAQ,CAACC,IAAMC,WAAWD,GAAGN;QAC3C;QACA,OAAO;IACX;AACJ"}
|