@scpxl/nodejs-framework 1.0.32 → 1.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/application/base-application.d.ts +7 -7
  2. package/dist/application/base-application.d.ts.map +1 -1
  3. package/dist/application/base-application.interface.d.ts +1 -1
  4. package/dist/application/base-application.interface.d.ts.map +1 -1
  5. package/dist/application/base-application.js +114 -14
  6. package/dist/application/base-application.js.map +2 -2
  7. package/dist/application/web-application.d.ts.map +1 -1
  8. package/dist/application/web-application.js +2 -1
  9. package/dist/application/web-application.js.map +2 -2
  10. package/dist/cache/manager.d.ts +1 -0
  11. package/dist/cache/manager.d.ts.map +1 -1
  12. package/dist/cache/manager.js +11 -2
  13. package/dist/cache/manager.js.map +2 -2
  14. package/dist/cli/index.js +28 -12
  15. package/dist/cli/index.js.map +2 -2
  16. package/dist/config/schema.d.ts +2 -63
  17. package/dist/config/schema.d.ts.map +1 -1
  18. package/dist/config/schema.js +1 -7
  19. package/dist/config/schema.js.map +2 -2
  20. package/dist/event/manager.js +2 -2
  21. package/dist/event/manager.js.map +2 -2
  22. package/dist/logger/logger.js +0 -1
  23. package/dist/logger/logger.js.map +2 -2
  24. package/dist/queue/manager.d.ts.map +1 -1
  25. package/dist/queue/manager.js +19 -7
  26. package/dist/queue/manager.js.map +2 -2
  27. package/dist/redis/instance.d.ts.map +1 -1
  28. package/dist/redis/instance.js +9 -1
  29. package/dist/redis/instance.js.map +2 -2
  30. package/dist/redis/manager.d.ts.map +1 -1
  31. package/dist/redis/manager.js +26 -16
  32. package/dist/redis/manager.js.map +3 -3
  33. package/dist/webserver/controller/entity.js +1 -1
  34. package/dist/webserver/controller/entity.js.map +2 -2
  35. package/dist/webserver/controller/health.js.map +1 -1
  36. package/dist/webserver/util.d.ts +1 -1
  37. package/dist/webserver/util.d.ts.map +1 -1
  38. package/dist/webserver/util.js +5 -23
  39. package/dist/webserver/util.js.map +2 -2
  40. package/dist/webserver/webserver.d.ts +2 -13
  41. package/dist/webserver/webserver.d.ts.map +1 -1
  42. package/dist/webserver/webserver.interface.d.ts +1 -21
  43. package/dist/webserver/webserver.interface.d.ts.map +1 -1
  44. package/dist/webserver/webserver.interface.js.map +1 -1
  45. package/dist/webserver/webserver.js +34 -36
  46. package/dist/webserver/webserver.js.map +2 -2
  47. package/dist/websocket/define-subscriber.d.ts +8 -1
  48. package/dist/websocket/define-subscriber.d.ts.map +1 -1
  49. package/dist/websocket/define-subscriber.js +2 -1
  50. package/dist/websocket/define-subscriber.js.map +2 -2
  51. package/dist/websocket/index.d.ts +4 -0
  52. package/dist/websocket/index.d.ts.map +1 -1
  53. package/dist/websocket/index.js +43 -1
  54. package/dist/websocket/index.js.map +2 -2
  55. package/dist/websocket/subscriber-middleware.d.ts +52 -0
  56. package/dist/websocket/subscriber-middleware.d.ts.map +1 -0
  57. package/dist/websocket/subscriber-middleware.js +200 -0
  58. package/dist/websocket/subscriber-middleware.js.map +7 -0
  59. package/dist/websocket/subscriber-utils.d.ts +88 -0
  60. package/dist/websocket/subscriber-utils.d.ts.map +1 -0
  61. package/dist/websocket/subscriber-utils.js +227 -0
  62. package/dist/websocket/subscriber-utils.js.map +7 -0
  63. package/dist/websocket/utils.d.ts.map +1 -1
  64. package/dist/websocket/utils.js +5 -1
  65. package/dist/websocket/utils.js.map +2 -2
  66. package/dist/websocket/websocket-base.d.ts.map +1 -1
  67. package/dist/websocket/websocket-base.js +9 -1
  68. package/dist/websocket/websocket-base.js.map +2 -2
  69. package/dist/websocket/websocket-server.d.ts +41 -1
  70. package/dist/websocket/websocket-server.d.ts.map +1 -1
  71. package/dist/websocket/websocket-server.js +90 -7
  72. package/dist/websocket/websocket-server.js.map +2 -2
  73. package/dist/websocket/websocket.interface.d.ts +7 -0
  74. package/dist/websocket/websocket.interface.d.ts.map +1 -1
  75. package/dist/websocket/websocket.interface.js.map +2 -2
  76. package/package.json +5 -6
@@ -0,0 +1,200 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import { Logger } from "../logger/index.js";
4
+ async function executeWithMiddleware(handler, middleware, context) {
5
+ for (const mw of middleware) {
6
+ try {
7
+ const shouldContinue = mw.onBefore ? await mw.onBefore(context) : true;
8
+ if (!shouldContinue) {
9
+ Logger.info({
10
+ message: "Middleware skipped handler execution",
11
+ meta: {
12
+ middleware: mw.name,
13
+ channel: context.channel
14
+ }
15
+ });
16
+ return;
17
+ }
18
+ } catch (error) {
19
+ Logger.error({
20
+ message: "Middleware onBefore failed",
21
+ meta: {
22
+ middleware: mw.name,
23
+ channel: context.channel,
24
+ error: error instanceof Error ? error.message : String(error)
25
+ }
26
+ });
27
+ throw error;
28
+ }
29
+ }
30
+ let result;
31
+ try {
32
+ result = await handler(context);
33
+ } catch (error) {
34
+ for (const mw of middleware) {
35
+ if (!mw.onError) {
36
+ continue;
37
+ }
38
+ try {
39
+ const shouldSuppress = await mw.onError(context, error instanceof Error ? error : new Error(String(error)));
40
+ if (shouldSuppress) {
41
+ return;
42
+ }
43
+ } catch (mwError) {
44
+ Logger.error({
45
+ message: "Middleware onError failed",
46
+ meta: {
47
+ middleware: mw.name,
48
+ channel: context.channel,
49
+ error: mwError instanceof Error ? mwError.message : String(mwError)
50
+ }
51
+ });
52
+ }
53
+ }
54
+ throw error;
55
+ }
56
+ for (const mw of middleware) {
57
+ if (!mw.onAfter) {
58
+ continue;
59
+ }
60
+ try {
61
+ await mw.onAfter(context, result);
62
+ } catch (error) {
63
+ Logger.error({
64
+ message: "Middleware onAfter failed",
65
+ meta: {
66
+ middleware: mw.name,
67
+ channel: context.channel,
68
+ error: error instanceof Error ? error.message : String(error)
69
+ }
70
+ });
71
+ }
72
+ }
73
+ }
74
+ __name(executeWithMiddleware, "executeWithMiddleware");
75
+ const loggingMiddleware = /* @__PURE__ */ __name((handlerName) => ({
76
+ name: "logging",
77
+ onBefore: /* @__PURE__ */ __name((context) => {
78
+ Logger.info({
79
+ message: `${handlerName}: Starting execution`,
80
+ meta: {
81
+ channel: context.channel
82
+ }
83
+ });
84
+ return true;
85
+ }, "onBefore"),
86
+ onAfter: /* @__PURE__ */ __name((context, result) => {
87
+ Logger.info({
88
+ message: `${handlerName}: Completed successfully`,
89
+ meta: {
90
+ channel: context.channel,
91
+ resultType: typeof result
92
+ }
93
+ });
94
+ }, "onAfter"),
95
+ onError: /* @__PURE__ */ __name((context, error) => {
96
+ Logger.error({
97
+ message: `${handlerName}: Failed`,
98
+ meta: {
99
+ channel: context.channel,
100
+ error: error.message
101
+ }
102
+ });
103
+ return false;
104
+ }, "onError")
105
+ }), "loggingMiddleware");
106
+ const timingMiddleware = /* @__PURE__ */ __name(() => {
107
+ const startTimes = /* @__PURE__ */ new Map();
108
+ return {
109
+ name: "timing",
110
+ onBefore: /* @__PURE__ */ __name((context) => {
111
+ startTimes.set(context.channel, Date.now());
112
+ return true;
113
+ }, "onBefore"),
114
+ onAfter: /* @__PURE__ */ __name((context) => {
115
+ const startTime = startTimes.get(context.channel);
116
+ if (startTime) {
117
+ const duration = Date.now() - startTime;
118
+ startTimes.delete(context.channel);
119
+ Logger.info({
120
+ message: "Handler execution timing",
121
+ meta: {
122
+ channel: context.channel,
123
+ durationMs: duration
124
+ }
125
+ });
126
+ }
127
+ }, "onAfter"),
128
+ onError: /* @__PURE__ */ __name((context) => {
129
+ startTimes.delete(context.channel);
130
+ return false;
131
+ }, "onError")
132
+ };
133
+ }, "timingMiddleware");
134
+ const validationMiddleware = /* @__PURE__ */ __name((validator) => ({
135
+ name: "validation",
136
+ onBefore: /* @__PURE__ */ __name(async (context) => {
137
+ try {
138
+ await validator(context.message);
139
+ return true;
140
+ } catch (error) {
141
+ Logger.warn({
142
+ message: "Message validation failed",
143
+ meta: {
144
+ channel: context.channel,
145
+ error: error instanceof Error ? error.message : String(error)
146
+ }
147
+ });
148
+ throw error;
149
+ }
150
+ }, "onBefore")
151
+ }), "validationMiddleware");
152
+ const rateLimitMiddleware = /* @__PURE__ */ __name((maxExecutions, windowMs) => {
153
+ const executionTimes = /* @__PURE__ */ new Map();
154
+ return {
155
+ name: "rate-limit",
156
+ onBefore: /* @__PURE__ */ __name((context) => {
157
+ const channel = context.channel;
158
+ const now = Date.now();
159
+ const times = executionTimes.get(channel) ?? [];
160
+ const recentTimes = times.filter((t) => now - t < windowMs);
161
+ if (recentTimes.length >= maxExecutions) {
162
+ Logger.warn({
163
+ message: "Rate limit exceeded",
164
+ meta: {
165
+ channel,
166
+ maxExecutions,
167
+ windowMs
168
+ }
169
+ });
170
+ return false;
171
+ }
172
+ recentTimes.push(now);
173
+ executionTimes.set(channel, recentTimes);
174
+ return true;
175
+ }, "onBefore")
176
+ };
177
+ }, "rateLimitMiddleware");
178
+ const errorRecoveryMiddleware = /* @__PURE__ */ __name((maxRetries = 3, _delayMs = 1e3) => ({
179
+ name: "error-recovery",
180
+ onError: /* @__PURE__ */ __name(async (context, error) => {
181
+ Logger.warn({
182
+ message: "Handler error, could implement retry logic",
183
+ meta: {
184
+ channel: context.channel,
185
+ error: error.message,
186
+ suggestedRetries: maxRetries
187
+ }
188
+ });
189
+ return false;
190
+ }, "onError")
191
+ }), "errorRecoveryMiddleware");
192
+ export {
193
+ errorRecoveryMiddleware,
194
+ executeWithMiddleware,
195
+ loggingMiddleware,
196
+ rateLimitMiddleware,
197
+ timingMiddleware,
198
+ validationMiddleware
199
+ };
200
+ //# sourceMappingURL=subscriber-middleware.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/websocket/subscriber-middleware.ts"],
4
+ "sourcesContent": ["import type { WebSocketSubscriberHandler, WebSocketSubscriberHandlerContext } from './websocket.interface.js';\nimport { Logger } from '../logger/index.js';\n\n/**\n * Middleware that can intercept and modify subscriber handler execution\n */\nexport interface WebSocketSubscriberMiddleware {\n /**\n * Unique identifier for the middleware\n */\n name: string;\n\n /**\n * Runs before the handler\n * Return false to skip handler execution\n */\n onBefore?: (context: WebSocketSubscriberHandlerContext) => boolean | Promise<boolean>;\n\n /**\n * Runs after successful handler execution\n */\n onAfter?: (context: WebSocketSubscriberHandlerContext, result: unknown) => void | Promise<void>;\n\n /**\n * Runs on handler error\n * Return true to suppress the error, false to rethrow\n */\n onError?: (context: WebSocketSubscriberHandlerContext, error: Error) => boolean | Promise<boolean>;\n}\n\n/**\n * Execute middleware pipeline and handler\n * @param handler - The handler to execute\n * @param middleware - Array of middleware to apply\n * @param context - Handler context\n */\nexport async function executeWithMiddleware(\n handler: WebSocketSubscriberHandler,\n middleware: WebSocketSubscriberMiddleware[],\n context: WebSocketSubscriberHandlerContext,\n): Promise<void> {\n // Execute \"before\" middleware\n for (const mw of middleware) {\n try {\n const shouldContinue = mw.onBefore ? await mw.onBefore(context) : true;\n if (!shouldContinue) {\n Logger.info({\n message: 'Middleware skipped handler execution',\n meta: {\n middleware: mw.name,\n channel: context.channel,\n },\n });\n return;\n }\n } catch (error) {\n Logger.error({\n message: 'Middleware onBefore failed',\n meta: {\n middleware: mw.name,\n channel: context.channel,\n error: error instanceof Error ? error.message : String(error),\n },\n });\n throw error;\n }\n }\n\n // Execute handler\n let result: unknown;\n try {\n result = await handler(context);\n } catch (error) {\n // Execute \"error\" middleware\n for (const mw of middleware) {\n if (!mw.onError) {\n continue;\n }\n\n try {\n const shouldSuppress = await mw.onError(context, error instanceof Error ? error : new Error(String(error)));\n if (shouldSuppress) {\n return;\n }\n } catch (mwError) {\n Logger.error({\n message: 'Middleware onError failed',\n meta: {\n middleware: mw.name,\n channel: context.channel,\n error: mwError instanceof Error ? mwError.message : String(mwError),\n },\n });\n }\n }\n\n throw error;\n }\n\n // Execute \"after\" middleware\n for (const mw of middleware) {\n if (!mw.onAfter) {\n continue;\n }\n\n try {\n await mw.onAfter(context, result);\n } catch (error) {\n Logger.error({\n message: 'Middleware onAfter failed',\n meta: {\n middleware: mw.name,\n channel: context.channel,\n error: error instanceof Error ? error.message : String(error),\n },\n });\n }\n }\n}\n\n/**\n * Built-in middleware for logging handler execution\n */\nexport const loggingMiddleware = (handlerName: string): WebSocketSubscriberMiddleware => ({\n name: 'logging',\n onBefore: context => {\n Logger.info({\n message: `${handlerName}: Starting execution`,\n meta: {\n channel: context.channel,\n },\n });\n return true;\n },\n onAfter: (context, result) => {\n Logger.info({\n message: `${handlerName}: Completed successfully`,\n meta: {\n channel: context.channel,\n resultType: typeof result,\n },\n });\n },\n onError: (context, error) => {\n Logger.error({\n message: `${handlerName}: Failed`,\n meta: {\n channel: context.channel,\n error: error.message,\n },\n });\n return false; // Don't suppress the error\n },\n});\n\n/**\n * Built-in middleware for timing handler execution\n */\nexport const timingMiddleware = (): WebSocketSubscriberMiddleware => {\n const startTimes = new Map<string, number>();\n\n return {\n name: 'timing',\n onBefore: context => {\n startTimes.set(context.channel, Date.now());\n return true;\n },\n onAfter: context => {\n const startTime = startTimes.get(context.channel);\n if (startTime) {\n const duration = Date.now() - startTime;\n startTimes.delete(context.channel);\n Logger.info({\n message: 'Handler execution timing',\n meta: {\n channel: context.channel,\n durationMs: duration,\n },\n });\n }\n },\n onError: context => {\n startTimes.delete(context.channel);\n return false;\n },\n };\n};\n\n/**\n * Built-in middleware for validating message structure\n */\nexport const validationMiddleware = (\n validator: (message: unknown) => void | Promise<void>,\n): WebSocketSubscriberMiddleware => ({\n name: 'validation',\n onBefore: async context => {\n try {\n await validator(context.message);\n return true;\n } catch (error) {\n Logger.warn({\n message: 'Message validation failed',\n meta: {\n channel: context.channel,\n error: error instanceof Error ? error.message : String(error),\n },\n });\n throw error;\n }\n },\n});\n\n/**\n * Built-in middleware for rate limiting\n */\nexport const rateLimitMiddleware = (maxExecutions: number, windowMs: number): WebSocketSubscriberMiddleware => {\n const executionTimes = new Map<string, number[]>();\n\n return {\n name: 'rate-limit',\n onBefore: context => {\n const channel = context.channel;\n const now = Date.now();\n const times = executionTimes.get(channel) ?? [];\n\n // Remove old entries\n const recentTimes = times.filter(t => now - t < windowMs);\n\n if (recentTimes.length >= maxExecutions) {\n Logger.warn({\n message: 'Rate limit exceeded',\n meta: {\n channel,\n maxExecutions,\n windowMs,\n },\n });\n return false;\n }\n\n recentTimes.push(now);\n executionTimes.set(channel, recentTimes);\n return true;\n },\n };\n};\n\n/**\n * Built-in middleware for error handling and recovery\n */\nexport const errorRecoveryMiddleware = (maxRetries = 3, _delayMs = 1000): WebSocketSubscriberMiddleware => ({\n name: 'error-recovery',\n onError: async (context, error) => {\n Logger.warn({\n message: 'Handler error, could implement retry logic',\n meta: {\n channel: context.channel,\n error: error.message,\n suggestedRetries: maxRetries,\n },\n });\n return false; // Don't suppress - let error bubble up\n },\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,88 @@
1
+ import type { WebSocketSubscriberHandler, WebSocketSubscriberHandlerContext, WebSocketSubscriberMatcher } from './websocket.interface.js';
2
+ /**
3
+ * Utility functions for building and composing WebSocket subscriber handlers
4
+ */
5
+ /**
6
+ * Create a predicate matcher for message properties
7
+ * @param key - The property key to check
8
+ * @param value - The expected value
9
+ */
10
+ export declare function matchByProperty(key: string, value: unknown): WebSocketSubscriberMatcher;
11
+ /**
12
+ * Create a predicate matcher for message property patterns
13
+ * @param key - The property key to check
14
+ * @param predicate - Function to test the value
15
+ */
16
+ export declare function matchByPropertyPredicate<_T = unknown>(key: string, predicate: (value: unknown) => boolean): WebSocketSubscriberMatcher;
17
+ /**
18
+ * Safely get nested property from an object
19
+ * @param obj - The object to search
20
+ * @param path - Dot-notation path (e.g., 'user.id' or 'data.items.0.name')
21
+ */
22
+ export declare function getNestedProperty(obj: any, path: string): unknown;
23
+ /**
24
+ * Wrap a handler with error handling
25
+ * @param handler - The handler to wrap
26
+ * @param onError - Error handler callback
27
+ * @param throwError - Whether to rethrow the error after handling
28
+ */
29
+ export declare function withErrorHandler<TMessage = any>(handler: WebSocketSubscriberHandler<TMessage>, onError?: (error: Error, context: WebSocketSubscriberHandlerContext<TMessage>) => void | Promise<void>, _throwError?: boolean): WebSocketSubscriberHandler<TMessage>;
30
+ /**
31
+ * Wrap a handler with logging
32
+ * @param handler - The handler to wrap
33
+ * @param handlerName - Name for logging purposes
34
+ */
35
+ export declare function withLogging<TMessage = any>(handler: WebSocketSubscriberHandler<TMessage>, handlerName?: string): WebSocketSubscriberHandler<TMessage>;
36
+ /**
37
+ * Wrap a handler with rate limiting
38
+ * @param handler - The handler to wrap
39
+ * @param maxExecutions - Max executions allowed
40
+ * @param windowMs - Time window in milliseconds
41
+ * @param onRateLimited - Optional callback when rate limited
42
+ */
43
+ export declare function withRateLimit<TMessage = any>(handler: WebSocketSubscriberHandler<TMessage>, maxExecutions: number, windowMs: number, onRateLimited?: (context: WebSocketSubscriberHandlerContext<TMessage>) => void | Promise<void>): WebSocketSubscriberHandler<TMessage>;
44
+ /**
45
+ * Wrap a handler with retry logic
46
+ * @param handler - The handler to wrap
47
+ * @param maxRetries - Maximum number of retries
48
+ * @param delayMs - Delay between retries in milliseconds
49
+ * @param backoffMultiplier - Multiplier for exponential backoff (default: 1, no backoff)
50
+ */
51
+ export declare function withRetry<TMessage = any>(handler: WebSocketSubscriberHandler<TMessage>, maxRetries: number, delayMs: number, backoffMultiplier?: number): WebSocketSubscriberHandler<TMessage>;
52
+ /**
53
+ * Compose multiple handlers into a single handler
54
+ * Executes handlers sequentially, passing context through each one
55
+ * @param handlers - Array of handlers to compose
56
+ */
57
+ export declare function composeHandlers<TMessage = any>(handlers: WebSocketSubscriberHandler<TMessage>[]): WebSocketSubscriberHandler<TMessage>;
58
+ /**
59
+ * Create a filter handler that conditionally executes based on a predicate
60
+ * @param predicate - Function that returns true if handler should execute
61
+ * @param handler - The handler to execute conditionally
62
+ */
63
+ export declare function withFilter<TMessage = any>(predicate: (context: WebSocketSubscriberHandlerContext<TMessage>) => boolean | Promise<boolean>, handler: WebSocketSubscriberHandler<TMessage>): WebSocketSubscriberHandler<TMessage>;
64
+ /**
65
+ * Validate message structure before execution
66
+ * @param validator - Function that validates the message and throws if invalid
67
+ * @param handler - The handler to wrap
68
+ */
69
+ export declare function withValidation<TMessage = any>(validator: (message: TMessage) => void | Promise<void>, handler: WebSocketSubscriberHandler<TMessage>): WebSocketSubscriberHandler<TMessage>;
70
+ /**
71
+ * Add metadata/context to a handler execution
72
+ * @param metadata - Metadata to add to context
73
+ * @param handler - The handler to wrap
74
+ */
75
+ export declare function withMetadata<TMessage = any>(metadata: Record<string, unknown>, handler: WebSocketSubscriberHandler<TMessage>): WebSocketSubscriberHandler<TMessage>;
76
+ /**
77
+ * Debounce handler execution by channel
78
+ * @param handler - The handler to wrap
79
+ * @param delayMs - Debounce delay in milliseconds
80
+ */
81
+ export declare function withDebounce<TMessage = any>(handler: WebSocketSubscriberHandler<TMessage>, delayMs: number): WebSocketSubscriberHandler<TMessage>;
82
+ /**
83
+ * Throttle handler execution by channel
84
+ * @param handler - The handler to wrap
85
+ * @param intervalMs - Throttle interval in milliseconds
86
+ */
87
+ export declare function withThrottle<TMessage = any>(handler: WebSocketSubscriberHandler<TMessage>, intervalMs: number): WebSocketSubscriberHandler<TMessage>;
88
+ //# sourceMappingURL=subscriber-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscriber-utils.d.ts","sourceRoot":"","sources":["../../src/websocket/subscriber-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,227 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import { Logger } from "../logger/index.js";
4
+ function matchByProperty(key, value) {
5
+ return (context) => {
6
+ try {
7
+ const messageValue = getNestedProperty(context.message, key);
8
+ return messageValue === value;
9
+ } catch {
10
+ return false;
11
+ }
12
+ };
13
+ }
14
+ __name(matchByProperty, "matchByProperty");
15
+ function matchByPropertyPredicate(key, predicate) {
16
+ return (context) => {
17
+ try {
18
+ const messageValue = getNestedProperty(context.message, key);
19
+ return predicate(messageValue);
20
+ } catch {
21
+ return false;
22
+ }
23
+ };
24
+ }
25
+ __name(matchByPropertyPredicate, "matchByPropertyPredicate");
26
+ function getNestedProperty(obj, path) {
27
+ const keys = path.split(".");
28
+ let current = obj;
29
+ for (const key of keys) {
30
+ if (current == null) {
31
+ return void 0;
32
+ }
33
+ current = current[key];
34
+ }
35
+ return current;
36
+ }
37
+ __name(getNestedProperty, "getNestedProperty");
38
+ function withErrorHandler(handler, onError, _throwError = false) {
39
+ return async (context) => {
40
+ try {
41
+ return await handler(context);
42
+ } catch (error) {
43
+ const err = error instanceof Error ? error : new Error(String(error));
44
+ if (onError) {
45
+ try {
46
+ await onError(err, context);
47
+ } catch (callbackError) {
48
+ Logger.error({
49
+ message: "Error handler callback failed",
50
+ meta: { originalError: err.message, callbackError }
51
+ });
52
+ }
53
+ }
54
+ if (_throwError) {
55
+ throw err;
56
+ }
57
+ }
58
+ };
59
+ }
60
+ __name(withErrorHandler, "withErrorHandler");
61
+ function withLogging(handler, handlerName = "subscriber-handler") {
62
+ return async (context) => {
63
+ const startTime = Date.now();
64
+ const messageKeys = context.message && typeof context.message === "object" ? Object.keys(context.message).slice(0, 5) : [];
65
+ Logger.info({
66
+ message: `${handlerName}: Starting handler execution`,
67
+ meta: {
68
+ channel: context.channel,
69
+ messageKeys
70
+ }
71
+ });
72
+ try {
73
+ const result = await handler(context);
74
+ const duration = Date.now() - startTime;
75
+ Logger.info({
76
+ message: `${handlerName}: Handler completed successfully`,
77
+ meta: { channel: context.channel, durationMs: duration }
78
+ });
79
+ return result;
80
+ } catch (error) {
81
+ const duration = Date.now() - startTime;
82
+ Logger.error({
83
+ message: `${handlerName}: Handler failed`,
84
+ meta: {
85
+ channel: context.channel,
86
+ error: error instanceof Error ? error.message : String(error),
87
+ durationMs: duration
88
+ }
89
+ });
90
+ throw error;
91
+ }
92
+ };
93
+ }
94
+ __name(withLogging, "withLogging");
95
+ function withRateLimit(handler, maxExecutions, windowMs, onRateLimited) {
96
+ const executionTimes = [];
97
+ return async (context) => {
98
+ const now = Date.now();
99
+ while (executionTimes.length > 0 && executionTimes[0] < now - windowMs) {
100
+ executionTimes.shift();
101
+ }
102
+ if (executionTimes.length >= maxExecutions) {
103
+ if (onRateLimited) {
104
+ await onRateLimited(context);
105
+ }
106
+ return;
107
+ }
108
+ executionTimes.push(now);
109
+ return await handler(context);
110
+ };
111
+ }
112
+ __name(withRateLimit, "withRateLimit");
113
+ function withRetry(handler, maxRetries, delayMs, backoffMultiplier = 1) {
114
+ return async (context) => {
115
+ let lastError = null;
116
+ let currentDelay = delayMs;
117
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
118
+ try {
119
+ return await handler(context);
120
+ } catch (error) {
121
+ lastError = error instanceof Error ? error : new Error(String(error));
122
+ if (attempt < maxRetries) {
123
+ await new Promise((resolve) => setTimeout(resolve, currentDelay));
124
+ currentDelay = Math.floor(currentDelay * backoffMultiplier);
125
+ }
126
+ }
127
+ }
128
+ throw lastError;
129
+ };
130
+ }
131
+ __name(withRetry, "withRetry");
132
+ function composeHandlers(handlers) {
133
+ return async (context) => {
134
+ for (const handler of handlers) {
135
+ await handler(context);
136
+ }
137
+ };
138
+ }
139
+ __name(composeHandlers, "composeHandlers");
140
+ function withFilter(predicate, handler) {
141
+ return async (context) => {
142
+ const shouldExecute = await predicate(context);
143
+ if (shouldExecute) {
144
+ return await handler(context);
145
+ }
146
+ };
147
+ }
148
+ __name(withFilter, "withFilter");
149
+ function withValidation(validator, handler) {
150
+ return async (context) => {
151
+ try {
152
+ await validator(context.message);
153
+ return await handler(context);
154
+ } catch (error) {
155
+ Logger.warn({
156
+ message: "Message validation failed",
157
+ meta: {
158
+ channel: context.channel,
159
+ error: error instanceof Error ? error.message : String(error)
160
+ }
161
+ });
162
+ throw error;
163
+ }
164
+ };
165
+ }
166
+ __name(withValidation, "withValidation");
167
+ function withMetadata(metadata, handler) {
168
+ return async (context) => {
169
+ const enrichedContext = {
170
+ ...context,
171
+ metadata
172
+ };
173
+ return await handler(enrichedContext);
174
+ };
175
+ }
176
+ __name(withMetadata, "withMetadata");
177
+ function withDebounce(handler, delayMs) {
178
+ const timers = /* @__PURE__ */ new Map();
179
+ return async (context) => {
180
+ const channel = context.channel;
181
+ const existingTimer = timers.get(channel);
182
+ if (existingTimer) {
183
+ clearTimeout(existingTimer);
184
+ }
185
+ return new Promise((resolve) => {
186
+ const timer = setTimeout(async () => {
187
+ try {
188
+ await handler(context);
189
+ } finally {
190
+ timers.delete(channel);
191
+ resolve();
192
+ }
193
+ }, delayMs);
194
+ timers.set(channel, timer);
195
+ });
196
+ };
197
+ }
198
+ __name(withDebounce, "withDebounce");
199
+ function withThrottle(handler, intervalMs) {
200
+ const lastExecutionTime = /* @__PURE__ */ new Map();
201
+ return async (context) => {
202
+ const channel = context.channel;
203
+ const now = Date.now();
204
+ const lastTime = lastExecutionTime.get(channel) ?? 0;
205
+ if (now - lastTime >= intervalMs) {
206
+ lastExecutionTime.set(channel, now);
207
+ return await handler(context);
208
+ }
209
+ };
210
+ }
211
+ __name(withThrottle, "withThrottle");
212
+ export {
213
+ composeHandlers,
214
+ getNestedProperty,
215
+ matchByProperty,
216
+ matchByPropertyPredicate,
217
+ withDebounce,
218
+ withErrorHandler,
219
+ withFilter,
220
+ withLogging,
221
+ withMetadata,
222
+ withRateLimit,
223
+ withRetry,
224
+ withThrottle,
225
+ withValidation
226
+ };
227
+ //# sourceMappingURL=subscriber-utils.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/websocket/subscriber-utils.ts"],
4
+ "sourcesContent": ["import type {\n WebSocketSubscriberHandler,\n WebSocketSubscriberHandlerContext,\n WebSocketSubscriberMatcher,\n} from './websocket.interface.js';\nimport { Logger } from '../logger/index.js';\n\n/**\n * Utility functions for building and composing WebSocket subscriber handlers\n */\n\n/**\n * Create a predicate matcher for message properties\n * @param key - The property key to check\n * @param value - The expected value\n */\nexport function matchByProperty(key: string, value: unknown): WebSocketSubscriberMatcher {\n return (context: WebSocketSubscriberHandlerContext) => {\n try {\n const messageValue = getNestedProperty(context.message, key);\n return messageValue === value;\n } catch {\n return false;\n }\n };\n}\n\n/**\n * Create a predicate matcher for message property patterns\n * @param key - The property key to check\n * @param predicate - Function to test the value\n */\nexport function matchByPropertyPredicate<_T = unknown>(\n key: string,\n predicate: (value: unknown) => boolean,\n): WebSocketSubscriberMatcher {\n return (context: WebSocketSubscriberHandlerContext) => {\n try {\n const messageValue = getNestedProperty(context.message, key);\n return predicate(messageValue);\n } catch {\n return false;\n }\n };\n}\n\n/**\n * Safely get nested property from an object\n * @param obj - The object to search\n * @param path - Dot-notation path (e.g., 'user.id' or 'data.items.0.name')\n */\nexport function getNestedProperty(obj: any, path: string): unknown {\n const keys = path.split('.');\n let current = obj;\n\n for (const key of keys) {\n if (current == null) {\n return undefined;\n }\n // eslint-disable-next-line security/detect-object-injection\n current = current[key];\n }\n\n return current;\n}\n\n/**\n * Wrap a handler with error handling\n * @param handler - The handler to wrap\n * @param onError - Error handler callback\n * @param throwError - Whether to rethrow the error after handling\n */\nexport function withErrorHandler<TMessage = any>(\n handler: WebSocketSubscriberHandler<TMessage>,\n onError?: (error: Error, context: WebSocketSubscriberHandlerContext<TMessage>) => void | Promise<void>,\n _throwError = false,\n): WebSocketSubscriberHandler<TMessage> {\n return async (context: WebSocketSubscriberHandlerContext<TMessage>) => {\n try {\n return await handler(context);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n\n if (onError) {\n try {\n await onError(err, context);\n } catch (callbackError) {\n Logger.error({\n message: 'Error handler callback failed',\n meta: { originalError: err.message, callbackError },\n });\n }\n }\n\n if (_throwError) {\n throw err;\n }\n }\n };\n}\n\n/**\n * Wrap a handler with logging\n * @param handler - The handler to wrap\n * @param handlerName - Name for logging purposes\n */\nexport function withLogging<TMessage = any>(\n handler: WebSocketSubscriberHandler<TMessage>,\n handlerName = 'subscriber-handler',\n): WebSocketSubscriberHandler<TMessage> {\n return async (context: WebSocketSubscriberHandlerContext<TMessage>) => {\n const startTime = Date.now();\n const messageKeys =\n context.message && typeof context.message === 'object'\n ? Object.keys(context.message as Record<string, unknown>).slice(0, 5)\n : [];\n Logger.info({\n message: `${handlerName}: Starting handler execution`,\n meta: {\n channel: context.channel,\n messageKeys,\n },\n });\n\n try {\n const result = await handler(context);\n const duration = Date.now() - startTime;\n Logger.info({\n message: `${handlerName}: Handler completed successfully`,\n meta: { channel: context.channel, durationMs: duration },\n });\n return result;\n } catch (error) {\n const duration = Date.now() - startTime;\n Logger.error({\n message: `${handlerName}: Handler failed`,\n meta: {\n channel: context.channel,\n error: error instanceof Error ? error.message : String(error),\n durationMs: duration,\n },\n });\n throw error;\n }\n };\n}\n\n/**\n * Wrap a handler with rate limiting\n * @param handler - The handler to wrap\n * @param maxExecutions - Max executions allowed\n * @param windowMs - Time window in milliseconds\n * @param onRateLimited - Optional callback when rate limited\n */\nexport function withRateLimit<TMessage = any>(\n handler: WebSocketSubscriberHandler<TMessage>,\n maxExecutions: number,\n windowMs: number,\n onRateLimited?: (context: WebSocketSubscriberHandlerContext<TMessage>) => void | Promise<void>,\n): WebSocketSubscriberHandler<TMessage> {\n const executionTimes: number[] = [];\n\n return async (context: WebSocketSubscriberHandlerContext<TMessage>) => {\n const now = Date.now();\n\n // Remove old entries outside the window\n while (executionTimes.length > 0 && executionTimes[0] < now - windowMs) {\n executionTimes.shift();\n }\n\n if (executionTimes.length >= maxExecutions) {\n if (onRateLimited) {\n await onRateLimited(context);\n }\n return;\n }\n\n executionTimes.push(now);\n return await handler(context);\n };\n}\n\n/**\n * Wrap a handler with retry logic\n * @param handler - The handler to wrap\n * @param maxRetries - Maximum number of retries\n * @param delayMs - Delay between retries in milliseconds\n * @param backoffMultiplier - Multiplier for exponential backoff (default: 1, no backoff)\n */\nexport function withRetry<TMessage = any>(\n handler: WebSocketSubscriberHandler<TMessage>,\n maxRetries: number,\n delayMs: number,\n backoffMultiplier = 1,\n): WebSocketSubscriberHandler<TMessage> {\n return async (context: WebSocketSubscriberHandlerContext<TMessage>) => {\n let lastError: Error | null = null;\n let currentDelay = delayMs;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await handler(context);\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n if (attempt < maxRetries) {\n await new Promise(resolve => setTimeout(resolve, currentDelay));\n currentDelay = Math.floor(currentDelay * backoffMultiplier);\n }\n }\n }\n\n throw lastError;\n };\n}\n\n/**\n * Compose multiple handlers into a single handler\n * Executes handlers sequentially, passing context through each one\n * @param handlers - Array of handlers to compose\n */\nexport function composeHandlers<TMessage = any>(\n handlers: WebSocketSubscriberHandler<TMessage>[],\n): WebSocketSubscriberHandler<TMessage> {\n return async (context: WebSocketSubscriberHandlerContext<TMessage>) => {\n for (const handler of handlers) {\n await handler(context);\n }\n };\n}\n\n/**\n * Create a filter handler that conditionally executes based on a predicate\n * @param predicate - Function that returns true if handler should execute\n * @param handler - The handler to execute conditionally\n */\nexport function withFilter<TMessage = any>(\n predicate: (context: WebSocketSubscriberHandlerContext<TMessage>) => boolean | Promise<boolean>,\n handler: WebSocketSubscriberHandler<TMessage>,\n): WebSocketSubscriberHandler<TMessage> {\n return async (context: WebSocketSubscriberHandlerContext<TMessage>) => {\n const shouldExecute = await predicate(context);\n if (shouldExecute) {\n return await handler(context);\n }\n };\n}\n\n/**\n * Validate message structure before execution\n * @param validator - Function that validates the message and throws if invalid\n * @param handler - The handler to wrap\n */\nexport function withValidation<TMessage = any>(\n validator: (message: TMessage) => void | Promise<void>,\n handler: WebSocketSubscriberHandler<TMessage>,\n): WebSocketSubscriberHandler<TMessage> {\n return async (context: WebSocketSubscriberHandlerContext<TMessage>) => {\n try {\n await validator(context.message);\n return await handler(context);\n } catch (error) {\n Logger.warn({\n message: 'Message validation failed',\n meta: {\n channel: context.channel,\n error: error instanceof Error ? error.message : String(error),\n },\n });\n throw error;\n }\n };\n}\n\n/**\n * Add metadata/context to a handler execution\n * @param metadata - Metadata to add to context\n * @param handler - The handler to wrap\n */\nexport function withMetadata<TMessage = any>(\n metadata: Record<string, unknown>,\n handler: WebSocketSubscriberHandler<TMessage>,\n): WebSocketSubscriberHandler<TMessage> {\n return async (context: WebSocketSubscriberHandlerContext<TMessage>) => {\n const enrichedContext = {\n ...context,\n metadata,\n } as any;\n\n return await handler(enrichedContext);\n };\n}\n\n/**\n * Debounce handler execution by channel\n * @param handler - The handler to wrap\n * @param delayMs - Debounce delay in milliseconds\n */\nexport function withDebounce<TMessage = any>(\n handler: WebSocketSubscriberHandler<TMessage>,\n delayMs: number,\n): WebSocketSubscriberHandler<TMessage> {\n const timers = new Map<string, NodeJS.Timeout>();\n\n return async (context: WebSocketSubscriberHandlerContext<TMessage>) => {\n const channel = context.channel;\n\n // Cancel previous timer for this channel\n const existingTimer = timers.get(channel);\n if (existingTimer) {\n clearTimeout(existingTimer);\n }\n\n // Set new timer\n return new Promise<void>(resolve => {\n const timer = setTimeout(async () => {\n try {\n await handler(context);\n } finally {\n timers.delete(channel);\n resolve();\n }\n }, delayMs);\n\n timers.set(channel, timer);\n });\n };\n}\n\n/**\n * Throttle handler execution by channel\n * @param handler - The handler to wrap\n * @param intervalMs - Throttle interval in milliseconds\n */\nexport function withThrottle<TMessage = any>(\n handler: WebSocketSubscriberHandler<TMessage>,\n intervalMs: number,\n): WebSocketSubscriberHandler<TMessage> {\n const lastExecutionTime = new Map<string, number>();\n\n return async (context: WebSocketSubscriberHandlerContext<TMessage>) => {\n const channel = context.channel;\n const now = Date.now();\n const lastTime = lastExecutionTime.get(channel) ?? 0;\n\n if (now - lastTime >= intervalMs) {\n lastExecutionTime.set(channel, now);\n return await handler(context);\n }\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/websocket/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,IAAI,CAAC;AAGhC,MAAM,WAAW,UAAU;IACzB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAE/F;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkBnF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEhE"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/websocket/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,SAAS,MAAM,IAAI,CAAC;AAGhC,MAAM,WAAW,UAAU;IACzB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAMzC;AAED,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAE/F;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkBnF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEhE"}
@@ -1,8 +1,12 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import crypto from "node:crypto";
3
4
  import { Logger } from "../logger/index.js";
4
5
  function generateClientId() {
5
- return Math.random().toString(36).substr(2, 9);
6
+ if (typeof crypto.randomUUID === "function") {
7
+ return crypto.randomUUID().replace(/-/g, "");
8
+ }
9
+ return crypto.randomBytes(16).toString("hex");
6
10
  }
7
11
  __name(generateClientId, "generateClientId");
8
12
  function log(message, meta, options) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/websocket/utils.ts"],
4
- "sourcesContent": ["import type WebSocket from 'ws';\nimport { Logger } from '../logger/index.js';\n\nexport interface LogOptions {\n muteWorker?: boolean;\n}\n\nexport function generateClientId(): string {\n return Math.random().toString(36).substr(2, 9);\n}\n\nexport function log(message: string, meta?: Record<string, unknown>, options?: LogOptions): void {\n Logger.custom({ level: 'webSocket', message, meta, options });\n}\n\nexport function parseServerMessage(message: WebSocket.Data): Record<string, unknown> {\n let parsedMessage;\n\n try {\n parsedMessage = JSON.parse(message.toString());\n } catch {\n throw new Error('Failed to parse JSON');\n }\n\n if (!parsedMessage) {\n throw new Error('Invalid WebSocket message');\n } else if (!parsedMessage.type) {\n throw new Error('Missing WebSocket message type');\n } else if (!parsedMessage.action) {\n throw new Error('Missing WebSocket message action');\n }\n\n return parsedMessage;\n}\n\nexport function getRouteKey(type: string, action: string): string {\n return `${type}:${action}`;\n}\n"],
5
- "mappings": ";;AACA,SAAS,cAAc;AAMhB,SAAS,mBAA2B;AACzC,SAAO,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC;AAC/C;AAFgB;AAIT,SAAS,IAAI,SAAiB,MAAgC,SAA4B;AAC/F,SAAO,OAAO,EAAE,OAAO,aAAa,SAAS,MAAM,QAAQ,CAAC;AAC9D;AAFgB;AAIT,SAAS,mBAAmB,SAAkD;AACnF,MAAI;AAEJ,MAAI;AACF,oBAAgB,KAAK,MAAM,QAAQ,SAAS,CAAC;AAAA,EAC/C,QAAQ;AACN,UAAM,IAAI,MAAM,sBAAsB;AAAA,EACxC;AAEA,MAAI,CAAC,eAAe;AAClB,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C,WAAW,CAAC,cAAc,MAAM;AAC9B,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD,WAAW,CAAC,cAAc,QAAQ;AAChC,UAAM,IAAI,MAAM,kCAAkC;AAAA,EACpD;AAEA,SAAO;AACT;AAlBgB;AAoBT,SAAS,YAAY,MAAc,QAAwB;AAChE,SAAO,GAAG,IAAI,IAAI,MAAM;AAC1B;AAFgB;",
4
+ "sourcesContent": ["import crypto from 'node:crypto';\nimport type WebSocket from 'ws';\nimport { Logger } from '../logger/index.js';\n\nexport interface LogOptions {\n muteWorker?: boolean;\n}\n\nexport function generateClientId(): string {\n if (typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID().replace(/-/g, '');\n }\n\n return crypto.randomBytes(16).toString('hex');\n}\n\nexport function log(message: string, meta?: Record<string, unknown>, options?: LogOptions): void {\n Logger.custom({ level: 'webSocket', message, meta, options });\n}\n\nexport function parseServerMessage(message: WebSocket.Data): Record<string, unknown> {\n let parsedMessage;\n\n try {\n parsedMessage = JSON.parse(message.toString());\n } catch {\n throw new Error('Failed to parse JSON');\n }\n\n if (!parsedMessage) {\n throw new Error('Invalid WebSocket message');\n } else if (!parsedMessage.type) {\n throw new Error('Missing WebSocket message type');\n } else if (!parsedMessage.action) {\n throw new Error('Missing WebSocket message action');\n }\n\n return parsedMessage;\n}\n\nexport function getRouteKey(type: string, action: string): string {\n return `${type}:${action}`;\n}\n"],
5
+ "mappings": ";;AAAA,OAAO,YAAY;AAEnB,SAAS,cAAc;AAMhB,SAAS,mBAA2B;AACzC,MAAI,OAAO,OAAO,eAAe,YAAY;AAC3C,WAAO,OAAO,WAAW,EAAE,QAAQ,MAAM,EAAE;AAAA,EAC7C;AAEA,SAAO,OAAO,YAAY,EAAE,EAAE,SAAS,KAAK;AAC9C;AANgB;AAQT,SAAS,IAAI,SAAiB,MAAgC,SAA4B;AAC/F,SAAO,OAAO,EAAE,OAAO,aAAa,SAAS,MAAM,QAAQ,CAAC;AAC9D;AAFgB;AAIT,SAAS,mBAAmB,SAAkD;AACnF,MAAI;AAEJ,MAAI;AACF,oBAAgB,KAAK,MAAM,QAAQ,SAAS,CAAC;AAAA,EAC/C,QAAQ;AACN,UAAM,IAAI,MAAM,sBAAsB;AAAA,EACxC;AAEA,MAAI,CAAC,eAAe;AAClB,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C,WAAW,CAAC,cAAc,MAAM;AAC9B,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD,WAAW,CAAC,cAAc,QAAQ;AAChC,UAAM,IAAI,MAAM,kCAAkC;AAAA,EACpD;AAEA,SAAO;AACT;AAlBgB;AAoBT,SAAS,YAAY,MAAc,QAAwB;AAChE,SAAO,GAAG,IAAI,IAAI,MAAM;AAC1B;AAFgB;",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"websocket-base.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAIvG,OAAO,KAAK,SAAS,MAAM,IAAI,CAAC;AAGhC,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,aAAa;IACzC,SAAS,CAAC,MAAM,EAAE,cAAc,EAAE,CAAM;IACxC,SAAS,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAa;IAE1E,SAAS,CAAC,aAAa,EAAE,cAAc,EAAE,CAAM;IAE/C,aAAoB,IAAI,IAAI,aAAa,CAAC;IAE1C,SAAS,CAAC,QAAQ,CAAC,yBAAyB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACvE,SAAS,CAAC,QAAQ,CAAC,iBAAiB,IAAI,OAAO;IAC/C,SAAS,CAAC,QAAQ,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;cAE5D,eAAe,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;cAwEtF,mBAAmB,CACjC,EAAE,EAAE,SAAS,EACb,OAAO,EAAE,SAAS,CAAC,IAAI,EACvB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAuDxE,SAAS,CAAC,WAAW,IAAI,IAAI;CAiB9B"}
1
+ {"version":3,"file":"websocket-base.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAIvG,OAAO,KAAK,SAAS,MAAM,IAAI,CAAC;AAGhC,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,aAAa;IACzC,SAAS,CAAC,MAAM,EAAE,cAAc,EAAE,CAAM;IACxC,SAAS,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAa;IAE1E,SAAS,CAAC,aAAa,EAAE,cAAc,EAAE,CAAM;IAE/C,aAAoB,IAAI,IAAI,aAAa,CAAC;IAE1C,SAAS,CAAC,QAAQ,CAAC,yBAAyB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACvE,SAAS,CAAC,QAAQ,CAAC,iBAAiB,IAAI,OAAO;IAC/C,SAAS,CAAC,QAAQ,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;cAE5D,eAAe,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;cAiFtF,mBAAmB,CACjC,EAAE,EAAE,SAAS,EACb,OAAO,EAAE,SAAS,CAAC,IAAI,EACvB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAuDxE,SAAS,CAAC,WAAW,IAAI,IAAI;CAiB9B"}
@@ -46,7 +46,15 @@ class WebSocketBase {
46
46
  const controllerInstance = new ControllerClass(controllerDependencies);
47
47
  const controllerHandler = controllerInstance[route.action];
48
48
  const routeKey = getRouteKey(route.type, route.action);
49
- this.routeHandlers.set(routeKey, controllerHandler);
49
+ if (typeof controllerHandler !== "function") {
50
+ log("Controller action not found", {
51
+ Controller: route.controllerName ?? ControllerClass.name,
52
+ Action: route.action,
53
+ RouteKey: routeKey
54
+ });
55
+ continue;
56
+ }
57
+ this.routeHandlers.set(routeKey, controllerHandler.bind(controllerInstance));
50
58
  }
51
59
  if (this.shouldPrintRoutes()) {
52
60
  log("Routes:", { Type: this.type });