@noony-serverless/core 0.3.4 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +199 -0
- 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/bodyValidationMiddleware.js +1 -1
- 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,342 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpenTelemetryProvider = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Standard OpenTelemetry SDK 2.0 Provider
|
|
6
|
+
*
|
|
7
|
+
* Implements telemetry using the official OpenTelemetry JavaScript SDK.
|
|
8
|
+
* Supports OTLP exporters for traces, metrics, and logs.
|
|
9
|
+
*
|
|
10
|
+
* Requirements:
|
|
11
|
+
* - Node.js >= 18.19.0 or >= 20.6.0
|
|
12
|
+
* - OTEL_EXPORTER_OTLP_ENDPOINT environment variable
|
|
13
|
+
* - @opentelemetry/sdk-node and related packages installed
|
|
14
|
+
*
|
|
15
|
+
* Auto-selected when OTEL_EXPORTER_OTLP_ENDPOINT is set.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // Environment setup
|
|
19
|
+
* OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318/v1/traces
|
|
20
|
+
*
|
|
21
|
+
* // Usage
|
|
22
|
+
* const provider = new OpenTelemetryProvider();
|
|
23
|
+
* const validation = await provider.validate();
|
|
24
|
+
* if (validation.valid) {
|
|
25
|
+
* await provider.initialize({
|
|
26
|
+
* serviceName: 'my-service',
|
|
27
|
+
* serviceVersion: '1.0.0'
|
|
28
|
+
* });
|
|
29
|
+
* }
|
|
30
|
+
*/
|
|
31
|
+
class OpenTelemetryProvider {
|
|
32
|
+
name = 'opentelemetry';
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
|
+
sdk; // NodeSDK
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
|
+
tracer; // Tracer
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
38
|
+
meter; // Meter
|
|
39
|
+
ready = false;
|
|
40
|
+
/**
|
|
41
|
+
* Validate OpenTelemetry configuration
|
|
42
|
+
*
|
|
43
|
+
* Checks:
|
|
44
|
+
* 1. OTEL_EXPORTER_OTLP_ENDPOINT is set
|
|
45
|
+
* 2. Endpoint is a valid URL
|
|
46
|
+
* 3. Required packages are available (checked lazily during init)
|
|
47
|
+
*/
|
|
48
|
+
async validate() {
|
|
49
|
+
const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
50
|
+
if (!endpoint) {
|
|
51
|
+
return {
|
|
52
|
+
valid: false,
|
|
53
|
+
reason: 'OTEL_EXPORTER_OTLP_ENDPOINT environment variable not set',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
new URL(endpoint);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return {
|
|
61
|
+
valid: false,
|
|
62
|
+
reason: `OTEL_EXPORTER_OTLP_ENDPOINT is not a valid URL: ${endpoint}`,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return { valid: true };
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Initialize OpenTelemetry SDK
|
|
69
|
+
*
|
|
70
|
+
* Sets up:
|
|
71
|
+
* - Resource attributes (service name, version, environment)
|
|
72
|
+
* - OTLP trace exporter
|
|
73
|
+
* - Composite propagator (W3C + Cloud Trace)
|
|
74
|
+
* - Tracer and Meter providers
|
|
75
|
+
*/
|
|
76
|
+
async initialize(config) {
|
|
77
|
+
try {
|
|
78
|
+
// Dynamic require to avoid compile-time dependency on OTEL packages
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
80
|
+
const otelApi = require('@opentelemetry/api');
|
|
81
|
+
const { trace, metrics } = otelApi;
|
|
82
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
83
|
+
const sdkNode = require('@opentelemetry/sdk-node');
|
|
84
|
+
const { NodeSDK } = sdkNode;
|
|
85
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
86
|
+
const exporterHttp = require('@opentelemetry/exporter-trace-otlp-http');
|
|
87
|
+
const { OTLPTraceExporter } = exporterHttp;
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
89
|
+
const resources = require('@opentelemetry/resources');
|
|
90
|
+
const { Resource } = resources;
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
92
|
+
const semConv = require('@opentelemetry/semantic-conventions');
|
|
93
|
+
const { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } = semConv;
|
|
94
|
+
// Create resource with service metadata
|
|
95
|
+
const resource = new Resource({
|
|
96
|
+
[ATTR_SERVICE_NAME]: config.serviceName,
|
|
97
|
+
[ATTR_SERVICE_VERSION]: config.serviceVersion || '1.0.0',
|
|
98
|
+
environment: config.environment || 'production',
|
|
99
|
+
});
|
|
100
|
+
// Configure trace exporter
|
|
101
|
+
const traceExporter = new OTLPTraceExporter({
|
|
102
|
+
url: config.exporters?.traces?.[0]?.endpoint ||
|
|
103
|
+
process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
104
|
+
headers: config.exporters?.traces?.[0]?.headers,
|
|
105
|
+
timeoutMillis: config.exporters?.traces?.[0]?.timeout,
|
|
106
|
+
});
|
|
107
|
+
// Configure composite propagator for W3C + Cloud Trace support
|
|
108
|
+
const textMapPropagator = this.createPropagator(config);
|
|
109
|
+
// Initialize SDK
|
|
110
|
+
this.sdk = new NodeSDK({
|
|
111
|
+
resource,
|
|
112
|
+
traceExporter,
|
|
113
|
+
textMapPropagator, // Use composite propagator
|
|
114
|
+
});
|
|
115
|
+
await this.sdk.start();
|
|
116
|
+
// Get tracer and meter
|
|
117
|
+
this.tracer = trace.getTracer(config.serviceName, config.serviceVersion || '1.0.0');
|
|
118
|
+
this.meter = metrics.getMeter(config.serviceName, config.serviceVersion || '1.0.0');
|
|
119
|
+
this.ready = true;
|
|
120
|
+
console.log('[Telemetry] OpenTelemetry provider initialized');
|
|
121
|
+
console.log('[Telemetry] Exporting to:', config.exporters?.traces?.[0]?.endpoint ||
|
|
122
|
+
process.env.OTEL_EXPORTER_OTLP_ENDPOINT);
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
console.error('[Telemetry] Failed to initialize OpenTelemetry provider:', error);
|
|
126
|
+
this.ready = false;
|
|
127
|
+
// Check if error is due to missing packages
|
|
128
|
+
if (error instanceof Error &&
|
|
129
|
+
error.message.includes('Cannot find module')) {
|
|
130
|
+
console.error('[Telemetry] OpenTelemetry packages not installed. Run:');
|
|
131
|
+
console.error(' npm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/exporter-trace-otlp-http @opentelemetry/resources @opentelemetry/semantic-conventions');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Create an OpenTelemetry span
|
|
137
|
+
*
|
|
138
|
+
* Creates a SERVER span with HTTP semantic conventions.
|
|
139
|
+
* Returns undefined if provider is not ready.
|
|
140
|
+
*/
|
|
141
|
+
createSpan(context) {
|
|
142
|
+
if (!this.ready || !this.tracer)
|
|
143
|
+
return undefined;
|
|
144
|
+
try {
|
|
145
|
+
// Dynamic import for SpanKind
|
|
146
|
+
const SpanKind = 1; // SERVER = 1 in OpenTelemetry
|
|
147
|
+
const span = this.tracer.startSpan('http.request', {
|
|
148
|
+
kind: SpanKind,
|
|
149
|
+
attributes: {
|
|
150
|
+
'http.method': context.req.method,
|
|
151
|
+
'http.url': context.req.url || context.req.path,
|
|
152
|
+
'http.target': context.req.path || '/',
|
|
153
|
+
'request.id': context.requestId,
|
|
154
|
+
'http.user_agent': context.req.headers?.['user-agent'] || '',
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
return {
|
|
158
|
+
setAttributes: (attrs) => {
|
|
159
|
+
span.setAttributes(attrs);
|
|
160
|
+
},
|
|
161
|
+
recordException: (error) => {
|
|
162
|
+
span.recordException(error);
|
|
163
|
+
},
|
|
164
|
+
setStatus: (status) => {
|
|
165
|
+
span.setStatus(status);
|
|
166
|
+
},
|
|
167
|
+
end: () => {
|
|
168
|
+
span.end();
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
console.error('[Telemetry] Failed to create span:', error);
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Record a metric as a histogram
|
|
179
|
+
*/
|
|
180
|
+
recordMetric(name, value, attributes) {
|
|
181
|
+
if (!this.ready || !this.meter)
|
|
182
|
+
return;
|
|
183
|
+
try {
|
|
184
|
+
const histogram = this.meter.createHistogram(name, {
|
|
185
|
+
description: `Histogram for ${name}`,
|
|
186
|
+
unit: 'ms',
|
|
187
|
+
});
|
|
188
|
+
histogram.record(value, attributes);
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
console.error('[Telemetry] Failed to record metric:', error);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Log with trace correlation
|
|
196
|
+
*
|
|
197
|
+
* Adds trace and span IDs to log output when available.
|
|
198
|
+
*/
|
|
199
|
+
log(level, message, attributes) {
|
|
200
|
+
if (!this.ready)
|
|
201
|
+
return;
|
|
202
|
+
try {
|
|
203
|
+
// Try to get active span for correlation
|
|
204
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
205
|
+
const { trace } = require('@opentelemetry/api');
|
|
206
|
+
const span = trace.getActiveSpan();
|
|
207
|
+
const traceContext = span
|
|
208
|
+
? {
|
|
209
|
+
traceId: span.spanContext().traceId,
|
|
210
|
+
spanId: span.spanContext().spanId,
|
|
211
|
+
traceFlags: span.spanContext().traceFlags,
|
|
212
|
+
}
|
|
213
|
+
: {};
|
|
214
|
+
console.log(JSON.stringify({
|
|
215
|
+
level,
|
|
216
|
+
message,
|
|
217
|
+
...traceContext,
|
|
218
|
+
...attributes,
|
|
219
|
+
timestamp: new Date().toISOString(),
|
|
220
|
+
}));
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
// Fallback to simple logging
|
|
224
|
+
console.log(JSON.stringify({ level, message, ...attributes }));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Check if OpenTelemetry provider is ready
|
|
229
|
+
*/
|
|
230
|
+
isReady() {
|
|
231
|
+
return this.ready;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Shutdown OpenTelemetry SDK
|
|
235
|
+
*
|
|
236
|
+
* Flushes pending telemetry data and closes exporters.
|
|
237
|
+
*/
|
|
238
|
+
async shutdown() {
|
|
239
|
+
if (this.ready && this.sdk) {
|
|
240
|
+
try {
|
|
241
|
+
await this.sdk.shutdown();
|
|
242
|
+
console.log('[Telemetry] OpenTelemetry provider shutdown complete');
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
console.error('[Telemetry] Error during shutdown:', error);
|
|
246
|
+
}
|
|
247
|
+
finally {
|
|
248
|
+
this.ready = false;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Create composite propagator based on configuration
|
|
254
|
+
*
|
|
255
|
+
* Supports:
|
|
256
|
+
* - W3C Trace Context (traceparent/tracestate)
|
|
257
|
+
* - Google Cloud Trace Context (X-Cloud-Trace-Context)
|
|
258
|
+
*
|
|
259
|
+
* When running on GCP, both formats are enabled by default for compatibility.
|
|
260
|
+
* This allows trace IDs to be synchronized between Cloud Run Load Balancer
|
|
261
|
+
* and your application.
|
|
262
|
+
*
|
|
263
|
+
* @param config Telemetry configuration
|
|
264
|
+
* @returns Configured propagator (W3C, Cloud Trace, or Composite)
|
|
265
|
+
*/
|
|
266
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
267
|
+
createPropagator(config) {
|
|
268
|
+
try {
|
|
269
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
270
|
+
const propagators = [];
|
|
271
|
+
// Determine which propagators to use
|
|
272
|
+
const useCloudTrace = config.propagation?.cloudTrace ?? this.isRunningOnGCP();
|
|
273
|
+
const useW3C = config.propagation?.w3c ?? true;
|
|
274
|
+
// Add Cloud Trace propagator (priority 1 - reads X-Cloud-Trace-Context from GCP)
|
|
275
|
+
if (useCloudTrace) {
|
|
276
|
+
try {
|
|
277
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
278
|
+
const cloudPropagator = require('@google-cloud/opentelemetry-cloud-trace-propagator');
|
|
279
|
+
const { CloudPropagator } = cloudPropagator;
|
|
280
|
+
propagators.push(new CloudPropagator());
|
|
281
|
+
console.log('[Telemetry] CloudPropagator enabled for GCP trace compatibility');
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
console.warn('[Telemetry] CloudPropagator requested but package not installed:', error instanceof Error ? error.message : error);
|
|
285
|
+
console.warn('[Telemetry] Install with: npm install @google-cloud/opentelemetry-cloud-trace-propagator');
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
// Add W3C Trace Context propagator (priority 2 - standard traceparent)
|
|
289
|
+
if (useW3C) {
|
|
290
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
291
|
+
const otelCore = require('@opentelemetry/core');
|
|
292
|
+
const { W3CTraceContextPropagator } = otelCore;
|
|
293
|
+
propagators.push(new W3CTraceContextPropagator());
|
|
294
|
+
console.log('[Telemetry] W3CTraceContextPropagator enabled');
|
|
295
|
+
}
|
|
296
|
+
// If multiple propagators, use CompositePropagator
|
|
297
|
+
if (propagators.length > 1) {
|
|
298
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
299
|
+
const otelCore = require('@opentelemetry/core');
|
|
300
|
+
const { CompositePropagator } = otelCore;
|
|
301
|
+
return new CompositePropagator({ propagators });
|
|
302
|
+
}
|
|
303
|
+
// If only one propagator, use it directly
|
|
304
|
+
if (propagators.length === 1) {
|
|
305
|
+
return propagators[0];
|
|
306
|
+
}
|
|
307
|
+
// Fallback to W3C if no propagators configured
|
|
308
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
309
|
+
const otelCore = require('@opentelemetry/core');
|
|
310
|
+
const { W3CTraceContextPropagator } = otelCore;
|
|
311
|
+
return new W3CTraceContextPropagator();
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
console.error('[Telemetry] Failed to create propagator:', error);
|
|
315
|
+
// Return W3C propagator as safe fallback
|
|
316
|
+
try {
|
|
317
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
318
|
+
const otelCore = require('@opentelemetry/core');
|
|
319
|
+
const { W3CTraceContextPropagator } = otelCore;
|
|
320
|
+
return new W3CTraceContextPropagator();
|
|
321
|
+
}
|
|
322
|
+
catch (fallbackError) {
|
|
323
|
+
console.error('[Telemetry] Failed to create fallback propagator:', fallbackError);
|
|
324
|
+
return undefined;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Detect if running on Google Cloud Platform
|
|
330
|
+
*/
|
|
331
|
+
isRunningOnGCP() {
|
|
332
|
+
return !!(process.env.GOOGLE_CLOUD_PROJECT ||
|
|
333
|
+
process.env.GCLOUD_PROJECT ||
|
|
334
|
+
process.env.GCP_PROJECT ||
|
|
335
|
+
process.env.K_SERVICE || // Cloud Run
|
|
336
|
+
process.env.FUNCTION_NAME || // Cloud Functions
|
|
337
|
+
process.env.GAE_APPLICATION // App Engine
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
exports.OpenTelemetryProvider = OpenTelemetryProvider;
|
|
342
|
+
//# sourceMappingURL=opentelemetry-provider.js.map
|
|
@@ -91,7 +91,7 @@ exports.BodyValidationMiddleware = BodyValidationMiddleware;
|
|
|
91
91
|
// Modified to fix type instantiation error
|
|
92
92
|
const bodyValidatorMiddleware = (schema) => ({
|
|
93
93
|
before: async (context) => {
|
|
94
|
-
context.req.parsedBody = await validateBody(schema, context.req.
|
|
94
|
+
context.req.parsedBody = await validateBody(schema, context.req.parsedBody);
|
|
95
95
|
},
|
|
96
96
|
});
|
|
97
97
|
exports.bodyValidatorMiddleware = bodyValidatorMiddleware;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseMiddleware, Context } from '../core';
|
|
2
|
+
import { ServiceDefinition } from '../core/containerPool';
|
|
2
3
|
/**
|
|
3
4
|
* Middleware to inject dependencies into the request context using typedi.
|
|
4
5
|
* This allows handlers to access shared services or data via context.container.
|
|
@@ -149,10 +150,14 @@ import { BaseMiddleware, Context } from '../core';
|
|
|
149
150
|
*/
|
|
150
151
|
export declare class DependencyInjectionMiddleware<TBody = unknown, TUser = unknown> implements BaseMiddleware<TBody, TUser> {
|
|
151
152
|
private services;
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
153
|
+
private options?;
|
|
154
|
+
constructor(services?: ServiceDefinition[], options?: {
|
|
155
|
+
/**
|
|
156
|
+
* Service scope: 'global' for process-lifetime, 'local' for request-lifetime
|
|
157
|
+
* @default 'local'
|
|
158
|
+
*/
|
|
159
|
+
scope?: "global" | "local";
|
|
160
|
+
} | undefined);
|
|
156
161
|
before(context: Context<TBody, TUser>): Promise<void>;
|
|
157
162
|
}
|
|
158
163
|
/**
|
|
@@ -249,8 +254,11 @@ export declare class DependencyInjectionMiddleware<TBody = unknown, TUser = unkn
|
|
|
249
254
|
* });
|
|
250
255
|
* ```
|
|
251
256
|
*/
|
|
252
|
-
export declare const dependencyInjection: <TBody = unknown, TUser = unknown>(services?: {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
257
|
+
export declare const dependencyInjection: <TBody = unknown, TUser = unknown>(services?: ServiceDefinition[], options?: {
|
|
258
|
+
/**
|
|
259
|
+
* Service scope: 'global' for process-lifetime, 'local' for request-lifetime
|
|
260
|
+
* @default 'local'
|
|
261
|
+
*/
|
|
262
|
+
scope?: "global" | "local";
|
|
263
|
+
}) => BaseMiddleware<TBody, TUser>;
|
|
256
264
|
//# sourceMappingURL=dependencyInjectionMiddleware.d.ts.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.dependencyInjection = exports.DependencyInjectionMiddleware = void 0;
|
|
5
|
-
const
|
|
5
|
+
const containerPool_1 = require("../core/containerPool");
|
|
6
6
|
/**
|
|
7
7
|
* Middleware to inject dependencies into the request context using typedi.
|
|
8
8
|
* This allows handlers to access shared services or data via context.container.
|
|
@@ -153,14 +153,25 @@ const typedi_1 = require("typedi");
|
|
|
153
153
|
*/
|
|
154
154
|
class DependencyInjectionMiddleware {
|
|
155
155
|
services;
|
|
156
|
-
|
|
156
|
+
options;
|
|
157
|
+
constructor(services = [], options) {
|
|
157
158
|
this.services = services;
|
|
159
|
+
this.options = options;
|
|
158
160
|
}
|
|
159
161
|
async before(context) {
|
|
160
|
-
this.
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
162
|
+
const scope = this.options?.scope || 'local';
|
|
163
|
+
if (scope === 'global') {
|
|
164
|
+
// Register services globally (process-lifetime)
|
|
165
|
+
// ⚠️ Use sparingly - only for truly shared services like DB connections
|
|
166
|
+
containerPool_1.containerPool.initializeGlobal(this.services);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
// Register services locally (request-lifetime)
|
|
170
|
+
// ✅ Recommended for most use cases - isolated per request
|
|
171
|
+
this.services.forEach((service) => {
|
|
172
|
+
context.container?.set(service.id, service.value);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
164
175
|
}
|
|
165
176
|
}
|
|
166
177
|
exports.DependencyInjectionMiddleware = DependencyInjectionMiddleware;
|
|
@@ -258,12 +269,21 @@ exports.DependencyInjectionMiddleware = DependencyInjectionMiddleware;
|
|
|
258
269
|
* });
|
|
259
270
|
* ```
|
|
260
271
|
*/
|
|
261
|
-
const dependencyInjection = (services = []) => ({
|
|
272
|
+
const dependencyInjection = (services = [], options) => ({
|
|
262
273
|
before: async (context) => {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
274
|
+
const scope = options?.scope || 'local';
|
|
275
|
+
if (scope === 'global') {
|
|
276
|
+
// Register services globally (process-lifetime)
|
|
277
|
+
// ⚠️ Use sparingly - only for truly shared services like DB connections
|
|
278
|
+
containerPool_1.containerPool.initializeGlobal(services);
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
// Register services locally (request-lifetime)
|
|
282
|
+
// ✅ Recommended for most use cases - isolated per request
|
|
283
|
+
services.forEach((service) => {
|
|
284
|
+
context.container?.set(service.id, service.value);
|
|
285
|
+
});
|
|
286
|
+
}
|
|
267
287
|
},
|
|
268
288
|
});
|
|
269
289
|
exports.dependencyInjection = dependencyInjection;
|
|
@@ -245,7 +245,7 @@ export declare class TokenVerificationAdapterFactory {
|
|
|
245
245
|
* @param expirationField - Optional field name for expiration (e.g., 'expiresAt', 'exp')
|
|
246
246
|
* @returns Configured adapter for API key tokens
|
|
247
247
|
*/
|
|
248
|
-
static forAPIKey<T extends
|
|
248
|
+
static forAPIKey<T extends object>(verificationPort: CustomTokenVerificationPort<T>, userIdField: keyof T, expirationField?: keyof T): CustomTokenVerificationPortAdapter<T>;
|
|
249
249
|
/**
|
|
250
250
|
* Create adapter for OAuth tokens with standard OAuth claims.
|
|
251
251
|
*
|
|
@@ -43,7 +43,7 @@ export interface AuthenticationResult {
|
|
|
43
43
|
success: boolean;
|
|
44
44
|
user?: UserContext;
|
|
45
45
|
token?: {
|
|
46
|
-
decoded:
|
|
46
|
+
decoded: unknown;
|
|
47
47
|
raw: string;
|
|
48
48
|
expiresAt: string;
|
|
49
49
|
issuer?: string;
|
|
@@ -63,7 +63,7 @@ export interface AuthGuardConfig {
|
|
|
63
63
|
allowedIssuers?: string[];
|
|
64
64
|
requireEmailVerification: boolean;
|
|
65
65
|
allowInactiveUsers: boolean;
|
|
66
|
-
customValidation?: (token:
|
|
66
|
+
customValidation?: (token: unknown, user: UserContext) => Promise<boolean>;
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
69
|
* Token validation service interface
|
|
@@ -74,17 +74,17 @@ export interface TokenValidator {
|
|
|
74
74
|
*/
|
|
75
75
|
validateToken(token: string): Promise<{
|
|
76
76
|
valid: boolean;
|
|
77
|
-
decoded?:
|
|
77
|
+
decoded?: unknown;
|
|
78
78
|
error?: string;
|
|
79
79
|
}>;
|
|
80
80
|
/**
|
|
81
81
|
* Extract user ID from decoded token
|
|
82
82
|
*/
|
|
83
|
-
extractUserId(decoded:
|
|
83
|
+
extractUserId(decoded: unknown): string;
|
|
84
84
|
/**
|
|
85
85
|
* Check if token is expired
|
|
86
86
|
*/
|
|
87
|
-
isTokenExpired(decoded:
|
|
87
|
+
isTokenExpired(decoded: unknown): boolean;
|
|
88
88
|
}
|
|
89
89
|
/**
|
|
90
90
|
* Fast Authentication Guard Implementation
|
|
@@ -215,14 +215,15 @@ let FastAuthGuard = class FastAuthGuard {
|
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
// Build successful authentication result
|
|
218
|
+
const decoded = tokenValidation.decoded;
|
|
218
219
|
const authResult = {
|
|
219
220
|
success: true,
|
|
220
221
|
user: userContext,
|
|
221
222
|
token: {
|
|
222
223
|
decoded: tokenValidation.decoded,
|
|
223
224
|
raw: token,
|
|
224
|
-
expiresAt: new Date(
|
|
225
|
-
issuer:
|
|
225
|
+
expiresAt: new Date(decoded.exp * 1000).toISOString(),
|
|
226
|
+
issuer: decoded.iss,
|
|
226
227
|
},
|
|
227
228
|
cached: false,
|
|
228
229
|
resolutionTimeUs: Number(process.hrtime.bigint() - startTime) / 1000,
|
|
@@ -162,16 +162,14 @@ export declare class PermissionGuardFactory {
|
|
|
162
162
|
getStats(): {
|
|
163
163
|
totalGuards: number;
|
|
164
164
|
guardsByType: Record<string, number>;
|
|
165
|
-
individualGuardStats:
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
165
|
+
individualGuardStats: ReturnType<BasePermissionGuard['getStats']>[];
|
|
166
|
+
aggregatedStats: {
|
|
167
|
+
totalChecks: number;
|
|
168
|
+
totalSuccesses: number;
|
|
169
|
+
totalFailures: number;
|
|
170
|
+
overallSuccessRate: number;
|
|
171
171
|
averageProcessingTimeUs: number;
|
|
172
|
-
|
|
173
|
-
}[];
|
|
174
|
-
aggregatedStats: any;
|
|
172
|
+
};
|
|
175
173
|
};
|
|
176
174
|
/**
|
|
177
175
|
* Clear guard cache
|
|
@@ -118,7 +118,7 @@ export declare class ExpressionPermissionResolver extends PermissionResolver<Per
|
|
|
118
118
|
/**
|
|
119
119
|
* Check if this resolver can handle the given requirement type
|
|
120
120
|
*/
|
|
121
|
-
canHandle(requirement:
|
|
121
|
+
canHandle(requirement: unknown): requirement is PermissionExpression;
|
|
122
122
|
/**
|
|
123
123
|
* Normalize expression for consistent cache keys
|
|
124
124
|
*
|
|
@@ -412,7 +412,7 @@ class ExpressionPermissionResolver extends PermissionResolver_1.PermissionResolv
|
|
|
412
412
|
* Check if this resolver can handle the given requirement type
|
|
413
413
|
*/
|
|
414
414
|
canHandle(requirement) {
|
|
415
|
-
return (requirement &&
|
|
415
|
+
return (!!requirement &&
|
|
416
416
|
typeof requirement === 'object' &&
|
|
417
417
|
PermissionResolver_1.PermissionUtils.isValidExpression(requirement));
|
|
418
418
|
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* different types of permission requirements. The generic type T represents
|
|
20
20
|
* the specific requirement format for each resolver.
|
|
21
21
|
*/
|
|
22
|
-
export declare abstract class PermissionResolver<T =
|
|
22
|
+
export declare abstract class PermissionResolver<T = unknown> {
|
|
23
23
|
/**
|
|
24
24
|
* Check if user permissions satisfy the requirement
|
|
25
25
|
*
|
|
@@ -96,6 +96,6 @@ export declare class PlainPermissionResolver extends PermissionResolver<string[]
|
|
|
96
96
|
* @param requirement - The requirement to check
|
|
97
97
|
* @returns true if this resolver can handle the requirement
|
|
98
98
|
*/
|
|
99
|
-
canHandle(requirement:
|
|
99
|
+
canHandle(requirement: unknown): requirement is string[];
|
|
100
100
|
}
|
|
101
101
|
//# sourceMappingURL=PlainPermissionResolver.d.ts.map
|
|
@@ -141,6 +141,6 @@ export declare class WildcardPermissionResolver extends PermissionResolver<strin
|
|
|
141
141
|
/**
|
|
142
142
|
* Check if this resolver can handle the given requirement type
|
|
143
143
|
*/
|
|
144
|
-
canHandle(requirement:
|
|
144
|
+
canHandle(requirement: unknown): requirement is string[];
|
|
145
145
|
}
|
|
146
146
|
//# sourceMappingURL=WildcardPermissionResolver.d.ts.map
|