@opra/nestjs-http 1.28.4 → 1.29.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2022 Panates
3
+ Copyright (c) 2020-present Panates®
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,19 +1,79 @@
1
+ <div align="center">
2
+
3
+ <a href="https://oprajs.com">
4
+ <img src="https://oprajs.com/img/opra-header-block.webp" width="880" alt="OPRA — Open Platform for Rich APIs" />
5
+ </a>
6
+
1
7
  # @opra/nestjs-http
2
8
 
9
+ NestJS HTTP module for the OPRA framework
10
+
3
11
  [![NPM Version][npm-image]][npm-url]
4
12
  [![NPM Downloads][downloads-image]][downloads-url]
5
13
  [![CI Tests][ci-test-image]][ci-test-url]
6
14
  [![Test Coverage][coveralls-image]][coveralls-url]
7
15
 
16
+ [🌐 Documentation](https://oprajs.com) · [🚀 Getting Started](https://oprajs.com/docs/introduction) · [📦 Packages](https://github.com/panates/opra#packages) · [💬 Issues](https://github.com/panates/opra/issues)
17
+
18
+ </div>
19
+
20
+ ---
21
+
22
+ NestJS HTTP module for the [OPRA](https://oprajs.com) framework. Register your OPRA API inside a NestJS application in a few lines.
23
+
24
+ ## Features
25
+
26
+ - **`OpraHttpModule`** — Dynamically configurable NestJS module (`forRoot` / `forRootAsync`)
27
+ - **`OpraHttpNestjsAdapter`** — NestJS adapter integrating OPRA's HTTP handler
28
+ - **`OpraExceptionFilter`** — Global exception filter that maps OPRA errors to HTTP responses
29
+ - **`OpraMiddleware`** — Request/response middleware for the OPRA pipeline
30
+ - Full support for NestJS **dependency injection**, **interceptors**, and **guards**
31
+
32
+ ## Installation
8
33
 
9
- ## Support
10
- You can report bugs and discuss features on the [GitHub issues](https://github.com/panates/opra/issues) page.
34
+ ```bash
35
+ npm install @opra/nestjs-http
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ```typescript
41
+ import { Module } from '@nestjs/common';
42
+ import { OpraHttpModule } from '@opra/nestjs-http';
43
+
44
+ @Module({
45
+ imports: [
46
+ OpraHttpModule.forRoot({
47
+ name: 'MyAPI',
48
+ basePath: 'v1',
49
+ schemaIsPublic: true,
50
+ controllers: [UsersController, ProductsController],
51
+ providers: [UsersService, ProductsService],
52
+ types: [User, Product],
53
+ }),
54
+ ],
55
+ })
56
+ export class AppModule {}
57
+ ```
58
+
59
+ ### Async configuration
60
+
61
+ ```typescript
62
+ OpraHttpModule.forRootAsync({
63
+ useFactory: (config: ConfigService) => ({
64
+ name: config.get('API_NAME'),
65
+ controllers: [UsersController],
66
+ }),
67
+ inject: [ConfigService],
68
+ });
69
+ ```
11
70
 
12
71
  ## Node Compatibility
13
- - node >= 20.x
14
72
 
73
+ - node >= 20.x
15
74
 
16
75
  ## License
76
+
17
77
  Available under [MIT](LICENSE) license.
18
78
 
19
79
  [npm-image]: https://img.shields.io/npm/v/@opra/nestjs-http
@@ -27,7 +27,7 @@ let OpraExceptionFilter = class OpraExceptionFilter extends BaseExceptionFilter
27
27
  if (ctx) {
28
28
  const adapter = this.moduleRef.get(OpraHttpNestjsAdapter);
29
29
  ctx.errors.push(exception);
30
- return adapter.handler.sendResponse(ctx);
30
+ return adapter.sendResponse(ctx);
31
31
  }
32
32
  super.catch(exception, host);
33
33
  }
@@ -2,7 +2,7 @@ var OpraHttpCoreModule_1;
2
2
  import { __decorate, __metadata } from "tslib";
3
3
  import { isConstructor } from '@jsopen/objects';
4
4
  import { Global, Logger, Module, RequestMethod, } from '@nestjs/common';
5
- import { APP_FILTER, ModuleRef } from '@nestjs/core';
5
+ import { APP_FILTER, HttpAdapterHost, ModuleRef } from '@nestjs/core';
6
6
  import { ApiDocumentFactory } from '@opra/common';
7
7
  import { HttpAdapter, HttpContext } from '@opra/http';
8
8
  import { OPRA_HTTP_API_CONFIG } from './constants.js';
@@ -56,8 +56,8 @@ let OpraHttpCoreModule = OpraHttpCoreModule_1 = class OpraHttpCoreModule {
56
56
  });
57
57
  const adapterProvider = {
58
58
  provide: token,
59
- inject: [ModuleRef, OPRA_HTTP_API_CONFIG],
60
- useFactory: async (moduleRef, apiConfig) => {
59
+ inject: [ModuleRef, HttpAdapterHost, OPRA_HTTP_API_CONFIG],
60
+ useFactory: async (moduleRef, httpAdapterHost, apiConfig) => {
61
61
  opraNestAdapter.scope = apiConfig.scope;
62
62
  opraNestAdapter.logger =
63
63
  opraNestAdapter.logger || new Logger(apiConfig.name);
@@ -83,6 +83,11 @@ let OpraHttpCoreModule = OpraHttpCoreModule_1 = class OpraHttpCoreModule {
83
83
  return x;
84
84
  });
85
85
  }
86
+ opraNestAdapter.setHttpHandler((req, res) => {
87
+ const httpInstance = httpAdapterHost.httpAdapter?.getInstance();
88
+ if (httpInstance)
89
+ httpInstance(req, res);
90
+ });
86
91
  return opraNestAdapter;
87
92
  },
88
93
  };
@@ -1,5 +1,8 @@
1
+ import * as http from 'node:http';
2
+ import { type IncomingMessage, type ServerResponse } from 'node:http';
1
3
  import { type Type } from '@nestjs/common';
2
- import { HttpAdapter } from '@opra/http';
4
+ import { HttpController, HttpOperation } from '@opra/common';
5
+ import { HttpAdapter, HttpContext } from '@opra/http';
3
6
  /**
4
7
  * OpraHttpNestjsAdapter
5
8
  *
@@ -28,6 +31,15 @@ export declare class OpraHttpNestjsAdapter extends HttpAdapter {
28
31
  * @returns {Promise<void>}
29
32
  */
30
33
  close(): Promise<void>;
34
+ createContext(_req: any, _res: any, args?: {
35
+ controller?: HttpController;
36
+ controllerInstance?: any;
37
+ operation?: HttpOperation;
38
+ operationHandler: Function;
39
+ }): Promise<HttpContext>;
40
+ protected _httpHandler?: (req: IncomingMessage, res: ServerResponse) => void;
41
+ setHttpHandler(handler: (req: IncomingMessage, res: ServerResponse) => void): void;
42
+ handleRawRequest(req: http.IncomingMessage, res: http.ServerResponse): Promise<void>;
31
43
  /**
32
44
  * Adds the root controller that serves the OPRA schema.
33
45
  *
@@ -1,9 +1,11 @@
1
1
  import { __decorate, __metadata, __param } from "tslib";
2
+ import * as http from 'node:http';
3
+ import {} from 'node:http';
2
4
  import nodePath from 'node:path';
3
5
  import { isConstructor } from '@jsopen/objects';
4
- import { Controller, Delete, Get, Head, Next, Options, Patch, Post, Put, Req, Res, Search, } from '@nestjs/common';
5
- import { HTTP_CONTROLLER_METADATA, HttpApi, HttpController, NotFoundError, } from '@opra/common';
6
- import { HttpAdapter, HttpContext } from '@opra/http';
6
+ import { Controller, Delete, Get, Head, HttpCode, Next, Options, Patch, Post, Put, Req, Res, Search, } from '@nestjs/common';
7
+ import { HTTP_CONTROLLER_METADATA, HttpApi, HttpController, HttpOperation, NotFoundError, } from '@opra/common';
8
+ import { HttpAdapter, HttpBundle, HttpContext, HttpRequest, HttpResponse, } from '@opra/http';
7
9
  import { OpraNestUtils, Public } from '@opra/nestjs';
8
10
  import { asMutable } from 'ts-gems';
9
11
  /**
@@ -39,6 +41,25 @@ export class OpraHttpNestjsAdapter extends HttpAdapter {
39
41
  async close() {
40
42
  //
41
43
  }
44
+ async createContext(_req, _res, args) {
45
+ const ctx = await super.createContext(_req, _res, args);
46
+ // @ts-ignore
47
+ ctx.platform = _req.route ? 'express' : 'fastify';
48
+ return ctx;
49
+ }
50
+ _httpHandler;
51
+ setHttpHandler(handler) {
52
+ this._httpHandler = handler;
53
+ }
54
+ async handleRawRequest(req, res) {
55
+ if (!this._httpHandler)
56
+ throw new Error('HTTP handler is not initialized. Call setHttpHandler() first.');
57
+ return new Promise((resolve, reject) => {
58
+ res.once('finish', resolve);
59
+ res.once('error', reject);
60
+ this._httpHandler(req, res);
61
+ });
62
+ }
42
63
  /**
43
64
  * Adds the root controller that serves the OPRA schema.
44
65
  *
@@ -49,7 +70,21 @@ export class OpraHttpNestjsAdapter extends HttpAdapter {
49
70
  const _this = this;
50
71
  let RootController = class RootController {
51
72
  schema(_req, next) {
52
- _this.handler.sendDocumentSchema(_req.opraContext).catch(() => next());
73
+ _this.sendDocumentSchema(_req.opraContext).catch(() => next());
74
+ }
75
+ bundle(_req, _res, next) {
76
+ Promise.resolve()
77
+ .then(async () => {
78
+ const bundle = new HttpBundle({
79
+ __adapter: _this,
80
+ platform: _req.route ? 'express' : 'fastify',
81
+ request: HttpRequest.create(_req),
82
+ response: HttpResponse.create(_res),
83
+ });
84
+ await _this.emitAsync('create-bundle', bundle);
85
+ await _this.handleBundle(bundle);
86
+ })
87
+ .catch(() => next());
53
88
  }
54
89
  };
55
90
  __decorate([
@@ -60,6 +95,16 @@ export class OpraHttpNestjsAdapter extends HttpAdapter {
60
95
  __metadata("design:paramtypes", [Object, Function]),
61
96
  __metadata("design:returntype", void 0)
62
97
  ], RootController.prototype, "schema", null);
98
+ __decorate([
99
+ Post('/\\$bundle'),
100
+ HttpCode(200),
101
+ __param(0, Req()),
102
+ __param(1, Res()),
103
+ __param(2, Next()),
104
+ __metadata("design:type", Function),
105
+ __metadata("design:paramtypes", [Object, Object, Function]),
106
+ __metadata("design:returntype", void 0)
107
+ ], RootController.prototype, "bundle", null);
63
108
  RootController = __decorate([
64
109
  Controller({
65
110
  path: this.basePath,
@@ -98,9 +143,9 @@ export class OpraHttpNestjsAdapter extends HttpAdapter {
98
143
  const adapter = this;
99
144
  // adapter.logger =
100
145
  /* Disable default error handler. Errors will be handled by OpraExceptionFilter */
101
- adapter.handler.onError = (context, error) => {
146
+ adapter.on('error', (error) => {
102
147
  throw error;
103
- };
148
+ });
104
149
  this.nestControllers.push(newClass);
105
150
  let metadataKeys;
106
151
  if (metadata.operations) {
@@ -115,7 +160,9 @@ export class OpraHttpNestjsAdapter extends HttpAdapter {
115
160
  const controller = api.findController(sourceClass);
116
161
  const operation = controller?.operations.get(k);
117
162
  const context = asMutable(_req.opraContext);
118
- if (!(context && operation && typeof operationHandler === 'function')) {
163
+ if (!(context &&
164
+ operation &&
165
+ typeof operationHandler === 'function')) {
119
166
  throw new NotFoundError({
120
167
  message: `No endpoint found for [${_req.method}]${_req.baseUrl}`,
121
168
  details: {
@@ -131,7 +178,7 @@ export class OpraHttpNestjsAdapter extends HttpAdapter {
131
178
  context.__controller = this;
132
179
  context.__handler = operationHandler;
133
180
  /* Handle request */
134
- await adapter.handler.handleRequest(context);
181
+ await adapter.handleRequest(context);
135
182
  },
136
183
  });
137
184
  /* Copy metadata keys from source function to new one */
@@ -1,6 +1,6 @@
1
1
  import { __decorate, __metadata } from "tslib";
2
2
  import { Injectable } from '@nestjs/common';
3
- import { HttpContext, HttpIncoming, HttpOutgoing } from '@opra/http';
3
+ import { HttpRequest, HttpResponse } from '@opra/http';
4
4
  import { OpraHttpNestjsAdapter } from './opra-http-nestjs-adapter.js';
5
5
  /**
6
6
  * OpraMiddleware
@@ -21,19 +21,18 @@ let OpraMiddleware = class OpraMiddleware {
21
21
  * @param next - Function that calls the next middleware.
22
22
  */
23
23
  use(req, res, next) {
24
- const request = HttpIncoming.from(req);
25
- const response = HttpOutgoing.from(res);
26
- /* Create the HttpContext */
27
- const context = new HttpContext({
28
- __adapter: this.opraAdapter,
29
- platform: req.route ? 'express' : 'fastify',
30
- request,
31
- response,
32
- });
33
- req.opraContext = context;
24
+ const request = HttpRequest.create(req);
25
+ const response = HttpResponse.create(res);
34
26
  this.opraAdapter
35
- .emitAsync('createContext', context)
36
- .then(() => next())
27
+ .createContext(request, response)
28
+ .then(async (context) => {
29
+ // @ts-ignore
30
+ context.platform = req.route ? 'express' : 'fastify';
31
+ req.opraContext = context;
32
+ await this.opraAdapter
33
+ .emitAsync('createContext', context)
34
+ .then(() => next());
35
+ })
37
36
  .catch(next);
38
37
  }
39
38
  };
package/package.json CHANGED
@@ -1,18 +1,19 @@
1
1
  {
2
2
  "name": "@opra/nestjs-http",
3
- "version": "1.28.4",
3
+ "version": "1.29.0",
4
4
  "description": "Opra NestJS Http Module",
5
5
  "author": "Panates",
6
6
  "license": "MIT",
7
+ "homepage": "https://www.oprajs.com",
7
8
  "dependencies": {
8
- "@jsopen/objects": "^2.2.2",
9
+ "@jsopen/objects": "^2.2.3",
9
10
  "tslib": "^2.8.1"
10
11
  },
11
12
  "peerDependencies": {
12
- "@opra/common": "^1.28.4",
13
- "@opra/core": "^1.28.4",
14
- "@opra/nestjs": "^1.28.4",
15
- "@opra/http": "^1.28.4",
13
+ "@opra/common": "^1.29.0",
14
+ "@opra/core": "^1.29.0",
15
+ "@opra/nestjs": "^1.29.0",
16
+ "@opra/http": "^1.29.0",
16
17
  "@nestjs/common": "^10.0.0 || ^11.0.0",
17
18
  "@nestjs/core": "^10.0.0 || ^11.0.0"
18
19
  },