yedra 0.14.2 → 0.14.3

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.
@@ -1,4 +1,4 @@
1
- import type { Server } from 'node:http';
1
+ import type { IncomingMessage, OutgoingMessage, Server } from 'node:http';
2
2
  import { WebSocketServer } from 'ws';
3
3
  import { Counter } from '../util/counter.js';
4
4
  import type { SecurityScheme } from '../util/security.js';
@@ -11,6 +11,7 @@ declare class Context {
11
11
  constructor(server: Server, wss: WebSocketServer, counter: Counter);
12
12
  stop(): Promise<void>;
13
13
  }
14
+ type ConnectMiddleware = (req: IncomingMessage, res: OutgoingMessage, next: () => void) => Promise<void>;
14
15
  export declare class Yedra {
15
16
  private restRoutes;
16
17
  private wsRoutes;
@@ -33,6 +34,7 @@ export declare class Yedra {
33
34
  }): object;
34
35
  private static loadStatic;
35
36
  private performRequest;
37
+ private middlewareNext;
36
38
  listen(port: number, options?: {
37
39
  tls?: {
38
40
  key: string;
@@ -51,6 +53,10 @@ export declare class Yedra {
51
53
  * Prevents all normal output from Yedra. Mostly useful for tests.
52
54
  */
53
55
  quiet?: boolean;
56
+ /**
57
+ * Add Express/Connect compatible middleware.
58
+ */
59
+ connectMiddlewares?: ConnectMiddleware[];
54
60
  }): Promise<Context>;
55
61
  private static errorResponse;
56
62
  private matchRestRoute;
@@ -157,6 +157,16 @@ export class Yedra {
157
157
  return Yedra.errorResponse(500, 'Internal Server Error.');
158
158
  }
159
159
  }
160
+ middlewareNext(req, res, middlewares, last) {
161
+ if (middlewares.length > 0) {
162
+ // apply the next middleware
163
+ middlewares[0](req, res, () => this.middlewareNext(req, res, middlewares.slice(1), last));
164
+ }
165
+ else {
166
+ // no middlewares left, invoke yedra
167
+ last();
168
+ }
169
+ }
160
170
  async listen(port, options) {
161
171
  const staticFiles = await Yedra.loadStatic(options?.static);
162
172
  const server = options?.tls === undefined
@@ -166,41 +176,45 @@ export class Yedra {
166
176
  cert: options.tls.cert,
167
177
  });
168
178
  const counter = new Counter();
169
- server.on('request', async (req, res) => {
170
- counter.increment();
171
- const url = new URL(req.url, 'http://localhost');
172
- const begin = Date.now();
173
- const response = await this.performRequest(staticFiles, {
174
- method: req.method ?? 'GET',
175
- url,
176
- body: req,
177
- headers: req.headers,
178
- });
179
- const status = response.status ?? 200;
180
- if (response.body instanceof ReadableStream) {
181
- res.writeHead(status, response.headers);
182
- for await (const chunk of response.body) {
183
- res.write(chunk);
184
- }
185
- }
186
- else if (response.body instanceof Uint8Array) {
187
- res.writeHead(status, response.headers);
188
- res.write(response.body);
189
- }
190
- else {
191
- res.writeHead(status, {
192
- 'content-type': 'application/json',
193
- ...response.headers,
179
+ server.on('request', (req, res) => {
180
+ // first, invoke the middleware chain
181
+ this.middlewareNext(req, res, options?.connectMiddlewares ?? [], async () => {
182
+ // this will be called after all middlewares are done
183
+ counter.increment();
184
+ const url = new URL(req.url, 'http://localhost');
185
+ const begin = Date.now();
186
+ const response = await this.performRequest(staticFiles, {
187
+ method: req.method ?? 'GET',
188
+ url,
189
+ body: req,
190
+ headers: req.headers,
194
191
  });
195
- res.write(JSON.stringify(response.body));
196
- }
197
- res.end();
198
- const duration = Date.now() - begin;
199
- if (options?.quiet !== true) {
200
- console.log(`${req.method} ${url.pathname} -> ${status} (${duration}ms)`);
201
- }
202
- this.track(req.method, status, duration / 1000);
203
- counter.decrement();
192
+ const status = response.status ?? 200;
193
+ if (response.body instanceof ReadableStream) {
194
+ res.writeHead(status, response.headers);
195
+ for await (const chunk of response.body) {
196
+ res.write(chunk);
197
+ }
198
+ }
199
+ else if (response.body instanceof Uint8Array) {
200
+ res.writeHead(status, response.headers);
201
+ res.write(response.body);
202
+ }
203
+ else {
204
+ res.writeHead(status, {
205
+ 'content-type': 'application/json',
206
+ ...response.headers,
207
+ });
208
+ res.write(JSON.stringify(response.body));
209
+ }
210
+ res.end();
211
+ const duration = Date.now() - begin;
212
+ if (options?.quiet !== true) {
213
+ console.log(`${req.method} ${url.pathname} -> ${status} (${duration}ms)`);
214
+ }
215
+ this.track(req.method, status, duration / 1000);
216
+ counter.decrement();
217
+ });
204
218
  });
205
219
  const wss = new WebSocketServer({ server });
206
220
  wss.on('connection', async (ws, req) => {
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "yedra",
3
- "version": "0.14.2",
3
+ "version": "0.14.3",
4
4
  "repository": "github:0codekit/yedra",
5
5
  "main": "dist/index.js",
6
6
  "devDependencies": {
7
7
  "@biomejs/biome": "^1.9.4",
8
- "@types/bun": "^1.2.12",
9
- "@types/node": "^22.15.17",
8
+ "@types/bun": "^1.2.13",
9
+ "@types/node": "^22.15.18",
10
10
  "@types/uuid": "^10.0.0",
11
11
  "@types/ws": "^8.18.1",
12
12
  "typescript": "^5.8.3"