@chidchanun/bcp 0.1.21 → 0.1.23
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 +38 -2
- package/docs/README.md +67 -11
- package/docs/developer-tools.md +166 -0
- package/docs/development-logging.md +234 -6
- package/docs/releases/0.1.22.md +142 -0
- package/docs/releases/0.1.23.md +131 -0
- package/package.json +3 -2
- package/packages/cli/bin/bcp.mjs +111 -0
- package/packages/cli/src/args.ts +32 -0
- package/packages/cli/src/developer-tools.ts +1249 -0
- package/packages/cli/src/index.ts +74 -0
- package/packages/client/src/form.tsx +20 -13
- package/packages/client/src/server.ts +15 -0
- package/packages/server/src/dev-hmr.ts +131 -9
- package/packages/server/src/logger.ts +474 -0
- package/packages/server/src/production-server.ts +0 -1746
- package/packages/server/src/standalone-production-runtime.ts +0 -1951
|
@@ -71,6 +71,20 @@ switch (cliOptions.command) {
|
|
|
71
71
|
break;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
case "doctor": {
|
|
75
|
+
await runDeveloperCommand(
|
|
76
|
+
"doctor"
|
|
77
|
+
);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
case "inspect": {
|
|
82
|
+
await runDeveloperCommand(
|
|
83
|
+
"inspect"
|
|
84
|
+
);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
|
|
74
88
|
case "help": {
|
|
75
89
|
printHelp();
|
|
76
90
|
break;
|
|
@@ -466,6 +480,59 @@ async function runDatabaseCommand() {
|
|
|
466
480
|
}
|
|
467
481
|
}
|
|
468
482
|
|
|
483
|
+
async function runDeveloperCommand(
|
|
484
|
+
command:
|
|
485
|
+
"doctor" |
|
|
486
|
+
"inspect"
|
|
487
|
+
): Promise<void> {
|
|
488
|
+
const rootDirectory =
|
|
489
|
+
resolveProjectRoot(
|
|
490
|
+
cliOptions.rootDirectory
|
|
491
|
+
);
|
|
492
|
+
|
|
493
|
+
const {
|
|
494
|
+
runDoctor,
|
|
495
|
+
runInspect,
|
|
496
|
+
} =
|
|
497
|
+
await import(
|
|
498
|
+
"./developer-tools.js"
|
|
499
|
+
);
|
|
500
|
+
|
|
501
|
+
const options = {
|
|
502
|
+
rootDirectory,
|
|
503
|
+
frameworkVersion:
|
|
504
|
+
FRAMEWORK_VERSION,
|
|
505
|
+
json:
|
|
506
|
+
cliOptions.json,
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
if (
|
|
510
|
+
command === "doctor"
|
|
511
|
+
) {
|
|
512
|
+
await runDoctor(
|
|
513
|
+
options
|
|
514
|
+
);
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
try {
|
|
519
|
+
await runInspect(
|
|
520
|
+
options
|
|
521
|
+
);
|
|
522
|
+
} catch (error) {
|
|
523
|
+
if (
|
|
524
|
+
cliOptions.json &&
|
|
525
|
+
error instanceof Error &&
|
|
526
|
+
error.name ===
|
|
527
|
+
"DeveloperToolJsonError"
|
|
528
|
+
) {
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
throw error;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
469
536
|
function installShutdownHandlers(
|
|
470
537
|
server: {
|
|
471
538
|
stop(): Promise<void>;
|
|
@@ -642,6 +709,8 @@ Commands:
|
|
|
642
709
|
routes Print discovered page and API routes
|
|
643
710
|
update [target] Update BCP Framework (default target: latest)
|
|
644
711
|
db <command> Manage database migrations
|
|
712
|
+
doctor Run project/runtime health diagnostics
|
|
713
|
+
inspect Print resolved env, config, dependencies and routes
|
|
645
714
|
help Show this help message
|
|
646
715
|
version Show framework version
|
|
647
716
|
|
|
@@ -652,6 +721,7 @@ Options:
|
|
|
652
721
|
--host <host> Alias for --hostname
|
|
653
722
|
--check Check for a BCP update without changing files
|
|
654
723
|
--dry-run Preview a BCP update without changing files
|
|
724
|
+
--json JSON output for doctor/inspect
|
|
655
725
|
-h, --help Show help
|
|
656
726
|
-v, --version Show version
|
|
657
727
|
|
|
@@ -664,6 +734,10 @@ Examples:
|
|
|
664
734
|
bcp build
|
|
665
735
|
bcp start
|
|
666
736
|
bcp routes
|
|
737
|
+
bcp doctor
|
|
738
|
+
bcp doctor --json
|
|
739
|
+
bcp inspect
|
|
740
|
+
bcp inspect --json
|
|
667
741
|
bcp update
|
|
668
742
|
bcp update --check
|
|
669
743
|
bcp db create create_users
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createContext,
|
|
3
|
+
createElement,
|
|
3
4
|
useContext,
|
|
4
5
|
useMemo,
|
|
5
6
|
useState,
|
|
@@ -320,19 +321,25 @@ export function Form({
|
|
|
320
321
|
null
|
|
321
322
|
);
|
|
322
323
|
|
|
323
|
-
return (
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
324
|
+
return createElement(
|
|
325
|
+
FormRuntimeContext.Provider,
|
|
326
|
+
{
|
|
327
|
+
value:
|
|
328
|
+
runtimeState,
|
|
329
|
+
},
|
|
330
|
+
createElement(
|
|
331
|
+
"form",
|
|
332
|
+
{
|
|
333
|
+
...props,
|
|
334
|
+
action:
|
|
335
|
+
progressiveAction,
|
|
336
|
+
method:
|
|
337
|
+
"post",
|
|
338
|
+
onSubmit:
|
|
339
|
+
handleSubmit,
|
|
340
|
+
},
|
|
341
|
+
children
|
|
342
|
+
)
|
|
336
343
|
);
|
|
337
344
|
}
|
|
338
345
|
|
|
@@ -15,6 +15,21 @@ export {
|
|
|
15
15
|
type ResponseCookieOptions,
|
|
16
16
|
} from "../../server/src/request-context.js";
|
|
17
17
|
|
|
18
|
+
export {
|
|
19
|
+
attachRequestId,
|
|
20
|
+
createLogger,
|
|
21
|
+
logger,
|
|
22
|
+
requestLogger,
|
|
23
|
+
resolveEnvironmentLogFormat,
|
|
24
|
+
resolveEnvironmentLogLevel,
|
|
25
|
+
|
|
26
|
+
type LogFields,
|
|
27
|
+
type LogFormat,
|
|
28
|
+
type LogLevel,
|
|
29
|
+
type Logger,
|
|
30
|
+
type LoggerOptions,
|
|
31
|
+
} from "../../server/src/logger.js";
|
|
32
|
+
|
|
18
33
|
export {
|
|
19
34
|
json,
|
|
20
35
|
redirect,
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type * as http from "node:http";
|
|
2
2
|
|
|
3
|
+
import {
|
|
4
|
+
createLogger,
|
|
5
|
+
} from "./logger.js";
|
|
6
|
+
|
|
3
7
|
export const DEV_EVENTS_PATH =
|
|
4
8
|
"/_bcp/dev-events";
|
|
5
9
|
|
|
@@ -12,11 +16,28 @@ const INTERNAL_API_PATHS =
|
|
|
12
16
|
]);
|
|
13
17
|
|
|
14
18
|
const HTTP_REQUEST_LOG_PATTERN =
|
|
15
|
-
/^(?:\[bcp\]\s+)?(
|
|
19
|
+
/^(?:\[bcp\]\s+)?(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\s+(\S+)\s+(\d{3})\s+(\d+(?:\.\d+)?)ms$/i;
|
|
20
|
+
|
|
21
|
+
const TIMING_LOG_PATTERN =
|
|
22
|
+
/^(Import|SSR):\s+(\d+(?:\.\d+)?)ms$/i;
|
|
16
23
|
|
|
17
24
|
let requestLogFilterInstalled =
|
|
18
25
|
false;
|
|
19
26
|
|
|
27
|
+
export interface DevHttpRequestLog {
|
|
28
|
+
method: string;
|
|
29
|
+
path: string;
|
|
30
|
+
status: number;
|
|
31
|
+
durationMs: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type DevTimingLog = {
|
|
35
|
+
event:
|
|
36
|
+
| "module.import"
|
|
37
|
+
| "ssr.render";
|
|
38
|
+
durationMs: number;
|
|
39
|
+
};
|
|
40
|
+
|
|
20
41
|
export function shouldLogDevApiPath(
|
|
21
42
|
pathname: string
|
|
22
43
|
): boolean {
|
|
@@ -39,20 +60,73 @@ export function shouldLogDevApiPath(
|
|
|
39
60
|
);
|
|
40
61
|
}
|
|
41
62
|
|
|
42
|
-
export function
|
|
63
|
+
export function parseDevHttpRequestLog(
|
|
43
64
|
line: string
|
|
44
|
-
):
|
|
65
|
+
): DevHttpRequestLog | null {
|
|
45
66
|
const match =
|
|
46
67
|
HTTP_REQUEST_LOG_PATTERN.exec(
|
|
47
68
|
line.trim()
|
|
48
69
|
);
|
|
49
70
|
|
|
50
71
|
if (!match) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
method:
|
|
77
|
+
match[1].toUpperCase(),
|
|
78
|
+
path:
|
|
79
|
+
match[2],
|
|
80
|
+
status:
|
|
81
|
+
Number(
|
|
82
|
+
match[3]
|
|
83
|
+
),
|
|
84
|
+
durationMs:
|
|
85
|
+
Number(
|
|
86
|
+
match[4]
|
|
87
|
+
),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function parseDevTimingLog(
|
|
92
|
+
line: string
|
|
93
|
+
): DevTimingLog | null {
|
|
94
|
+
const match =
|
|
95
|
+
TIMING_LOG_PATTERN.exec(
|
|
96
|
+
line.trim()
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
if (!match) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
event:
|
|
105
|
+
match[1].toLowerCase() ===
|
|
106
|
+
"ssr"
|
|
107
|
+
? "ssr.render"
|
|
108
|
+
: "module.import",
|
|
109
|
+
durationMs:
|
|
110
|
+
Number(
|
|
111
|
+
match[2]
|
|
112
|
+
),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function shouldWriteDevConsoleLine(
|
|
117
|
+
line: string
|
|
118
|
+
): boolean {
|
|
119
|
+
const request =
|
|
120
|
+
parseDevHttpRequestLog(
|
|
121
|
+
line
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
if (!request) {
|
|
51
125
|
return true;
|
|
52
126
|
}
|
|
53
127
|
|
|
54
128
|
return shouldLogDevApiPath(
|
|
55
|
-
|
|
129
|
+
request.path
|
|
56
130
|
);
|
|
57
131
|
}
|
|
58
132
|
|
|
@@ -68,18 +142,66 @@ function installRequestLogFilter(): void {
|
|
|
68
142
|
console.log.bind(
|
|
69
143
|
console
|
|
70
144
|
);
|
|
145
|
+
const devLogger =
|
|
146
|
+
createLogger({
|
|
147
|
+
name:
|
|
148
|
+
"bcp-dev",
|
|
149
|
+
write(
|
|
150
|
+
line
|
|
151
|
+
) {
|
|
152
|
+
originalLog(
|
|
153
|
+
line
|
|
154
|
+
);
|
|
155
|
+
},
|
|
156
|
+
});
|
|
71
157
|
|
|
72
158
|
console.log = (
|
|
73
159
|
...args: unknown[]
|
|
74
160
|
) => {
|
|
75
161
|
if (
|
|
76
162
|
args.length === 1 &&
|
|
77
|
-
typeof args[0] === "string"
|
|
78
|
-
!shouldWriteDevConsoleLine(
|
|
79
|
-
args[0]
|
|
80
|
-
)
|
|
163
|
+
typeof args[0] === "string"
|
|
81
164
|
) {
|
|
82
|
-
|
|
165
|
+
const request =
|
|
166
|
+
parseDevHttpRequestLog(
|
|
167
|
+
args[0]
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
if (request) {
|
|
171
|
+
if (
|
|
172
|
+
shouldLogDevApiPath(
|
|
173
|
+
request.path
|
|
174
|
+
)
|
|
175
|
+
) {
|
|
176
|
+
devLogger.info(
|
|
177
|
+
"HTTP request",
|
|
178
|
+
{
|
|
179
|
+
event:
|
|
180
|
+
"http.request",
|
|
181
|
+
...request,
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const timing =
|
|
190
|
+
parseDevTimingLog(
|
|
191
|
+
args[0]
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
if (timing) {
|
|
195
|
+
devLogger.debug(
|
|
196
|
+
timing.event ===
|
|
197
|
+
"ssr.render"
|
|
198
|
+
? "SSR render"
|
|
199
|
+
: "Module import",
|
|
200
|
+
timing
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
83
205
|
}
|
|
84
206
|
|
|
85
207
|
originalLog(
|