@chidchanun/bcp 0.1.22 → 0.1.24
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 +241 -640
- package/docs/README.md +114 -337
- package/docs/auth-route-guards.md +14 -0
- package/docs/developer-tools.md +83 -12
- package/docs/development-logging.md +234 -6
- package/docs/file-upload.md +280 -0
- package/docs/releases/0.1.22.md +66 -1
- package/docs/releases/0.1.23.md +131 -0
- package/docs/releases/0.1.24.md +166 -0
- package/package.json +3 -2
- package/packages/bundler/src/server-production-actions.ts +15 -0
- package/packages/bundler/src/server-production-guards.ts +15 -0
- package/packages/cli/bin/bcp.mjs +111 -0
- package/packages/client/src/form.tsx +20 -13
- package/packages/client/src/server.ts +31 -0
- package/packages/server/src/dev-hmr.ts +131 -9
- package/packages/server/src/dev-route-graph.ts +91 -0
- package/packages/server/src/logger.ts +474 -0
- package/packages/server/src/middleware-dev-server.ts +217 -9
- package/packages/server/src/upload.ts +556 -0
|
@@ -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(
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export interface DevRouteGraphEntry {
|
|
2
|
+
pathname: string;
|
|
3
|
+
filePath: string;
|
|
4
|
+
layouts: string[];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function hasDevClientRouteGraphChanged(
|
|
8
|
+
currentRoutes: DevRouteGraphEntry[],
|
|
9
|
+
nextRoutes: DevRouteGraphEntry[]
|
|
10
|
+
): boolean {
|
|
11
|
+
if (
|
|
12
|
+
currentRoutes.length !==
|
|
13
|
+
nextRoutes.length
|
|
14
|
+
) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const current =
|
|
19
|
+
normalizeRouteGraph(
|
|
20
|
+
currentRoutes
|
|
21
|
+
);
|
|
22
|
+
const next =
|
|
23
|
+
normalizeRouteGraph(
|
|
24
|
+
nextRoutes
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
for (
|
|
28
|
+
let index = 0;
|
|
29
|
+
index < current.length;
|
|
30
|
+
index++
|
|
31
|
+
) {
|
|
32
|
+
const left =
|
|
33
|
+
current[index];
|
|
34
|
+
const right =
|
|
35
|
+
next[index];
|
|
36
|
+
|
|
37
|
+
if (
|
|
38
|
+
left.pathname !==
|
|
39
|
+
right.pathname ||
|
|
40
|
+
left.filePath !==
|
|
41
|
+
right.filePath ||
|
|
42
|
+
left.layouts.length !==
|
|
43
|
+
right.layouts.length
|
|
44
|
+
) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
for (
|
|
49
|
+
let layoutIndex = 0;
|
|
50
|
+
layoutIndex <
|
|
51
|
+
left.layouts.length;
|
|
52
|
+
layoutIndex++
|
|
53
|
+
) {
|
|
54
|
+
if (
|
|
55
|
+
left.layouts[
|
|
56
|
+
layoutIndex
|
|
57
|
+
] !==
|
|
58
|
+
right.layouts[
|
|
59
|
+
layoutIndex
|
|
60
|
+
]
|
|
61
|
+
) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function normalizeRouteGraph(
|
|
71
|
+
routes: DevRouteGraphEntry[]
|
|
72
|
+
): DevRouteGraphEntry[] {
|
|
73
|
+
return routes
|
|
74
|
+
.map(
|
|
75
|
+
(route) => ({
|
|
76
|
+
pathname:
|
|
77
|
+
route.pathname,
|
|
78
|
+
filePath:
|
|
79
|
+
route.filePath,
|
|
80
|
+
layouts: [
|
|
81
|
+
...route.layouts,
|
|
82
|
+
],
|
|
83
|
+
})
|
|
84
|
+
)
|
|
85
|
+
.sort(
|
|
86
|
+
(left, right) =>
|
|
87
|
+
left.pathname.localeCompare(
|
|
88
|
+
right.pathname
|
|
89
|
+
)
|
|
90
|
+
);
|
|
91
|
+
}
|