@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
@@ -0,0 +1,299 @@
1
+ # Releasing BCP Framework
2
+
3
+ The source repository is a private npm workspace package for development. Release artifacts are staged separately so monorepo-only paths cannot accidentally become the published package contract.
4
+
5
+ BCP Framework and `create-bcp-app` are prepared for public release under the MIT License. Normal build and test tooling never performs a real `npm publish` automatically. The dedicated release publish command requires explicit confirmation and a matching Git tag.
6
+
7
+ The selected public npm identities for the first release are:
8
+
9
+ ```text
10
+ @chidchanun/bcp
11
+ create-bcp-app
12
+ ```
13
+
14
+ Application source continues importing from `bcp`. `create-bcp-app` stores the scoped framework package behind the dependency key `bcp` using an npm alias.
15
+
16
+ ## 1. Synchronize versions
17
+
18
+ Use the version helper instead of editing package metadata manually:
19
+
20
+ ```bash
21
+ npm run version:set -- 0.1.0
22
+ ```
23
+
24
+ It synchronizes the release version across:
25
+
26
+ ```text
27
+ package.json
28
+ packages/client/package.json
29
+ create-bcp-app/package.json
30
+ package-lock.json
31
+ ```
32
+
33
+ Review `CHANGELOG.md` after changing the version. The BCP CLI reads the framework version from package metadata instead of a duplicated hard-coded constant.
34
+
35
+ ## 2. Run the normal release gate
36
+
37
+ ```bash
38
+ npm run release:check
39
+ ```
40
+
41
+ This runs type checking, the complete unit/integration/E2E/package test suite, then verifies:
42
+
43
+ - synchronized semver metadata
44
+ - required documentation
45
+ - MIT license metadata and license files
46
+ - staged public package exports
47
+ - public npm access configuration
48
+ - exact `v<version>` matching when the check runs from a Git tag
49
+
50
+ ## 3. Verify npm package names and ownership
51
+
52
+ Before the first publish, authenticate to npm:
53
+
54
+ ```bash
55
+ npm login
56
+ npm whoami
57
+ ```
58
+
59
+ Then run:
60
+
61
+ ```bash
62
+ npm run release:name-check
63
+ ```
64
+
65
+ The default RC package names are now locked by `scripts/release-env.mjs` to:
66
+
67
+ ```text
68
+ @chidchanun/bcp
69
+ create-bcp-app
70
+ ```
71
+
72
+ The check queries both package names. If a package is not present in the registry, the name is treated as currently available. If it already exists, the current npm account must be listed as an owner or the check fails.
73
+
74
+ The defaults may still be overridden deliberately for a future rename:
75
+
76
+ ```bash
77
+ BCP_PACKAGE_NAME=@another-scope/bcp npm run release:name-check
78
+ ```
79
+
80
+ PowerShell:
81
+
82
+ ```powershell
83
+ $env:BCP_PACKAGE_NAME="@another-scope/bcp"
84
+ npm run release:name-check
85
+ ```
86
+
87
+ The Release Check workflow also accepts the optional repository variables:
88
+
89
+ ```text
90
+ BCP_PACKAGE_NAME
91
+ BCP_CREATE_PACKAGE_NAME
92
+ ```
93
+
94
+ When those variables are unset or empty, the locked defaults above are used. Package-name availability can change at any time, so treat this check as a point-in-time release gate rather than a permanent reservation.
95
+
96
+ ## 4. Verify the release version against npm
97
+
98
+ Run:
99
+
100
+ ```bash
101
+ npm run release:version-check
102
+ ```
103
+
104
+ This separately checks the exact local release version against both selected npm package names.
105
+
106
+ The gate fails when:
107
+
108
+ - `<package>@<local-version>` already exists and therefore cannot be republished
109
+ - the local version is older than or equal to the registry's current latest version
110
+
111
+ Because `@chidchanun/bcp` and `create-bcp-app` are new package names at the time of the first RC check, `0.1.0` is valid as their initial release version unless either name/version is published before the release completes.
112
+
113
+ ## 5. Run npm publish dry-run and clean-install smoke
114
+
115
+ ```bash
116
+ npm run release:dry-run
117
+ ```
118
+
119
+ This performs `npm publish --dry-run` for both staged packages, packs fresh tarballs, installs the framework tarball into a temporary clean project, executes the installed BCP CLI, installs the `create-bcp-app` tarball separately, and generates another temporary app from the installed generator.
120
+
121
+ No package is uploaded to the npm registry.
122
+
123
+ Artifacts are written to:
124
+
125
+ ```text
126
+ .package/artifacts/
127
+ ```
128
+
129
+ ## 6. Run the complete Release Candidate gate
130
+
131
+ For the final local RC check:
132
+
133
+ ```bash
134
+ npm run rc:check
135
+ ```
136
+
137
+ This is equivalent to:
138
+
139
+ ```bash
140
+ npm run release:check
141
+ npm run release:name-check
142
+ npm run release:version-check
143
+ npm run release:dry-run
144
+ ```
145
+
146
+ Run this immediately before creating the release tag.
147
+
148
+ ## 7. Inspect package contents
149
+
150
+ Review:
151
+
152
+ ```text
153
+ .package/bcp/package.json
154
+ .package/bcp/LICENSE
155
+ .package/create-bcp-app/package.json
156
+ .package/artifacts/*.tgz
157
+ ```
158
+
159
+ Useful manual checks:
160
+
161
+ ```bash
162
+ npm pack --dry-run .package/bcp
163
+ npm pack --dry-run .package/create-bcp-app
164
+ ```
165
+
166
+ The framework package is published as:
167
+
168
+ ```text
169
+ @chidchanun/bcp
170
+ ```
171
+
172
+ but exposes application import paths through the npm alias key:
173
+
174
+ ```text
175
+ bcp
176
+ bcp/island
177
+ bcp/cache
178
+ bcp/config
179
+ bcp/middleware
180
+ ```
181
+
182
+ and the executable:
183
+
184
+ ```text
185
+ bcp
186
+ ```
187
+
188
+ A generated application's `package.json` should therefore contain a dependency equivalent to:
189
+
190
+ ```json
191
+ {
192
+ "dependencies": {
193
+ "bcp": "npm:@chidchanun/bcp@^0.1.0"
194
+ }
195
+ }
196
+ ```
197
+
198
+ ## 8. Create the release tag
199
+
200
+ Only after `npm run rc:check` passes and `CHANGELOG.md` is ready:
201
+
202
+ ```bash
203
+ git status
204
+ git tag -a v0.1.0 -m "BCP Framework v0.1.0"
205
+ git push origin v0.1.0
206
+ ```
207
+
208
+ Use the actual version from `package.json` in the tag.
209
+
210
+ The GitHub Release Check workflow validates a `v*` tag, rechecks the npm target version, and uploads the npm tarballs as workflow artifacts. It does not publish them.
211
+
212
+ ## 9. Guarded first publish
213
+
214
+ After the tag workflow artifacts have been reviewed, publish from an authenticated local npm session with:
215
+
216
+ ```bash
217
+ npm run release:publish -- --yes
218
+ ```
219
+
220
+ The command refuses to publish unless all of these conditions are true:
221
+
222
+ - `--yes` is supplied
223
+ - the git working tree is clean
224
+ - HEAD has the exact tag `v<package-version>`
225
+ - npm authentication succeeds
226
+ - the RC checks succeed again
227
+ - staged package names and versions match the selected release
228
+ - the target version has not already been published
229
+
230
+ For `0.x` releases the default npm dist-tag is:
231
+
232
+ ```text
233
+ next
234
+ ```
235
+
236
+ For `1.x` and later it defaults to:
237
+
238
+ ```text
239
+ latest
240
+ ```
241
+
242
+ Override the tag explicitly when needed:
243
+
244
+ ```bash
245
+ BCP_DIST_TAG=beta npm run release:publish -- --yes
246
+ ```
247
+
248
+ PowerShell example:
249
+
250
+ ```powershell
251
+ $env:BCP_DIST_TAG="beta"
252
+ npm run release:publish -- --yes
253
+ ```
254
+
255
+ The framework publishes first. `create-bcp-app` publishes only after the framework publish succeeds and npm confirms that version is visible in the registry.
256
+
257
+ ## 10. Recover from a partial publish
258
+
259
+ If the framework package was published successfully but publishing `create-bcp-app` failed, fix the external issue without changing the release commit or tag, then use:
260
+
261
+ ```bash
262
+ npm run release:publish -- --yes --resume
263
+ ```
264
+
265
+ `--resume` skips versions that already exist and attempts only the missing package. Do not use `--resume` to overwrite or replace an existing npm version; npm versions are immutable.
266
+
267
+ ## 11. Install the preview release
268
+
269
+ The recommended path is the generator:
270
+
271
+ ```bash
272
+ npx create-bcp-app@next my-app
273
+ ```
274
+
275
+ For a `0.x` release published with the default `next` dist-tag, a manual install that preserves the `bcp` import name is:
276
+
277
+ ```bash
278
+ npm install bcp@npm:@chidchanun/bcp@next react react-dom
279
+ ```
280
+
281
+ Application code then continues using:
282
+
283
+ ```ts
284
+ import {
285
+ Link,
286
+ } from "bcp";
287
+ ```
288
+
289
+ The scoped package can also be installed directly as `@chidchanun/bcp@next`, but applications using the framework's documented `bcp` import path should prefer the alias form above.
290
+
291
+ ## 12. Trusted publishing after the initial release
292
+
293
+ For subsequent releases, prefer npm Trusted Publishing with GitHub Actions instead of a long-lived write token. npm supports GitHub Actions OIDC publishing and recommends trusted publishing for CI-based releases.
294
+
295
+ The first package version must exist before its npm package settings can be configured for a trusted publisher. After the initial manual release, configure the repository/workflow as a trusted publisher on npm and move the real publish action into the guarded GitHub release workflow.
296
+
297
+ ## License
298
+
299
+ BCP Framework and `create-bcp-app` use the MIT License. See `LICENSE` and `create-bcp-app/LICENSE`.
@@ -0,0 +1,103 @@
1
+ # Routing
2
+
3
+ BCP Framework uses the `app/` directory as the routing source of truth.
4
+
5
+ ## Static routes
6
+
7
+ ```text
8
+ app/page.tsx /
9
+ app/about/page.tsx /about
10
+ ```
11
+
12
+ ## Dynamic segments
13
+
14
+ ```text
15
+ app/users/[id]/page.tsx
16
+ ```
17
+
18
+ A request to `/users/15` receives:
19
+
20
+ ```ts
21
+ {
22
+ params: {
23
+ id: "15",
24
+ },
25
+ }
26
+ ```
27
+
28
+ ## Catch-all segments
29
+
30
+ ```text
31
+ app/docs/[...slug]/page.tsx
32
+ ```
33
+
34
+ `/docs/guides/install` receives:
35
+
36
+ ```ts
37
+ params.slug // ["guides", "install"]
38
+ ```
39
+
40
+ A required catch-all must consume at least one URL segment.
41
+
42
+ ## Optional catch-all segments
43
+
44
+ ```text
45
+ app/catalog/[[...slug]]/page.tsx
46
+ ```
47
+
48
+ Both `/catalog` and `/catalog/hardware/keyboards` match. The base route receives `slug === undefined`; nested paths receive a string array.
49
+
50
+ ## Route groups
51
+
52
+ ```text
53
+ app/(admin)/layout.tsx
54
+ app/(admin)/settings/page.tsx
55
+ ```
56
+
57
+ The public URL is `/settings`. The `(admin)` segment participates in filesystem layout composition but is removed from the public pathname.
58
+
59
+ ## Priority
60
+
61
+ When multiple patterns can match, BCP prefers:
62
+
63
+ ```text
64
+ static
65
+ → dynamic
66
+ → catch-all
67
+ → optional catch-all
68
+ ```
69
+
70
+ Route discovery rejects ambiguous patterns and duplicate public paths instead of selecting a route nondeterministically.
71
+
72
+ ## Layouts
73
+
74
+ Layouts are inherited from the app root through nested directories and route groups. Client navigation preserves compatible layout identities so layout state can survive page changes.
75
+
76
+ ## Special files
77
+
78
+ BCP recognizes route-adjacent special files including:
79
+
80
+ ```text
81
+ layout.tsx
82
+ loading.tsx
83
+ error.tsx
84
+ not-found.tsx
85
+ ```
86
+
87
+ ## Navigation
88
+
89
+ Use `Link`, `navigate` or `useRouter` from `bcp` for client navigation.
90
+
91
+ ```tsx
92
+ import {
93
+ Link,
94
+ } from "bcp";
95
+
96
+ export default function Page() {
97
+ return (
98
+ <Link href="/about">
99
+ About
100
+ </Link>
101
+ );
102
+ }
103
+ ```
@@ -0,0 +1,57 @@
1
+ # Security
2
+
3
+ BCP Framework applies a security gateway in both development and standalone production modes.
4
+
5
+ ## Default response headers
6
+
7
+ The default policy includes:
8
+
9
+ ```http
10
+ X-Content-Type-Options: nosniff
11
+ X-Frame-Options: SAMEORIGIN
12
+ Referrer-Policy: strict-origin-when-cross-origin
13
+ Permissions-Policy: camera=(), microphone=(), geolocation=()
14
+ ```
15
+
16
+ `X-Powered-By` is hidden by default.
17
+
18
+ ## Content Security Policy
19
+
20
+ CSP is configurable but disabled by default:
21
+
22
+ ```ts
23
+ security: {
24
+ contentSecurityPolicy:
25
+ "default-src 'self'; script-src 'self' 'unsafe-inline'",
26
+ }
27
+ ```
28
+
29
+ The current client bootstrap still uses inline script content in some runtime paths, so enabling a strict CSP without a compatible nonce/hash policy can block hydration or development tooling. Nonce/hash support is a future hardening area.
30
+
31
+ ## Request body limit
32
+
33
+ The default request body limit is 1 MiB:
34
+
35
+ ```ts
36
+ server: {
37
+ bodyLimit: 1024 * 1024,
38
+ }
39
+ ```
40
+
41
+ Requests exceeding the limit are rejected by the outer gateway with HTTP 413 before reaching the API handler.
42
+
43
+ ## Static assets
44
+
45
+ Public asset resolution decodes the URL, rejects null bytes, resolves the candidate beneath `public/`, resolves filesystem symlinks and verifies the final real path remains inside the public directory. This prevents path and symlink traversal from escaping the public root.
46
+
47
+ ## Middleware URLs
48
+
49
+ Middleware rewrites must remain same-origin. Redirects and rewrites reject non-HTTP(S) protocols and URLs containing embedded credentials.
50
+
51
+ ## Header validation
52
+
53
+ Security config values reject carriage return, line feed and null bytes to prevent response-header injection through framework configuration.
54
+
55
+ ## Deployment note
56
+
57
+ The security gateway is the outer production layer, so security headers and body limits also apply to response-cache hits, middleware responses, static assets and error responses.
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@chidchanun/bcp",
3
+ "version": "0.1.0",
4
+ "description": "BCP Framework - a React full-stack framework with file-based routing, SSR, APIs, middleware, islands, caching and standalone production builds.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/chidchanun/bcp-freamwork.git"
10
+ },
11
+ "homepage": "https://github.com/chidchanun/bcp-freamwork#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/chidchanun/bcp-freamwork/issues"
14
+ },
15
+ "keywords": [
16
+ "bcp",
17
+ "react",
18
+ "framework",
19
+ "ssr",
20
+ "routing",
21
+ "fullstack"
22
+ ],
23
+ "engines": {
24
+ "node": ">=24.11.0"
25
+ },
26
+ "bin": {
27
+ "bcp": "./packages/cli/bin/bcp.mjs"
28
+ },
29
+ "exports": {
30
+ ".": {
31
+ "types": "./packages/client/src/index.tsx",
32
+ "default": "./packages/client/src/index.tsx"
33
+ },
34
+ "./island": {
35
+ "types": "./packages/client/src/islands.tsx",
36
+ "default": "./packages/client/src/islands.tsx"
37
+ },
38
+ "./cache": {
39
+ "types": "./packages/client/src/cache.ts",
40
+ "default": "./packages/client/src/cache.ts"
41
+ },
42
+ "./config": {
43
+ "types": "./packages/client/src/config.ts",
44
+ "default": "./packages/client/src/config.ts"
45
+ },
46
+ "./middleware": {
47
+ "types": "./packages/server/src/middleware.ts",
48
+ "default": "./packages/server/src/middleware.ts"
49
+ },
50
+ "./package.json": "./package.json"
51
+ },
52
+ "dependencies": {
53
+ "@babel/core": "^8.0.1",
54
+ "@babel/preset-react": "^8.0.1",
55
+ "@babel/preset-typescript": "^8.0.1",
56
+ "chokidar": "^5.0.0",
57
+ "esbuild": "^0.28.2",
58
+ "react-refresh": "^0.18.0",
59
+ "tsx": "^4.23.12"
60
+ },
61
+ "peerDependencies": {
62
+ "react": "^19.2.8",
63
+ "react-dom": "^19.2.8"
64
+ },
65
+ "publishConfig": {
66
+ "access": "public"
67
+ }
68
+ }