@chidchanun/bcp 0.1.0
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/CHANGELOG.md +49 -0
- package/LICENSE +21 -0
- package/README.md +241 -0
- package/docs/caching.md +76 -0
- package/docs/configuration.md +97 -0
- package/docs/deployment.md +74 -0
- package/docs/getting-started.md +82 -0
- package/docs/middleware.md +58 -0
- package/docs/releasing.md +299 -0
- package/docs/routing.md +103 -0
- package/docs/security.md +57 -0
- package/package.json +68 -0
- package/packages/bundler/src/client-islands.ts +1457 -0
- package/packages/bundler/src/incremental-context.ts +206 -0
- package/packages/bundler/src/index.ts +1991 -0
- package/packages/bundler/src/module-graph.ts +317 -0
- package/packages/bundler/src/partial-hydration.ts +414 -0
- package/packages/bundler/src/production.ts +974 -0
- package/packages/bundler/src/server-production-middleware.ts +447 -0
- package/packages/bundler/src/server-production.ts +1193 -0
- package/packages/bundler/src/special-files.ts +131 -0
- package/packages/cache/src/index.ts +761 -0
- package/packages/cli/bin/bcp.mjs +93 -0
- package/packages/cli/src/args.ts +305 -0
- package/packages/cli/src/bootstrap.ts +514 -0
- package/packages/cli/src/index.ts +504 -0
- package/packages/cli/src/version.ts +45 -0
- package/packages/client/src/cache.ts +11 -0
- package/packages/client/src/config.ts +18 -0
- package/packages/client/src/error-boundary.tsx +149 -0
- package/packages/client/src/hydration.ts +3 -0
- package/packages/client/src/index.tsx +57 -0
- package/packages/client/src/islands.tsx +315 -0
- package/packages/client/src/metadata.ts +281 -0
- package/packages/client/src/navigation-loading.ts +52 -0
- package/packages/client/src/navigation-state.ts +80 -0
- package/packages/client/src/not-found.ts +34 -0
- package/packages/client/src/persistent-layout-runtime.ts +273 -0
- package/packages/client/src/router-v2.tsx +969 -0
- package/packages/client/src/router.tsx +1 -0
- package/packages/config/src/index.ts +1038 -0
- package/packages/env/src/index.ts +593 -0
- package/packages/router/src/advanced-router.ts +1032 -0
- package/packages/router/src/index.ts +1 -0
- package/packages/server/src/compression.ts +249 -0
- package/packages/server/src/dev-document-metadata.ts +154 -0
- package/packages/server/src/dev-hmr.ts +225 -0
- package/packages/server/src/index.ts +2265 -0
- package/packages/server/src/metadata.ts +478 -0
- package/packages/server/src/middleware-dev-server.ts +260 -0
- package/packages/server/src/middleware-loader.ts +140 -0
- package/packages/server/src/middleware-proxy.ts +516 -0
- package/packages/server/src/middleware.ts +704 -0
- package/packages/server/src/navigation-payload.ts +471 -0
- package/packages/server/src/production-server.ts +1746 -0
- package/packages/server/src/response-cache-proxy.ts +828 -0
- package/packages/server/src/security-proxy.ts +406 -0
- package/packages/server/src/security.ts +451 -0
- package/packages/server/src/standalone-production-runtime-v2.ts +2047 -0
- package/packages/server/src/standalone-production-runtime-v3.ts +250 -0
- package/packages/server/src/standalone-production-runtime-v4.ts +289 -0
- package/packages/server/src/standalone-production-runtime-v5.ts +289 -0
- package/packages/server/src/standalone-production-runtime.ts +1951 -0
- package/packages/server/src/standalone-production-server.ts +6 -0
- package/packages/server/src/static-assets.ts +262 -0
- package/packages/server/src/static-dev-server.ts +854 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import * as net from "node:net";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import {
|
|
5
|
+
pathToFileURL,
|
|
6
|
+
} from "node:url";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
assertMiddlewareModule,
|
|
10
|
+
} from "./middleware-loader.js";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
createMiddlewareProxy,
|
|
14
|
+
} from "./middleware-proxy.js";
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
createStandaloneProductionServer as createBaseStandaloneProductionServer,
|
|
18
|
+
type StandaloneApiRoute,
|
|
19
|
+
type StandalonePageRoute,
|
|
20
|
+
type StandaloneProductionServerOptions as BaseStandaloneProductionServerOptions,
|
|
21
|
+
} from "./standalone-production-runtime-v2.js";
|
|
22
|
+
|
|
23
|
+
import type {
|
|
24
|
+
MiddlewareModule,
|
|
25
|
+
} from "./middleware.js";
|
|
26
|
+
|
|
27
|
+
export type {
|
|
28
|
+
StandaloneApiRoute,
|
|
29
|
+
StandalonePageRoute,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export interface StandaloneProductionServerOptions
|
|
33
|
+
extends BaseStandaloneProductionServerOptions {}
|
|
34
|
+
|
|
35
|
+
export function createStandaloneProductionServer(
|
|
36
|
+
options: StandaloneProductionServerOptions
|
|
37
|
+
) {
|
|
38
|
+
let baseServer:
|
|
39
|
+
ReturnType<
|
|
40
|
+
typeof createBaseStandaloneProductionServer
|
|
41
|
+
> | null =
|
|
42
|
+
null;
|
|
43
|
+
|
|
44
|
+
let middlewareProxy:
|
|
45
|
+
ReturnType<
|
|
46
|
+
typeof createMiddlewareProxy
|
|
47
|
+
> | null =
|
|
48
|
+
null;
|
|
49
|
+
|
|
50
|
+
let started =
|
|
51
|
+
false;
|
|
52
|
+
|
|
53
|
+
async function start(): Promise<void> {
|
|
54
|
+
if (started) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const middlewareFile =
|
|
59
|
+
path.join(
|
|
60
|
+
options.buildDirectory,
|
|
61
|
+
"server",
|
|
62
|
+
"middleware.mjs"
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
if (
|
|
66
|
+
!fs.existsSync(
|
|
67
|
+
middlewareFile
|
|
68
|
+
)
|
|
69
|
+
) {
|
|
70
|
+
baseServer =
|
|
71
|
+
createBaseStandaloneProductionServer(
|
|
72
|
+
options
|
|
73
|
+
);
|
|
74
|
+
await baseServer.start();
|
|
75
|
+
started =
|
|
76
|
+
true;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const module =
|
|
81
|
+
await import(
|
|
82
|
+
pathToFileURL(
|
|
83
|
+
middlewareFile
|
|
84
|
+
).href
|
|
85
|
+
) as MiddlewareModule;
|
|
86
|
+
|
|
87
|
+
assertMiddlewareModule(
|
|
88
|
+
module,
|
|
89
|
+
middlewareFile
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const internalPort =
|
|
93
|
+
await findFreePort();
|
|
94
|
+
|
|
95
|
+
baseServer =
|
|
96
|
+
createBaseStandaloneProductionServer({
|
|
97
|
+
...options,
|
|
98
|
+
port:
|
|
99
|
+
internalPort,
|
|
100
|
+
hostname:
|
|
101
|
+
"127.0.0.1",
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
await baseServer.start();
|
|
105
|
+
|
|
106
|
+
middlewareProxy =
|
|
107
|
+
createMiddlewareProxy({
|
|
108
|
+
port:
|
|
109
|
+
options.port,
|
|
110
|
+
hostname:
|
|
111
|
+
options.hostname,
|
|
112
|
+
upstreamPort:
|
|
113
|
+
internalPort,
|
|
114
|
+
upstreamHostname:
|
|
115
|
+
"127.0.0.1",
|
|
116
|
+
getMiddleware:
|
|
117
|
+
() =>
|
|
118
|
+
module,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
await middlewareProxy.start();
|
|
123
|
+
} catch (error) {
|
|
124
|
+
await baseServer.stop();
|
|
125
|
+
baseServer =
|
|
126
|
+
null;
|
|
127
|
+
middlewareProxy =
|
|
128
|
+
null;
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
started =
|
|
133
|
+
true;
|
|
134
|
+
|
|
135
|
+
console.log(
|
|
136
|
+
`[BCP Middleware] Production gateway: http://${options.hostname}:${options.port}`
|
|
137
|
+
);
|
|
138
|
+
console.log(
|
|
139
|
+
`[BCP Middleware] Standalone module: ${middlewareFile}`
|
|
140
|
+
);
|
|
141
|
+
console.log("");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function stop(): Promise<void> {
|
|
145
|
+
if (middlewareProxy) {
|
|
146
|
+
await middlewareProxy.stop();
|
|
147
|
+
middlewareProxy =
|
|
148
|
+
null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (baseServer) {
|
|
152
|
+
await baseServer.stop();
|
|
153
|
+
baseServer =
|
|
154
|
+
null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
started =
|
|
158
|
+
false;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
start,
|
|
163
|
+
stop,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function findFreePort(): Promise<number> {
|
|
168
|
+
const server =
|
|
169
|
+
net.createServer();
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
await new Promise<void>(
|
|
173
|
+
(
|
|
174
|
+
resolve,
|
|
175
|
+
reject
|
|
176
|
+
) => {
|
|
177
|
+
const onError =
|
|
178
|
+
(error: Error) => {
|
|
179
|
+
server.off(
|
|
180
|
+
"listening",
|
|
181
|
+
onListening
|
|
182
|
+
);
|
|
183
|
+
reject(
|
|
184
|
+
error
|
|
185
|
+
);
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const onListening =
|
|
189
|
+
() => {
|
|
190
|
+
server.off(
|
|
191
|
+
"error",
|
|
192
|
+
onError
|
|
193
|
+
);
|
|
194
|
+
resolve();
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
server.once(
|
|
198
|
+
"error",
|
|
199
|
+
onError
|
|
200
|
+
);
|
|
201
|
+
server.once(
|
|
202
|
+
"listening",
|
|
203
|
+
onListening
|
|
204
|
+
);
|
|
205
|
+
server.listen(
|
|
206
|
+
0,
|
|
207
|
+
"127.0.0.1"
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
const address =
|
|
213
|
+
server.address();
|
|
214
|
+
|
|
215
|
+
if (
|
|
216
|
+
!address ||
|
|
217
|
+
typeof address ===
|
|
218
|
+
"string"
|
|
219
|
+
) {
|
|
220
|
+
throw new Error(
|
|
221
|
+
"BCP Framework: could not allocate middleware production port."
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return address.port;
|
|
226
|
+
} finally {
|
|
227
|
+
if (
|
|
228
|
+
server.listening
|
|
229
|
+
) {
|
|
230
|
+
await new Promise<void>(
|
|
231
|
+
(
|
|
232
|
+
resolve,
|
|
233
|
+
reject
|
|
234
|
+
) => {
|
|
235
|
+
server.close(
|
|
236
|
+
(error) => {
|
|
237
|
+
if (error) {
|
|
238
|
+
reject(
|
|
239
|
+
error
|
|
240
|
+
);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
resolve();
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import * as net from "node:net";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
createResponseCacheProxy,
|
|
7
|
+
type ResponseCacheManifest,
|
|
8
|
+
} from "./response-cache-proxy.js";
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
createStandaloneProductionServer as createBaseStandaloneProductionServer,
|
|
12
|
+
type StandaloneApiRoute,
|
|
13
|
+
type StandalonePageRoute,
|
|
14
|
+
type StandaloneProductionServerOptions as BaseStandaloneProductionServerOptions,
|
|
15
|
+
} from "./standalone-production-runtime-v3.js";
|
|
16
|
+
|
|
17
|
+
export type {
|
|
18
|
+
StandaloneApiRoute,
|
|
19
|
+
StandalonePageRoute,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export interface StandaloneProductionServerOptions
|
|
23
|
+
extends BaseStandaloneProductionServerOptions {}
|
|
24
|
+
|
|
25
|
+
export function createStandaloneProductionServer(
|
|
26
|
+
options: StandaloneProductionServerOptions
|
|
27
|
+
) {
|
|
28
|
+
let baseServer:
|
|
29
|
+
ReturnType<
|
|
30
|
+
typeof createBaseStandaloneProductionServer
|
|
31
|
+
> | null =
|
|
32
|
+
null;
|
|
33
|
+
|
|
34
|
+
let cacheProxy:
|
|
35
|
+
ReturnType<
|
|
36
|
+
typeof createResponseCacheProxy
|
|
37
|
+
> | null =
|
|
38
|
+
null;
|
|
39
|
+
|
|
40
|
+
let started =
|
|
41
|
+
false;
|
|
42
|
+
|
|
43
|
+
async function start(): Promise<void> {
|
|
44
|
+
if (started) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const manifest =
|
|
49
|
+
readCacheManifest(
|
|
50
|
+
options.buildDirectory
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const responseCacheEnabled =
|
|
54
|
+
process.env
|
|
55
|
+
.BCP_RESPONSE_CACHE !==
|
|
56
|
+
"0";
|
|
57
|
+
|
|
58
|
+
const hasCacheRoutes =
|
|
59
|
+
responseCacheEnabled &&
|
|
60
|
+
(
|
|
61
|
+
manifest.pages.length > 0 ||
|
|
62
|
+
manifest.apiRoutes.length > 0
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
if (!hasCacheRoutes) {
|
|
66
|
+
baseServer =
|
|
67
|
+
createBaseStandaloneProductionServer(
|
|
68
|
+
options
|
|
69
|
+
);
|
|
70
|
+
await baseServer.start();
|
|
71
|
+
started =
|
|
72
|
+
true;
|
|
73
|
+
|
|
74
|
+
if (
|
|
75
|
+
!responseCacheEnabled
|
|
76
|
+
) {
|
|
77
|
+
console.log(
|
|
78
|
+
"[BCP Cache] Production response cache disabled by configuration."
|
|
79
|
+
);
|
|
80
|
+
console.log("");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const internalPort =
|
|
87
|
+
await findFreePort();
|
|
88
|
+
|
|
89
|
+
baseServer =
|
|
90
|
+
createBaseStandaloneProductionServer({
|
|
91
|
+
...options,
|
|
92
|
+
port:
|
|
93
|
+
internalPort,
|
|
94
|
+
hostname:
|
|
95
|
+
"127.0.0.1",
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
await baseServer.start();
|
|
99
|
+
|
|
100
|
+
cacheProxy =
|
|
101
|
+
createResponseCacheProxy({
|
|
102
|
+
port:
|
|
103
|
+
options.port,
|
|
104
|
+
hostname:
|
|
105
|
+
options.hostname,
|
|
106
|
+
upstreamPort:
|
|
107
|
+
internalPort,
|
|
108
|
+
upstreamHostname:
|
|
109
|
+
"127.0.0.1",
|
|
110
|
+
manifest,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
await cacheProxy.start();
|
|
115
|
+
} catch (error) {
|
|
116
|
+
await baseServer.stop();
|
|
117
|
+
baseServer =
|
|
118
|
+
null;
|
|
119
|
+
cacheProxy =
|
|
120
|
+
null;
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
started =
|
|
125
|
+
true;
|
|
126
|
+
|
|
127
|
+
console.log(
|
|
128
|
+
`[BCP Cache] Production response cache: ${manifest.pages.length} page(s), ${manifest.apiRoutes.length} API route(s)`
|
|
129
|
+
);
|
|
130
|
+
console.log(
|
|
131
|
+
`[BCP Cache] Gateway: http://${options.hostname}:${options.port}`
|
|
132
|
+
);
|
|
133
|
+
console.log("");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function stop(): Promise<void> {
|
|
137
|
+
if (cacheProxy) {
|
|
138
|
+
await cacheProxy.stop();
|
|
139
|
+
cacheProxy =
|
|
140
|
+
null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (baseServer) {
|
|
144
|
+
await baseServer.stop();
|
|
145
|
+
baseServer =
|
|
146
|
+
null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
started =
|
|
150
|
+
false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
start,
|
|
155
|
+
stop,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function readCacheManifest(
|
|
160
|
+
buildDirectory: string
|
|
161
|
+
): ResponseCacheManifest {
|
|
162
|
+
const filePath =
|
|
163
|
+
path.join(
|
|
164
|
+
buildDirectory,
|
|
165
|
+
"server",
|
|
166
|
+
"cache-manifest.json"
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
if (
|
|
170
|
+
!fs.existsSync(
|
|
171
|
+
filePath
|
|
172
|
+
)
|
|
173
|
+
) {
|
|
174
|
+
return {
|
|
175
|
+
version: 1,
|
|
176
|
+
pages: [],
|
|
177
|
+
apiRoutes: [],
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const parsed =
|
|
182
|
+
JSON.parse(
|
|
183
|
+
fs.readFileSync(
|
|
184
|
+
filePath,
|
|
185
|
+
"utf8"
|
|
186
|
+
)
|
|
187
|
+
) as Partial<ResponseCacheManifest>;
|
|
188
|
+
|
|
189
|
+
if (
|
|
190
|
+
parsed.version !== 1 ||
|
|
191
|
+
!Array.isArray(
|
|
192
|
+
parsed.pages
|
|
193
|
+
) ||
|
|
194
|
+
!Array.isArray(
|
|
195
|
+
parsed.apiRoutes
|
|
196
|
+
)
|
|
197
|
+
) {
|
|
198
|
+
throw new Error(
|
|
199
|
+
`BCP Framework: invalid cache manifest at "${filePath}".`
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return parsed as ResponseCacheManifest;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async function findFreePort(): Promise<number> {
|
|
207
|
+
const server =
|
|
208
|
+
net.createServer();
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
await new Promise<void>(
|
|
212
|
+
(
|
|
213
|
+
resolve,
|
|
214
|
+
reject
|
|
215
|
+
) => {
|
|
216
|
+
const onError =
|
|
217
|
+
(error: Error) => {
|
|
218
|
+
server.off(
|
|
219
|
+
"listening",
|
|
220
|
+
onListening
|
|
221
|
+
);
|
|
222
|
+
reject(
|
|
223
|
+
error
|
|
224
|
+
);
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const onListening =
|
|
228
|
+
() => {
|
|
229
|
+
server.off(
|
|
230
|
+
"error",
|
|
231
|
+
onError
|
|
232
|
+
);
|
|
233
|
+
resolve();
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
server.once(
|
|
237
|
+
"error",
|
|
238
|
+
onError
|
|
239
|
+
);
|
|
240
|
+
server.once(
|
|
241
|
+
"listening",
|
|
242
|
+
onListening
|
|
243
|
+
);
|
|
244
|
+
server.listen(
|
|
245
|
+
0,
|
|
246
|
+
"127.0.0.1"
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
const address =
|
|
252
|
+
server.address();
|
|
253
|
+
|
|
254
|
+
if (
|
|
255
|
+
!address ||
|
|
256
|
+
typeof address ===
|
|
257
|
+
"string"
|
|
258
|
+
) {
|
|
259
|
+
throw new Error(
|
|
260
|
+
"BCP Framework: could not allocate production cache port."
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return address.port;
|
|
265
|
+
} finally {
|
|
266
|
+
if (
|
|
267
|
+
server.listening
|
|
268
|
+
) {
|
|
269
|
+
await new Promise<void>(
|
|
270
|
+
(
|
|
271
|
+
resolve,
|
|
272
|
+
reject
|
|
273
|
+
) => {
|
|
274
|
+
server.close(
|
|
275
|
+
(error) => {
|
|
276
|
+
if (error) {
|
|
277
|
+
reject(
|
|
278
|
+
error
|
|
279
|
+
);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
resolve();
|
|
283
|
+
}
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|