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 +29 -1
- package/package.json +1 -1
- package/src/api.d.ts +1 -1
- package/src/api.ts +9 -4
- package/src/cli.ts +45 -23
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
|
-
>
|
|
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
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
|
-
|
|
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
|
-
|
|
12
|
-
|
|
17
|
+
if (!is_dev_mode) {
|
|
18
|
+
const update_commands = config.update;
|
|
19
|
+
const n_update_commands = update_commands.length;
|
|
13
20
|
|
|
14
|
-
|
|
15
|
-
|
|
21
|
+
if (n_update_commands > 0) {
|
|
22
|
+
log('running %d update commands', n_update_commands);
|
|
16
23
|
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
for (let i = 0; i < n_update_commands; i++) {
|
|
25
|
+
const config_update_command = update_commands[i];
|
|
19
26
|
|
|
20
|
-
|
|
27
|
+
log('[%d] %s', i, config_update_command);
|
|
21
28
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
35
|
+
await update_proc.exited;
|
|
29
36
|
|
|
30
|
-
|
|
37
|
+
log('[%d] exited with code %d', i, update_proc.exitCode);
|
|
31
38
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
83
|
-
|
|
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
|
-
|
|
91
|
-
|
|
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
|
|