spooder 4.0.2 → 4.1.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.
package/README.md CHANGED
@@ -56,6 +56,7 @@ If there are any issues with the provided configuration, a warning will be print
56
56
  The `CLI` component of `spooder` is a global command-line tool for running server processes.
57
57
 
58
58
  - [CLI > Usage](#cli-usage)
59
+ - [CLI > Dev Mode](#cli-dev-mode)
59
60
  - [CLI > Auto Restart](#cli-auto-restart)
60
61
  - [CLI > Auto Update](#cli-auto-update)
61
62
  - [CLI > Canary](#cli-canary)
@@ -94,6 +95,33 @@ While `spooder` uses a `bun run` command by default, it is possible to use any c
94
95
  }
95
96
  }
96
97
  ```
98
+
99
+ <a id="cli-dev-mode"></a>
100
+ ## CLI > Dev Mode
101
+
102
+ `spooder` can be started in development mode by providing the `--dev` flag when starting the server.
103
+
104
+ ```bash
105
+ spooder --dev
106
+ ```
107
+
108
+ The following differences will be observed when running in development mode:
109
+
110
+ - Update commands defined in `spooder.update` will not be executed when starting a server.
111
+ - If the server crashes and `auto_restart` is enabled, the server will not be restarted, and spooder will exit with the same exit code as the server.
112
+ - If canary is configured, reports will not be dispatched to GitHub and instead be printed to the console; this includes crash reports.
113
+
114
+ It is possible to detect in userland if a server is running in development mode by checking the `SPOODER_ENV` environment variable.
115
+
116
+ ```ts
117
+ if (process.env.SPOODER_DEV === 'dev') {
118
+ // Server is running in development mode.
119
+ }
120
+ ```
121
+
122
+ > [!NOTE]
123
+ > `SPOODER_ENV` should be either `dev` or `prod`. If the variable is not defined, the server was not started by the `spooder` CLI.
124
+
97
125
  <a id="cli-auto-restart"></a>
98
126
  ## CLI > Auto Restart
99
127
 
@@ -579,7 +607,7 @@ server.default((req, status_code) => {
579
607
  Register a handler for uncaught errors.
580
608
 
581
609
  > [!NOTE]
582
- > This handler does not accept asynchronous functions and must return a `Response` object.
610
+ > Unlike other handlers, this should only return `Response` or `Promise<Response>`.
583
611
  ```ts
584
612
  server.error((err, req, url) => {
585
613
  return new Response('Custom Internal Server Error Message', { status: 500 });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "spooder",
3
3
  "type": "module",
4
- "version": "4.0.2",
4
+ "version": "4.1.1",
5
5
  "exports": {
6
6
  ".": {
7
7
  "bun": "./src/api.ts",
package/src/api.d.ts CHANGED
@@ -43,7 +43,7 @@ type JsonSerializable = JsonPrimitive | JsonObject | JsonArray | ToJson;
43
43
  type HandlerReturnType = Resolvable<string | number | BunFile | Response | JsonSerializable | Blob>;
44
44
  type RequestHandler = (req: Request, url: URL) => HandlerReturnType;
45
45
  type WebhookHandler = (payload: JsonSerializable) => HandlerReturnType;
46
- type ErrorHandler = (err: Error, req: Request, url: URL) => Response;
46
+ type ErrorHandler = (err: Error, req: Request, url: URL) => Resolvable<Response>;
47
47
  type DefaultHandler = (req: Request, status_code: number) => HandlerReturnType;
48
48
  type StatusCodeHandler = (req: Request) => HandlerReturnType;
49
49
  type ServerSentEventClient = {
package/src/api.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { dispatch_report } from './dispatch';
2
- import { get_config } from './config';
3
2
  import http from 'node:http';
4
3
  import path from 'node:path';
5
4
  import fs from 'node:fs/promises';
@@ -72,7 +71,13 @@ async function handle_error(prefix: string, err_message_or_obj: string | object,
72
71
  }
73
72
  }
74
73
 
75
- await dispatch_report(prefix + error_message, final_err);
74
+ if (process.env.SPOODER_ENV === 'dev') {
75
+ log('[dev] dispatch_report %s', prefix + error_message);
76
+ log('[dev] without --dev, this would raise a canary report');
77
+ log('[dev] %o', final_err);
78
+ } else {
79
+ await dispatch_report(prefix + error_message, final_err);
80
+ }
76
81
  }
77
82
 
78
83
  export async function panic(err_message_or_obj: string | object, ...err: object[]): Promise<void> {
@@ -244,7 +249,7 @@ type JsonSerializable = JsonPrimitive | JsonObject | JsonArray | ToJson;
244
249
  type HandlerReturnType = Resolvable<string | number | BunFile | Response | JsonSerializable | Blob>;
245
250
  type RequestHandler = (req: Request, url: URL) => HandlerReturnType;
246
251
  type WebhookHandler = (payload: JsonSerializable) => HandlerReturnType;
247
- type ErrorHandler = (err: Error, req: Request, url: URL) => Response;
252
+ type ErrorHandler = (err: Error, req: Request, url: URL) => Resolvable<Response>;
248
253
  type DefaultHandler = (req: Request, status_code: number) => HandlerReturnType;
249
254
  type StatusCodeHandler = (req: Request) => HandlerReturnType;
250
255
 
@@ -408,7 +413,7 @@ export function serve(port: number) {
408
413
  return new Response(http.STATUS_CODES[status_code], { status: status_code });
409
414
  } catch (e) {
410
415
  if (error_handler !== undefined)
411
- return error_handler(e as Error, req, url);
416
+ return await error_handler(e as Error, req, url);
412
417
 
413
418
  return new Response(http.STATUS_CODES[500], { status: 500 });
414
419
  }
package/src/cli.ts CHANGED
@@ -6,34 +6,44 @@ import { dispatch_report } from './dispatch';
6
6
  async function start_server() {
7
7
  log('start_server');
8
8
 
9
+ const argv = process.argv.slice(2);
10
+ const is_dev_mode = argv.includes('--dev');
11
+
12
+ if (is_dev_mode)
13
+ log('[dev] spooder has been started in dev mode');
14
+
9
15
  const config = await get_config();
10
16
 
11
- const update_commands = config.update;
12
- const n_update_commands = update_commands.length;
17
+ if (!is_dev_mode) {
18
+ const update_commands = config.update;
19
+ const n_update_commands = update_commands.length;
13
20
 
14
- if (n_update_commands > 0) {
15
- log('running %d update commands', n_update_commands);
21
+ if (n_update_commands > 0) {
22
+ log('running %d update commands', n_update_commands);
16
23
 
17
- for (let i = 0; i < n_update_commands; i++) {
18
- const config_update_command = update_commands[i];
24
+ for (let i = 0; i < n_update_commands; i++) {
25
+ const config_update_command = update_commands[i];
19
26
 
20
- log('[%d] %s', i, config_update_command);
27
+ log('[%d] %s', i, config_update_command);
21
28
 
22
- const update_proc = Bun.spawn(parse_command_line(config_update_command), {
23
- cwd: process.cwd(),
24
- stdout: 'inherit',
25
- stderr: 'inherit'
26
- });
29
+ const update_proc = Bun.spawn(parse_command_line(config_update_command), {
30
+ cwd: process.cwd(),
31
+ stdout: 'inherit',
32
+ stderr: 'inherit'
33
+ });
27
34
 
28
- await update_proc.exited;
35
+ await update_proc.exited;
29
36
 
30
- log('[%d] exited with code %d', i, update_proc.exitCode);
37
+ log('[%d] exited with code %d', i, update_proc.exitCode);
31
38
 
32
- if (update_proc.exitCode !== 0) {
33
- log('aborting update due to non-zero exit code from [%d]', i);
34
- break;
39
+ if (update_proc.exitCode !== 0) {
40
+ log('aborting update due to non-zero exit code from [%d]', i);
41
+ break;
42
+ }
35
43
  }
36
44
  }
45
+ } else {
46
+ log('[dev] skipping update commands in dev mode');
37
47
  }
38
48
 
39
49
  const crash_console_history = config.canary.crash_console_history;
@@ -42,6 +52,7 @@ async function start_server() {
42
52
  const std_mode = include_crash_history ? 'pipe' : 'inherit';
43
53
  const proc = Bun.spawn(parse_command_line(config.run), {
44
54
  cwd: process.cwd(),
55
+ env: { ...process.env, SPOODER_ENV: is_dev_mode ? 'dev' : 'prod' },
45
56
  stdout: std_mode,
46
57
  stderr: std_mode
47
58
  });
@@ -79,16 +90,27 @@ async function start_server() {
79
90
 
80
91
  if (proc_exit_code !== 0) {
81
92
  const console_output = include_crash_history ? strip_color_codes(stream_history.join('\n')) : undefined;
82
- dispatch_report('crash: server exited unexpectedly', [{
83
- proc_exit_code, console_output
84
- }]);
93
+
94
+ if (is_dev_mode) {
95
+ log('[dev] crash: server exited unexpectedly (exit code %d)', proc_exit_code);
96
+ log('[dev] without --dev, this would raise a canary report');
97
+ log('[dev] console output:\n%s', console_output);
98
+ } else {
99
+ dispatch_report('crash: server exited unexpectedly', [{
100
+ proc_exit_code, console_output
101
+ }]);
102
+ }
85
103
  }
86
-
87
104
 
88
105
  const auto_restart_ms = config.auto_restart;
89
106
  if (auto_restart_ms > -1) {
90
- log('restarting server in %dms', auto_restart_ms);
91
- setTimeout(start_server, auto_restart_ms);
107
+ if (is_dev_mode) {
108
+ log('[dev] auto-restart is disabled in dev mode');
109
+ process.exit(proc_exit_code ?? 0);
110
+ } else {
111
+ log('restarting server in %dms', auto_restart_ms);
112
+ setTimeout(start_server, auto_restart_ms);
113
+ }
92
114
  }
93
115
  }
94
116