@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
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable framework changes are tracked here before release.
|
|
4
|
+
|
|
5
|
+
## 0.1.0 - Pre-release
|
|
6
|
+
|
|
7
|
+
### Framework core
|
|
8
|
+
|
|
9
|
+
- React SSR and hydration
|
|
10
|
+
- File-based pages and nested layouts
|
|
11
|
+
- Dynamic, catch-all and optional catch-all routes
|
|
12
|
+
- Route groups
|
|
13
|
+
- API route handlers
|
|
14
|
+
- Client navigation and loading state
|
|
15
|
+
- Error and not-found handling
|
|
16
|
+
- Metadata API
|
|
17
|
+
- Environment variables and automatic development env reload
|
|
18
|
+
- Middleware and request interception
|
|
19
|
+
|
|
20
|
+
### Performance
|
|
21
|
+
|
|
22
|
+
- Production client build and standalone Node.js server
|
|
23
|
+
- Compression and module preload support
|
|
24
|
+
- Partial hydration and client islands
|
|
25
|
+
- Island hydration and prefetch strategies
|
|
26
|
+
- Route response cache and data cache
|
|
27
|
+
- Cache tag/path invalidation
|
|
28
|
+
|
|
29
|
+
### Reliability and security
|
|
30
|
+
|
|
31
|
+
- Unit, integration and production E2E tests
|
|
32
|
+
- Framework configuration with frozen standalone settings
|
|
33
|
+
- Security response headers
|
|
34
|
+
- Request body limits
|
|
35
|
+
- Middleware URL validation
|
|
36
|
+
- Static path traversal protection
|
|
37
|
+
|
|
38
|
+
### Packaging and Release Candidate
|
|
39
|
+
|
|
40
|
+
- Publish staging package for BCP Framework
|
|
41
|
+
- Executable `bcp` CLI launcher
|
|
42
|
+
- `create-bcp-app` project generator
|
|
43
|
+
- Package smoke and release metadata checks
|
|
44
|
+
- npm package name/ownership release gate
|
|
45
|
+
- `npm publish --dry-run` verification for framework and generator
|
|
46
|
+
- Clean-install smoke checks from packed tarballs
|
|
47
|
+
- MIT License for BCP Framework and `create-bcp-app`
|
|
48
|
+
- Tag-triggered GitHub Release Check workflow with npm artifact upload
|
|
49
|
+
- Initial framework documentation
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 chidchanun
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# BCP Framework
|
|
2
|
+
|
|
3
|
+
BCP Framework is a React full-stack framework with file-based routing, SSR, client navigation, API routes, middleware, metadata, client islands, cache/revalidation, security defaults and standalone production builds.
|
|
4
|
+
|
|
5
|
+
> Current status: pre-release `0.1.0`. The repository can produce npm-ready tarballs, validate Release Candidates and run npm publish dry-runs, but publishing to npm is intentionally a separate manual release action.
|
|
6
|
+
|
|
7
|
+
## Quick start
|
|
8
|
+
|
|
9
|
+
After the packages are published:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx create-bcp-app my-app
|
|
13
|
+
cd my-app
|
|
14
|
+
npm run dev
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Open `http://localhost:3000`.
|
|
18
|
+
|
|
19
|
+
For local package testing from this repository:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm run package:check
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This creates package tarballs under `.package/artifacts` and verifies that `create-bcp-app` can generate a project from the packed BCP Framework artifact.
|
|
26
|
+
|
|
27
|
+
## Project structure
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
app/
|
|
31
|
+
├─ layout.tsx
|
|
32
|
+
├─ page.tsx
|
|
33
|
+
├─ loading.tsx
|
|
34
|
+
├─ error.tsx
|
|
35
|
+
├─ not-found.tsx
|
|
36
|
+
├─ users/
|
|
37
|
+
│ └─ [id]/
|
|
38
|
+
│ └─ page.tsx
|
|
39
|
+
└─ api/
|
|
40
|
+
└─ hello/
|
|
41
|
+
└─ route.ts
|
|
42
|
+
|
|
43
|
+
public/
|
|
44
|
+
bcp.config.ts
|
|
45
|
+
package.json
|
|
46
|
+
tsconfig.json
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Commands
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
bcp dev
|
|
53
|
+
bcp routes
|
|
54
|
+
bcp build
|
|
55
|
+
bcp start
|
|
56
|
+
bcp version
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
CLI server overrides are available with `--port` and `--hostname`.
|
|
60
|
+
|
|
61
|
+
## Routing
|
|
62
|
+
|
|
63
|
+
BCP supports:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
app/page.tsx /
|
|
67
|
+
app/about/page.tsx /about
|
|
68
|
+
app/users/[id]/page.tsx /users/:id
|
|
69
|
+
app/docs/[...slug]/page.tsx /docs/*
|
|
70
|
+
app/catalog/[[...slug]]/page.tsx /catalog and /catalog/*
|
|
71
|
+
app/(admin)/settings/page.tsx /settings
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Static routes have priority over dynamic routes, which have priority over catch-all routes.
|
|
75
|
+
|
|
76
|
+
## API routes
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
// app/api/hello/route.ts
|
|
80
|
+
export function GET() {
|
|
81
|
+
return Response.json({
|
|
82
|
+
message: "Hello",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Supported methods include GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. HEAD falls back to GET when no explicit HEAD handler exists, and OPTIONS is generated automatically when appropriate.
|
|
88
|
+
|
|
89
|
+
## Metadata
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import type {
|
|
93
|
+
Metadata,
|
|
94
|
+
} from "bcp";
|
|
95
|
+
|
|
96
|
+
export const metadata: Metadata = {
|
|
97
|
+
title: "Dashboard",
|
|
98
|
+
description: "Dashboard page",
|
|
99
|
+
};
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Dynamic routes can export `generateMetadata()` and receive route params.
|
|
103
|
+
|
|
104
|
+
## Cache and revalidation
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
export const revalidate = 60;
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Server data can use:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import {
|
|
114
|
+
cache,
|
|
115
|
+
dedupe,
|
|
116
|
+
revalidatePath,
|
|
117
|
+
revalidateTag,
|
|
118
|
+
} from "bcp/cache";
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The current cache implementation is process-local and intentionally does not provide distributed invalidation across multiple Node.js instances.
|
|
122
|
+
|
|
123
|
+
## Middleware
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
import {
|
|
127
|
+
next,
|
|
128
|
+
redirect,
|
|
129
|
+
type MiddlewareRequest,
|
|
130
|
+
} from "bcp/middleware";
|
|
131
|
+
|
|
132
|
+
export function middleware(
|
|
133
|
+
request: MiddlewareRequest
|
|
134
|
+
) {
|
|
135
|
+
if (
|
|
136
|
+
request.nextUrl.pathname === "/private" &&
|
|
137
|
+
!request.cookies.has("session")
|
|
138
|
+
) {
|
|
139
|
+
return redirect("/login");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return next();
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Configuration
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
import {
|
|
150
|
+
defineConfig,
|
|
151
|
+
} from "bcp/config";
|
|
152
|
+
|
|
153
|
+
export default defineConfig({
|
|
154
|
+
server: {
|
|
155
|
+
port: 3000,
|
|
156
|
+
hostname: "localhost",
|
|
157
|
+
bodyLimit: 1024 * 1024,
|
|
158
|
+
},
|
|
159
|
+
compression: true,
|
|
160
|
+
build: {
|
|
161
|
+
minify: true,
|
|
162
|
+
sourceMaps: false,
|
|
163
|
+
},
|
|
164
|
+
cache: {
|
|
165
|
+
response: true,
|
|
166
|
+
},
|
|
167
|
+
security: {
|
|
168
|
+
poweredByHeader: false,
|
|
169
|
+
contentSecurityPolicy: false,
|
|
170
|
+
frameOptions: "SAMEORIGIN",
|
|
171
|
+
referrerPolicy:
|
|
172
|
+
"strict-origin-when-cross-origin",
|
|
173
|
+
permissionsPolicy:
|
|
174
|
+
"camera=(), microphone=(), geolocation=()",
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Development/build precedence is CLI > `BCP_*` environment > `bcp.config.*` > defaults. Standalone start uses CLI > runtime environment > the config frozen into the production build.
|
|
180
|
+
|
|
181
|
+
## Production
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
npm run build
|
|
185
|
+
npm start
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
The standalone output is generated under:
|
|
189
|
+
|
|
190
|
+
```text
|
|
191
|
+
.bcp-framework/build/
|
|
192
|
+
├─ client/
|
|
193
|
+
├─ public/
|
|
194
|
+
└─ server/
|
|
195
|
+
├─ server.mjs
|
|
196
|
+
├─ middleware.mjs
|
|
197
|
+
├─ cache-manifest.json
|
|
198
|
+
└─ config.json
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Package preparation
|
|
202
|
+
|
|
203
|
+
The development monorepo stays private. Publishable artifacts are produced separately:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
npm run package:prepare
|
|
207
|
+
npm run package:check
|
|
208
|
+
npm run release:check
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
For the final Release Candidate gate:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
npm login
|
|
215
|
+
npm run rc:check
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
`rc:check` validates tests/release metadata, checks npm package-name availability or ownership, performs `npm publish --dry-run`, and clean-installs both generated tarballs into temporary projects.
|
|
219
|
+
|
|
220
|
+
`package:prepare` stages the framework at `.package/bcp`. The default package name is `bcp`; set `BCP_PACKAGE_NAME` when preparing a scoped or alternate package name.
|
|
221
|
+
|
|
222
|
+
No real npm publish command is run automatically by the repository.
|
|
223
|
+
|
|
224
|
+
## Documentation
|
|
225
|
+
|
|
226
|
+
- [Getting Started](docs/getting-started.md)
|
|
227
|
+
- [Routing](docs/routing.md)
|
|
228
|
+
- [Configuration](docs/configuration.md)
|
|
229
|
+
- [Caching](docs/caching.md)
|
|
230
|
+
- [Middleware](docs/middleware.md)
|
|
231
|
+
- [Security](docs/security.md)
|
|
232
|
+
- [Deployment](docs/deployment.md)
|
|
233
|
+
- [Releasing](docs/releasing.md)
|
|
234
|
+
|
|
235
|
+
## Requirements
|
|
236
|
+
|
|
237
|
+
BCP Framework currently targets Node.js 24.11 or newer and React 19.
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
BCP Framework and `create-bcp-app` are released under the MIT License. See [LICENSE](LICENSE).
|
package/docs/caching.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Caching and Revalidation
|
|
2
|
+
|
|
3
|
+
## Route response cache
|
|
4
|
+
|
|
5
|
+
A page or API route can opt into production response caching:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
export const revalidate = 60;
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Values:
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
number > 0 cache for that many seconds
|
|
15
|
+
false cache until explicitly invalidated
|
|
16
|
+
0 disable route response caching
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
BCP returns `X-BCP-Cache` values such as `MISS`, `HIT` and `BYPASS` for cache-enabled production routes.
|
|
20
|
+
|
|
21
|
+
Requests containing credentials or explicit no-cache directives bypass the shared response cache. Responses that set cookies or are explicitly private/no-store are not stored when the route semantics require respecting the response policy.
|
|
22
|
+
|
|
23
|
+
## Data cache
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import {
|
|
27
|
+
cache,
|
|
28
|
+
} from "bcp/cache";
|
|
29
|
+
|
|
30
|
+
const loadUser = cache(
|
|
31
|
+
async (id: string) => {
|
|
32
|
+
return database.user.find(id);
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
key: "user",
|
|
36
|
+
revalidate: 60,
|
|
37
|
+
tags: ["users"],
|
|
38
|
+
paths: ["/users"],
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Concurrent calls for the same cache key share in-flight work.
|
|
44
|
+
|
|
45
|
+
## Request-scoped dedupe
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import {
|
|
49
|
+
dedupe,
|
|
50
|
+
} from "bcp/cache";
|
|
51
|
+
|
|
52
|
+
const loadSession = dedupe(
|
|
53
|
+
async () => loadCurrentSession(),
|
|
54
|
+
"current-session"
|
|
55
|
+
);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`dedupe()` shares work only inside a request context.
|
|
59
|
+
|
|
60
|
+
## Invalidation
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import {
|
|
64
|
+
revalidatePath,
|
|
65
|
+
revalidateTag,
|
|
66
|
+
} from "bcp/cache";
|
|
67
|
+
|
|
68
|
+
revalidateTag("users");
|
|
69
|
+
revalidatePath("/dashboard");
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Path invalidation clears the matching path and descendants.
|
|
73
|
+
|
|
74
|
+
## Current deployment limitation
|
|
75
|
+
|
|
76
|
+
The cache runtime is in-memory and process-local. Restarting the Node.js process clears it, and multiple application instances do not share cache state or invalidation events. A distributed adapter such as Redis is a future extension rather than part of the current release.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
BCP Framework reads one project config file from the project root:
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
bcp.config.ts
|
|
7
|
+
bcp.config.mts
|
|
8
|
+
bcp.config.js
|
|
9
|
+
bcp.config.mjs
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Only one may exist at a time.
|
|
13
|
+
|
|
14
|
+
## Example
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import {
|
|
18
|
+
defineConfig,
|
|
19
|
+
} from "bcp/config";
|
|
20
|
+
|
|
21
|
+
export default defineConfig({
|
|
22
|
+
server: {
|
|
23
|
+
port: 3000,
|
|
24
|
+
hostname: "localhost",
|
|
25
|
+
bodyLimit: 1024 * 1024,
|
|
26
|
+
},
|
|
27
|
+
compression: true,
|
|
28
|
+
build: {
|
|
29
|
+
minify: true,
|
|
30
|
+
sourceMaps: false,
|
|
31
|
+
},
|
|
32
|
+
cache: {
|
|
33
|
+
response: true,
|
|
34
|
+
},
|
|
35
|
+
experimental: {
|
|
36
|
+
partialHydration: true,
|
|
37
|
+
islands: true,
|
|
38
|
+
},
|
|
39
|
+
security: {
|
|
40
|
+
poweredByHeader: false,
|
|
41
|
+
contentSecurityPolicy: false,
|
|
42
|
+
frameOptions: "SAMEORIGIN",
|
|
43
|
+
referrerPolicy:
|
|
44
|
+
"strict-origin-when-cross-origin",
|
|
45
|
+
permissionsPolicy:
|
|
46
|
+
"camera=(), microphone=(), geolocation=()",
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Precedence
|
|
52
|
+
|
|
53
|
+
For `dev` and `build`:
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
CLI options
|
|
57
|
+
→ BCP_* environment
|
|
58
|
+
→ bcp.config.*
|
|
59
|
+
→ framework defaults
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
For a standalone production `start`:
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
CLI server override
|
|
66
|
+
→ runtime BCP_* environment
|
|
67
|
+
→ configuration frozen at build time
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
This allows a built artifact to retain build-sensitive settings while still supporting deployment port/hostname overrides.
|
|
71
|
+
|
|
72
|
+
## Environment overrides
|
|
73
|
+
|
|
74
|
+
Common framework overrides include:
|
|
75
|
+
|
|
76
|
+
```text
|
|
77
|
+
BCP_PORT
|
|
78
|
+
BCP_HOSTNAME
|
|
79
|
+
BCP_COMPRESSION
|
|
80
|
+
BCP_BUILD_MINIFY
|
|
81
|
+
BCP_BUILD_SOURCE_MAPS
|
|
82
|
+
BCP_RESPONSE_CACHE
|
|
83
|
+
BCP_BODY_LIMIT
|
|
84
|
+
BCP_POWERED_BY_HEADER
|
|
85
|
+
BCP_SECURITY_CSP
|
|
86
|
+
BCP_SECURITY_FRAME_OPTIONS
|
|
87
|
+
BCP_SECURITY_REFERRER_POLICY
|
|
88
|
+
BCP_SECURITY_PERMISSIONS_POLICY
|
|
89
|
+
BCP_EXPERIMENTAL_PARTIAL_HYDRATION
|
|
90
|
+
BCP_EXPERIMENTAL_ISLANDS
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Application environment variables prefixed with `BCP_PUBLIC_` may be embedded into browser bundles. Other application variables remain server-side.
|
|
94
|
+
|
|
95
|
+
## Config reload in development
|
|
96
|
+
|
|
97
|
+
Changes to supported `.env*` files or `bcp.config.*` restart the development worker so the new resolved configuration is applied without restarting the parent CLI manually.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Deployment
|
|
2
|
+
|
|
3
|
+
## Build
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm run build
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
BCP writes the production artifact to `.bcp-framework/build`.
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
.bcp-framework/build/
|
|
13
|
+
├─ client/
|
|
14
|
+
├─ public/
|
|
15
|
+
├─ manifest.json
|
|
16
|
+
└─ server/
|
|
17
|
+
├─ server.mjs
|
|
18
|
+
├─ middleware.mjs
|
|
19
|
+
├─ cache-manifest.json
|
|
20
|
+
└─ config.json
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Start
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm start
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or run the standalone bundle directly:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
node .bcp-framework/build/server/server.mjs
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Runtime server overrides
|
|
36
|
+
|
|
37
|
+
The build retains the configured server defaults. Deployment can override the public bind address with supported runtime variables:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
BCP_PORT
|
|
41
|
+
BCP_HOSTNAME
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The CLI also supports:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
bcp start --port 8080 --hostname 0.0.0.0
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Containers
|
|
51
|
+
|
|
52
|
+
A minimal deployment image needs the standalone build plus the runtime dependencies required by the generated server bundle, including React/React DOM when they remain external to the bundle.
|
|
53
|
+
|
|
54
|
+
A typical application image can install production dependencies, copy `.bcp-framework/build`, expose the runtime port and execute `npm start` or `node .bcp-framework/build/server/server.mjs`.
|
|
55
|
+
|
|
56
|
+
## Reverse proxies
|
|
57
|
+
|
|
58
|
+
BCP can run behind a reverse proxy or tunnel. Forward the original host correctly when application middleware or absolute URL construction depends on host information.
|
|
59
|
+
|
|
60
|
+
## Multiple instances
|
|
61
|
+
|
|
62
|
+
The current response/data cache is process-local. If multiple containers or Node.js processes serve the application, each maintains independent cache entries and invalidation state.
|
|
63
|
+
|
|
64
|
+
## Production verification
|
|
65
|
+
|
|
66
|
+
Before deployment:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm run typecheck
|
|
70
|
+
npm test
|
|
71
|
+
npm run build
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
For framework releases themselves, use `npm run release:check` in the framework repository.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
## Create an application
|
|
4
|
+
|
|
5
|
+
Once `bcp` and `create-bcp-app` are published:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx create-bcp-app my-app
|
|
9
|
+
cd my-app
|
|
10
|
+
npm run dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The generator creates a React + TypeScript project with a root layout, home page, API example and `bcp.config.ts`.
|
|
14
|
+
|
|
15
|
+
## Generated scripts
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"scripts": {
|
|
20
|
+
"dev": "bcp dev",
|
|
21
|
+
"build": "bcp build",
|
|
22
|
+
"start": "bcp start",
|
|
23
|
+
"routes": "bcp routes",
|
|
24
|
+
"typecheck": "tsc --noEmit"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## First page
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
// app/page.tsx
|
|
33
|
+
export default function HomePage() {
|
|
34
|
+
return (
|
|
35
|
+
<main>
|
|
36
|
+
<h1>Hello BCP</h1>
|
|
37
|
+
</main>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## First API route
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
// app/api/hello/route.ts
|
|
46
|
+
export function GET() {
|
|
47
|
+
return Response.json({
|
|
48
|
+
message: "Hello",
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Inspect routes
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm run routes
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Production
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm run build
|
|
63
|
+
npm start
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The production server is standalone and reads build-time configuration from the generated server artifact while still allowing supported runtime environment and CLI server overrides.
|
|
67
|
+
|
|
68
|
+
## Local tarball testing
|
|
69
|
+
|
|
70
|
+
Before npm publication, package artifacts can be created from the framework repository:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm run package:check
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Then a project can be generated against the local tarball:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
node create-bcp-app/bin/create-bcp-app.mjs my-app \
|
|
80
|
+
--no-install \
|
|
81
|
+
--bcp file:../.package/artifacts/bcp-0.1.0.tgz
|
|
82
|
+
```
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Middleware
|
|
2
|
+
|
|
3
|
+
Create `middleware.ts` in the project root.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import {
|
|
7
|
+
next,
|
|
8
|
+
redirect,
|
|
9
|
+
rewrite,
|
|
10
|
+
type MiddlewareConfig,
|
|
11
|
+
type MiddlewareRequest,
|
|
12
|
+
} from "bcp/middleware";
|
|
13
|
+
|
|
14
|
+
export const config: MiddlewareConfig = {
|
|
15
|
+
matcher: [
|
|
16
|
+
"/dashboard/:path*",
|
|
17
|
+
"/api/private/:path*",
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function middleware(
|
|
22
|
+
request: MiddlewareRequest
|
|
23
|
+
) {
|
|
24
|
+
if (
|
|
25
|
+
!request.cookies.has("session")
|
|
26
|
+
) {
|
|
27
|
+
return redirect("/login");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return next();
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Results
|
|
35
|
+
|
|
36
|
+
Middleware may:
|
|
37
|
+
|
|
38
|
+
- continue with `next()`
|
|
39
|
+
- rewrite to another same-origin route with `rewrite()`
|
|
40
|
+
- redirect to an HTTP(S) URL with `redirect()`
|
|
41
|
+
- return a `Response` directly
|
|
42
|
+
- mutate request and response headers through middleware options
|
|
43
|
+
|
|
44
|
+
## Matchers
|
|
45
|
+
|
|
46
|
+
Matchers support exact paths, dynamic path segments and catch-all patterns such as:
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
/dashboard
|
|
50
|
+
/users/:id
|
|
51
|
+
/dashboard/:path*
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Security constraints
|
|
55
|
+
|
|
56
|
+
Rewrites must stay on the same origin. Redirects and rewrites reject unsupported URL protocols and embedded URL credentials. Header values ultimately pass through Node.js response validation, while framework configuration rejects CR/LF/null-byte injection in security header settings.
|
|
57
|
+
|
|
58
|
+
Framework-internal `/_bcp/*` requests bypass user middleware execution where required by the runtime.
|