@noony-serverless/core 0.3.4 → 0.4.0
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/build/core/containerPool.d.ts +129 -26
- package/build/core/containerPool.js +213 -68
- package/build/core/handler.d.ts +2 -2
- package/build/core/handler.js +6 -12
- package/build/core/index.d.ts +1 -0
- package/build/core/index.js +1 -0
- package/build/core/logger.d.ts +89 -1
- package/build/core/logger.js +136 -5
- package/build/core/telemetry/config.d.ts +331 -0
- package/build/core/telemetry/config.js +153 -0
- package/build/core/telemetry/index.d.ts +22 -0
- package/build/core/telemetry/index.js +45 -0
- package/build/core/telemetry/provider.d.ts +203 -0
- package/build/core/telemetry/provider.js +3 -0
- package/build/core/telemetry/providers/console-provider.d.ts +54 -0
- package/build/core/telemetry/providers/console-provider.js +124 -0
- package/build/core/telemetry/providers/index.d.ts +10 -0
- package/build/core/telemetry/providers/index.js +19 -0
- package/build/core/telemetry/providers/noop-provider.d.ts +51 -0
- package/build/core/telemetry/providers/noop-provider.js +67 -0
- package/build/core/telemetry/providers/opentelemetry-provider.d.ts +102 -0
- package/build/core/telemetry/providers/opentelemetry-provider.js +342 -0
- package/build/middlewares/dependencyInjectionMiddleware.d.ts +16 -8
- package/build/middlewares/dependencyInjectionMiddleware.js +31 -11
- package/build/middlewares/guards/adapters/CustomTokenVerificationPortAdapter.d.ts +1 -1
- package/build/middlewares/guards/guards/FastAuthGuard.d.ts +5 -5
- package/build/middlewares/guards/guards/FastAuthGuard.js +3 -2
- package/build/middlewares/guards/guards/PermissionGuardFactory.d.ts +7 -9
- package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.js +1 -1
- package/build/middlewares/guards/resolvers/PermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/PlainPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/resolvers/WildcardPermissionResolver.d.ts +1 -1
- package/build/middlewares/guards/services/FastUserContextService.d.ts +11 -32
- package/build/middlewares/index.d.ts +1 -0
- package/build/middlewares/index.js +1 -0
- package/build/middlewares/openTelemetryMiddleware.d.ts +162 -0
- package/build/middlewares/openTelemetryMiddleware.js +359 -0
- package/build/middlewares/rateLimitingMiddleware.js +16 -5
- package/build/utils/container.utils.js +4 -1
- package/build/utils/fastify-wrapper.d.ts +74 -0
- package/build/utils/fastify-wrapper.js +175 -0
- package/build/utils/index.d.ts +4 -0
- package/build/utils/index.js +23 -1
- package/build/utils/otel.helper.d.ts +122 -0
- package/build/utils/otel.helper.js +258 -0
- package/build/utils/pubsub-trace.utils.d.ts +102 -0
- package/build/utils/pubsub-trace.utils.js +155 -0
- package/build/utils/wrapper-utils.d.ts +177 -0
- package/build/utils/wrapper-utils.js +236 -0
- package/package.json +61 -2
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import type { HttpFunction } from '@google-cloud/functions-framework';
|
|
2
|
+
import type { Request, Response } from 'express';
|
|
3
|
+
import { Handler } from '../core/handler';
|
|
4
|
+
/**
|
|
5
|
+
* Create an HttpFunction wrapper for a Noony handler
|
|
6
|
+
*
|
|
7
|
+
* Wraps a Noony handler into a Google Cloud Functions `HttpFunction` for production deployment.
|
|
8
|
+
* This pattern ensures proper initialization, error handling, and prevents double responses.
|
|
9
|
+
*
|
|
10
|
+
* @param noonyHandler - The Noony handler to wrap (contains middleware chain and controller)
|
|
11
|
+
* @param functionName - Name for error logging purposes
|
|
12
|
+
* @param initializeDependencies - Async function that initializes dependencies (database, services, etc.)
|
|
13
|
+
* Uses singleton pattern to prevent re-initialization on warm starts
|
|
14
|
+
* @returns HttpFunction compatible with `@google-cloud/functions-framework`
|
|
15
|
+
*
|
|
16
|
+
* @remarks
|
|
17
|
+
* This function ensures:
|
|
18
|
+
* - Dependencies are initialized before handler execution (optimized for cold/warm starts)
|
|
19
|
+
* - Errors are caught and returned as proper HTTP responses
|
|
20
|
+
* - Response is not sent twice (`headersSent` check)
|
|
21
|
+
* - `RESPONSE_SENT` errors are ignored (response already sent by middleware)
|
|
22
|
+
* - Real errors return 500 with generic message for security
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* Creating and registering Cloud Functions:
|
|
26
|
+
* ```typescript
|
|
27
|
+
* import { http } from '@google-cloud/functions-framework';
|
|
28
|
+
* import { createHttpFunction } from '@noony-serverless/core';
|
|
29
|
+
* import { loginHandler } from './handlers/auth.handlers';
|
|
30
|
+
*
|
|
31
|
+
* // Initialize dependencies once per cold start
|
|
32
|
+
* let initialized = false;
|
|
33
|
+
* async function initializeDependencies(): Promise<void> {
|
|
34
|
+
* if (initialized) return;
|
|
35
|
+
* const db = await databaseService.connect();
|
|
36
|
+
* await initializeServices(db);
|
|
37
|
+
* initialized = true;
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* // Create and register function
|
|
41
|
+
* const loginFunction = createHttpFunction(
|
|
42
|
+
* loginHandler,
|
|
43
|
+
* 'login',
|
|
44
|
+
* initializeDependencies
|
|
45
|
+
* );
|
|
46
|
+
* http('login', loginFunction);
|
|
47
|
+
* export const login = loginFunction;
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* Execution flow:
|
|
52
|
+
* ```
|
|
53
|
+
* HTTP Request → createHttpFunction wrapper
|
|
54
|
+
* │
|
|
55
|
+
* ▼
|
|
56
|
+
* initializeDependencies() (only on cold start)
|
|
57
|
+
* │
|
|
58
|
+
* ▼
|
|
59
|
+
* noonyHandler.execute(req, res)
|
|
60
|
+
* │
|
|
61
|
+
* ├─── errorHandler()
|
|
62
|
+
* ├─── authMiddleware()
|
|
63
|
+
* ├─── requirePermission()
|
|
64
|
+
* ├─── bodyValidator()
|
|
65
|
+
* ├─── ResponseWrapperMiddleware
|
|
66
|
+
* └─── Controller function
|
|
67
|
+
* │
|
|
68
|
+
* ▼
|
|
69
|
+
* HTTP Response
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* @see {@link wrapNoonyHandler} for Express integration (local development)
|
|
73
|
+
*/
|
|
74
|
+
export declare function createHttpFunction(noonyHandler: Handler<unknown>, functionName: string, initializeDependencies: () => Promise<void>): HttpFunction;
|
|
75
|
+
/**
|
|
76
|
+
* Wrap a Noony handler for use with Express routing
|
|
77
|
+
*
|
|
78
|
+
* Wraps a Noony handler into an Express route handler for local development environments.
|
|
79
|
+
* This pattern enables running all endpoints through a single Express app with standard
|
|
80
|
+
* Express routing, middleware, and error handling.
|
|
81
|
+
*
|
|
82
|
+
* @param noonyHandler - The Noony handler to wrap (contains middleware chain and controller)
|
|
83
|
+
* @param functionName - Name for error logging purposes
|
|
84
|
+
* @param initializeDependencies - Async function that initializes dependencies (database, services, etc.)
|
|
85
|
+
* Uses singleton pattern to prevent re-initialization across requests
|
|
86
|
+
* @returns Express route handler compatible with Express Router: `(req: Request, res: Response) => Promise<void>`
|
|
87
|
+
*
|
|
88
|
+
* @remarks
|
|
89
|
+
* This wrapper ensures:
|
|
90
|
+
* - Dependencies are initialized before handler execution (singleton pattern for efficiency)
|
|
91
|
+
* - Noony handlers work seamlessly with Express routing and middleware
|
|
92
|
+
* - Errors are caught and returned as proper HTTP responses
|
|
93
|
+
* - Response is not sent twice (`headersSent` check)
|
|
94
|
+
* - `RESPONSE_SENT` errors are ignored (response already sent by middleware)
|
|
95
|
+
* - Real errors return 500 with generic message for security
|
|
96
|
+
*
|
|
97
|
+
* **Differences from createHttpFunction:**
|
|
98
|
+
*
|
|
99
|
+
* | Aspect | createHttpFunction | wrapNoonyHandler |
|
|
100
|
+
* |--------|-------------------|------------------|
|
|
101
|
+
* | **Use case** | Production deployment | Local development |
|
|
102
|
+
* | **Framework** | Cloud Functions Framework | Express |
|
|
103
|
+
* | **Return type** | `HttpFunction` | Express handler |
|
|
104
|
+
* | **Registration** | `http('name', fn)` | `app.get('/path', fn)` |
|
|
105
|
+
* | **Deployment** | Individual functions | Single Express app |
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* Creating Express app with multiple routes:
|
|
109
|
+
* ```typescript
|
|
110
|
+
* import express, { Express } from 'express';
|
|
111
|
+
* import { wrapNoonyHandler } from '@noony-serverless/core';
|
|
112
|
+
* import { loginHandler, logoutHandler, getConfigHandler } from './handlers';
|
|
113
|
+
*
|
|
114
|
+
* // Initialize dependencies once per app startup
|
|
115
|
+
* let initialized = false;
|
|
116
|
+
* async function initializeDependencies(): Promise<void> {
|
|
117
|
+
* if (initialized) return;
|
|
118
|
+
* const db = await databaseService.connect();
|
|
119
|
+
* await initializeServices(db);
|
|
120
|
+
* initialized = true;
|
|
121
|
+
* }
|
|
122
|
+
*
|
|
123
|
+
* function createExpressApp(): Express {
|
|
124
|
+
* const app = express();
|
|
125
|
+
*
|
|
126
|
+
* // Global Express middleware
|
|
127
|
+
* app.use(cors());
|
|
128
|
+
* app.use(express.json());
|
|
129
|
+
*
|
|
130
|
+
* // Health check (no DB required)
|
|
131
|
+
* app.get('/health', (_req, res) => {
|
|
132
|
+
* res.json({ success: true, data: { status: 'healthy' } });
|
|
133
|
+
* });
|
|
134
|
+
*
|
|
135
|
+
* // Auth routes
|
|
136
|
+
* app.post('/api/auth/login', wrapNoonyHandler(loginHandler, 'login', initializeDependencies));
|
|
137
|
+
* app.post('/api/auth/logout', wrapNoonyHandler(logoutHandler, 'logout', initializeDependencies));
|
|
138
|
+
*
|
|
139
|
+
* // Config routes
|
|
140
|
+
* app.get('/api/config', wrapNoonyHandler(getConfigHandler, 'getConfig', initializeDependencies));
|
|
141
|
+
*
|
|
142
|
+
* // 404 handler
|
|
143
|
+
* app.use((_req, res) => {
|
|
144
|
+
* res.status(404).json({
|
|
145
|
+
* success: false,
|
|
146
|
+
* error: { code: 'NOT_FOUND', message: 'Endpoint not found' }
|
|
147
|
+
* });
|
|
148
|
+
* });
|
|
149
|
+
*
|
|
150
|
+
* return app;
|
|
151
|
+
* }
|
|
152
|
+
*
|
|
153
|
+
* // Start server
|
|
154
|
+
* const app = createExpressApp();
|
|
155
|
+
* const PORT = process.env.PORT || 3000;
|
|
156
|
+
* app.listen(PORT, () => {
|
|
157
|
+
* console.log(`Server running on port ${PORT}`);
|
|
158
|
+
* });
|
|
159
|
+
* ```
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* Express routing with path parameters:
|
|
163
|
+
* ```typescript
|
|
164
|
+
* const app = express();
|
|
165
|
+
*
|
|
166
|
+
* // Routes with path parameters work seamlessly
|
|
167
|
+
* app.get('/api/users/:userId', wrapNoonyHandler(getUserHandler, 'getUser', initializeDependencies));
|
|
168
|
+
* app.patch('/api/config/sections/:sectionId', wrapNoonyHandler(updateSectionHandler, 'updateSection', initializeDependencies));
|
|
169
|
+
* app.delete('/api/config/sections/:sectionId', wrapNoonyHandler(deleteSectionHandler, 'deleteSection', initializeDependencies));
|
|
170
|
+
*
|
|
171
|
+
* // Path parameters available in Noony handler via context.req.params
|
|
172
|
+
* ```
|
|
173
|
+
*
|
|
174
|
+
* @see {@link createHttpFunction} for Cloud Functions Framework integration (production deployment)
|
|
175
|
+
*/
|
|
176
|
+
export declare function wrapNoonyHandler(noonyHandler: Handler<unknown>, functionName: string, initializeDependencies: () => Promise<void>): (req: Request, res: Response) => Promise<void>;
|
|
177
|
+
//# sourceMappingURL=wrapper-utils.d.ts.map
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createHttpFunction = createHttpFunction;
|
|
4
|
+
exports.wrapNoonyHandler = wrapNoonyHandler;
|
|
5
|
+
const logger_1 = require("../core/logger");
|
|
6
|
+
/**
|
|
7
|
+
* Create an HttpFunction wrapper for a Noony handler
|
|
8
|
+
*
|
|
9
|
+
* Wraps a Noony handler into a Google Cloud Functions `HttpFunction` for production deployment.
|
|
10
|
+
* This pattern ensures proper initialization, error handling, and prevents double responses.
|
|
11
|
+
*
|
|
12
|
+
* @param noonyHandler - The Noony handler to wrap (contains middleware chain and controller)
|
|
13
|
+
* @param functionName - Name for error logging purposes
|
|
14
|
+
* @param initializeDependencies - Async function that initializes dependencies (database, services, etc.)
|
|
15
|
+
* Uses singleton pattern to prevent re-initialization on warm starts
|
|
16
|
+
* @returns HttpFunction compatible with `@google-cloud/functions-framework`
|
|
17
|
+
*
|
|
18
|
+
* @remarks
|
|
19
|
+
* This function ensures:
|
|
20
|
+
* - Dependencies are initialized before handler execution (optimized for cold/warm starts)
|
|
21
|
+
* - Errors are caught and returned as proper HTTP responses
|
|
22
|
+
* - Response is not sent twice (`headersSent` check)
|
|
23
|
+
* - `RESPONSE_SENT` errors are ignored (response already sent by middleware)
|
|
24
|
+
* - Real errors return 500 with generic message for security
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* Creating and registering Cloud Functions:
|
|
28
|
+
* ```typescript
|
|
29
|
+
* import { http } from '@google-cloud/functions-framework';
|
|
30
|
+
* import { createHttpFunction } from '@noony-serverless/core';
|
|
31
|
+
* import { loginHandler } from './handlers/auth.handlers';
|
|
32
|
+
*
|
|
33
|
+
* // Initialize dependencies once per cold start
|
|
34
|
+
* let initialized = false;
|
|
35
|
+
* async function initializeDependencies(): Promise<void> {
|
|
36
|
+
* if (initialized) return;
|
|
37
|
+
* const db = await databaseService.connect();
|
|
38
|
+
* await initializeServices(db);
|
|
39
|
+
* initialized = true;
|
|
40
|
+
* }
|
|
41
|
+
*
|
|
42
|
+
* // Create and register function
|
|
43
|
+
* const loginFunction = createHttpFunction(
|
|
44
|
+
* loginHandler,
|
|
45
|
+
* 'login',
|
|
46
|
+
* initializeDependencies
|
|
47
|
+
* );
|
|
48
|
+
* http('login', loginFunction);
|
|
49
|
+
* export const login = loginFunction;
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* Execution flow:
|
|
54
|
+
* ```
|
|
55
|
+
* HTTP Request → createHttpFunction wrapper
|
|
56
|
+
* │
|
|
57
|
+
* ▼
|
|
58
|
+
* initializeDependencies() (only on cold start)
|
|
59
|
+
* │
|
|
60
|
+
* ▼
|
|
61
|
+
* noonyHandler.execute(req, res)
|
|
62
|
+
* │
|
|
63
|
+
* ├─── errorHandler()
|
|
64
|
+
* ├─── authMiddleware()
|
|
65
|
+
* ├─── requirePermission()
|
|
66
|
+
* ├─── bodyValidator()
|
|
67
|
+
* ├─── ResponseWrapperMiddleware
|
|
68
|
+
* └─── Controller function
|
|
69
|
+
* │
|
|
70
|
+
* ▼
|
|
71
|
+
* HTTP Response
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* @see {@link wrapNoonyHandler} for Express integration (local development)
|
|
75
|
+
*/
|
|
76
|
+
function createHttpFunction(noonyHandler, functionName, initializeDependencies) {
|
|
77
|
+
return async (req, res) => {
|
|
78
|
+
try {
|
|
79
|
+
// Ensure dependencies are initialized
|
|
80
|
+
await initializeDependencies();
|
|
81
|
+
// Execute Noony handler (runs middleware chain + controller)
|
|
82
|
+
// Cast is safe because Handler.execute internally adapts GCP Request/Response
|
|
83
|
+
await noonyHandler.execute(req, res);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
// Only handle errors if they're real errors (not RESPONSE_SENT markers)
|
|
87
|
+
if (error instanceof Error && error.message === 'RESPONSE_SENT') {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
logger_1.logger.error(`${functionName} function error`, {
|
|
91
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
92
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
93
|
+
});
|
|
94
|
+
// Graceful error handling - only send if headers not already sent
|
|
95
|
+
if (!res.headersSent) {
|
|
96
|
+
res.status(500).json({
|
|
97
|
+
success: false,
|
|
98
|
+
error: {
|
|
99
|
+
code: 'INTERNAL_SERVER_ERROR',
|
|
100
|
+
message: 'An unexpected error occurred',
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Wrap a Noony handler for use with Express routing
|
|
109
|
+
*
|
|
110
|
+
* Wraps a Noony handler into an Express route handler for local development environments.
|
|
111
|
+
* This pattern enables running all endpoints through a single Express app with standard
|
|
112
|
+
* Express routing, middleware, and error handling.
|
|
113
|
+
*
|
|
114
|
+
* @param noonyHandler - The Noony handler to wrap (contains middleware chain and controller)
|
|
115
|
+
* @param functionName - Name for error logging purposes
|
|
116
|
+
* @param initializeDependencies - Async function that initializes dependencies (database, services, etc.)
|
|
117
|
+
* Uses singleton pattern to prevent re-initialization across requests
|
|
118
|
+
* @returns Express route handler compatible with Express Router: `(req: Request, res: Response) => Promise<void>`
|
|
119
|
+
*
|
|
120
|
+
* @remarks
|
|
121
|
+
* This wrapper ensures:
|
|
122
|
+
* - Dependencies are initialized before handler execution (singleton pattern for efficiency)
|
|
123
|
+
* - Noony handlers work seamlessly with Express routing and middleware
|
|
124
|
+
* - Errors are caught and returned as proper HTTP responses
|
|
125
|
+
* - Response is not sent twice (`headersSent` check)
|
|
126
|
+
* - `RESPONSE_SENT` errors are ignored (response already sent by middleware)
|
|
127
|
+
* - Real errors return 500 with generic message for security
|
|
128
|
+
*
|
|
129
|
+
* **Differences from createHttpFunction:**
|
|
130
|
+
*
|
|
131
|
+
* | Aspect | createHttpFunction | wrapNoonyHandler |
|
|
132
|
+
* |--------|-------------------|------------------|
|
|
133
|
+
* | **Use case** | Production deployment | Local development |
|
|
134
|
+
* | **Framework** | Cloud Functions Framework | Express |
|
|
135
|
+
* | **Return type** | `HttpFunction` | Express handler |
|
|
136
|
+
* | **Registration** | `http('name', fn)` | `app.get('/path', fn)` |
|
|
137
|
+
* | **Deployment** | Individual functions | Single Express app |
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* Creating Express app with multiple routes:
|
|
141
|
+
* ```typescript
|
|
142
|
+
* import express, { Express } from 'express';
|
|
143
|
+
* import { wrapNoonyHandler } from '@noony-serverless/core';
|
|
144
|
+
* import { loginHandler, logoutHandler, getConfigHandler } from './handlers';
|
|
145
|
+
*
|
|
146
|
+
* // Initialize dependencies once per app startup
|
|
147
|
+
* let initialized = false;
|
|
148
|
+
* async function initializeDependencies(): Promise<void> {
|
|
149
|
+
* if (initialized) return;
|
|
150
|
+
* const db = await databaseService.connect();
|
|
151
|
+
* await initializeServices(db);
|
|
152
|
+
* initialized = true;
|
|
153
|
+
* }
|
|
154
|
+
*
|
|
155
|
+
* function createExpressApp(): Express {
|
|
156
|
+
* const app = express();
|
|
157
|
+
*
|
|
158
|
+
* // Global Express middleware
|
|
159
|
+
* app.use(cors());
|
|
160
|
+
* app.use(express.json());
|
|
161
|
+
*
|
|
162
|
+
* // Health check (no DB required)
|
|
163
|
+
* app.get('/health', (_req, res) => {
|
|
164
|
+
* res.json({ success: true, data: { status: 'healthy' } });
|
|
165
|
+
* });
|
|
166
|
+
*
|
|
167
|
+
* // Auth routes
|
|
168
|
+
* app.post('/api/auth/login', wrapNoonyHandler(loginHandler, 'login', initializeDependencies));
|
|
169
|
+
* app.post('/api/auth/logout', wrapNoonyHandler(logoutHandler, 'logout', initializeDependencies));
|
|
170
|
+
*
|
|
171
|
+
* // Config routes
|
|
172
|
+
* app.get('/api/config', wrapNoonyHandler(getConfigHandler, 'getConfig', initializeDependencies));
|
|
173
|
+
*
|
|
174
|
+
* // 404 handler
|
|
175
|
+
* app.use((_req, res) => {
|
|
176
|
+
* res.status(404).json({
|
|
177
|
+
* success: false,
|
|
178
|
+
* error: { code: 'NOT_FOUND', message: 'Endpoint not found' }
|
|
179
|
+
* });
|
|
180
|
+
* });
|
|
181
|
+
*
|
|
182
|
+
* return app;
|
|
183
|
+
* }
|
|
184
|
+
*
|
|
185
|
+
* // Start server
|
|
186
|
+
* const app = createExpressApp();
|
|
187
|
+
* const PORT = process.env.PORT || 3000;
|
|
188
|
+
* app.listen(PORT, () => {
|
|
189
|
+
* console.log(`Server running on port ${PORT}`);
|
|
190
|
+
* });
|
|
191
|
+
* ```
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* Express routing with path parameters:
|
|
195
|
+
* ```typescript
|
|
196
|
+
* const app = express();
|
|
197
|
+
*
|
|
198
|
+
* // Routes with path parameters work seamlessly
|
|
199
|
+
* app.get('/api/users/:userId', wrapNoonyHandler(getUserHandler, 'getUser', initializeDependencies));
|
|
200
|
+
* app.patch('/api/config/sections/:sectionId', wrapNoonyHandler(updateSectionHandler, 'updateSection', initializeDependencies));
|
|
201
|
+
* app.delete('/api/config/sections/:sectionId', wrapNoonyHandler(deleteSectionHandler, 'deleteSection', initializeDependencies));
|
|
202
|
+
*
|
|
203
|
+
* // Path parameters available in Noony handler via context.req.params
|
|
204
|
+
* ```
|
|
205
|
+
*
|
|
206
|
+
* @see {@link createHttpFunction} for Cloud Functions Framework integration (production deployment)
|
|
207
|
+
*/
|
|
208
|
+
function wrapNoonyHandler(noonyHandler, functionName, initializeDependencies) {
|
|
209
|
+
return async (req, res) => {
|
|
210
|
+
try {
|
|
211
|
+
// Ensure dependencies are initialized
|
|
212
|
+
await initializeDependencies();
|
|
213
|
+
// Execute Noony handler with Express req/res (cast to generic types)
|
|
214
|
+
await noonyHandler.executeGeneric(req, res);
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
if (error instanceof Error && error.message === 'RESPONSE_SENT') {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
logger_1.logger.error(`${functionName} handler error`, {
|
|
221
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
222
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
223
|
+
});
|
|
224
|
+
if (!res.headersSent) {
|
|
225
|
+
res.status(500).json({
|
|
226
|
+
success: false,
|
|
227
|
+
error: {
|
|
228
|
+
code: 'INTERNAL_SERVER_ERROR',
|
|
229
|
+
message: 'An unexpected error occurred',
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=wrapper-utils.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noony-serverless/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "A Middy base framework compatible with Firebase and GCP Cloud Functions with TypeScript",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -71,5 +71,64 @@
|
|
|
71
71
|
"ts-jest": "^29.1.1",
|
|
72
72
|
"typescript": "^5.3.3"
|
|
73
73
|
},
|
|
74
|
-
"
|
|
74
|
+
"peerDependencies": {
|
|
75
|
+
"@fastify/otel": "^1.0.0",
|
|
76
|
+
"@google-cloud/opentelemetry-cloud-trace-propagator": "^0.21.0",
|
|
77
|
+
"@opentelemetry/api": "^1.9.0",
|
|
78
|
+
"@opentelemetry/auto-instrumentations-node": "^0.200.0",
|
|
79
|
+
"@opentelemetry/core": "^1.28.0",
|
|
80
|
+
"@opentelemetry/exporter-metrics-otlp-http": "^0.205.0",
|
|
81
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.205.0",
|
|
82
|
+
"@opentelemetry/instrumentation-http": "^0.200.0",
|
|
83
|
+
"@opentelemetry/resources": "^2.0.0",
|
|
84
|
+
"@opentelemetry/sdk-node": "^2.0.0",
|
|
85
|
+
"@opentelemetry/semantic-conventions": "^1.28.0",
|
|
86
|
+
"dd-trace": "^5.0.0",
|
|
87
|
+
"newrelic": "^12.0.0"
|
|
88
|
+
},
|
|
89
|
+
"peerDependenciesMeta": {
|
|
90
|
+
"@google-cloud/opentelemetry-cloud-trace-propagator": {
|
|
91
|
+
"optional": true
|
|
92
|
+
},
|
|
93
|
+
"@opentelemetry/api": {
|
|
94
|
+
"optional": true
|
|
95
|
+
},
|
|
96
|
+
"@opentelemetry/core": {
|
|
97
|
+
"optional": true
|
|
98
|
+
},
|
|
99
|
+
"@opentelemetry/sdk-node": {
|
|
100
|
+
"optional": true
|
|
101
|
+
},
|
|
102
|
+
"@opentelemetry/resources": {
|
|
103
|
+
"optional": true
|
|
104
|
+
},
|
|
105
|
+
"@opentelemetry/semantic-conventions": {
|
|
106
|
+
"optional": true
|
|
107
|
+
},
|
|
108
|
+
"@opentelemetry/instrumentation-http": {
|
|
109
|
+
"optional": true
|
|
110
|
+
},
|
|
111
|
+
"@opentelemetry/exporter-trace-otlp-http": {
|
|
112
|
+
"optional": true
|
|
113
|
+
},
|
|
114
|
+
"@opentelemetry/exporter-metrics-otlp-http": {
|
|
115
|
+
"optional": true
|
|
116
|
+
},
|
|
117
|
+
"@opentelemetry/auto-instrumentations-node": {
|
|
118
|
+
"optional": true
|
|
119
|
+
},
|
|
120
|
+
"@fastify/otel": {
|
|
121
|
+
"optional": true
|
|
122
|
+
},
|
|
123
|
+
"newrelic": {
|
|
124
|
+
"optional": true
|
|
125
|
+
},
|
|
126
|
+
"dd-trace": {
|
|
127
|
+
"optional": true
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"private": false,
|
|
131
|
+
"optionalDependencies": {
|
|
132
|
+
"@google-cloud/opentelemetry-cloud-trace-propagator": "^0.21.0"
|
|
133
|
+
}
|
|
75
134
|
}
|