@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.
Files changed (66) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/LICENSE +21 -0
  3. package/README.md +241 -0
  4. package/docs/caching.md +76 -0
  5. package/docs/configuration.md +97 -0
  6. package/docs/deployment.md +74 -0
  7. package/docs/getting-started.md +82 -0
  8. package/docs/middleware.md +58 -0
  9. package/docs/releasing.md +299 -0
  10. package/docs/routing.md +103 -0
  11. package/docs/security.md +57 -0
  12. package/package.json +68 -0
  13. package/packages/bundler/src/client-islands.ts +1457 -0
  14. package/packages/bundler/src/incremental-context.ts +206 -0
  15. package/packages/bundler/src/index.ts +1991 -0
  16. package/packages/bundler/src/module-graph.ts +317 -0
  17. package/packages/bundler/src/partial-hydration.ts +414 -0
  18. package/packages/bundler/src/production.ts +974 -0
  19. package/packages/bundler/src/server-production-middleware.ts +447 -0
  20. package/packages/bundler/src/server-production.ts +1193 -0
  21. package/packages/bundler/src/special-files.ts +131 -0
  22. package/packages/cache/src/index.ts +761 -0
  23. package/packages/cli/bin/bcp.mjs +93 -0
  24. package/packages/cli/src/args.ts +305 -0
  25. package/packages/cli/src/bootstrap.ts +514 -0
  26. package/packages/cli/src/index.ts +504 -0
  27. package/packages/cli/src/version.ts +45 -0
  28. package/packages/client/src/cache.ts +11 -0
  29. package/packages/client/src/config.ts +18 -0
  30. package/packages/client/src/error-boundary.tsx +149 -0
  31. package/packages/client/src/hydration.ts +3 -0
  32. package/packages/client/src/index.tsx +57 -0
  33. package/packages/client/src/islands.tsx +315 -0
  34. package/packages/client/src/metadata.ts +281 -0
  35. package/packages/client/src/navigation-loading.ts +52 -0
  36. package/packages/client/src/navigation-state.ts +80 -0
  37. package/packages/client/src/not-found.ts +34 -0
  38. package/packages/client/src/persistent-layout-runtime.ts +273 -0
  39. package/packages/client/src/router-v2.tsx +969 -0
  40. package/packages/client/src/router.tsx +1 -0
  41. package/packages/config/src/index.ts +1038 -0
  42. package/packages/env/src/index.ts +593 -0
  43. package/packages/router/src/advanced-router.ts +1032 -0
  44. package/packages/router/src/index.ts +1 -0
  45. package/packages/server/src/compression.ts +249 -0
  46. package/packages/server/src/dev-document-metadata.ts +154 -0
  47. package/packages/server/src/dev-hmr.ts +225 -0
  48. package/packages/server/src/index.ts +2265 -0
  49. package/packages/server/src/metadata.ts +478 -0
  50. package/packages/server/src/middleware-dev-server.ts +260 -0
  51. package/packages/server/src/middleware-loader.ts +140 -0
  52. package/packages/server/src/middleware-proxy.ts +516 -0
  53. package/packages/server/src/middleware.ts +704 -0
  54. package/packages/server/src/navigation-payload.ts +471 -0
  55. package/packages/server/src/production-server.ts +1746 -0
  56. package/packages/server/src/response-cache-proxy.ts +828 -0
  57. package/packages/server/src/security-proxy.ts +406 -0
  58. package/packages/server/src/security.ts +451 -0
  59. package/packages/server/src/standalone-production-runtime-v2.ts +2047 -0
  60. package/packages/server/src/standalone-production-runtime-v3.ts +250 -0
  61. package/packages/server/src/standalone-production-runtime-v4.ts +289 -0
  62. package/packages/server/src/standalone-production-runtime-v5.ts +289 -0
  63. package/packages/server/src/standalone-production-runtime.ts +1951 -0
  64. package/packages/server/src/standalone-production-server.ts +6 -0
  65. package/packages/server/src/static-assets.ts +262 -0
  66. 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).
@@ -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.