@scpxl/nodejs-framework 1.0.13 โ 1.0.14
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 +69 -146
- package/dist/logger/logger.d.ts +4 -1
- package/dist/logger/logger.d.ts.map +1 -1
- package/dist/logger/logger.js +34 -19
- package/dist/logger/logger.js.map +2 -2
- package/dist/websocket/websocket-base.js +1 -1
- package/dist/websocket/websocket-base.js.map +1 -1
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -2,194 +2,117 @@
|
|
|
2
2
|
|
|
3
3
|
A comprehensive Node.js framework for building modern applications with support for web servers, databases, queues, caching, and more.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Opinionated TypeScript framework combining Fastify, WebSockets, Redis, BullMQ, and MikroORM under a unified Application lifecycle.
|
|
6
6
|
|
|
7
|
-
Install
|
|
7
|
+
## Install
|
|
8
8
|
|
|
9
|
-
```
|
|
9
|
+
```bash
|
|
10
10
|
npm install @scpxl/nodejs-framework
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
## Quick Start
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
|
-
import {
|
|
16
|
+
import { Application } from '@scpxl/nodejs-framework';
|
|
17
17
|
|
|
18
|
-
const app = new
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
host: '0.0.0.0'
|
|
22
|
-
},
|
|
23
|
-
database: {
|
|
24
|
-
host: 'localhost',
|
|
25
|
-
port: 5432,
|
|
26
|
-
dbName: 'myapp',
|
|
27
|
-
user: 'user',
|
|
28
|
-
password: 'password'
|
|
29
|
-
}
|
|
18
|
+
const app = new Application({
|
|
19
|
+
webserver: { port: 3000 },
|
|
20
|
+
logger: { level: 'info' },
|
|
30
21
|
});
|
|
31
22
|
|
|
32
23
|
await app.start();
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Features
|
|
36
|
-
|
|
37
|
-
- ๐ **FastAPI-powered Web Server** with auto-routing
|
|
38
|
-
- ๐๏ธ **Database Integration** with MikroORM and PostgreSQL
|
|
39
|
-
- ๐ฆ **Queue System** using BullMQ and Redis
|
|
40
|
-
- ๐ **WebSocket Support** for real-time communication
|
|
41
|
-
- ๐๏ธ **Caching Layer** with Redis integration
|
|
42
|
-
- โ๏ธ **AWS S3 Integration** for file storage
|
|
43
|
-
- ๐ **Authentication System** with JWT
|
|
44
|
-
- ๐ **Structured Logging** with Winston
|
|
45
|
-
- ๐งช **Built-in Testing Utils**
|
|
46
|
-
- โก **Performance Monitoring**
|
|
47
24
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
```sh
|
|
55
|
-
git clone https://github.com/PXLbros/pxl-nodejs-framework.git
|
|
56
|
-
cd pxl-nodejs-framework
|
|
57
|
-
nvm use
|
|
58
|
-
npm install
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### Build
|
|
62
|
-
|
|
63
|
-
```sh
|
|
64
|
-
npm run build
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### Testing with Yalc (Local Development)
|
|
68
|
-
|
|
69
|
-
For local testing before publishing to NPM:
|
|
70
|
-
|
|
71
|
-
```sh
|
|
72
|
-
# Build and publish locally
|
|
73
|
-
npm run build:local
|
|
74
|
-
|
|
75
|
-
# In your project
|
|
76
|
-
yalc add @pxl/nodejs-framework
|
|
25
|
+
app.webserver.route({
|
|
26
|
+
method: 'GET',
|
|
27
|
+
url: '/health',
|
|
28
|
+
handler: async () => ({ ok: true }),
|
|
29
|
+
});
|
|
77
30
|
```
|
|
78
31
|
|
|
79
|
-
##
|
|
80
|
-
|
|
81
|
-
### Local Development
|
|
82
|
-
|
|
83
|
-
For local development with automatic publishing through **Yalc**:
|
|
32
|
+
## Add WebSocket
|
|
84
33
|
|
|
85
|
-
```
|
|
86
|
-
|
|
34
|
+
```ts
|
|
35
|
+
app.websocket.onConnection(client => {
|
|
36
|
+
client.sendJSON({ welcome: true });
|
|
37
|
+
});
|
|
87
38
|
```
|
|
88
39
|
|
|
89
|
-
|
|
40
|
+
## Add Queue Job
|
|
90
41
|
|
|
91
|
-
```
|
|
92
|
-
|
|
42
|
+
```ts
|
|
43
|
+
await app.queue.manager.add('email', { userId: 123 });
|
|
93
44
|
```
|
|
94
45
|
|
|
95
|
-
|
|
46
|
+
## Configuration Example
|
|
96
47
|
|
|
97
|
-
```
|
|
98
|
-
|
|
48
|
+
```ts
|
|
49
|
+
new Application({
|
|
50
|
+
webserver: { port: 3000 },
|
|
51
|
+
websocket: { enabled: true },
|
|
52
|
+
queue: { enabled: true },
|
|
53
|
+
redis: { host: '127.0.0.1', port: 6379 },
|
|
54
|
+
database: {
|
|
55
|
+
/* MikroORM config */
|
|
56
|
+
},
|
|
57
|
+
logger: { level: 'info' },
|
|
58
|
+
});
|
|
99
59
|
```
|
|
100
60
|
|
|
101
|
-
##
|
|
102
|
-
|
|
103
|
-
This project uses GitHub Actions for continuous integration and deployment:
|
|
104
|
-
|
|
105
|
-
### Build and Test (CI)
|
|
106
|
-
|
|
107
|
-
- Runs on all pull requests
|
|
108
|
-
- Installs dependencies, runs linting, builds the project, and runs tests
|
|
109
|
-
|
|
110
|
-
### Build and Publish
|
|
111
|
-
|
|
112
|
-
- Runs on pushes to `main`/`master` branches and version tags
|
|
113
|
-
- Builds the project and publishes to npm
|
|
114
|
-
- Beta releases are published on pushes to main/master branches
|
|
115
|
-
- Stable releases are published when version tags are created
|
|
116
|
-
|
|
117
|
-
### Setup for Publishing
|
|
118
|
-
|
|
119
|
-
To enable automatic publishing, configure the following repository secret:
|
|
120
|
-
|
|
121
|
-
- `NPM_TOKEN`: Your npm authentication token
|
|
122
|
-
|
|
123
|
-
> **Note**: The `dist/` folder is gitignored and automatically generated during the CI/CD process. Do not commit built files to the repository.
|
|
124
|
-
|
|
125
|
-
## Releasing
|
|
61
|
+
## Features
|
|
126
62
|
|
|
127
|
-
|
|
63
|
+
- Unified lifecycle (start/stop all subsystems)
|
|
64
|
+
- Fastify routing + raw access
|
|
65
|
+
- WebSocket client + room management
|
|
66
|
+
- BullMQ queue integration
|
|
67
|
+
- MikroORM database integration
|
|
68
|
+
- Redis cache + pub/sub
|
|
69
|
+
- Structured logging
|
|
70
|
+
- Utilities & services layer
|
|
128
71
|
|
|
129
|
-
|
|
72
|
+
## Documentation
|
|
130
73
|
|
|
131
|
-
|
|
132
|
-
# Patch release (1.0.0 โ 1.0.1)
|
|
133
|
-
npm run release -- --patch
|
|
74
|
+
Full docs & guides (VitePress) + API reference (TypeDoc).
|
|
134
75
|
|
|
135
|
-
|
|
136
|
-
|
|
76
|
+
- Getting Started, Concepts, Guides
|
|
77
|
+
- API: https://pxlbros.github.io/pxl-nodejs-framework/
|
|
137
78
|
|
|
138
|
-
|
|
139
|
-
npm run release -- --major
|
|
79
|
+
To run local docs site (once cloned):
|
|
140
80
|
|
|
141
|
-
|
|
142
|
-
npm run
|
|
81
|
+
```bash
|
|
82
|
+
npm run docs:site:dev
|
|
143
83
|
```
|
|
144
84
|
|
|
145
|
-
|
|
85
|
+
## Graceful Shutdown
|
|
146
86
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
2. Verify you're on the main/master branch
|
|
151
|
-
3. Update the version in `package.json`
|
|
152
|
-
4. Create a git commit and tag
|
|
153
|
-
5. Push to origin, triggering GitHub Actions
|
|
154
|
-
|
|
155
|
-
### Dry Run
|
|
156
|
-
|
|
157
|
-
Preview what the release script will do without making changes:
|
|
158
|
-
|
|
159
|
-
```sh
|
|
160
|
-
npm run release -- --patch --dry-run
|
|
87
|
+
```ts
|
|
88
|
+
process.on('SIGINT', () => app.stop());
|
|
89
|
+
process.on('SIGTERM', () => app.stop());
|
|
161
90
|
```
|
|
162
91
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
For more information about the release script:
|
|
92
|
+
## Example Service Pattern
|
|
166
93
|
|
|
167
|
-
```
|
|
168
|
-
|
|
94
|
+
```ts
|
|
95
|
+
class UserService {
|
|
96
|
+
constructor(private app: Application) {}
|
|
97
|
+
async register(data: any) {
|
|
98
|
+
// use app.database / app.queue / app.logger
|
|
99
|
+
}
|
|
100
|
+
}
|
|
169
101
|
```
|
|
170
102
|
|
|
171
|
-
##
|
|
103
|
+
## When Not to Use
|
|
172
104
|
|
|
173
|
-
|
|
105
|
+
If you only need a single HTTP server or minimal script, this framework may be heavier than needed.
|
|
174
106
|
|
|
175
|
-
|
|
107
|
+
## Contributing
|
|
176
108
|
|
|
177
|
-
|
|
109
|
+
Issues and PRs welcome. Development scripts remain available:
|
|
178
110
|
|
|
179
|
-
```
|
|
180
|
-
npm run
|
|
111
|
+
```bash
|
|
112
|
+
npm run dev # watch build
|
|
113
|
+
npm run build # production build
|
|
181
114
|
```
|
|
182
115
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
### Automated Documentation Deployment
|
|
186
|
-
|
|
187
|
-
Documentation is automatically built and deployed to GitHub Pages when:
|
|
188
|
-
|
|
189
|
-
- Code is pushed to the `main` or `master` branch
|
|
190
|
-
- Pull requests are opened against `main` or `master` branch
|
|
191
|
-
- Manual workflow dispatch is triggered
|
|
192
|
-
|
|
193
|
-
The documentation will be available at: `https://[your-username].github.io/[repository-name]/`
|
|
116
|
+
---
|
|
194
117
|
|
|
195
|
-
|
|
118
|
+
Released under ISC License.
|
package/dist/logger/logger.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export declare class Logger {
|
|
|
12
12
|
sentryDsn: string;
|
|
13
13
|
environment: string;
|
|
14
14
|
}): void;
|
|
15
|
-
log({ level, message, meta, options, }: {
|
|
15
|
+
log({ level, message, meta, options: _options, }: {
|
|
16
16
|
level: LoggerLevels;
|
|
17
17
|
message: unknown;
|
|
18
18
|
meta?: Record<string, unknown>;
|
|
@@ -23,16 +23,19 @@ export declare class Logger {
|
|
|
23
23
|
meta?: Record<string, unknown>;
|
|
24
24
|
options?: LogOptions;
|
|
25
25
|
}): void;
|
|
26
|
+
debug(message: unknown, meta?: Record<string, unknown>): void;
|
|
26
27
|
info({ message, meta, options, }: {
|
|
27
28
|
message: unknown;
|
|
28
29
|
meta?: Record<string, unknown>;
|
|
29
30
|
options?: LogOptions;
|
|
30
31
|
}): void;
|
|
32
|
+
info(message: unknown, meta?: Record<string, unknown>): void;
|
|
31
33
|
warn({ message, meta, options, }: {
|
|
32
34
|
message: unknown;
|
|
33
35
|
meta?: Record<string, unknown>;
|
|
34
36
|
options?: LogOptions;
|
|
35
37
|
}): void;
|
|
38
|
+
warn(message: unknown, meta?: Record<string, unknown>): void;
|
|
36
39
|
error({ error, message, meta, options, }: {
|
|
37
40
|
error: Error | unknown;
|
|
38
41
|
message?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logger/logger.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,MAAM,MAAM,YAAY,GACpB,OAAO,GACP,MAAM,GACN,MAAM,GACN,SAAS,GACT,UAAU,GACV,OAAO,GACP,WAAW,GACX,WAAW,GACX,OAAO,GACP,UAAU,GACV,OAAO,GACP,OAAO,CAAC;AAEZ,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAS;IAChC,OAAO,CAAC,MAAM,CAAiB;IAE/B,OAAO,CAAC,WAAW,CAAqB;IAEjC,mBAAmB,UAAS;IAEnC,OAAO;WAwDO,WAAW,IAAI,MAAM;IAQnC,OAAO,CAAC,eAAe;IAwBhB,UAAU,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAiBxF,GAAG,CAAC,EACT,KAAK,EACL,OAAO,EACP,IAAI,EACJ,OAAO,
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logger/logger.ts"],"names":[],"mappings":"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"}
|
package/dist/logger/logger.js
CHANGED
|
@@ -102,7 +102,7 @@ class Logger {
|
|
|
102
102
|
level,
|
|
103
103
|
message,
|
|
104
104
|
meta,
|
|
105
|
-
options
|
|
105
|
+
options: _options
|
|
106
106
|
}) {
|
|
107
107
|
if (message instanceof Error) {
|
|
108
108
|
const errorMessage = message.stack ?? message.toString();
|
|
@@ -113,26 +113,41 @@ class Logger {
|
|
|
113
113
|
this.logger.log(level, JSON.stringify(message), meta);
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
-
debug({
|
|
117
|
-
message
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
116
|
+
debug(messageOrOptions, meta) {
|
|
117
|
+
if (typeof messageOrOptions === "object" && messageOrOptions !== null && "message" in messageOrOptions) {
|
|
118
|
+
const {
|
|
119
|
+
message,
|
|
120
|
+
meta: optionsMeta,
|
|
121
|
+
options
|
|
122
|
+
} = messageOrOptions;
|
|
123
|
+
this.log({ level: "debug", message, meta: optionsMeta, options });
|
|
124
|
+
} else {
|
|
125
|
+
this.log({ level: "debug", message: messageOrOptions, meta, options: void 0 });
|
|
126
|
+
}
|
|
122
127
|
}
|
|
123
|
-
info({
|
|
124
|
-
message
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
128
|
+
info(messageOrOptions, meta) {
|
|
129
|
+
if (typeof messageOrOptions === "object" && messageOrOptions !== null && "message" in messageOrOptions) {
|
|
130
|
+
const {
|
|
131
|
+
message,
|
|
132
|
+
meta: optionsMeta,
|
|
133
|
+
options
|
|
134
|
+
} = messageOrOptions;
|
|
135
|
+
this.log({ level: "info", message, meta: optionsMeta, options });
|
|
136
|
+
} else {
|
|
137
|
+
this.log({ level: "info", message: messageOrOptions, meta, options: void 0 });
|
|
138
|
+
}
|
|
129
139
|
}
|
|
130
|
-
warn({
|
|
131
|
-
message
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
140
|
+
warn(messageOrOptions, meta) {
|
|
141
|
+
if (typeof messageOrOptions === "object" && messageOrOptions !== null && "message" in messageOrOptions) {
|
|
142
|
+
const {
|
|
143
|
+
message,
|
|
144
|
+
meta: optionsMeta,
|
|
145
|
+
options
|
|
146
|
+
} = messageOrOptions;
|
|
147
|
+
this.log({ level: "warn", message, meta: optionsMeta, options });
|
|
148
|
+
} else {
|
|
149
|
+
this.log({ level: "warn", message: messageOrOptions, meta, options: void 0 });
|
|
150
|
+
}
|
|
136
151
|
}
|
|
137
152
|
error({
|
|
138
153
|
error,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/logger/logger.ts"],
|
|
4
|
-
"sourcesContent": ["import * as Sentry from '@sentry/node';\nimport { nodeProfilingIntegration } from '@sentry/profiling-node';\nimport cluster from 'node:cluster';\nimport winston from 'winston';\nimport type { LogOptions } from '../websocket/utils.js';\n\nexport type LoggerLevels =\n | 'error'\n | 'warn'\n | 'info'\n | 'command'\n | 'database'\n | 'redis'\n | 'webServer'\n | 'webSocket'\n | 'queue'\n | 'queueJob'\n | 'event'\n | 'debug';\n\nexport class Logger {\n private static instance: Logger;\n private logger: winston.Logger;\n\n private environment: string | undefined;\n\n public isSentryInitialized = false;\n\n private constructor() {\n this.environment = process.env.NODE_ENV;\n\n const customFormat = this.getCustomFormat();\n\n const customLevels: winston.config.AbstractConfigSetLevels = {\n error: 0,\n warn: 1,\n info: 2,\n command: 3,\n database: 4,\n redis: 5,\n webServer: 6,\n webSocket: 7,\n queue: 8,\n queueJob: 9,\n event: 10,\n debug: 11,\n };\n\n const customColors: winston.config.AbstractConfigSetColors = {\n error: 'red',\n warn: 'yellow',\n info: 'blue',\n command: 'cyan',\n database: 'brightGreen',\n redis: 'brightYellow',\n webServer: 'brightBlue',\n webSocket: 'brightMagenta',\n queue: 'gray',\n queueJob: 'blue',\n event: 'brightGreen',\n debug: 'brightCyan',\n };\n\n winston.addColors(customColors);\n\n this.logger = winston.createLogger({\n levels: customLevels,\n level: this.environment === 'production' ? 'info' : 'debug',\n format: winston.format.combine(\n winston.format.timestamp({\n format: 'YYYY-MM-DD HH:mm:ss',\n }),\n winston.format.errors({ stack: true }),\n winston.format.splat(),\n winston.format.json(),\n ),\n transports: [\n new winston.transports.Console({\n format: winston.format.combine(winston.format.colorize(), customFormat),\n }),\n ],\n });\n }\n\n public static getInstance(): Logger {\n if (!Logger.instance) {\n Logger.instance = new Logger();\n }\n\n return Logger.instance;\n }\n\n private getCustomFormat(): winston.Logform.Format {\n return winston.format.printf(({ level, message, timestamp, ...meta }) => {\n if (cluster.isWorker && cluster.worker) {\n meta['Worker'] = cluster.worker.id; // .process.pid;\n }\n\n const metaString = Object.entries(meta)\n .map(([key, value]) => {\n return `${key}: ${value}`;\n })\n .join(' | ');\n\n if (level === 'error') {\n if (this.isSentryInitialized) {\n const errorMessage = typeof message === 'string' ? message : JSON.stringify(message);\n\n Sentry.captureException(new Error(errorMessage));\n }\n }\n\n return `[${timestamp}] ${level}: ${message}${metaString ? ` (${metaString})` : ''}`;\n });\n }\n\n public initSentry({ sentryDsn, environment }: { sentryDsn: string; environment: string }): void {\n if (!sentryDsn) {\n this.logger.warn('Missing Sentry DSN when initializing Sentry');\n\n return;\n }\n\n Sentry.init({\n dsn: sentryDsn,\n integrations: [nodeProfilingIntegration()],\n tracesSampleRate: 1.0,\n environment,\n });\n\n this.isSentryInitialized = true;\n }\n\n public log({\n level,\n message,\n meta,\n options,\n }: {\n level: LoggerLevels;\n message: unknown;\n meta?: Record<string, unknown>;\n options?: LogOptions;\n }): void {\n // if (options?.muteWorker) {\n // }\n\n if (message instanceof Error) {\n const errorMessage = message.stack ?? message.toString();\n this.logger.log(level, errorMessage, meta);\n } else if (typeof message === 'string') {\n this.logger.log(level, message, meta);\n } else {\n this.logger.log(level, JSON.stringify(message), meta);\n }\n }\n\n public debug({\n message,\n meta,\n options,\n }: {\n message: unknown;\n meta?: Record<string, unknown>;\n options?: LogOptions;\n }): void {\n this.log({ level: 'debug', message, meta, options });\n }\n\n public info({\n message,\n meta,\n options,\n }: {\n message: unknown;\n meta?: Record<string, unknown>;\n options?: LogOptions;\n }): void {\n this.log({ level: 'info', message, meta, options });\n }\n\n public warn({\n message,\n meta,\n options,\n }: {\n message: unknown;\n meta?: Record<string, unknown>;\n options?: LogOptions;\n }): void {\n this.log({ level: 'warn', message, meta, options });\n }\n\n public error({\n error,\n message,\n meta,\n options,\n }: {\n error: Error | unknown;\n message?: string;\n meta?: Record<string, unknown>;\n options?: LogOptions;\n }): void {\n if (message) {\n // If a message is provided, combine it with the error for better context\n const errorMessage = error instanceof Error ? error.message : String(error);\n const combinedMessage = `${message}: ${errorMessage}`;\n this.log({ level: 'error', message: combinedMessage, meta, options });\n\n // Also capture the original error for Sentry if it's an Error object\n if (error instanceof Error && this.isSentryInitialized) {\n Sentry.captureException(error);\n }\n } else {\n // Original behavior when no message is provided\n this.log({ level: 'error', message: error, meta, options });\n }\n }\n\n public custom({\n level,\n message,\n meta,\n options,\n }: {\n level: LoggerLevels;\n message: unknown;\n meta?: Record<string, unknown>;\n options?: LogOptions;\n }): void {\n this.log({ level, message, meta, options });\n }\n}\n\nexport default Logger.getInstance();\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import * as Sentry from '@sentry/node';\nimport { nodeProfilingIntegration } from '@sentry/profiling-node';\nimport cluster from 'node:cluster';\nimport winston from 'winston';\nimport type { LogOptions } from '../websocket/utils.js';\n\nexport type LoggerLevels =\n | 'error'\n | 'warn'\n | 'info'\n | 'command'\n | 'database'\n | 'redis'\n | 'webServer'\n | 'webSocket'\n | 'queue'\n | 'queueJob'\n | 'event'\n | 'debug';\n\nexport class Logger {\n private static instance: Logger;\n private logger: winston.Logger;\n\n private environment: string | undefined;\n\n public isSentryInitialized = false;\n\n private constructor() {\n this.environment = process.env.NODE_ENV;\n\n const customFormat = this.getCustomFormat();\n\n const customLevels: winston.config.AbstractConfigSetLevels = {\n error: 0,\n warn: 1,\n info: 2,\n command: 3,\n database: 4,\n redis: 5,\n webServer: 6,\n webSocket: 7,\n queue: 8,\n queueJob: 9,\n event: 10,\n debug: 11,\n };\n\n const customColors: winston.config.AbstractConfigSetColors = {\n error: 'red',\n warn: 'yellow',\n info: 'blue',\n command: 'cyan',\n database: 'brightGreen',\n redis: 'brightYellow',\n webServer: 'brightBlue',\n webSocket: 'brightMagenta',\n queue: 'gray',\n queueJob: 'blue',\n event: 'brightGreen',\n debug: 'brightCyan',\n };\n\n winston.addColors(customColors);\n\n this.logger = winston.createLogger({\n levels: customLevels,\n level: this.environment === 'production' ? 'info' : 'debug',\n format: winston.format.combine(\n winston.format.timestamp({\n format: 'YYYY-MM-DD HH:mm:ss',\n }),\n winston.format.errors({ stack: true }),\n winston.format.splat(),\n winston.format.json(),\n ),\n transports: [\n new winston.transports.Console({\n format: winston.format.combine(winston.format.colorize(), customFormat),\n }),\n ],\n });\n }\n\n public static getInstance(): Logger {\n if (!Logger.instance) {\n Logger.instance = new Logger();\n }\n\n return Logger.instance;\n }\n\n private getCustomFormat(): winston.Logform.Format {\n return winston.format.printf(({ level, message, timestamp, ...meta }) => {\n if (cluster.isWorker && cluster.worker) {\n meta['Worker'] = cluster.worker.id; // .process.pid;\n }\n\n const metaString = Object.entries(meta)\n .map(([key, value]) => {\n return `${key}: ${value}`;\n })\n .join(' | ');\n\n if (level === 'error') {\n if (this.isSentryInitialized) {\n const errorMessage = typeof message === 'string' ? message : JSON.stringify(message);\n\n Sentry.captureException(new Error(errorMessage));\n }\n }\n\n return `[${timestamp}] ${level}: ${message}${metaString ? ` (${metaString})` : ''}`;\n });\n }\n\n public initSentry({ sentryDsn, environment }: { sentryDsn: string; environment: string }): void {\n if (!sentryDsn) {\n this.logger.warn('Missing Sentry DSN when initializing Sentry');\n\n return;\n }\n\n Sentry.init({\n dsn: sentryDsn,\n integrations: [nodeProfilingIntegration()],\n tracesSampleRate: 1.0,\n environment,\n });\n\n this.isSentryInitialized = true;\n }\n\n public log({\n level,\n message,\n meta,\n options: _options,\n }: {\n level: LoggerLevels;\n message: unknown;\n meta?: Record<string, unknown>;\n options?: LogOptions;\n }): void {\n // if (options?.muteWorker) {\n // }\n\n if (message instanceof Error) {\n const errorMessage = message.stack ?? message.toString();\n this.logger.log(level, errorMessage, meta);\n } else if (typeof message === 'string') {\n this.logger.log(level, message, meta);\n } else {\n this.logger.log(level, JSON.stringify(message), meta);\n }\n }\n\n public debug({\n message,\n meta,\n options,\n }: {\n message: unknown;\n meta?: Record<string, unknown>;\n options?: LogOptions;\n }): void;\n public debug(message: unknown, meta?: Record<string, unknown>): void;\n public debug(\n messageOrOptions: unknown | { message: unknown; meta?: Record<string, unknown>; options?: LogOptions },\n meta?: Record<string, unknown>,\n ): void {\n if (typeof messageOrOptions === 'object' && messageOrOptions !== null && 'message' in messageOrOptions) {\n const {\n message,\n meta: optionsMeta,\n options,\n } = messageOrOptions as { message: unknown; meta?: Record<string, unknown>; options?: LogOptions };\n this.log({ level: 'debug', message, meta: optionsMeta, options });\n } else {\n this.log({ level: 'debug', message: messageOrOptions, meta, options: undefined });\n }\n }\n\n public info({\n message,\n meta,\n options,\n }: {\n message: unknown;\n meta?: Record<string, unknown>;\n options?: LogOptions;\n }): void;\n public info(message: unknown, meta?: Record<string, unknown>): void;\n public info(\n messageOrOptions: unknown | { message: unknown; meta?: Record<string, unknown>; options?: LogOptions },\n meta?: Record<string, unknown>,\n ): void {\n if (typeof messageOrOptions === 'object' && messageOrOptions !== null && 'message' in messageOrOptions) {\n const {\n message,\n meta: optionsMeta,\n options,\n } = messageOrOptions as { message: unknown; meta?: Record<string, unknown>; options?: LogOptions };\n this.log({ level: 'info', message, meta: optionsMeta, options });\n } else {\n this.log({ level: 'info', message: messageOrOptions, meta, options: undefined });\n }\n }\n\n public warn({\n message,\n meta,\n options,\n }: {\n message: unknown;\n meta?: Record<string, unknown>;\n options?: LogOptions;\n }): void;\n public warn(message: unknown, meta?: Record<string, unknown>): void;\n public warn(\n messageOrOptions: unknown | { message: unknown; meta?: Record<string, unknown>; options?: LogOptions },\n meta?: Record<string, unknown>,\n ): void {\n if (typeof messageOrOptions === 'object' && messageOrOptions !== null && 'message' in messageOrOptions) {\n const {\n message,\n meta: optionsMeta,\n options,\n } = messageOrOptions as { message: unknown; meta?: Record<string, unknown>; options?: LogOptions };\n this.log({ level: 'warn', message, meta: optionsMeta, options });\n } else {\n this.log({ level: 'warn', message: messageOrOptions, meta, options: undefined });\n }\n }\n\n public error({\n error,\n message,\n meta,\n options,\n }: {\n error: Error | unknown;\n message?: string;\n meta?: Record<string, unknown>;\n options?: LogOptions;\n }): void {\n if (message) {\n // If a message is provided, combine it with the error for better context\n const errorMessage = error instanceof Error ? error.message : String(error);\n const combinedMessage = `${message}: ${errorMessage}`;\n this.log({ level: 'error', message: combinedMessage, meta, options });\n\n // Also capture the original error for Sentry if it's an Error object\n if (error instanceof Error && this.isSentryInitialized) {\n Sentry.captureException(error);\n }\n } else {\n // Original behavior when no message is provided\n this.log({ level: 'error', message: error, meta, options });\n }\n }\n\n public custom({\n level,\n message,\n meta,\n options,\n }: {\n level: LoggerLevels;\n message: unknown;\n meta?: Record<string, unknown>;\n options?: LogOptions;\n }): void {\n this.log({ level, message, meta, options });\n }\n}\n\nexport default Logger.getInstance();\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -22,7 +22,7 @@ class WebSocketBase {
|
|
|
22
22
|
const controllers = await Loader.loadModulesInDirectory({
|
|
23
23
|
directory: controllersDirectory,
|
|
24
24
|
// NOTE:
|
|
25
|
-
// When getting "system", it gets /app/node_modules/@
|
|
25
|
+
// When getting "system", it gets /app/node_modules/@scpxl/nodejs-framework/dist/websocket/controllers/server
|
|
26
26
|
// Therefor .js is needed also
|
|
27
27
|
// Fix so only .ts vs .js is needed
|
|
28
28
|
extensions: [".ts", ".js"]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/websocket/websocket-base.ts"],
|
|
4
|
-
"sourcesContent": ["import { existsSync } from 'fs';\nimport type { WebSocketMessageHandler, WebSocketRoute, WebSocketType } from './websocket.interface.js';\nimport { getRouteKey, log, parseServerMessage } from './utils.js';\nimport type { WebSocketServerBaseControllerType } from './controller/server/base.interface.js';\nimport type { WebSocketClientBaseControllerType } from './controller/client/base.interface.js';\nimport type WebSocket from 'ws';\nimport { Helper, Loader } from '../util/index.js';\n\nexport default abstract class WebSocketBase {\n protected routes: WebSocketRoute[] = [];\n protected routeHandlers: Map<string, WebSocketMessageHandler> = new Map();\n\n protected defaultRoutes: WebSocketRoute[] = [];\n\n public abstract get type(): WebSocketType;\n\n protected abstract getControllerDependencies(): any;\n protected abstract shouldPrintRoutes(): boolean;\n protected abstract handleMessageError(clientId: string, error: string): void;\n\n protected async configureRoutes(routes: WebSocketRoute[], controllersDirectory: string): Promise<void> {\n // log ('Configuring routes', { Type: this.type, 'Controllers Directory': controllersDirectory });\n\n const controllersDirectoryExists = await existsSync(controllersDirectory);\n\n if (!controllersDirectoryExists) {\n log('Controllers directory not found', {\n Directory: controllersDirectory,\n });\n\n return;\n }\n\n const scriptFileExtension = Helper.getScriptFileExtension();\n\n // Load controllers\n const controllers = await Loader.loadModulesInDirectory({\n directory: controllersDirectory,\n // NOTE:\n // When getting \"system\", it gets /app/node_modules/@
|
|
4
|
+
"sourcesContent": ["import { existsSync } from 'fs';\nimport type { WebSocketMessageHandler, WebSocketRoute, WebSocketType } from './websocket.interface.js';\nimport { getRouteKey, log, parseServerMessage } from './utils.js';\nimport type { WebSocketServerBaseControllerType } from './controller/server/base.interface.js';\nimport type { WebSocketClientBaseControllerType } from './controller/client/base.interface.js';\nimport type WebSocket from 'ws';\nimport { Helper, Loader } from '../util/index.js';\n\nexport default abstract class WebSocketBase {\n protected routes: WebSocketRoute[] = [];\n protected routeHandlers: Map<string, WebSocketMessageHandler> = new Map();\n\n protected defaultRoutes: WebSocketRoute[] = [];\n\n public abstract get type(): WebSocketType;\n\n protected abstract getControllerDependencies(): any;\n protected abstract shouldPrintRoutes(): boolean;\n protected abstract handleMessageError(clientId: string, error: string): void;\n\n protected async configureRoutes(routes: WebSocketRoute[], controllersDirectory: string): Promise<void> {\n // log ('Configuring routes', { Type: this.type, 'Controllers Directory': controllersDirectory });\n\n const controllersDirectoryExists = await existsSync(controllersDirectory);\n\n if (!controllersDirectoryExists) {\n log('Controllers directory not found', {\n Directory: controllersDirectory,\n });\n\n return;\n }\n\n const scriptFileExtension = Helper.getScriptFileExtension();\n\n // Load controllers\n const controllers = await Loader.loadModulesInDirectory({\n directory: controllersDirectory,\n // NOTE:\n // When getting \"system\", it gets /app/node_modules/@scpxl/nodejs-framework/dist/websocket/controllers/server\n // Therefor .js is needed also\n // Fix so only .ts vs .js is needed\n extensions: ['.ts', '.js'],\n });\n\n for (const route of routes) {\n let ControllerClass: WebSocketServerBaseControllerType | WebSocketClientBaseControllerType;\n\n // log('Registering route', {\n // Type: route.type,\n // Controller: route.controller ? route.controller.toString() : route.controllerName,\n // Action: route.action,\n // });\n\n if (route.controller) {\n ControllerClass = route.controller;\n } else if (route.controllerName) {\n ControllerClass = controllers[route.controllerName];\n } else {\n throw new Error('WebSocket controller config not found');\n }\n\n if (typeof ControllerClass !== 'function') {\n log('Controller not found', {\n Controller: route.controllerName,\n Path: `${controllersDirectory}/${route.controllerName}.${scriptFileExtension}`,\n });\n\n continue;\n }\n\n const controllerDependencies = this.getControllerDependencies();\n\n const controllerInstance = new ControllerClass(controllerDependencies);\n\n const controllerHandler = controllerInstance[\n route.action as keyof typeof controllerInstance\n ] as WebSocketMessageHandler;\n const routeKey = getRouteKey(route.type, route.action);\n\n this.routeHandlers.set(routeKey, controllerHandler);\n }\n\n if (this.shouldPrintRoutes()) {\n log('Routes:', { Type: this.type });\n\n this.printRoutes();\n }\n }\n\n protected async handleServerMessage(ws: WebSocket, message: WebSocket.Data, clientId: string): Promise<void | any> {\n try {\n const parsedMessage = parseServerMessage(message);\n const type = parsedMessage.type;\n const action = parsedMessage.action;\n\n log('Incoming message', {\n 'Client ID': clientId,\n Type: type ?? '-',\n Action: action ?? '-',\n });\n\n const routeKey = getRouteKey(parsedMessage.type as string, parsedMessage.action as string);\n\n const messageHandler = this.routeHandlers.get(routeKey);\n\n if (messageHandler) {\n const messageResponse = await messageHandler(ws, clientId, parsedMessage.data);\n\n return {\n type,\n action,\n response: messageResponse,\n };\n }\n // throw new Error(`Route handler not found (Route Key: ${routeKey} | Type: ${type} | Action: ${action})`);\n\n log('Route handler not found', {\n RouteKey: routeKey,\n Type: type,\n Action: action,\n });\n\n // if (\n // typeof this.applicationConfig.webSocket\n // ?.serverMessageHandler === 'function'\n // ) {\n // // Execute custom application subscriber event handler\n // this.applicationConfig.webSocket.serverMessageHandler(\n // {\n // ws,\n // clientId,\n // parsedMessage,\n // },\n // );\n // }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n\n log(errorMessage);\n\n this.handleMessageError(clientId, errorMessage);\n }\n }\n\n protected printRoutes(): void {\n let routesString = '';\n\n const routeKeys = Array.from(this.routeHandlers.keys());\n\n routeKeys.forEach((routeKey, index) => {\n const [type, action] = routeKey.split(':');\n\n routesString += `Type: ${type} -> Action: ${action}`;\n\n if (index !== routeKeys.length - 1) {\n routesString += '\\n';\n }\n });\n\n log(routesString);\n }\n}\n"],
|
|
5
5
|
"mappings": ";;AAAA,SAAS,kBAAkB;AAE3B,SAAS,aAAa,KAAK,0BAA0B;AAIrD,SAAS,QAAQ,cAAc;AAE/B,MAAO,cAAqC;AAAA,EAR5C,OAQ4C;AAAA;AAAA;AAAA,EAChC,SAA2B,CAAC;AAAA,EAC5B,gBAAsD,oBAAI,IAAI;AAAA,EAE9D,gBAAkC,CAAC;AAAA,EAQ7C,MAAgB,gBAAgB,QAA0B,sBAA6C;AAGrG,UAAM,6BAA6B,MAAM,WAAW,oBAAoB;AAExE,QAAI,CAAC,4BAA4B;AAC/B,UAAI,mCAAmC;AAAA,QACrC,WAAW;AAAA,MACb,CAAC;AAED;AAAA,IACF;AAEA,UAAM,sBAAsB,OAAO,uBAAuB;AAG1D,UAAM,cAAc,MAAM,OAAO,uBAAuB;AAAA,MACtD,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA,MAKX,YAAY,CAAC,OAAO,KAAK;AAAA,IAC3B,CAAC;AAED,eAAW,SAAS,QAAQ;AAC1B,UAAI;AAQJ,UAAI,MAAM,YAAY;AACpB,0BAAkB,MAAM;AAAA,MAC1B,WAAW,MAAM,gBAAgB;AAC/B,0BAAkB,YAAY,MAAM,cAAc;AAAA,MACpD,OAAO;AACL,cAAM,IAAI,MAAM,uCAAuC;AAAA,MACzD;AAEA,UAAI,OAAO,oBAAoB,YAAY;AACzC,YAAI,wBAAwB;AAAA,UAC1B,YAAY,MAAM;AAAA,UAClB,MAAM,GAAG,oBAAoB,IAAI,MAAM,cAAc,IAAI,mBAAmB;AAAA,QAC9E,CAAC;AAED;AAAA,MACF;AAEA,YAAM,yBAAyB,KAAK,0BAA0B;AAE9D,YAAM,qBAAqB,IAAI,gBAAgB,sBAAsB;AAErE,YAAM,oBAAoB,mBACxB,MAAM,MACR;AACA,YAAM,WAAW,YAAY,MAAM,MAAM,MAAM,MAAM;AAErD,WAAK,cAAc,IAAI,UAAU,iBAAiB;AAAA,IACpD;AAEA,QAAI,KAAK,kBAAkB,GAAG;AAC5B,UAAI,WAAW,EAAE,MAAM,KAAK,KAAK,CAAC;AAElC,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,MAAgB,oBAAoB,IAAe,SAAyB,UAAuC;AACjH,QAAI;AACF,YAAM,gBAAgB,mBAAmB,OAAO;AAChD,YAAM,OAAO,cAAc;AAC3B,YAAM,SAAS,cAAc;AAE7B,UAAI,oBAAoB;AAAA,QACtB,aAAa;AAAA,QACb,MAAM,QAAQ;AAAA,QACd,QAAQ,UAAU;AAAA,MACpB,CAAC;AAED,YAAM,WAAW,YAAY,cAAc,MAAgB,cAAc,MAAgB;AAEzF,YAAM,iBAAiB,KAAK,cAAc,IAAI,QAAQ;AAEtD,UAAI,gBAAgB;AAClB,cAAM,kBAAkB,MAAM,eAAe,IAAI,UAAU,cAAc,IAAI;AAE7E,eAAO;AAAA,UACL;AAAA,UACA;AAAA,UACA,UAAU;AAAA,QACZ;AAAA,MACF;AAGA,UAAI,2BAA2B;AAAA,QAC7B,UAAU;AAAA,QACV,MAAM;AAAA,QACN,QAAQ;AAAA,MACV,CAAC;AAAA,IAeH,SAAS,OAAO;AACd,YAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU;AAE9D,UAAI,YAAY;AAEhB,WAAK,mBAAmB,UAAU,YAAY;AAAA,IAChD;AAAA,EACF;AAAA,EAEU,cAAoB;AAC5B,QAAI,eAAe;AAEnB,UAAM,YAAY,MAAM,KAAK,KAAK,cAAc,KAAK,CAAC;AAEtD,cAAU,QAAQ,CAAC,UAAU,UAAU;AACrC,YAAM,CAAC,MAAM,MAAM,IAAI,SAAS,MAAM,GAAG;AAEzC,sBAAgB,SAAS,IAAI,eAAe,MAAM;AAElD,UAAI,UAAU,UAAU,SAAS,GAAG;AAClC,wBAAgB;AAAA,MAClB;AAAA,IACF,CAAC;AAED,QAAI,YAAY;AAAA,EAClB;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scpxl/nodejs-framework",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
4
4
|
"description": "PXL Node.js Framework",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.0.0"
|
|
@@ -70,8 +70,12 @@
|
|
|
70
70
|
"build:tsc": "npm run clean && tsc",
|
|
71
71
|
"build:local": "npm run clean && node esbuild.config.js && yalc push",
|
|
72
72
|
"docs": "typedoc",
|
|
73
|
+
"docs:site:dev": "vitepress dev docs",
|
|
74
|
+
"docs:site:build": "vitepress build docs",
|
|
75
|
+
"docs:site:preview": "vitepress preview docs",
|
|
73
76
|
"release": "node scripts/release.js",
|
|
74
77
|
"prepare": "husky",
|
|
78
|
+
"postinstall": "npm run build || echo 'Build failed, dist files may be missing'",
|
|
75
79
|
"lint": "eslint .",
|
|
76
80
|
"lint:fix": "eslint . --fix",
|
|
77
81
|
"format": "prettier --check .",
|
|
@@ -115,7 +119,8 @@
|
|
|
115
119
|
"ts-node": "^10.9.2",
|
|
116
120
|
"tsc-alias": "^1.8.16",
|
|
117
121
|
"tsconfig-paths": "^4.2.0",
|
|
118
|
-
"typedoc": "^0.28.7"
|
|
122
|
+
"typedoc": "^0.28.7",
|
|
123
|
+
"vitepress": "^1.6.4"
|
|
119
124
|
},
|
|
120
125
|
"dependencies": {
|
|
121
126
|
"@aws-sdk/client-s3": "^3.496.0",
|