@emmett-community/emmett-expressjs-with-openapi 0.2.0 → 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/README.md +223 -25
- package/dist/chunk-BY65ZALY.cjs +12 -0
- package/dist/chunk-BY65ZALY.cjs.map +1 -0
- package/dist/chunk-I46UH36B.js +12 -0
- package/dist/chunk-I46UH36B.js.map +1 -0
- package/dist/{handler-importer-OJGFQON5.js → handler-importer-6A237UML.js} +21 -2
- package/dist/handler-importer-6A237UML.js.map +1 -0
- package/dist/{handler-importer-4BVBIZX3.cjs → handler-importer-UFV7TKBN.cjs} +21 -2
- package/dist/handler-importer-UFV7TKBN.cjs.map +1 -0
- package/dist/index.cjs +129 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +119 -1
- package/dist/index.d.ts +119 -1
- package/dist/index.js +116 -21
- package/dist/index.js.map +1 -1
- package/dist/{openapi-parser-NFUD7ZGZ.cjs → openapi-parser-PW5USNZ4.cjs} +27 -8
- package/dist/openapi-parser-PW5USNZ4.cjs.map +1 -0
- package/dist/{openapi-parser-CCYU636U.js → openapi-parser-QYXNHNSZ.js} +27 -7
- package/dist/openapi-parser-QYXNHNSZ.js.map +1 -0
- package/package.json +9 -2
- package/dist/handler-importer-4BVBIZX3.cjs.map +0 -1
- package/dist/handler-importer-OJGFQON5.js.map +0 -1
- package/dist/openapi-parser-CCYU636U.js.map +0 -1
- package/dist/openapi-parser-NFUD7ZGZ.cjs.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -6,6 +6,54 @@ import { Brand, Event, TestEventStream, EventStore } from '@event-driven-io/emme
|
|
|
6
6
|
import supertest, { Test, Response as Response$1 } from 'supertest';
|
|
7
7
|
import TestAgent from 'supertest/lib/agent';
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Observability types for emmett-expressjs-with-openapi.
|
|
11
|
+
*
|
|
12
|
+
* This module provides optional logging integration
|
|
13
|
+
* following a "silent by default" philosophy.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Minimal logger interface compatible with Pino, Winston, console, and similar loggers.
|
|
17
|
+
* All methods are optional to support partial implementations.
|
|
18
|
+
*/
|
|
19
|
+
interface Logger {
|
|
20
|
+
debug?(msg: string, data?: unknown): void;
|
|
21
|
+
info?(msg: string, data?: unknown): void;
|
|
22
|
+
warn?(msg: string, data?: unknown): void;
|
|
23
|
+
error?(msg: string, err?: unknown): void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Observability configuration options.
|
|
27
|
+
*/
|
|
28
|
+
type ObservabilityOptions = {
|
|
29
|
+
/**
|
|
30
|
+
* Optional logger instance for diagnostic output.
|
|
31
|
+
* When not provided, the library operates silently.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* import pino from 'pino';
|
|
36
|
+
*
|
|
37
|
+
* const logger = pino();
|
|
38
|
+
*
|
|
39
|
+
* const app = await getApplication({
|
|
40
|
+
* observability: { logger },
|
|
41
|
+
* });
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
logger?: Logger;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Internal helper to safely call logger methods, handling partial implementations.
|
|
48
|
+
* Always use: safeLog.error(logger, msg, error) - never { error }
|
|
49
|
+
*/
|
|
50
|
+
declare const safeLog: {
|
|
51
|
+
debug: (logger: Logger | undefined, msg: string, data?: unknown) => void | undefined;
|
|
52
|
+
info: (logger: Logger | undefined, msg: string, data?: unknown) => void | undefined;
|
|
53
|
+
warn: (logger: Logger | undefined, msg: string, data?: unknown) => void | undefined;
|
|
54
|
+
error: (logger: Logger | undefined, msg: string, error?: unknown) => void | undefined;
|
|
55
|
+
};
|
|
56
|
+
|
|
9
57
|
type AuthClient = {
|
|
10
58
|
verifyIdToken: (token: string) => Promise<unknown>;
|
|
11
59
|
};
|
|
@@ -332,6 +380,12 @@ declare const send: (response: Response, statusCode: number, options?: HttpRespo
|
|
|
332
380
|
declare const sendProblem: (response: Response, statusCode: number, options?: HttpProblemResponseOptions) => void;
|
|
333
381
|
|
|
334
382
|
type WebApiSetup = (router: Router) => void;
|
|
383
|
+
/**
|
|
384
|
+
* Options forwarded to pino-http. Typed loosely to avoid hard dependency.
|
|
385
|
+
*
|
|
386
|
+
* @see https://github.com/pinojs/pino-http
|
|
387
|
+
*/
|
|
388
|
+
type PinoHttpOptions = Record<string, unknown>;
|
|
335
389
|
type ApplicationOptions = {
|
|
336
390
|
apis?: WebApiSetup[];
|
|
337
391
|
mapError?: ErrorToProblemDetailsMapping;
|
|
@@ -339,6 +393,25 @@ type ApplicationOptions = {
|
|
|
339
393
|
disableJsonMiddleware?: boolean;
|
|
340
394
|
disableUrlEncodingMiddleware?: boolean;
|
|
341
395
|
disableProblemDetailsMiddleware?: boolean;
|
|
396
|
+
/**
|
|
397
|
+
* Optional Pino HTTP logger configuration.
|
|
398
|
+
* When true, enables pino-http with defaults.
|
|
399
|
+
* When an object, forwards the options to pino-http.
|
|
400
|
+
* Requires the 'pino-http' package to be installed.
|
|
401
|
+
*
|
|
402
|
+
* @see https://github.com/pinojs/pino-http
|
|
403
|
+
* @example
|
|
404
|
+
* ```typescript
|
|
405
|
+
* const app = await getApplication({
|
|
406
|
+
* pinoHttp: true,
|
|
407
|
+
* });
|
|
408
|
+
*
|
|
409
|
+
* const app = await getApplication({
|
|
410
|
+
* pinoHttp: { autoLogging: false },
|
|
411
|
+
* });
|
|
412
|
+
* ```
|
|
413
|
+
*/
|
|
414
|
+
pinoHttp?: boolean | PinoHttpOptions;
|
|
342
415
|
/**
|
|
343
416
|
* Optional OpenAPI validator configuration.
|
|
344
417
|
* When provided, enables request/response validation against an OpenAPI specification.
|
|
@@ -366,15 +439,60 @@ type ApplicationOptions = {
|
|
|
366
439
|
* ```
|
|
367
440
|
*/
|
|
368
441
|
openApiValidator?: OpenApiValidatorOptions;
|
|
442
|
+
/**
|
|
443
|
+
* Optional observability configuration for logging.
|
|
444
|
+
* When not provided, the library operates silently (no logs).
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* ```typescript
|
|
448
|
+
* import pino from 'pino';
|
|
449
|
+
*
|
|
450
|
+
* const logger = pino();
|
|
451
|
+
*
|
|
452
|
+
* const app = await getApplication({
|
|
453
|
+
* observability: { logger },
|
|
454
|
+
* });
|
|
455
|
+
* ```
|
|
456
|
+
*/
|
|
457
|
+
observability?: ObservabilityOptions;
|
|
369
458
|
};
|
|
370
459
|
declare const getApplication: (options: ApplicationOptions) => Promise<express.Application>;
|
|
371
460
|
type StartApiOptions = {
|
|
372
461
|
port?: number;
|
|
462
|
+
/**
|
|
463
|
+
* Optional logger for lifecycle events.
|
|
464
|
+
*/
|
|
465
|
+
logger?: Logger;
|
|
373
466
|
};
|
|
374
467
|
declare const startAPI: (app: Application, options?: StartApiOptions) => http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
|
|
375
468
|
|
|
376
469
|
type HttpHandler<RequestType extends Request> = (request: RequestType) => Promise<HttpResponse> | HttpResponse;
|
|
377
470
|
declare const on: <RequestType extends Request>(handle: HttpHandler<RequestType>) => (request: RequestType, response: Response, _next: NextFunction) => Promise<void>;
|
|
471
|
+
/**
|
|
472
|
+
* Options for the traced handler wrapper.
|
|
473
|
+
*/
|
|
474
|
+
type TracedHandlerOptions = {
|
|
475
|
+
/**
|
|
476
|
+
* Custom span name. Defaults to 'emmett.http.handle_request'.
|
|
477
|
+
*/
|
|
478
|
+
spanName?: string;
|
|
479
|
+
};
|
|
480
|
+
/**
|
|
481
|
+
* Wraps an HTTP handler with OpenTelemetry tracing.
|
|
482
|
+
* Creates a span that captures request method, route, and response status.
|
|
483
|
+
*
|
|
484
|
+
* If OpenTelemetry is not initialized by the application, spans are no-ops
|
|
485
|
+
* with zero overhead.
|
|
486
|
+
*
|
|
487
|
+
* @example
|
|
488
|
+
* ```typescript
|
|
489
|
+
* router.post('/carts', tracedOn(async (req) => {
|
|
490
|
+
* // Your handler logic
|
|
491
|
+
* return Created({ createdId: cartId });
|
|
492
|
+
* }));
|
|
493
|
+
* ```
|
|
494
|
+
*/
|
|
495
|
+
declare const tracedOn: <RequestType extends Request>(handle: HttpHandler<RequestType>, options?: TracedHandlerOptions) => (request: RequestType, response: Response, _next: NextFunction) => Promise<void>;
|
|
378
496
|
declare const OK: (options?: HttpResponseOptions) => HttpResponse;
|
|
379
497
|
declare const Created: (options: CreatedHttpResponseOptions) => HttpResponse;
|
|
380
498
|
declare const Accepted: (options: AcceptedHttpResponseOptions) => HttpResponse;
|
|
@@ -459,4 +577,4 @@ declare const ApiE2ESpecification: {
|
|
|
459
577
|
*/
|
|
460
578
|
declare const registerHandlerModule: (modulePath: string, moduleExports: any) => void;
|
|
461
579
|
|
|
462
|
-
export { Accepted, type AcceptedHttpResponseOptions, ApiE2ESpecification, type ApiE2ESpecificationAssert, ApiSpecification, type ApiSpecificationAssert, type ApplicationOptions, BadRequest, Conflict, Created, type CreatedHttpResponseOptions, DefaultHttpProblemResponseOptions, DefaultHttpResponseOptions, type E2EResponseAssert, type ETag, ETagErrors, type ErrorToProblemDetailsMapping, type FirebaseAuthSecurityOptions, Forbidden, HeaderNames, type HttpHandler, HttpProblem, type HttpProblemResponseOptions, HttpResponse, type HttpResponseOptions, type ImportedHandlerModules, NoContent, type NoContentHttpResponseOptions, NotFound, OK, type OpenAPIV3Document, type OpenApiValidatorOptions, PreconditionFailed, type ResponseAssert, type SecurityHandlers, type StartApiOptions, type TestRequest, type WeakETag, WeakETagRegex, type WebApiSetup, createFirebaseAuthSecurityHandlers, createOpenApiValidatorOptions, existingStream, expect, expectError, expectNewEvents, expectResponse, getApplication, getETagFromIfMatch, getETagFromIfNotMatch, getETagValueFromIfMatch, getWeakETagValue, isOpenApiValidatorAvailable, isWeakETag, on, registerHandlerModule, send, sendAccepted, sendCreated, sendProblem, setETag, startAPI, toWeakETag };
|
|
580
|
+
export { Accepted, type AcceptedHttpResponseOptions, ApiE2ESpecification, type ApiE2ESpecificationAssert, ApiSpecification, type ApiSpecificationAssert, type ApplicationOptions, BadRequest, Conflict, Created, type CreatedHttpResponseOptions, DefaultHttpProblemResponseOptions, DefaultHttpResponseOptions, type E2EResponseAssert, type ETag, ETagErrors, type ErrorToProblemDetailsMapping, type FirebaseAuthSecurityOptions, Forbidden, HeaderNames, type HttpHandler, HttpProblem, type HttpProblemResponseOptions, HttpResponse, type HttpResponseOptions, type ImportedHandlerModules, type Logger, NoContent, type NoContentHttpResponseOptions, NotFound, OK, type ObservabilityOptions, type OpenAPIV3Document, type OpenApiValidatorOptions, type PinoHttpOptions, PreconditionFailed, type ResponseAssert, type SecurityHandlers, type StartApiOptions, type TestRequest, type TracedHandlerOptions, type WeakETag, WeakETagRegex, type WebApiSetup, createFirebaseAuthSecurityHandlers, createOpenApiValidatorOptions, existingStream, expect, expectError, expectNewEvents, expectResponse, getApplication, getETagFromIfMatch, getETagFromIfNotMatch, getETagValueFromIfMatch, getWeakETagValue, isOpenApiValidatorAvailable, isWeakETag, on, registerHandlerModule, safeLog, send, sendAccepted, sendCreated, sendProblem, setETag, startAPI, toWeakETag, tracedOn };
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,54 @@ import { Brand, Event, TestEventStream, EventStore } from '@event-driven-io/emme
|
|
|
6
6
|
import supertest, { Test, Response as Response$1 } from 'supertest';
|
|
7
7
|
import TestAgent from 'supertest/lib/agent';
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Observability types for emmett-expressjs-with-openapi.
|
|
11
|
+
*
|
|
12
|
+
* This module provides optional logging integration
|
|
13
|
+
* following a "silent by default" philosophy.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Minimal logger interface compatible with Pino, Winston, console, and similar loggers.
|
|
17
|
+
* All methods are optional to support partial implementations.
|
|
18
|
+
*/
|
|
19
|
+
interface Logger {
|
|
20
|
+
debug?(msg: string, data?: unknown): void;
|
|
21
|
+
info?(msg: string, data?: unknown): void;
|
|
22
|
+
warn?(msg: string, data?: unknown): void;
|
|
23
|
+
error?(msg: string, err?: unknown): void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Observability configuration options.
|
|
27
|
+
*/
|
|
28
|
+
type ObservabilityOptions = {
|
|
29
|
+
/**
|
|
30
|
+
* Optional logger instance for diagnostic output.
|
|
31
|
+
* When not provided, the library operates silently.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* import pino from 'pino';
|
|
36
|
+
*
|
|
37
|
+
* const logger = pino();
|
|
38
|
+
*
|
|
39
|
+
* const app = await getApplication({
|
|
40
|
+
* observability: { logger },
|
|
41
|
+
* });
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
logger?: Logger;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Internal helper to safely call logger methods, handling partial implementations.
|
|
48
|
+
* Always use: safeLog.error(logger, msg, error) - never { error }
|
|
49
|
+
*/
|
|
50
|
+
declare const safeLog: {
|
|
51
|
+
debug: (logger: Logger | undefined, msg: string, data?: unknown) => void | undefined;
|
|
52
|
+
info: (logger: Logger | undefined, msg: string, data?: unknown) => void | undefined;
|
|
53
|
+
warn: (logger: Logger | undefined, msg: string, data?: unknown) => void | undefined;
|
|
54
|
+
error: (logger: Logger | undefined, msg: string, error?: unknown) => void | undefined;
|
|
55
|
+
};
|
|
56
|
+
|
|
9
57
|
type AuthClient = {
|
|
10
58
|
verifyIdToken: (token: string) => Promise<unknown>;
|
|
11
59
|
};
|
|
@@ -332,6 +380,12 @@ declare const send: (response: Response, statusCode: number, options?: HttpRespo
|
|
|
332
380
|
declare const sendProblem: (response: Response, statusCode: number, options?: HttpProblemResponseOptions) => void;
|
|
333
381
|
|
|
334
382
|
type WebApiSetup = (router: Router) => void;
|
|
383
|
+
/**
|
|
384
|
+
* Options forwarded to pino-http. Typed loosely to avoid hard dependency.
|
|
385
|
+
*
|
|
386
|
+
* @see https://github.com/pinojs/pino-http
|
|
387
|
+
*/
|
|
388
|
+
type PinoHttpOptions = Record<string, unknown>;
|
|
335
389
|
type ApplicationOptions = {
|
|
336
390
|
apis?: WebApiSetup[];
|
|
337
391
|
mapError?: ErrorToProblemDetailsMapping;
|
|
@@ -339,6 +393,25 @@ type ApplicationOptions = {
|
|
|
339
393
|
disableJsonMiddleware?: boolean;
|
|
340
394
|
disableUrlEncodingMiddleware?: boolean;
|
|
341
395
|
disableProblemDetailsMiddleware?: boolean;
|
|
396
|
+
/**
|
|
397
|
+
* Optional Pino HTTP logger configuration.
|
|
398
|
+
* When true, enables pino-http with defaults.
|
|
399
|
+
* When an object, forwards the options to pino-http.
|
|
400
|
+
* Requires the 'pino-http' package to be installed.
|
|
401
|
+
*
|
|
402
|
+
* @see https://github.com/pinojs/pino-http
|
|
403
|
+
* @example
|
|
404
|
+
* ```typescript
|
|
405
|
+
* const app = await getApplication({
|
|
406
|
+
* pinoHttp: true,
|
|
407
|
+
* });
|
|
408
|
+
*
|
|
409
|
+
* const app = await getApplication({
|
|
410
|
+
* pinoHttp: { autoLogging: false },
|
|
411
|
+
* });
|
|
412
|
+
* ```
|
|
413
|
+
*/
|
|
414
|
+
pinoHttp?: boolean | PinoHttpOptions;
|
|
342
415
|
/**
|
|
343
416
|
* Optional OpenAPI validator configuration.
|
|
344
417
|
* When provided, enables request/response validation against an OpenAPI specification.
|
|
@@ -366,15 +439,60 @@ type ApplicationOptions = {
|
|
|
366
439
|
* ```
|
|
367
440
|
*/
|
|
368
441
|
openApiValidator?: OpenApiValidatorOptions;
|
|
442
|
+
/**
|
|
443
|
+
* Optional observability configuration for logging.
|
|
444
|
+
* When not provided, the library operates silently (no logs).
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* ```typescript
|
|
448
|
+
* import pino from 'pino';
|
|
449
|
+
*
|
|
450
|
+
* const logger = pino();
|
|
451
|
+
*
|
|
452
|
+
* const app = await getApplication({
|
|
453
|
+
* observability: { logger },
|
|
454
|
+
* });
|
|
455
|
+
* ```
|
|
456
|
+
*/
|
|
457
|
+
observability?: ObservabilityOptions;
|
|
369
458
|
};
|
|
370
459
|
declare const getApplication: (options: ApplicationOptions) => Promise<express.Application>;
|
|
371
460
|
type StartApiOptions = {
|
|
372
461
|
port?: number;
|
|
462
|
+
/**
|
|
463
|
+
* Optional logger for lifecycle events.
|
|
464
|
+
*/
|
|
465
|
+
logger?: Logger;
|
|
373
466
|
};
|
|
374
467
|
declare const startAPI: (app: Application, options?: StartApiOptions) => http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
|
|
375
468
|
|
|
376
469
|
type HttpHandler<RequestType extends Request> = (request: RequestType) => Promise<HttpResponse> | HttpResponse;
|
|
377
470
|
declare const on: <RequestType extends Request>(handle: HttpHandler<RequestType>) => (request: RequestType, response: Response, _next: NextFunction) => Promise<void>;
|
|
471
|
+
/**
|
|
472
|
+
* Options for the traced handler wrapper.
|
|
473
|
+
*/
|
|
474
|
+
type TracedHandlerOptions = {
|
|
475
|
+
/**
|
|
476
|
+
* Custom span name. Defaults to 'emmett.http.handle_request'.
|
|
477
|
+
*/
|
|
478
|
+
spanName?: string;
|
|
479
|
+
};
|
|
480
|
+
/**
|
|
481
|
+
* Wraps an HTTP handler with OpenTelemetry tracing.
|
|
482
|
+
* Creates a span that captures request method, route, and response status.
|
|
483
|
+
*
|
|
484
|
+
* If OpenTelemetry is not initialized by the application, spans are no-ops
|
|
485
|
+
* with zero overhead.
|
|
486
|
+
*
|
|
487
|
+
* @example
|
|
488
|
+
* ```typescript
|
|
489
|
+
* router.post('/carts', tracedOn(async (req) => {
|
|
490
|
+
* // Your handler logic
|
|
491
|
+
* return Created({ createdId: cartId });
|
|
492
|
+
* }));
|
|
493
|
+
* ```
|
|
494
|
+
*/
|
|
495
|
+
declare const tracedOn: <RequestType extends Request>(handle: HttpHandler<RequestType>, options?: TracedHandlerOptions) => (request: RequestType, response: Response, _next: NextFunction) => Promise<void>;
|
|
378
496
|
declare const OK: (options?: HttpResponseOptions) => HttpResponse;
|
|
379
497
|
declare const Created: (options: CreatedHttpResponseOptions) => HttpResponse;
|
|
380
498
|
declare const Accepted: (options: AcceptedHttpResponseOptions) => HttpResponse;
|
|
@@ -459,4 +577,4 @@ declare const ApiE2ESpecification: {
|
|
|
459
577
|
*/
|
|
460
578
|
declare const registerHandlerModule: (modulePath: string, moduleExports: any) => void;
|
|
461
579
|
|
|
462
|
-
export { Accepted, type AcceptedHttpResponseOptions, ApiE2ESpecification, type ApiE2ESpecificationAssert, ApiSpecification, type ApiSpecificationAssert, type ApplicationOptions, BadRequest, Conflict, Created, type CreatedHttpResponseOptions, DefaultHttpProblemResponseOptions, DefaultHttpResponseOptions, type E2EResponseAssert, type ETag, ETagErrors, type ErrorToProblemDetailsMapping, type FirebaseAuthSecurityOptions, Forbidden, HeaderNames, type HttpHandler, HttpProblem, type HttpProblemResponseOptions, HttpResponse, type HttpResponseOptions, type ImportedHandlerModules, NoContent, type NoContentHttpResponseOptions, NotFound, OK, type OpenAPIV3Document, type OpenApiValidatorOptions, PreconditionFailed, type ResponseAssert, type SecurityHandlers, type StartApiOptions, type TestRequest, type WeakETag, WeakETagRegex, type WebApiSetup, createFirebaseAuthSecurityHandlers, createOpenApiValidatorOptions, existingStream, expect, expectError, expectNewEvents, expectResponse, getApplication, getETagFromIfMatch, getETagFromIfNotMatch, getETagValueFromIfMatch, getWeakETagValue, isOpenApiValidatorAvailable, isWeakETag, on, registerHandlerModule, send, sendAccepted, sendCreated, sendProblem, setETag, startAPI, toWeakETag };
|
|
580
|
+
export { Accepted, type AcceptedHttpResponseOptions, ApiE2ESpecification, type ApiE2ESpecificationAssert, ApiSpecification, type ApiSpecificationAssert, type ApplicationOptions, BadRequest, Conflict, Created, type CreatedHttpResponseOptions, DefaultHttpProblemResponseOptions, DefaultHttpResponseOptions, type E2EResponseAssert, type ETag, ETagErrors, type ErrorToProblemDetailsMapping, type FirebaseAuthSecurityOptions, Forbidden, HeaderNames, type HttpHandler, HttpProblem, type HttpProblemResponseOptions, HttpResponse, type HttpResponseOptions, type ImportedHandlerModules, type Logger, NoContent, type NoContentHttpResponseOptions, NotFound, OK, type ObservabilityOptions, type OpenAPIV3Document, type OpenApiValidatorOptions, type PinoHttpOptions, PreconditionFailed, type ResponseAssert, type SecurityHandlers, type StartApiOptions, type TestRequest, type TracedHandlerOptions, type WeakETag, WeakETagRegex, type WebApiSetup, createFirebaseAuthSecurityHandlers, createOpenApiValidatorOptions, existingStream, expect, expectError, expectNewEvents, expectResponse, getApplication, getETagFromIfMatch, getETagFromIfNotMatch, getETagValueFromIfMatch, getWeakETagValue, isOpenApiValidatorAvailable, isWeakETag, on, registerHandlerModule, safeLog, send, sendAccepted, sendCreated, sendProblem, setETag, startAPI, toWeakETag, tracedOn };
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
registerHandlerModule
|
|
3
3
|
} from "./chunk-5TC7YUZR.js";
|
|
4
|
+
import {
|
|
5
|
+
safeLog
|
|
6
|
+
} from "./chunk-I46UH36B.js";
|
|
4
7
|
|
|
5
8
|
// src/index.ts
|
|
6
9
|
import "express-async-errors";
|
|
7
10
|
|
|
8
11
|
// src/application.ts
|
|
12
|
+
import { trace, SpanStatusCode } from "@opentelemetry/api";
|
|
9
13
|
import express, {
|
|
10
14
|
Router
|
|
11
15
|
} from "express";
|
|
@@ -15,7 +19,8 @@ import { createRequire } from "module";
|
|
|
15
19
|
|
|
16
20
|
// src/middlewares/problemDetailsMiddleware.ts
|
|
17
21
|
import { ProblemDocument } from "http-problem-details";
|
|
18
|
-
var problemDetailsMiddleware = (mapError) => (error, request, response, _next) => {
|
|
22
|
+
var problemDetailsMiddleware = (mapError, logger) => (error, request, response, _next) => {
|
|
23
|
+
safeLog.error(logger, "Request error", error);
|
|
19
24
|
let problemDetails;
|
|
20
25
|
if (mapError) problemDetails = mapError(error, request);
|
|
21
26
|
problemDetails = problemDetails ?? defaultErrorToProblemDetailsMapping(error);
|
|
@@ -39,6 +44,7 @@ var defaultErrorToProblemDetailsMapping = (error) => {
|
|
|
39
44
|
};
|
|
40
45
|
|
|
41
46
|
// src/application.ts
|
|
47
|
+
var tracer = trace.getTracer("@emmett-community/emmett-expressjs-with-openapi");
|
|
42
48
|
var getApplication = async (options) => {
|
|
43
49
|
const app = express();
|
|
44
50
|
const {
|
|
@@ -48,10 +54,39 @@ var getApplication = async (options) => {
|
|
|
48
54
|
disableJsonMiddleware,
|
|
49
55
|
disableUrlEncodingMiddleware,
|
|
50
56
|
disableProblemDetailsMiddleware,
|
|
51
|
-
|
|
57
|
+
pinoHttp,
|
|
58
|
+
openApiValidator,
|
|
59
|
+
observability
|
|
52
60
|
} = options;
|
|
61
|
+
const logger = observability?.logger;
|
|
62
|
+
safeLog.debug(logger, "Initializing Express application", {
|
|
63
|
+
hasApis: !!apis?.length,
|
|
64
|
+
hasOpenApiValidator: !!openApiValidator,
|
|
65
|
+
hasPinoHttp: !!pinoHttp
|
|
66
|
+
});
|
|
53
67
|
const router = Router();
|
|
54
68
|
app.set("etag", enableDefaultExpressEtag ?? false);
|
|
69
|
+
if (pinoHttp !== void 0 && pinoHttp !== false) {
|
|
70
|
+
try {
|
|
71
|
+
const require2 = createRequire(import.meta.url);
|
|
72
|
+
const mod = require2("pino-http");
|
|
73
|
+
const provider = mod.default ?? mod;
|
|
74
|
+
if (typeof provider !== "function") {
|
|
75
|
+
throw new Error("Invalid pino-http module: missing default export");
|
|
76
|
+
}
|
|
77
|
+
const options2 = pinoHttp === true ? void 0 : pinoHttp;
|
|
78
|
+
const middleware = provider(options2);
|
|
79
|
+
app.use(middleware);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
safeLog.warn(
|
|
82
|
+
logger,
|
|
83
|
+
"Pino HTTP configuration provided but pino-http package is not installed. Install it with: npm install pino-http"
|
|
84
|
+
);
|
|
85
|
+
throw new Error(
|
|
86
|
+
"pino-http package is required when pinoHttp option is used"
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
55
90
|
if (!disableJsonMiddleware) app.use(express.json());
|
|
56
91
|
if (!disableUrlEncodingMiddleware)
|
|
57
92
|
app.use(
|
|
@@ -65,20 +100,52 @@ var getApplication = async (options) => {
|
|
|
65
100
|
activateESMResolver();
|
|
66
101
|
const handlersBasePath = typeof openApiValidator.operationHandlers === "string" ? openApiValidator.operationHandlers : openApiValidator.operationHandlers.basePath;
|
|
67
102
|
if (handlersBasePath) {
|
|
68
|
-
const { extractHandlerModules } = await import("./openapi-parser-
|
|
69
|
-
const { importAndRegisterHandlers } = await import("./handler-importer-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
103
|
+
const { extractHandlerModules } = await import("./openapi-parser-QYXNHNSZ.js");
|
|
104
|
+
const { importAndRegisterHandlers } = await import("./handler-importer-6A237UML.js");
|
|
105
|
+
const modules = await tracer.startActiveSpan(
|
|
106
|
+
"emmett.openapi.parse_spec",
|
|
107
|
+
async (span) => {
|
|
108
|
+
try {
|
|
109
|
+
const result = await extractHandlerModules(
|
|
110
|
+
openApiValidator.apiSpec,
|
|
111
|
+
handlersBasePath,
|
|
112
|
+
logger
|
|
113
|
+
);
|
|
114
|
+
span.setAttribute("emmett.handlers.count", result.length);
|
|
115
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
116
|
+
return result;
|
|
117
|
+
} catch (error) {
|
|
118
|
+
span.recordException(error);
|
|
119
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
120
|
+
throw error;
|
|
121
|
+
} finally {
|
|
122
|
+
span.end();
|
|
123
|
+
}
|
|
78
124
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
125
|
+
);
|
|
126
|
+
const importedHandlers = await tracer.startActiveSpan(
|
|
127
|
+
"emmett.http.import_handlers",
|
|
128
|
+
async (span) => {
|
|
129
|
+
try {
|
|
130
|
+
const result = await importAndRegisterHandlers(modules, logger);
|
|
131
|
+
span.setAttribute(
|
|
132
|
+
"emmett.handlers.count",
|
|
133
|
+
Object.keys(result).length
|
|
134
|
+
);
|
|
135
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
136
|
+
return result;
|
|
137
|
+
} catch (error) {
|
|
138
|
+
safeLog.error(logger, "Failed to auto-import handler modules", error);
|
|
139
|
+
span.recordException(error);
|
|
140
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
141
|
+
throw error;
|
|
142
|
+
} finally {
|
|
143
|
+
span.end();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
if (openApiValidator.initializeHandlers) {
|
|
148
|
+
await openApiValidator.initializeHandlers(importedHandlers);
|
|
82
149
|
}
|
|
83
150
|
}
|
|
84
151
|
} else {
|
|
@@ -114,8 +181,9 @@ var getApplication = async (options) => {
|
|
|
114
181
|
} else {
|
|
115
182
|
app.use(middleware);
|
|
116
183
|
}
|
|
117
|
-
} catch {
|
|
118
|
-
|
|
184
|
+
} catch (error) {
|
|
185
|
+
safeLog.warn(
|
|
186
|
+
logger,
|
|
119
187
|
"OpenAPI validator configuration provided but express-openapi-validator package is not installed. Install it with: npm install express-openapi-validator"
|
|
120
188
|
);
|
|
121
189
|
throw new Error(
|
|
@@ -130,14 +198,15 @@ var getApplication = async (options) => {
|
|
|
130
198
|
app.use(router);
|
|
131
199
|
}
|
|
132
200
|
if (!disableProblemDetailsMiddleware)
|
|
133
|
-
app.use(problemDetailsMiddleware(mapError));
|
|
201
|
+
app.use(problemDetailsMiddleware(mapError, logger));
|
|
202
|
+
safeLog.info(logger, "Express application initialized");
|
|
134
203
|
return app;
|
|
135
204
|
};
|
|
136
205
|
var startAPI = (app, options = { port: 3e3 }) => {
|
|
137
|
-
const { port } = options;
|
|
206
|
+
const { port, logger } = options;
|
|
138
207
|
const server = http.createServer(app);
|
|
139
208
|
server.on("listening", () => {
|
|
140
|
-
|
|
209
|
+
safeLog.info(logger, "Server up listening", { port });
|
|
141
210
|
});
|
|
142
211
|
return server.listen(port);
|
|
143
212
|
};
|
|
@@ -191,10 +260,34 @@ var getETagValueFromIfMatch = (request) => {
|
|
|
191
260
|
};
|
|
192
261
|
|
|
193
262
|
// src/handler.ts
|
|
263
|
+
import { trace as trace2, SpanStatusCode as SpanStatusCode2 } from "@opentelemetry/api";
|
|
264
|
+
var tracer2 = trace2.getTracer("@emmett-community/emmett-expressjs-with-openapi");
|
|
194
265
|
var on = (handle) => async (request, response, _next) => {
|
|
195
266
|
const setResponse = await Promise.resolve(handle(request));
|
|
196
267
|
return setResponse(response);
|
|
197
268
|
};
|
|
269
|
+
var tracedOn = (handle, options) => async (request, response, _next) => {
|
|
270
|
+
const spanName = options?.spanName ?? "emmett.http.handle_request";
|
|
271
|
+
return tracer2.startActiveSpan(spanName, async (span) => {
|
|
272
|
+
try {
|
|
273
|
+
span.setAttribute("http.method", request.method);
|
|
274
|
+
const route = (request.baseUrl ?? "") + (request.route?.path ?? request.path);
|
|
275
|
+
span.setAttribute("http.route", route);
|
|
276
|
+
const setResponse = await Promise.resolve(handle(request));
|
|
277
|
+
setResponse(response);
|
|
278
|
+
span.setAttribute("http.status_code", response.statusCode);
|
|
279
|
+
span.setStatus({
|
|
280
|
+
code: response.statusCode >= 400 ? SpanStatusCode2.ERROR : SpanStatusCode2.OK
|
|
281
|
+
});
|
|
282
|
+
} catch (error) {
|
|
283
|
+
span.recordException(error);
|
|
284
|
+
span.setStatus({ code: SpanStatusCode2.ERROR });
|
|
285
|
+
throw error;
|
|
286
|
+
} finally {
|
|
287
|
+
span.end();
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
};
|
|
198
291
|
var OK = (options) => (response) => {
|
|
199
292
|
send(response, 200, options);
|
|
200
293
|
};
|
|
@@ -473,12 +566,14 @@ export {
|
|
|
473
566
|
isWeakETag,
|
|
474
567
|
on,
|
|
475
568
|
registerHandlerModule,
|
|
569
|
+
safeLog,
|
|
476
570
|
send,
|
|
477
571
|
sendAccepted,
|
|
478
572
|
sendCreated,
|
|
479
573
|
sendProblem,
|
|
480
574
|
setETag,
|
|
481
575
|
startAPI,
|
|
482
|
-
toWeakETag
|
|
576
|
+
toWeakETag,
|
|
577
|
+
tracedOn
|
|
483
578
|
};
|
|
484
579
|
//# sourceMappingURL=index.js.map
|