@shadimakhoul/ggcoach 1.0.21 → 1.0.23

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 ADDED
@@ -0,0 +1,381 @@
1
+ # @shadimakhoul/ggcoach
2
+
3
+ Shared utilities, middleware, and types for Node.js/Express microservices.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @shadimakhoul/ggcoach
9
+ ```
10
+
11
+ ## Contents
12
+
13
+ - [JWT](#jwt)
14
+ - [Middleware](#middleware)
15
+ - [Request Validation](#request-validation)
16
+ - [OpenAPI / Swagger](#openapi--swagger)
17
+ - [Config & Bootstrap](#config--bootstrap)
18
+ - [Logger](#logger)
19
+ - [Types](#types)
20
+
21
+ ---
22
+
23
+ ## JWT
24
+
25
+ Generic JWT helpers. You define the payload shape; the library handles signing and verification.
26
+
27
+ ```ts
28
+ import { generateToken, generateRefreshToken, verifyToken, JWTConfig, BaseJWTPayload } from '@shadimakhoul/ggcoach';
29
+ ```
30
+
31
+ ### `JWTConfig`
32
+
33
+ ```ts
34
+ interface JWTConfig {
35
+ secret: string;
36
+ expiresIn: string; // e.g. '1h', '7d'
37
+ issuer: string; // e.g. 'my-auth-service'
38
+ audience: string; // e.g. 'my-app'
39
+ }
40
+ ```
41
+
42
+ ### `BaseJWTPayload`
43
+
44
+ The minimum shape required by the library. Extend it with your own fields.
45
+
46
+ ```ts
47
+ interface BaseJWTPayload {
48
+ tokenType?: 'access' | 'refresh';
49
+ tokenVersion?: number;
50
+ }
51
+ ```
52
+
53
+ ### Usage
54
+
55
+ ```ts
56
+ // 1. Define your payload
57
+ interface MyPayload extends BaseJWTPayload {
58
+ userId: string;
59
+ role: string;
60
+ }
61
+
62
+ const config: JWTConfig = {
63
+ secret: process.env.JWT_SECRET!,
64
+ expiresIn: '1h',
65
+ issuer: 'my-auth-service',
66
+ audience: 'my-app',
67
+ };
68
+
69
+ // 2. Issue tokens
70
+ const accessToken = generateToken<MyPayload>(config, { userId: '123', role: 'admin' });
71
+ const refreshToken = generateRefreshToken<MyPayload>(config, { userId: '123', role: 'admin' });
72
+ // tokenType is stamped automatically: 'access' / 'refresh'
73
+
74
+ // 3. Verify
75
+ const decoded = verifyToken<MyPayload>(config, accessToken);
76
+ // decoded.tokenType === 'access'
77
+ ```
78
+
79
+ > `verifyToken` throws `Error('Invalid or expired token')` on failure.
80
+
81
+ ---
82
+
83
+ ## Middleware
84
+
85
+ ```ts
86
+ import {
87
+ authenticateToken,
88
+ optionalAuth,
89
+ requireAdmin,
90
+ requireSuperAdmin,
91
+ requireInternalToken,
92
+ createRateLimiter,
93
+ authRateLimiter,
94
+ generalRateLimiter,
95
+ errorHandler,
96
+ createCorsOptions,
97
+ corsMiddleware,
98
+ } from '@shadimakhoul/ggcoach';
99
+ ```
100
+
101
+ ### `authenticateToken(JWT_SECRET)`
102
+
103
+ Express middleware that reads a `Bearer` token from `Authorization`, verifies it (issuer `ggcoach-auth-service`, audience `ggcoach-app`), checks the token version against Redis, and sets `req.user`. Requires Redis to be initialized (see [Redis](#redis)).
104
+
105
+ ```ts
106
+ app.use(authenticateToken(process.env.JWT_SECRET!));
107
+ ```
108
+
109
+ ### `optionalAuth(JWT_SECRET)`
110
+
111
+ Same as `authenticateToken` but does not reject the request if no token is provided or if it's invalid. `req.user` is set only when a valid token is present.
112
+
113
+ ```ts
114
+ app.use(optionalAuth(process.env.JWT_SECRET!));
115
+ ```
116
+
117
+ ### `requireAdmin` / `requireSuperAdmin`
118
+
119
+ Guards that check `req.user.accountType`. Must be placed after `authenticateToken`.
120
+
121
+ ```ts
122
+ router.get('/admin/users', authenticateToken(secret), requireAdmin, handler);
123
+ router.post('/admin/promote', authenticateToken(secret), requireSuperAdmin, handler);
124
+ ```
125
+
126
+ ### `requireInternalToken(ALLOW_DIRECT_ACCESS, INTERNAL_SERVICE_TOKEN)`
127
+
128
+ Validates the `x-internal-token` header for service-to-service calls.
129
+
130
+ ```ts
131
+ app.use(requireInternalToken(
132
+ process.env.ALLOW_DIRECT_ACCESS === 'true',
133
+ process.env.INTERNAL_SERVICE_TOKEN!,
134
+ ));
135
+ ```
136
+
137
+ ### Rate limiters
138
+
139
+ ```ts
140
+ // Pre-built limiters
141
+ app.use('/auth', authRateLimiter); // 5 req / 15 min
142
+ app.use(generalRateLimiter); // 1000 req / 15 min
143
+
144
+ // Custom limiter
145
+ const customLimiter = createRateLimiter(
146
+ 5 * 60 * 1000, // windowMs
147
+ 20, // max requests
148
+ );
149
+ ```
150
+
151
+ ### `errorHandler`
152
+
153
+ Centralised Express error handler. Recognises `ECONNREFUSED`/`ETIMEDOUT` socket errors and Sequelize/Joi validation errors, mapping each to an appropriate status code. In `development`, also echoes the stack trace and `x-request-id` header. Register as the last middleware.
154
+
155
+ ```ts
156
+ app.use(errorHandler);
157
+ ```
158
+
159
+ ### `createCorsOptions(allowedOrigins?, allowedHosts?)` / `corsMiddleware`
160
+
161
+ Returns a CORS options object for the `cors` package. Passing no arguments allows all origins. `corsMiddleware` is a ready-to-use instance built from the no-argument defaults.
162
+
163
+ ```ts
164
+ // Allow specific origins and wildcard sub-domains
165
+ app.use(cors(createCorsOptions(
166
+ ['https://app.example.com'],
167
+ ['example.com'], // matches *.example.com
168
+ )));
169
+ ```
170
+
171
+ ---
172
+
173
+ ## Request Validation
174
+
175
+ ```ts
176
+ import { validateRequest, validateRequestZod, validateUploadedFilesZod } from '@shadimakhoul/ggcoach';
177
+ ```
178
+
179
+ ### `validateRequest(joiSchema)`
180
+
181
+ Validates `req.body` against a Joi schema, stripping unknown keys and collecting all errors before responding `400`.
182
+
183
+ ```ts
184
+ router.post('/users', validateRequest(createUserJoiSchema), handler);
185
+ ```
186
+
187
+ ### `validateRequestZod(zodSchema, target?, contentType?)`
188
+
189
+ Validates `req.body` (default), `req.params`, or `req.query` against a Zod schema and replaces it with the parsed value.
190
+
191
+ ```ts
192
+ router.get('/users/:id', validateRequestZod(idParamSchema, 'params'), handler);
193
+ router.post('/users', validateRequestZod(createUserSchema), handler);
194
+ ```
195
+
196
+ ### `validateUploadedFilesZod(fileSchema, requestBodySchema?)`
197
+
198
+ Validates `req.files` (e.g. from `multer`) against a Zod schema. Intended for `multipart/form-data` uploads.
199
+
200
+ ```ts
201
+ router.post('/upload', validateUploadedFilesZod(fileArraySchema), handler);
202
+ ```
203
+
204
+ > All three attach schema metadata (`__schema`, `__schemaType`, `__schemaTarget`, `__contentType`) to the middleware function, which [`buildOpenApiSpecFromExpress`](#openapi--swagger) reads to auto-generate request bodies/parameters.
205
+
206
+ ---
207
+
208
+ ## OpenAPI / Swagger
209
+
210
+ ```ts
211
+ import { buildOpenApiSpecFromExpress, zodToOpenAPI, setupSwagger } from '@shadimakhoul/ggcoach';
212
+ ```
213
+
214
+ ### `buildOpenApiSpecFromExpress(app, baseSpec, options?)`
215
+
216
+ Walks a live Express app's router stack and generates an OpenAPI paths object: routes and methods via `express-list-endpoints`, request bodies/parameters from any `validateRequest*` schemas attached to route handlers, and a `security: [{ bearerAuth: [] }]` requirement on routes guarded by `authenticateToken`, `requireAdmin`, or `requireSuperAdmin`. Generated paths are merged under whatever `paths` already exist on `baseSpec`.
217
+
218
+ ```ts
219
+ const spec = buildOpenApiSpecFromExpress(app, {
220
+ openapi: '3.0.0',
221
+ info: { title: 'My Service', version: '1.0.0' },
222
+ paths: {},
223
+ }, {
224
+ tagResolver: (path, method) => (path.startsWith('/admin') ? ['Admin'] : ['Public']),
225
+ });
226
+ ```
227
+
228
+ ### `zodToOpenAPI(zodSchema)`
229
+
230
+ Converts a Zod schema to an OpenAPI-compatible JSON Schema object (normalises `z.toJSONSchema` output — nullable unions, `const`, nested `properties`/`items`/`oneOf`/`anyOf`/`allOf`). Used internally by `buildOpenApiSpecFromExpress`.
231
+
232
+ ### `setupSwagger(port, app, options?)`
233
+
234
+ Serves `swagger.json` and the Swagger UI (pre-themed dark mode) on an Express app.
235
+
236
+ ```ts
237
+ setupSwagger(3000, app, {
238
+ getSpec: () => buildOpenApiSpecFromExpress(app, baseSpec),
239
+ // or a static spec:
240
+ // spec: mySpec,
241
+ basePath: '/api-docs', // default
242
+ });
243
+ ```
244
+
245
+ ---
246
+
247
+ ## Config & Bootstrap
248
+
249
+ ### `initExpress(isDevelopment, allowedOrigins?, allowedHosts?)`
250
+
251
+ Creates a pre-configured Express app with Helmet, CORS, general rate limiting, JSON/urlencoded body parsing (10mb limit), and Morgan logging piped through the shared [logger](#logger).
252
+
253
+ ```ts
254
+ import { initExpress } from '@shadimakhoul/ggcoach';
255
+
256
+ const app = initExpress(
257
+ process.env.NODE_ENV === 'development',
258
+ ['https://app.example.com'],
259
+ );
260
+ ```
261
+
262
+ ### Redis
263
+
264
+ ```ts
265
+ import { initializeRedis, getRedisClient, closeRedis, buildRedisUrl } from '@shadimakhoul/ggcoach';
266
+
267
+ await initializeRedis(process.env.REDIS_URL!);
268
+ const client = getRedisClient();
269
+ await closeRedis();
270
+ ```
271
+
272
+ `initializeRedis(hostOrUrl, username?, password?)` accepts either a full `redis://`/`rediss://` URL or a bare host (in which case it connects on port `16837`). It's a singleton — subsequent calls return the existing open client. `authenticateToken`/`optionalAuth` rely on `getRedisClient()`, so initialize Redis before mounting auth middleware.
273
+
274
+ `buildRedisUrl(value, user?, password?)` builds a `redis://`/`rediss://` connection string from a host, a Heroku-style Redis hostname (`redis-XXXX.example.com` → port `XXXX`), or an existing URL, injecting credentials only if not already present. Useful for normalising `REDIS_URL`/`REDIS_HOST` env vars before passing them to `initializeRedis`.
275
+
276
+ ```ts
277
+ const url = buildRedisUrl(process.env.REDIS_HOST, process.env.REDIS_USER, process.env.REDIS_PASSWORD);
278
+ await initializeRedis(url);
279
+ ```
280
+
281
+ ### Secrets bootstrap
282
+
283
+ ```ts
284
+ import { bootstrapSecrets } from '@shadimakhoul/ggcoach';
285
+
286
+ await bootstrapSecrets('my-service', {
287
+ secretsServiceUrl: process.env.SECRETS_SERVICE_URL!,
288
+ internalServiceToken: process.env.INTERNAL_SERVICE_TOKEN,
289
+ dev: process.env.NODE_ENV === 'development',
290
+ retries: 3,
291
+ retryDelayMs: 3000,
292
+ });
293
+ ```
294
+
295
+ Fetches secrets for `serviceName` from a central secrets service and populates `process.env` for any key not already set. Fails silently (after exhausting `retries`) so a missing/unreachable secrets service doesn't crash startup — pair with `validateEnvVars` to enforce required vars afterward.
296
+
297
+ ### Env validation
298
+
299
+ ```ts
300
+ import { validateEnvVars } from '@shadimakhoul/ggcoach';
301
+
302
+ validateEnvVars(['JWT_SECRET', 'REDIS_URL', 'DATABASE_URL']);
303
+ ```
304
+
305
+ Throws (by default) if any required env var is missing, logging each missing key at `crit` level first. Pass `throwOnMissing = false` to log a `warn` and return `false` instead of throwing.
306
+
307
+ ---
308
+
309
+ ## Logger
310
+
311
+ Winston logger pre-configured with console + file transports, custom levels (`alert` > `crit` > `error` > `warn` > `info`), and optional Telegram alerting.
312
+
313
+ ```ts
314
+ import { logger, initLogger, stream } from '@shadimakhoul/ggcoach';
315
+
316
+ logger.info('Server started');
317
+ logger.warn('Something looks off');
318
+ logger.error('Something failed', { error });
319
+ logger.crit('Critical failure', { error });
320
+ logger.alert('Page someone now');
321
+ ```
322
+
323
+ The default export `logger` lazily initializes on first use (writing to `./logs/combined.log` and `./logs/error.log`, log level from `LOG_LEVEL` env var, default `info`). Call `initLogger(logsDir?, telegramConfig?)` explicitly if you need a custom logs directory or to configure Telegram before the first log call.
324
+
325
+ ### Telegram alerting
326
+
327
+ If `TELEGRAM_BOT_TOKEN` and `TELEGRAM_CHAT_ID` are set in the environment, `alert`/`crit`/`error` level logs are automatically forwarded to Telegram — no code changes needed. Per-level chat IDs fall back to `TELEGRAM_CHAT_ID` if unset:
328
+
329
+ ```bash
330
+ TELEGRAM_BOT_TOKEN=...
331
+ TELEGRAM_CHAT_ID=... # default fallback chat
332
+ TELEGRAM_ALERT_CHAT_ID=... # optional override for `alert` level
333
+ TELEGRAM_CRIT_CHAT_ID=... # optional override for `crit` level
334
+ TELEGRAM_ERROR_CHAT_ID=... # optional override for `error` level
335
+ ```
336
+
337
+ Or configure it explicitly instead of via env vars:
338
+
339
+ ```ts
340
+ initLogger(undefined, {
341
+ botToken: process.env.TELEGRAM_BOT_TOKEN!,
342
+ chatIds: { alert: '...', crit: '...', error: '...' },
343
+ });
344
+ ```
345
+
346
+ ### `stream`
347
+
348
+ Adapter for Morgan (or any logger expecting a `{ write(message) }` stream); used internally by `initExpress`.
349
+
350
+ ---
351
+
352
+ ## Types
353
+
354
+ Key types exported from the package:
355
+
356
+ | Type | Description |
357
+ |---|---|
358
+ | `JWTConfig` | Config object for all JWT helpers |
359
+ | `BaseJWTPayload` | Minimum payload shape — extend for your project |
360
+ | `JWTPayload` | ggCoach-specific payload extending `BaseJWTPayload` |
361
+ | `UserAttributes` | Full ggCoach user model shape |
362
+ | `UserCreationAttributes` | `UserAttributes` minus auto-generated fields |
363
+ | `AuthResponse` | Standard auth endpoint response envelope |
364
+ | `AccountType` | Enum: `Client`, `Provider`, `Admin`, `SuperAdmin` |
365
+ | `IApiResponse<T>` | Generic `{ success, data?, message?, error?, meta? }` response envelope |
366
+ | `IAdminUser` | Admin dashboard user shape |
367
+ | `IPermission` | Permission record shape |
368
+ | `IAppRole` | Role record shape (name, permissions, active users count) |
369
+ | `IPaginationQuery` | Standard `page`/`limit`/`sortBy`/`sortOrder`/`search` query shape |
370
+ | `OpenApiSpec`, `OpenApiPaths`, `TagResolver`, `BuildOptions`, `Endpoint`, `SchemaMap` | Supporting types for [`buildOpenApiSpecFromExpress`](#openapi--swagger) |
371
+
372
+ `Express.Request` is also augmented globally with an optional `user?: JWTPayload` field.
373
+
374
+ ---
375
+
376
+ ## Publishing
377
+
378
+ ```bash
379
+ npm run build # compile TypeScript to dist/
380
+ npm publish # runs build first via prepublishOnly
381
+ ```
@@ -1,5 +1,15 @@
1
1
  import { AccountType } from "./enums";
2
- export interface JWTPayload {
2
+ export interface JWTConfig {
3
+ secret: string;
4
+ expiresIn: string;
5
+ issuer: string;
6
+ audience: string;
7
+ }
8
+ export interface BaseJWTPayload {
9
+ tokenType?: 'access' | 'refresh';
10
+ tokenVersion?: number;
11
+ }
12
+ export interface JWTPayload extends BaseJWTPayload {
3
13
  id: number;
4
14
  email: string;
5
15
  phoneNumber: string | null;
@@ -9,8 +19,8 @@ export interface JWTPayload {
9
19
  is_active: boolean;
10
20
  emailVerified: boolean;
11
21
  phoneVerified: boolean;
12
- tokenVersion?: number;
13
- tokenType?: 'access' | 'refresh';
22
+ roleId?: number | null;
23
+ permissions?: string[];
14
24
  }
15
25
  export interface UserAttributes {
16
26
  id: number;
@@ -28,6 +38,11 @@ export interface UserAttributes {
28
38
  tokenVersion?: number;
29
39
  created_at?: Date;
30
40
  updated_at?: Date;
41
+ roleId?: number | null;
42
+ permissions?: string[];
43
+ twoFactorEnabled?: boolean;
44
+ twoFactorSecret?: string | null;
45
+ twoFactorTempSecret?: string | null;
31
46
  }
32
47
  declare global {
33
48
  namespace Express {
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../types/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,UAAU,CAAC,EAAE,IAAI,CAAC;CACnB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,IAAI,CAAC,EAAE,UAAU,CAAC;SACnB;KACF;CACF;AAED,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAClD,cAAc,EACZ,IAAI,GACJ,WAAW,GACX,YAAY,GACZ,YAAY,GACZ,eAAe,GACf,iBAAiB,GACjB,eAAe,GACf,iBAAiB,CACpB;CAAG;AAEJ,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE;QACL,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;QACvC,MAAM,EAAE;YACN,YAAY,EAAE,MAAM,CAAC;YACrB,aAAa,EAAE,MAAM,CAAC;SACvB,CAAC;KACH,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../types/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,UAAW,SAAQ,cAAc;IAChD,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,IAAI,CAAC,EAAE,UAAU,CAAC;SACnB;KACF;CACF;AAED,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAClD,cAAc,EACZ,IAAI,GACJ,WAAW,GACX,YAAY,GACZ,YAAY,GACZ,eAAe,GACf,iBAAiB,GACjB,eAAe,GACf,iBAAiB,CACpB;CAAG;AAEJ,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE;QACL,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;QACvC,MAAM,EAAE;YACN,YAAY,EAAE,MAAM,CAAC;YACrB,aAAa,EAAE,MAAM,CAAC;SACvB,CAAC;KACH,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
@@ -1,6 +1,8 @@
1
1
  export * from './jwt';
2
2
  export * from './logger';
3
3
  export * from './openapi';
4
+ export * from './redis';
4
5
  export * from './secrets';
6
+ export * from './validateEnv';
5
7
  export * from './zodToOpenAPI';
6
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC"}
@@ -17,6 +17,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./jwt"), exports);
18
18
  __exportStar(require("./logger"), exports);
19
19
  __exportStar(require("./openapi"), exports);
20
+ __exportStar(require("./redis"), exports);
20
21
  __exportStar(require("./secrets"), exports);
22
+ __exportStar(require("./validateEnv"), exports);
21
23
  __exportStar(require("./zodToOpenAPI"), exports);
22
24
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wCAAsB;AACtB,2CAAyB;AACzB,4CAA0B;AAC1B,4CAA0B;AAC1B,iDAA+B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wCAAsB;AACtB,2CAAyB;AACzB,4CAA0B;AAC1B,0CAAwB;AACxB,4CAA0B;AAC1B,gDAA8B;AAC9B,iDAA+B"}
@@ -1,5 +1,5 @@
1
- import { JWTPayload, UserAttributes } from '../types';
2
- export declare const generateToken: (JWT_SECRET: string, JWT_EXPIRES_IN: string, user: UserAttributes) => string;
3
- export declare const verifyToken: (JWT_SECRET: string, token: string) => JWTPayload;
4
- export declare const generateRefreshToken: (JWT_SECRET: string, JWT_EXPIRES_IN: string, user: UserAttributes) => string;
1
+ import { BaseJWTPayload, JWTConfig } from '../types';
2
+ export declare const generateToken: <T extends BaseJWTPayload>(config: JWTConfig, payload: T) => string;
3
+ export declare const generateRefreshToken: <T extends BaseJWTPayload>(config: JWTConfig, payload: T) => string;
4
+ export declare const verifyToken: <T extends BaseJWTPayload>(config: JWTConfig, token: string) => T;
5
5
  //# sourceMappingURL=jwt.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../utils/jwt.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAGtD,eAAO,MAAM,aAAa,eAAgB,MAAM,kBAAkB,MAAM,QAAQ,cAAc,KAAG,MAsBhG,CAAC;AAEF,eAAO,MAAM,WAAW,eAAgB,MAAM,SAAS,MAAM,KAAG,UAW/D,CAAC;AAEF,eAAO,MAAM,oBAAoB,eAAgB,MAAM,kBAAkB,MAAM,QAAQ,cAAc,KAAG,MAsBvG,CAAC"}
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../utils/jwt.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErD,eAAO,MAAM,aAAa,qCAAsC,SAAS,iBAAe,MAQvF,CAAC;AAEF,eAAO,MAAM,oBAAoB,qCAAsC,SAAS,iBAAe,MAQ9F,CAAC;AAEF,eAAO,MAAM,WAAW,qCAAsC,SAAS,SAAS,MAAM,MASrF,CAAC"}
package/dist/utils/jwt.js CHANGED
@@ -3,63 +3,36 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.generateRefreshToken = exports.verifyToken = exports.generateToken = void 0;
6
+ exports.verifyToken = exports.generateRefreshToken = exports.generateToken = void 0;
7
7
  const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
8
- const generateToken = (JWT_SECRET, JWT_EXPIRES_IN, user) => {
9
- const payload = {
10
- id: user.id,
11
- email: user.email,
12
- phoneNumber: user.phoneNumber,
13
- firstName: user.firstName,
14
- lastName: user.lastName,
15
- accountType: user.accountType,
16
- is_active: user.is_active,
17
- emailVerified: user.emailVerified,
18
- phoneVerified: user.phoneVerified,
19
- tokenVersion: user.tokenVersion ?? 0,
20
- tokenType: 'access',
21
- };
8
+ const generateToken = (config, payload) => {
22
9
  const options = {
23
- expiresIn: JWT_EXPIRES_IN,
24
- issuer: 'ggcoach-auth-service',
25
- audience: 'ggcoach-app'
10
+ expiresIn: config.expiresIn,
11
+ issuer: config.issuer,
12
+ audience: config.audience,
26
13
  };
27
- return jsonwebtoken_1.default.sign(payload, JWT_SECRET, options);
14
+ return jsonwebtoken_1.default.sign({ ...payload, tokenType: 'access' }, config.secret, options);
28
15
  };
29
16
  exports.generateToken = generateToken;
30
- const verifyToken = (JWT_SECRET, token) => {
17
+ const generateRefreshToken = (config, payload) => {
18
+ const options = {
19
+ expiresIn: config.expiresIn,
20
+ issuer: config.issuer,
21
+ audience: config.audience,
22
+ };
23
+ return jsonwebtoken_1.default.sign({ ...payload, tokenType: 'refresh' }, config.secret, options);
24
+ };
25
+ exports.generateRefreshToken = generateRefreshToken;
26
+ const verifyToken = (config, token) => {
31
27
  try {
32
- const decoded = jsonwebtoken_1.default.verify(token, JWT_SECRET, {
33
- issuer: 'ggcoach-auth-service',
34
- audience: 'ggcoach-app'
28
+ return jsonwebtoken_1.default.verify(token, config.secret, {
29
+ issuer: config.issuer,
30
+ audience: config.audience,
35
31
  });
36
- return decoded;
37
32
  }
38
- catch (error) {
33
+ catch {
39
34
  throw new Error('Invalid or expired token');
40
35
  }
41
36
  };
42
37
  exports.verifyToken = verifyToken;
43
- const generateRefreshToken = (JWT_SECRET, JWT_EXPIRES_IN, user) => {
44
- const payload = {
45
- id: user.id,
46
- email: user.email,
47
- phoneNumber: user.phoneNumber,
48
- firstName: user.firstName,
49
- lastName: user.lastName,
50
- accountType: user.accountType,
51
- is_active: user.is_active,
52
- emailVerified: user.emailVerified,
53
- phoneVerified: user.phoneVerified,
54
- tokenVersion: user.tokenVersion ?? 0,
55
- tokenType: 'refresh',
56
- };
57
- const options = {
58
- expiresIn: JWT_EXPIRES_IN,
59
- issuer: 'ggcoach-auth-service',
60
- audience: 'ggcoach-app'
61
- };
62
- return jsonwebtoken_1.default.sign(payload, JWT_SECRET, options);
63
- };
64
- exports.generateRefreshToken = generateRefreshToken;
65
38
  //# sourceMappingURL=jwt.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../utils/jwt.ts"],"names":[],"mappings":";;;;;;AAAA,gEAA+B;AAIxB,MAAM,aAAa,GAAG,CAAC,UAAkB,EAAE,cAAsB,EAAE,IAAoB,EAAU,EAAE;IACxG,MAAM,OAAO,GAAe;QAC1B,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,CAAC;QACpC,SAAS,EAAE,QAAQ;KACpB,CAAC;IAEF,MAAM,OAAO,GAAoB;QAC/B,SAAS,EAAE,cAAc;QACzB,MAAM,EAAE,sBAAsB;QAC9B,QAAQ,EAAE,aAAa;KACL,CAAC;IAErB,OAAO,sBAAG,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC,CAAC;AAtBW,QAAA,aAAa,iBAsBxB;AAEK,MAAM,WAAW,GAAG,CAAC,UAAkB,EAAE,KAAa,EAAc,EAAE;IAC3E,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE;YAC5C,MAAM,EAAE,sBAAsB;YAC9B,QAAQ,EAAE,aAAa;SACxB,CAAe,CAAC;QAEjB,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC,CAAC;AAXW,QAAA,WAAW,eAWtB;AAEK,MAAM,oBAAoB,GAAG,CAAC,UAAkB,EAAE,cAAsB,EAAE,IAAoB,EAAU,EAAE;IAC/G,MAAM,OAAO,GAAe;QAC1B,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,CAAC;QACpC,SAAS,EAAE,SAAS;KACrB,CAAC;IAEF,MAAM,OAAO,GAAoB;QAC/B,SAAS,EAAE,cAAc;QACzB,MAAM,EAAE,sBAAsB;QAC9B,QAAQ,EAAE,aAAa;KACL,CAAC;IAErB,OAAO,sBAAG,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC,CAAC;AAtBW,QAAA,oBAAoB,wBAsB/B"}
1
+ {"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../utils/jwt.ts"],"names":[],"mappings":";;;;;;AAAA,gEAA+B;AAGxB,MAAM,aAAa,GAAG,CAA2B,MAAiB,EAAE,OAAU,EAAU,EAAE;IAC/F,MAAM,OAAO,GAAoB;QAC/B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;KACP,CAAC;IAErB,OAAO,sBAAG,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC/E,CAAC,CAAC;AARW,QAAA,aAAa,iBAQxB;AAEK,MAAM,oBAAoB,GAAG,CAA2B,MAAiB,EAAE,OAAU,EAAU,EAAE;IACtG,MAAM,OAAO,GAAoB;QAC/B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;KACP,CAAC;IAErB,OAAO,sBAAG,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAChF,CAAC,CAAC;AARW,QAAA,oBAAoB,wBAQ/B;AAEK,MAAM,WAAW,GAAG,CAA2B,MAAiB,EAAE,KAAa,EAAK,EAAE;IAC3F,IAAI,CAAC;QACH,OAAO,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE;YACtC,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;SAC1B,CAAM,CAAC;IACV,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC,CAAC;AATW,QAAA,WAAW,eAStB"}
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAuB9B,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AA6DD,eAAO,MAAM,UAAU,aACZ,MAAM,mBACE,cAAc,KAC9B,QAAQ,MA4DV,CAAC;AAGF,eAAO,MAAM,MAAM,gBAQjB,CAAC;AAGH,eAAO,MAAM,MAAM;qBACA,MAAM;CAIxB,CAAC"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAuB9B,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AA6DD,eAAO,MAAM,UAAU,aACZ,MAAM,mBACE,cAAc,KAC9B,QAAQ,MAsEV,CAAC;AAGF,eAAO,MAAM,MAAM,gBAQjB,CAAC;AAGH,eAAO,MAAM,MAAM;qBACA,MAAM;CAIxB,CAAC"}
@@ -66,6 +66,16 @@ const logFormat = printf(({ level, message, timestamp: ts, ...meta }) => {
66
66
  });
67
67
  let loggerInstance = null;
68
68
  const initLogger = (logsDir = path_1.default.resolve(process.cwd(), 'logs'), telegramConfig) => {
69
+ if (!telegramConfig && process.env.TELEGRAM_BOT_TOKEN && process.env.TELEGRAM_CHAT_ID) {
70
+ telegramConfig = {
71
+ botToken: process.env.TELEGRAM_BOT_TOKEN,
72
+ chatIds: {
73
+ alert: process.env.TELEGRAM_ALERT_CHAT_ID || process.env.TELEGRAM_CHAT_ID,
74
+ crit: process.env.TELEGRAM_CRIT_CHAT_ID || process.env.TELEGRAM_CHAT_ID,
75
+ error: process.env.TELEGRAM_ERROR_CHAT_ID || process.env.TELEGRAM_CHAT_ID,
76
+ },
77
+ };
78
+ }
69
79
  if (!fs_1.default.existsSync(logsDir)) {
70
80
  try {
71
81
  fs_1.default.mkdirSync(logsDir, { recursive: true });
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../utils/logger.ts"],"names":[],"mappings":";;;;;;AAAA,sDAA8B;AAC9B,0EAAgD;AAChD,gDAAwB;AACxB,4CAAoB;AACpB,kDAA0B;AAE1B,MAAM,YAAY,GAAG;IACnB,MAAM,EAAE;QACN,KAAK,EAAE,CAAC;QACR,IAAI,EAAE,CAAC;QACP,KAAK,EAAE,CAAC;QACR,IAAI,EAAE,CAAC;QACP,IAAI,EAAE,CAAC;KACR;IACD,MAAM,EAAE;QACN,KAAK,EAAE,MAAM;QACb,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,KAAK;QACZ,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,OAAO;KACd;CACF,CAAC;AAWF,SAAS,mBAAmB,CAAC,QAAgB,EAAE,MAAc,EAAE,IAAY;IACzE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3E,MAAM,GAAG,GAAG,eAAK,CAAC,OAAO,CACvB;QACE,QAAQ,EAAE,kBAAkB;QAC5B,IAAI,EAAE,OAAO,QAAQ,cAAc;QACnC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;KAC3F,EACD,CAAC,GAAG,EAAE,EAAE;QACN,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,EAAE,CAAC;YAE5C,OAAO,CAAC,IAAI,CAAC,4BAA4B,GAAG,CAAC,UAAU,aAAa,MAAM,EAAE,CAAC,CAAC;QAChF,CAAC;IACH,CAAC,CACF,CAAC;IACF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;QAEtB,OAAO,CAAC,IAAI,CAAC,2BAA2B,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IACH,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChB,GAAG,CAAC,GAAG,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,iBAAkB,SAAQ,2BAAe;IAK7C,YAAY,IAA8D;QACxE,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;QAClC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IACpC,CAAC;IAED,GAAG,CAAC,IAAS,EAAE,QAAoB;QACjC,YAAY,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9C,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,SAAS,IAAI,CAAC,OAAO,EAAE,CAAC;YACpE,mBAAmB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACxD,CAAC;QACD,QAAQ,EAAE,CAAC;IACb,CAAC;CACF;AAED,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,iBAAO,CAAC,MAAM,CAAC;AAEhE,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE;IACtE,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,OAAO,GAAG,EAAE,KAAK,KAAK,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;AACrD,CAAC,CAAC,CAAC;AAEH,IAAI,cAAc,GAA0B,IAAI,CAAC;AAM1C,MAAM,UAAU,GAAG,CACxB,UAAkB,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,EACrD,cAA+B,EACf,EAAE;IAElB,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,YAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YAEb,OAAO,CAAC,IAAI,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAGD,MAAM,UAAU,GAAwB,EAAE,CAAC;IAG3C,UAAU,CAAC,IAAI,CACb,IAAI,iBAAO,CAAC,UAAU,CAAC,OAAO,CAAC;QAC7B,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,SAAS,CAAC;KACjE,CAAC,CACH,CAAC;IAGF,IAAI,CAAC;QACH,UAAU,CAAC,IAAI,CACb,IAAI,iBAAO,CAAC,UAAU,CAAC,IAAI,CAAC;YAC1B,QAAQ,EAAE,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC;YACzC,KAAK,EAAE,OAAO;YACd,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE,EAAE,SAAS,CAAC;SACxC,CAAC,CACH,CAAC;QAEF,UAAU,CAAC,IAAI,CACb,IAAI,iBAAO,CAAC,UAAU,CAAC,IAAI,CAAC;YAC1B,QAAQ,EAAE,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC;YAC5C,KAAK,EAAE,MAAM;YACb,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE,EAAE,SAAS,CAAC;SACxC,CAAC,CACH,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QAEb,OAAO,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAC;IAC/E,CAAC;IAED,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC;QAC7C,KAAK,MAAM,KAAK,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAU,EAAE,CAAC;YACxD,UAAU,CAAC,IAAI,CAAC,IAAI,iBAAiB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAClG,CAAC;IACH,CAAC;IAED,cAAc,GAAG,iBAAO,CAAC,YAAY,CAAC;QACpC,MAAM,EAAE,YAAY,CAAC,MAAM;QAC3B,KAAK,EAAG,OAAO,CAAC,GAAG,CAAC,SAAoB,IAAI,MAAM;QAClD,UAAU;QACV,WAAW,EAAE,KAAK;KACnB,CAAC,CAAC;IAEH,iBAAO,CAAC,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IAEvC,OAAO,cAAc,CAAC;AACxB,CAAC,CAAC;AA/DW,QAAA,UAAU,cA+DrB;AAGW,QAAA,MAAM,GAAG,IAAI,KAAK,CAAC,EAAoB,EAAE;IACpD,GAAG,CAAC,MAAM,EAAE,IAAI;QACd,IAAI,CAAC,cAAc,EAAE,CAAC;YAEpB,IAAA,kBAAU,GAAE,CAAC;QACf,CAAC;QACD,OAAQ,cAAsB,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC;CACF,CAAC,CAAC;AAGU,QAAA,MAAM,GAAG;IACpB,KAAK,EAAE,CAAC,OAAe,EAAE,EAAE;QAEzB,cAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9B,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../utils/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const buildRedisUrl: (value?: string, user?: string, password?: string) => string;
2
+ //# sourceMappingURL=redis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../utils/redis.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,WAAY,MAAM,SAAS,MAAM,aAAa,MAAM,KAAG,MAkBhF,CAAC"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildRedisUrl = void 0;
4
+ const buildRedisUrl = (value, user, password) => {
5
+ if (!value) {
6
+ throw new Error('REDIS_URL or REDIS_HOST must be set');
7
+ }
8
+ const url = /^rediss?:\/\//i.test(value)
9
+ ? new URL(value)
10
+ : new URL(`redis://${value}:${value.match(/^redis-(\d+)\./)?.[1] || '6379'}`);
11
+ if (user && !url.username) {
12
+ url.username = user;
13
+ }
14
+ if (password && !url.password) {
15
+ url.password = password;
16
+ }
17
+ return url.toString();
18
+ };
19
+ exports.buildRedisUrl = buildRedisUrl;
20
+ //# sourceMappingURL=redis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis.js","sourceRoot":"","sources":["../../utils/redis.ts"],"names":[],"mappings":";;;AAAO,MAAM,aAAa,GAAG,CAAC,KAAc,EAAE,IAAa,EAAE,QAAiB,EAAU,EAAE;IACxF,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IAED,MAAM,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC;QACtC,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC;QAChB,CAAC,CAAC,IAAI,GAAG,CAAC,WAAW,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC;IAEhF,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC1B,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,IAAI,QAAQ,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,GAAG,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC1B,CAAC;IAED,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC,CAAC;AAlBW,QAAA,aAAa,iBAkBxB"}
@@ -0,0 +1,2 @@
1
+ export declare const validateEnvVars: (required: string[], throwOnMissing?: boolean) => boolean;
2
+ //# sourceMappingURL=validateEnv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateEnv.d.ts","sourceRoot":"","sources":["../../utils/validateEnv.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,eAAe,aAAc,MAAM,EAAE,+BAA0B,OAiB3E,CAAC"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateEnvVars = void 0;
4
+ const logger_1 = require("./logger");
5
+ const validateEnvVars = (required, throwOnMissing = true) => {
6
+ const missing = required.filter((name) => !process.env[name]);
7
+ if (missing.length === 0) {
8
+ logger_1.logger.info('All required environment variables are present');
9
+ return true;
10
+ }
11
+ const message = `Missing required environment variables: ${missing.join(', ')}`;
12
+ missing.forEach((m) => logger_1.logger.crit(`ENV MISSING: ${m}`));
13
+ if (throwOnMissing) {
14
+ throw new Error(message);
15
+ }
16
+ logger_1.logger.warn(message);
17
+ return false;
18
+ };
19
+ exports.validateEnvVars = validateEnvVars;
20
+ //# sourceMappingURL=validateEnv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateEnv.js","sourceRoot":"","sources":["../../utils/validateEnv.ts"],"names":[],"mappings":";;;AAAA,qCAAkC;AAE3B,MAAM,eAAe,GAAG,CAAC,QAAkB,EAAE,cAAc,GAAG,IAAI,EAAW,EAAE;IACpF,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAE9D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,eAAM,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,OAAO,GAAG,2CAA2C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAChF,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC;IAEzD,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IAED,eAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrB,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAjBW,QAAA,eAAe,mBAiB1B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shadimakhoul/ggcoach",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "description": "Shared utilities and types for GGCoach microservices",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",