spooder 3.2.0 → 3.2.2

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
@@ -613,6 +613,14 @@ server.dir('/content', './public/content', { index: 'index.html' });
613
613
 
614
614
  The above will serve `./public/content/index.html` when `/content` is requested.
615
615
 
616
+ #### `server.stop(method: ServerStop)`
617
+
618
+ The `stop` function allows you to stop the server. `method` is one of `ServerStop.IMMEDIATE` or `ServerStop.GRACEFUL`.
619
+
620
+ `ServerStop.GRACEFUL` will stop accepting new requests and wait for all in-flight requests to complete before stopping the server. This is the default behavior.
621
+
622
+ `ServerStop.IMMEDIATE` will immediately stop the server, terminating all in-flight requests.
623
+
616
624
  ---
617
625
 
618
626
  #### `route_location(redirect_url: string)`
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "spooder",
3
3
  "type": "module",
4
- "version": "3.2.0",
4
+ "version": "3.2.2",
5
5
  "exports": {
6
6
  ".": {
7
7
  "bun": "./src/api.ts",
package/src/api.d.ts CHANGED
@@ -13,6 +13,13 @@ type DirOptions = {
13
13
  };
14
14
  /** Built-in route handler for redirecting to a different URL. */
15
15
  export declare function route_location(redirect_url: string): (req: Request, url: URL) => Response;
16
+ export declare const ServerStop: {
17
+ /** Stops the server immediately, terminating in-flight requests. */
18
+ IMMEDIATE: number;
19
+ /** Stops the server after all in-flight requests have completed. */
20
+ GRACEFUL: number;
21
+ };
22
+ type ServerStop = typeof ServerStop[keyof typeof ServerStop];
16
23
  export declare function serve(port: number): {
17
24
  /** Register a handler for a specific route. */
18
25
  route: (path: string, handler: RequestHandler) => void;
@@ -24,5 +31,7 @@ export declare function serve(port: number): {
24
31
  handle: (status_code: number, handler: StatusCodeHandler) => void;
25
32
  /** Register a handler for uncaught errors. */
26
33
  error: (handler: ErrorHandler) => void;
34
+ /** Stops the server. */
35
+ stop: (method?: ServerStop) => void;
27
36
  };
28
37
  export {};
package/src/api.ts CHANGED
@@ -98,6 +98,21 @@ function route_directory(route_path: string, dir: string, options: DirOptions):
98
98
  };
99
99
  }
100
100
 
101
+ export const ServerStop = {
102
+ /** Stops the server immediately, terminating in-flight requests. */
103
+ IMMEDIATE: 0,
104
+
105
+ /** Stops the server after all in-flight requests have completed. */
106
+ GRACEFUL: 1
107
+ };
108
+
109
+ type ServerStop = typeof ServerStop[keyof typeof ServerStop];
110
+
111
+ function print_request_info(req: Request, res: Response, url: URL): Response {
112
+ console.log(`[${res.status}] ${req.method} ${url.pathname}`);
113
+ return res;
114
+ }
115
+
101
116
  export function serve(port: number) {
102
117
  const routes = new Map<string[], RequestHandler>();
103
118
  const handlers = new Map<number, StatusCodeHandler>();
@@ -136,76 +151,74 @@ export function serve(port: number) {
136
151
  const url = new URL(req.url);
137
152
  let status_code = 200;
138
153
 
139
- console.log(`${req.method} ${url.pathname}`);
154
+ try {
155
+ const route_array = url.pathname.split('/').filter(e => !(e === '..' || e === '.'));
156
+ let handler: RequestHandler | undefined;
140
157
 
141
- const route_array = url.pathname.split('/').filter(e => !(e === '..' || e === '.'));
142
- let handler: RequestHandler | undefined;
158
+ for (const [path, route_handler] of routes) {
159
+ const is_trailing_wildcard = path[path.length - 1] === '*';
160
+ if (!is_trailing_wildcard && path.length !== route_array.length)
161
+ continue;
143
162
 
144
- for (const [path, route_handler] of routes) {
145
- const is_trailing_wildcard = path[path.length - 1] === '*';
146
- if (!is_trailing_wildcard && path.length !== route_array.length)
147
- continue;
163
+ let match = true;
164
+ for (let i = 0; i < path.length; i++) {
165
+ const path_part = path[i];
148
166
 
149
- let match = true;
150
- for (let i = 0; i < path.length; i++) {
151
- const path_part = path[i];
167
+ if (path_part === '*')
168
+ continue;
152
169
 
153
- if (path_part === '*')
154
- continue;
170
+ if (path_part.startsWith(':')) {
171
+ url.searchParams.append(path_part.slice(1), route_array[i]);
172
+ continue;
173
+ }
155
174
 
156
- if (path_part.startsWith(':')) {
157
- url.searchParams.append(path_part.slice(1), route_array[i]);
158
- continue;
175
+ if (path_part !== route_array[i]) {
176
+ match = false;
177
+ break;
178
+ }
159
179
  }
160
180
 
161
- if (path_part !== route_array[i]) {
162
- match = false;
181
+ if (match) {
182
+ handler = route_handler;
163
183
  break;
164
184
  }
165
185
  }
166
186
 
167
- if (match) {
168
- handler = route_handler;
169
- break;
187
+ // Check for a handler for the route.
188
+ if (handler !== undefined) {
189
+ const response = await resolve_handler(handler(req, url), status_code, true);
190
+ if (response instanceof Response)
191
+ return print_request_info(req, response, url);
192
+
193
+ // If the handler returned a status code, use that instead.
194
+ status_code = response;
195
+ } else {
196
+ status_code = 404;
170
197
  }
171
- }
172
198
 
173
- // Check for a handler for the route.
174
- if (handler !== undefined) {
175
- const response = await resolve_handler(handler(req, url), status_code, true);
176
- if (response instanceof Response)
177
- return response;
199
+ // Fallback to checking for a handler for the status code.
200
+ const status_code_handler = handlers.get(status_code);
201
+ if (status_code_handler !== undefined) {
202
+ const response = await resolve_handler(status_code_handler(req), status_code);
203
+ if (response instanceof Response)
204
+ return print_request_info(req, response, url);
205
+ }
178
206
 
179
- // If the handler returned a status code, use that instead.
180
- status_code = response;
181
- } else {
182
- status_code = 404;
183
- }
207
+ // Fallback to the default handler, if any.
208
+ if (default_handler !== undefined) {
209
+ const response = await resolve_handler(default_handler(req, status_code), status_code);
210
+ if (response instanceof Response)
211
+ return print_request_info(req, response, url);
212
+ }
184
213
 
185
- // Fallback to checking for a handler for the status code.
186
- const status_code_handler = handlers.get(status_code);
187
- if (status_code_handler !== undefined) {
188
- const response = await resolve_handler(status_code_handler(req), status_code);
189
- if (response instanceof Response)
190
- return response;
191
- }
214
+ // Fallback to returning a basic response.
215
+ return print_request_info(req, new Response(http.STATUS_CODES[status_code], { status: status_code }), url);
216
+ } catch (e) {
217
+ if (error_handler !== undefined)
218
+ return print_request_info(req, error_handler(e as Error), url);
192
219
 
193
- // Fallback to the default handler, if any.
194
- if (default_handler !== undefined) {
195
- const response = await resolve_handler(default_handler(req, status_code), status_code);
196
- if (response instanceof Response)
197
- return response;
220
+ return print_request_info(req, new Response(http.STATUS_CODES[500], { status: 500 }), url);
198
221
  }
199
-
200
- // Fallback to returning a basic response.
201
- return new Response(http.STATUS_CODES[status_code], { status: status_code });
202
- },
203
-
204
- error(err: Error): Response {
205
- if (error_handler !== undefined)
206
- return error_handler(err);
207
-
208
- return new Response(http.STATUS_CODES[500], { status: 500 });
209
222
  }
210
223
  });
211
224
 
@@ -238,6 +251,11 @@ export function serve(port: number) {
238
251
  /** Register a handler for uncaught errors. */
239
252
  error: (handler: ErrorHandler): void => {
240
253
  error_handler = handler;
254
+ },
255
+
256
+ /** Stops the server. */
257
+ stop: (method: ServerStop = ServerStop.GRACEFUL): void => {
258
+ server.stop(method === ServerStop.IMMEDIATE);
241
259
  }
242
260
  }
243
261
  }