owebjs 1.5.7-dev → 1.5.8-dev

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 CHANGED
@@ -72,10 +72,10 @@ second average
72
72
  | Runtime | Version | Requests/sec |
73
73
  | ------------------------- | --------- | -----------: |
74
74
  | uWebSockets.js | 20.52.0 | 79,149 |
75
- | **Oweb (uWS)** | 1.5.7-dev | 70,535 |
75
+ | **Oweb (uWS)** | 1.5.8-dev | 76,853 |
76
76
  | 0http | 4.4.0 | 46,605 |
77
77
  | Fastify | 4.23.2 | 46,238 |
78
- | **Oweb (Fastify)** | 1.5.7-dev | 42,570 |
78
+ | **Oweb (Fastify)** | 1.5.8-dev | 42,570 |
79
79
  | Node.js http.createServer | 24.5.0 | 42,544 |
80
80
  | Express | 5.2.1 | 24,913 |
81
81
 
@@ -83,6 +83,49 @@ This is a synthetic "Hello, Word!" benchmark that aims to evaluate the framework
83
83
  The overhead that each framework has on your application depends on your application.
84
84
  You should always benchmark if performance matters to you.
85
85
 
86
+ ## Best Performance
87
+
88
+ For the highest throughput, use these defaults:
89
+
90
+ - Enable uWebSockets runtime: `uWebSocketsEnabled: true`
91
+ - Disable powered-by header: `poweredByHeader: false`
92
+ - For headers that should be sent on every request (for example CORS-related headers), use `staticResponseHeaders` instead of per-request hooks
93
+
94
+ Example (production-oriented):
95
+
96
+ ```js
97
+ import Oweb from 'owebjs';
98
+
99
+ const app = await new Oweb({
100
+ uWebSocketsEnabled: true,
101
+ poweredByHeader: false,
102
+ staticResponseHeaders: {
103
+ // CORS (set your real origin in production)
104
+ 'access-control-allow-origin': 'https://yourdomain.com',
105
+ 'access-control-allow-methods': 'GET,POST,PUT,PATCH,DELETE,OPTIONS',
106
+ 'access-control-allow-headers': 'Content-Type, Authorization',
107
+ vary: 'Origin',
108
+
109
+ // Security headers
110
+ 'x-content-type-options': 'nosniff',
111
+ 'x-frame-options': 'DENY',
112
+ 'referrer-policy': 'strict-origin-when-cross-origin',
113
+ 'permissions-policy': 'geolocation=(), microphone=(), camera=()',
114
+ 'cross-origin-opener-policy': 'same-origin',
115
+ 'cross-origin-resource-policy': 'same-site',
116
+ },
117
+ }).setup();
118
+
119
+ await app.loadRoutes({
120
+ directory: 'routes',
121
+ hmr: {
122
+ enabled: false,
123
+ },
124
+ });
125
+
126
+ await app.start({ port: 3000, host: '0.0.0.0' });
127
+ ```
128
+
86
129
  ## First App (2 Minutes)
87
130
 
88
131
  Start with a minimal app, then we will add route conventions step by step.
package/dist/index.d.ts CHANGED
@@ -21,6 +21,7 @@ export { HTTPMethods } from 'fastify/types/utils';
21
21
  interface OwebOptions extends FastifyServerOptions {
22
22
  uWebSocketsEnabled?: boolean;
23
23
  poweredByHeader?: boolean;
24
+ staticResponseHeaders?: Record<string, string>;
24
25
  OWEB_INTERNAL_ERROR_HANDLER?: Function;
25
26
  }
26
27
  interface LoadRoutesOptions {
@@ -61,7 +61,9 @@ class Oweb extends _FastifyInstance {
61
61
  async setup() {
62
62
  if (this._options.uWebSocketsEnabled) {
63
63
  const serverimp = (await import("../uwebsocket/server.js")).default;
64
- const server = await serverimp({});
64
+ const server = await serverimp({
65
+ staticResponseHeaders: this._options.staticResponseHeaders
66
+ });
65
67
  this.uServer = server;
66
68
  this._options.serverFactory = (handler) => {
67
69
  server.on("request", handler);
@@ -74,7 +76,19 @@ class Oweb extends _FastifyInstance {
74
76
  if (!this._options.uWebSocketsEnabled) {
75
77
  await fastify.register(websocketPlugin);
76
78
  }
77
- if (this._options.poweredByHeader) {
79
+ const staticHeaderEntries = this._options.staticResponseHeaders ? Object.entries(this._options.staticResponseHeaders) : [];
80
+ if (!this._options.uWebSocketsEnabled && (this._options.poweredByHeader || staticHeaderEntries.length)) {
81
+ fastify.addHook("onRequest", (_, res, done) => {
82
+ if (this._options.poweredByHeader) {
83
+ res.header("X-Powered-By", "Oweb");
84
+ }
85
+ for (let i = 0; i < staticHeaderEntries.length; i++) {
86
+ const [key, value] = staticHeaderEntries[i];
87
+ res.header(key, value);
88
+ }
89
+ done();
90
+ });
91
+ } else if (this._options.poweredByHeader) {
78
92
  fastify.addHook("onRequest", (_, res, done) => {
79
93
  res.header("X-Powered-By", "Oweb");
80
94
  done();
@@ -17,8 +17,9 @@ class HttpResponse extends Writable {
17
17
  __headers;
18
18
  headersSent;
19
19
  finished;
20
+ staticHeaders;
20
21
  _socket = null;
21
- constructor(uResponse, uServer) {
22
+ constructor(uResponse, uServer, staticHeaders) {
22
23
  super();
23
24
  this.res = uResponse;
24
25
  this.server = uServer;
@@ -27,6 +28,7 @@ class HttpResponse extends Writable {
27
28
  this.__headers = {};
28
29
  this.headersSent = false;
29
30
  this.finished = false;
31
+ this.staticHeaders = staticHeaders;
30
32
  }
31
33
  get socket() {
32
34
  if (!this._socket) {
@@ -62,6 +64,18 @@ class HttpResponse extends Writable {
62
64
  if (this.headersSent || this.isClosed()) return;
63
65
  const message = this.statusMessage || http.STATUS_CODES[this.statusCode] || "Unknown";
64
66
  this.res.writeStatus(`${this.statusCode} ${message}`);
67
+ if (this.staticHeaders?.length) {
68
+ for (let i = 0; i < this.staticHeaders.length; i++) {
69
+ const [key, value] = this.staticHeaders[i];
70
+ if (key === "content-length" || key === "transfer-encoding") {
71
+ continue;
72
+ }
73
+ if (this.__headers[key] !== void 0) {
74
+ continue;
75
+ }
76
+ this.res.writeHeader(key, value);
77
+ }
78
+ }
65
79
  const keys = Object.keys(this.__headers);
66
80
  for (let i = 0; i < keys.length; i++) {
67
81
  const key = keys[i];
@@ -6,7 +6,7 @@ const REQUEST_EVENT = "request";
6
6
  import HttpRequest from './request.js';
7
7
  import HttpResponse from './response.js';
8
8
  import http from "node:http";
9
- async function server_default({ cert_file_name, key_file_name }) {
9
+ async function server_default({ cert_file_name, key_file_name, staticResponseHeaders }) {
10
10
  let uWS;
11
11
  uWS = (await import("uWebSockets.js")).default;
12
12
  let appType = "App";
@@ -22,6 +22,10 @@ async function server_default({ cert_file_name, key_file_name }) {
22
22
  cert_file_name,
23
23
  key_file_name
24
24
  };
25
+ const normalizedStaticHeaders = staticResponseHeaders ? Object.entries(staticResponseHeaders).map(([k, v]) => [
26
+ k.toLowerCase(),
27
+ String(v)
28
+ ]) : void 0;
25
29
  const copyArrayBufferToBuffer = /* @__PURE__ */ __name((bytes) => {
26
30
  const src = new Uint8Array(bytes);
27
31
  const out = Buffer.allocUnsafe(src.byteLength);
@@ -47,7 +51,7 @@ async function server_default({ cert_file_name, key_file_name }) {
47
51
  query,
48
52
  url
49
53
  });
50
- const resWrapper = new HttpResponse(res, uServer);
54
+ const resWrapper = new HttpResponse(res, uServer, normalizedStaticHeaders);
51
55
  reqWrapper.res = resWrapper;
52
56
  resWrapper.req = reqWrapper;
53
57
  reqWrapper.bindSocketFactory(() => resWrapper.socket);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "owebjs",
3
- "version": "1.5.7-dev",
3
+ "version": "1.5.8-dev",
4
4
  "description": "A flexible and modern web framework built on top of Fastify",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",