yedra 0.14.5 → 0.15.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.
@@ -11,6 +11,18 @@ declare class Context {
11
11
  constructor(server: Server, wss: WebSocketServer, counter: Counter);
12
12
  stop(): Promise<void>;
13
13
  }
14
+ type ServeResponse = {
15
+ status?: number;
16
+ body: Uint8Array | string;
17
+ headers?: Record<string, string>;
18
+ };
19
+ type ServeFallback = (req: {
20
+ href: string;
21
+ }) => ServeResponse | Promise<ServeResponse>;
22
+ type ServeConfig = {
23
+ dir: string;
24
+ fallback?: string | ServeFallback;
25
+ };
14
26
  type ConnectMiddleware = (req: IncomingMessage, res: ServerResponse, next: () => void) => void;
15
27
  export declare class Yedra {
16
28
  private restRoutes;
@@ -32,7 +44,7 @@ export declare class Yedra {
32
44
  url: string;
33
45
  }[];
34
46
  }): object;
35
- private static loadStatic;
47
+ private static loadServe;
36
48
  private performRequest;
37
49
  private middlewareNext;
38
50
  listen(port: number, options?: {
@@ -45,10 +57,7 @@ export declare class Yedra {
45
57
  path: string;
46
58
  get?: () => Promise<string> | string;
47
59
  };
48
- static?: {
49
- dir: string;
50
- fallback?: string;
51
- };
60
+ serve?: ServeConfig;
52
61
  /**
53
62
  * Prevents all normal output from Yedra. Mostly useful for tests.
54
63
  */
@@ -3,6 +3,7 @@ import { createServer as createHttpServer } from 'node:http';
3
3
  import { createServer as createHttpsServer } from 'node:https';
4
4
  import { extname, join } from 'node:path';
5
5
  import { URL } from 'node:url';
6
+ import { isUint8Array } from 'node:util/types';
6
7
  import mime from 'mime';
7
8
  import { WebSocketServer } from 'ws';
8
9
  import { Counter } from '../util/counter.js';
@@ -82,14 +83,17 @@ export class Yedra {
82
83
  paths,
83
84
  };
84
85
  }
85
- static async loadStatic(options) {
86
- if (options === undefined) {
87
- return new Map();
86
+ static async loadServe(config) {
87
+ if (config === undefined) {
88
+ return {
89
+ files: new Map(),
90
+ fallback: undefined,
91
+ };
88
92
  }
89
93
  const staticFiles = new Map();
90
- const files = await readdir(options.dir, { recursive: true });
94
+ const files = await readdir(config.dir, { recursive: true });
91
95
  await Promise.all(files.map(async (file) => {
92
- const absolute = join(options.dir, file);
96
+ const absolute = join(config.dir, file);
93
97
  if (!(await stat(absolute)).isFile()) {
94
98
  return;
95
99
  }
@@ -99,16 +103,30 @@ export class Yedra {
99
103
  mime: mime.getType(extname(file)) ?? 'application/octet-stream',
100
104
  });
101
105
  }));
102
- if (options.fallback) {
103
- const data = await readFile(options.fallback);
104
- staticFiles.set('__fallback', {
105
- data,
106
- mime: mime.getType(extname(options.fallback)) ?? 'application/octet-stream',
107
- });
106
+ if (config.fallback) {
107
+ if (typeof config.fallback === 'string') {
108
+ const data = await readFile(config.fallback);
109
+ staticFiles.set('__fallback', {
110
+ data,
111
+ mime: mime.getType(extname(config.fallback)) ??
112
+ 'application/octet-stream',
113
+ });
114
+ return {
115
+ files: staticFiles,
116
+ fallback: undefined,
117
+ };
118
+ }
119
+ return {
120
+ files: staticFiles,
121
+ fallback: config.fallback,
122
+ };
108
123
  }
109
- return staticFiles;
124
+ return {
125
+ files: staticFiles,
126
+ fallback: undefined,
127
+ };
110
128
  }
111
- async performRequest(staticFiles, req) {
129
+ async performRequest(serveData, req) {
112
130
  if (req.method !== 'GET' &&
113
131
  req.method !== 'POST' &&
114
132
  req.method !== 'PUT' &&
@@ -120,7 +138,8 @@ export class Yedra {
120
138
  // no matching route found
121
139
  if (req.method === 'GET') {
122
140
  // look for a static file
123
- const staticFile = staticFiles.get(req.url.pathname) ?? staticFiles.get('__fallback');
141
+ const staticFile = serveData.files.get(req.url.pathname) ??
142
+ serveData.files.get('__fallback');
124
143
  if (staticFile !== undefined) {
125
144
  return {
126
145
  status: 200,
@@ -130,6 +149,25 @@ export class Yedra {
130
149
  },
131
150
  };
132
151
  }
152
+ if (serveData.fallback !== undefined) {
153
+ try {
154
+ const response = await serveData.fallback({ href: req.url.href });
155
+ return {
156
+ status: response.status ?? 200,
157
+ body: isUint8Array(response.body)
158
+ ? response.body
159
+ : Buffer.from(response.body, 'utf-8'),
160
+ headers: response.headers,
161
+ };
162
+ }
163
+ catch (error) {
164
+ if (error instanceof HttpError) {
165
+ return Yedra.errorResponse(error.status, error.message);
166
+ }
167
+ console.error(error);
168
+ return Yedra.errorResponse(500, 'Internal Server Error.');
169
+ }
170
+ }
133
171
  }
134
172
  if (match.invalidMethod) {
135
173
  // we found a route, but it did not match the request method
@@ -168,7 +206,7 @@ export class Yedra {
168
206
  }
169
207
  }
170
208
  async listen(port, options) {
171
- const staticFiles = await Yedra.loadStatic(options?.static);
209
+ const serveData = await Yedra.loadServe(options?.serve);
172
210
  const server = options?.tls === undefined
173
211
  ? createHttpServer()
174
212
  : createHttpsServer({
@@ -183,7 +221,7 @@ export class Yedra {
183
221
  counter.increment();
184
222
  const url = new URL(req.url, 'http://localhost');
185
223
  const begin = Date.now();
186
- const response = await this.performRequest(staticFiles, {
224
+ const response = await this.performRequest(serveData, {
187
225
  method: req.method ?? 'GET',
188
226
  url,
189
227
  body: req,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yedra",
3
- "version": "0.14.5",
3
+ "version": "0.15.1",
4
4
  "repository": "github:0codekit/yedra",
5
5
  "main": "dist/index.js",
6
6
  "devDependencies": {