@chidchanun/bcp 0.1.8 → 0.1.10
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 +82 -0
- package/README.md +218 -7
- package/docs/application-modules.md +63 -3
- package/docs/releasing.md +34 -19
- package/docs/route-guards.md +240 -0
- package/docs/server-data-loaders.md +240 -0
- package/docs/updating.md +130 -0
- package/package.json +1 -1
- package/packages/bundler/src/server-production-guards.ts +497 -0
- package/packages/bundler/src/server-production-middleware.ts +33 -8
- package/packages/bundler/src/server-production.ts +25 -0
- package/packages/cli/src/args.ts +58 -0
- package/packages/cli/src/index.ts +41 -13
- package/packages/cli/src/update.ts +860 -0
- package/packages/client/src/index.tsx +5 -0
- package/packages/client/src/loader-data.tsx +229 -0
- package/packages/client/src/router-v2.tsx +254 -29
- package/packages/server/src/dev-navigation-target.ts +188 -0
- package/packages/server/src/index.ts +209 -119
- package/packages/server/src/navigation-payload.ts +24 -1
- package/packages/server/src/navigation-response.ts +284 -0
- package/packages/server/src/page-guard.ts +529 -0
- package/packages/server/src/page-loader.ts +643 -0
- package/packages/server/src/standalone-production-runtime-v2-guard.ts +815 -0
- package/packages/server/src/standalone-production-runtime-v2-navigation.ts +785 -0
- package/packages/server/src/standalone-production-runtime-v2.ts +131 -19
- package/packages/server/src/standalone-production-runtime-v3.ts +1 -1
- package/packages/server/src/standalone-production-runtime-v4.ts +42 -2
- package/packages/server/src/static-dev-server.ts +21 -17
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,88 @@
|
|
|
2
2
|
|
|
3
3
|
All notable framework changes are tracked here before release.
|
|
4
4
|
|
|
5
|
+
## 0.1.10 - Framework updater and protected route guards
|
|
6
|
+
|
|
7
|
+
### Framework updater
|
|
8
|
+
|
|
9
|
+
- Added `bcp update` to resolve and install the current `@chidchanun/bcp@latest` release from an existing BCP application.
|
|
10
|
+
- Added `bcp update <version-or-tag>` for explicitly targeting a published version or npm dist-tag.
|
|
11
|
+
- Added `bcp update --check` and `bcp update --dry-run` so projects can inspect an available update without changing package metadata or lockfiles.
|
|
12
|
+
- Existing generated `bcp` npm aliases and direct `@chidchanun/bcp` dependencies are detected automatically.
|
|
13
|
+
- Package-manager detection supports npm, pnpm, Yarn and Bun lockfiles and refuses to guess when conflicting lockfiles are present.
|
|
14
|
+
- Failed installs restore the original `package.json` and detected lockfile before returning an error.
|
|
15
|
+
- Projects published before the updater can bootstrap it once with `npx @chidchanun/bcp@latest update`; subsequent releases can use `bcp update` or the generated `npm run update` script directly.
|
|
16
|
+
- Generated applications pin the exact resolved BCP version so a normal package-manager install does not silently cross framework releases.
|
|
17
|
+
- Added unit coverage for updater argument parsing, dependency planning, package-manager detection and ambiguous dependency rejection.
|
|
18
|
+
- Added publish-artifact smoke checks requiring the updater source and CLI dispatch wiring.
|
|
19
|
+
|
|
20
|
+
### Protected routes and auth guards
|
|
21
|
+
|
|
22
|
+
- Added scoped `guard.ts` / `guard.tsx` files that protect pages in their route directory and descendant page directories.
|
|
23
|
+
- Guards execute from app root toward the matched page and receive `params`, target `searchParams` and merged ancestor `parentData`.
|
|
24
|
+
- A guard may return JSON-safe authorization data or a Web `Response`; redirects stop the pipeline before loader/page execution.
|
|
25
|
+
- Guards run inside the normal BCP request context, so sessions, cookies, headers, request URLs, request IDs and other `bcp/server` helpers are available directly.
|
|
26
|
+
- Loader context now receives merged `guardData`, avoiding repeated session/role lookups after a guard has already validated the request.
|
|
27
|
+
- Added public `useGuardData<T>()` so pages can consume the same guard result during SSR, hydration and SPA navigation.
|
|
28
|
+
- Guard-only routes are supported without requiring a page loader.
|
|
29
|
+
- Response cookies set by allowed guards or redirecting guards are preserved on document and navigation responses.
|
|
30
|
+
- Guard return values use the same JSON-safe validation rules as loader data and reject unsupported/circular values before transport.
|
|
31
|
+
- Direct requests and SPA navigation use the same authorization policy, including target-page params/query values and redirects.
|
|
32
|
+
- Standalone production generates a server-only `guards.mjs` evaluator and places the guard gateway after project middleware but before loader/page execution.
|
|
33
|
+
- User-supplied internal guard transport headers are stripped before authorization evaluation so clients cannot forge guard results.
|
|
34
|
+
- Internal serialized guard data is size-limited before it is proxied to the inner standalone runtime.
|
|
35
|
+
- Route-guarded pages are excluded from the automatic production response cache because their output may depend on session/role identity.
|
|
36
|
+
- Added `/guard-demo/[id]` and guard-only fixtures covering parent/child guard data, roles, cookies, loader integration and redirects.
|
|
37
|
+
- Added unit, development integration and standalone E2E coverage for guards, including forged-header rejection and guard-only production routes.
|
|
38
|
+
- Added publish-artifact smoke checks for the guard evaluator, standalone guard runtime, public hook and loader/guard bridge.
|
|
39
|
+
- Added dedicated protected-route documentation and updated README guidance for middleware versus route guards.
|
|
40
|
+
|
|
41
|
+
### Release channel
|
|
42
|
+
|
|
43
|
+
- Stable BCP releases now publish to the npm `latest` dist-tag by default even while the framework is pre-1.0.
|
|
44
|
+
- Maintainers can still select `next`, `beta` or another channel explicitly through `BCP_DIST_TAG`.
|
|
45
|
+
|
|
46
|
+
## 0.1.9 - Server data loaders
|
|
47
|
+
|
|
48
|
+
### Server rendering and data
|
|
49
|
+
|
|
50
|
+
- Added route-level `loader.ts` / `loader.tsx` files next to `page.tsx` for server-only page data loading before SSR.
|
|
51
|
+
- Added public `useLoaderData<T>()` through `bcp` so the page consumes the same loader value during SSR, browser hydration and later client navigations.
|
|
52
|
+
- Loader context includes matched route `params` and a fresh `URLSearchParams` instance for the target request query string.
|
|
53
|
+
- Loaders run inside the normal request context, so `cookies()`, `headers()`, `requestUrl()`, request/auth helpers and JWT session APIs can be used directly.
|
|
54
|
+
- Loader modules may import application server-only/database modules without placing those dependencies in the browser bundle.
|
|
55
|
+
- Loaders may return either JSON-safe data or a Web `Response`, including `redirect()` responses.
|
|
56
|
+
- Response cookies created while a loader runs are merged into the final page, navigation or redirect response.
|
|
57
|
+
- Loader results are serialized into framework data with the existing script-safe serialization rules and are provided to SSR through an internal loader-data provider.
|
|
58
|
+
- Loader data rejects unsupported values such as functions, symbols, BigInt, non-finite numbers, class instances, Date/Map/Set objects and circular graphs.
|
|
59
|
+
- Having both `loader.ts` and `loader.tsx` next to one page is rejected as an ambiguous route configuration.
|
|
60
|
+
|
|
61
|
+
### SPA navigation and cache safety
|
|
62
|
+
|
|
63
|
+
- Loader-backed routes now participate in BCP SPA navigation instead of requiring a full document reload.
|
|
64
|
+
- `/_bcp/navigation` executes the target route loader on the server and returns fresh loader data together with route metadata and client asset information.
|
|
65
|
+
- Navigation loaders receive a request context for the target page URL rather than the internal navigation transport URL, preserving target query parameters, cookies, sessions and request helpers.
|
|
66
|
+
- Loader redirects are converted to a navigation redirect payload while preserving all response cookies; same-origin redirects continue through the SPA router and cross-origin redirects use normal browser navigation.
|
|
67
|
+
- Non-navigation Web `Response` values continue to fall back to a document request so their original HTTP semantics remain authoritative.
|
|
68
|
+
- Client navigation explicitly sends same-origin credentials, aborts superseded requests and uses a monotonically increasing navigation sequence so stale responses cannot update router state after a newer navigation has started.
|
|
69
|
+
- Navigation redirect chains are capped at 10 redirects to prevent loops.
|
|
70
|
+
- `useNavigation()` becomes active before the server request starts and route loading markup can be displayed while the target client runtime/assets finish after the payload arrives.
|
|
71
|
+
- Standalone loader navigation is placed inside the existing middleware/security chain rather than bypassing application middleware or framework security gateways.
|
|
72
|
+
- Production response-cache manifests continue to exclude loader-backed pages automatically because loader output may be user/request specific.
|
|
73
|
+
- Navigation payload responses use `Cache-Control: no-store` and `X-Content-Type-Options: nosniff`.
|
|
74
|
+
|
|
75
|
+
### Production and reliability
|
|
76
|
+
|
|
77
|
+
- Standalone production entries bundle each loader into the server artifact only and attach it to the corresponding page route definition.
|
|
78
|
+
- Added a standalone loader-navigation gateway only when an application actually has loader-backed routes; applications without loaders keep the existing production runtime path.
|
|
79
|
+
- Development loader imports use a server-side cache-busting version so edits are reflected without creating a client dependency edge.
|
|
80
|
+
- Added a `/loader-demo/[id]` fixture covering route params, query params, cookies, request method, request URL, SSR serialization and redirect response cookies.
|
|
81
|
+
- Added unit coverage for loader discovery, execution, response returns, serialization validation, duplicate-loader detection and SPA redirect/cookie transport.
|
|
82
|
+
- Added development integration coverage for SSR loader data plus SPA navigation data, target request context, sessions and redirect cookies.
|
|
83
|
+
- Added standalone production E2E coverage to verify the same SPA loader protocol after production bundling.
|
|
84
|
+
- Expanded package artifact smoke checks to require the client router, dev navigation target runtime, navigation response transport and standalone loader navigation runtime.
|
|
85
|
+
- Added dedicated server data loader documentation and updated the main README/application boundary guidance.
|
|
86
|
+
|
|
5
87
|
## 0.1.8 - JWT cookie sessions and auth preset
|
|
6
88
|
|
|
7
89
|
### Authentication
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
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
4
|
|
|
5
|
-
> Current
|
|
5
|
+
> Current release target: `0.1.10`. BCP is still pre-1.0 and validates each release candidate before the manual npm publish step.
|
|
6
6
|
|
|
7
7
|
## Quick start
|
|
8
8
|
|
|
@@ -33,9 +33,13 @@ app/
|
|
|
33
33
|
├─ loading.tsx
|
|
34
34
|
├─ error.tsx
|
|
35
35
|
├─ not-found.tsx
|
|
36
|
-
├─
|
|
37
|
-
│
|
|
38
|
-
│
|
|
36
|
+
├─ dashboard/
|
|
37
|
+
│ ├─ guard.ts
|
|
38
|
+
│ ├─ page.tsx
|
|
39
|
+
│ └─ users/
|
|
40
|
+
│ └─ [id]/
|
|
41
|
+
│ ├─ loader.ts
|
|
42
|
+
│ └─ page.tsx
|
|
39
43
|
└─ api/
|
|
40
44
|
└─ hello/
|
|
41
45
|
└─ route.ts
|
|
@@ -73,7 +77,7 @@ Server-only modules can declare:
|
|
|
73
77
|
import "bcp/server-only";
|
|
74
78
|
```
|
|
75
79
|
|
|
76
|
-
Database helpers generated by `create-bcp-app` include the server-only marker automatically. A server-only helper must not be imported from a page/client graph
|
|
80
|
+
Database helpers generated by `create-bcp-app` include the server-only marker automatically. A server-only helper must not be imported from a hydrated page/client graph. Use an API route or a server-only route primitive such as `loader.ts` or `guard.ts`.
|
|
77
81
|
|
|
78
82
|
See [Application Modules](docs/application-modules.md) for the complete boundary model and examples.
|
|
79
83
|
|
|
@@ -88,11 +92,42 @@ bcp dev
|
|
|
88
92
|
bcp routes
|
|
89
93
|
bcp build
|
|
90
94
|
bcp start
|
|
95
|
+
bcp update
|
|
91
96
|
bcp version
|
|
92
97
|
```
|
|
93
98
|
|
|
94
99
|
CLI server overrides are available with `--port` and `--hostname`.
|
|
95
100
|
|
|
101
|
+
## Updating an existing project
|
|
102
|
+
|
|
103
|
+
Once a project is on a BCP version that contains the updater, update to the current npm `latest` release with:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
bcp update
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Preview an update without changing files:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
bcp update --check
|
|
113
|
+
bcp update --dry-run
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Or select a published version/dist-tag explicitly:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
bcp update 0.1.10
|
|
120
|
+
bcp update next
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Versions published before the updater do not recognize `bcp update`. Bootstrap the newest CLI once from those projects:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npx @chidchanun/bcp@latest update
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The updater changes the framework dependency and package-manager lockfile, detects npm/pnpm/Yarn/Bun from the project lockfile, and restores package metadata if installation fails. It does not overwrite application source files, database schemas or authentication code. See [Updating BCP Framework](docs/updating.md) for the complete behavior and migration notes.
|
|
130
|
+
|
|
96
131
|
## Routing
|
|
97
132
|
|
|
98
133
|
BCP supports:
|
|
@@ -123,7 +158,7 @@ Supported methods include GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. HEAD
|
|
|
123
158
|
|
|
124
159
|
## Server request APIs
|
|
125
160
|
|
|
126
|
-
BCP 0.1.7 adds request-scoped server helpers through `bcp/server`.
|
|
161
|
+
BCP 0.1.7 adds request-scoped server helpers through `bcp/server`. These helpers are server-only and are available from API handlers, server data loaders and route guards.
|
|
127
162
|
|
|
128
163
|
```ts
|
|
129
164
|
import {
|
|
@@ -196,6 +231,174 @@ export async function POST() {
|
|
|
196
231
|
|
|
197
232
|
`redirect()` defaults to status `307`; supported statuses are `301`, `302`, `303`, `307` and `308`. Use `cookieStore.delete("session")` to expire a cookie. See [Server Request APIs](docs/server-request-apis.md) for proxy trust, URL handling, response helpers, request isolation, cookie options and boundary details.
|
|
198
233
|
|
|
234
|
+
## Server data loaders
|
|
235
|
+
|
|
236
|
+
BCP 0.1.9 adds a server-only `loader.ts` convention next to `page.tsx`. The loader runs before SSR, receives route `params` plus `searchParams`, and can use `bcp/server` APIs, sessions and server-only database modules.
|
|
237
|
+
|
|
238
|
+
```text
|
|
239
|
+
app/users/[id]/
|
|
240
|
+
├─ loader.ts
|
|
241
|
+
└─ page.tsx
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
// app/users/[id]/loader.ts
|
|
246
|
+
import {
|
|
247
|
+
getSession,
|
|
248
|
+
redirect,
|
|
249
|
+
} from "bcp/server";
|
|
250
|
+
|
|
251
|
+
export async function loader({
|
|
252
|
+
params,
|
|
253
|
+
searchParams,
|
|
254
|
+
}: {
|
|
255
|
+
params: {
|
|
256
|
+
id: string;
|
|
257
|
+
};
|
|
258
|
+
searchParams: URLSearchParams;
|
|
259
|
+
}) {
|
|
260
|
+
const session =
|
|
261
|
+
await getSession();
|
|
262
|
+
|
|
263
|
+
if (!session) {
|
|
264
|
+
return redirect(
|
|
265
|
+
"/login",
|
|
266
|
+
303
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
id:
|
|
272
|
+
params.id,
|
|
273
|
+
query:
|
|
274
|
+
searchParams.get("q"),
|
|
275
|
+
session,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Pages consume the serializable result with `useLoaderData<T>()`:
|
|
281
|
+
|
|
282
|
+
```tsx
|
|
283
|
+
"use client";
|
|
284
|
+
|
|
285
|
+
import {
|
|
286
|
+
useLoaderData,
|
|
287
|
+
} from "bcp";
|
|
288
|
+
|
|
289
|
+
export default function UserPage() {
|
|
290
|
+
const data =
|
|
291
|
+
useLoaderData<{
|
|
292
|
+
id: string;
|
|
293
|
+
query: string | null;
|
|
294
|
+
}>();
|
|
295
|
+
|
|
296
|
+
return (
|
|
297
|
+
<main>
|
|
298
|
+
User {data.id}
|
|
299
|
+
</main>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Loader data is validated as JSON-safe before SSR and is serialized into framework data so hydration reads the same value without importing `loader.ts` into the browser graph. A loader may also return a Web `Response`; response cookies are preserved on redirects.
|
|
305
|
+
|
|
306
|
+
Loader-backed pages now use the same SPA navigation model as normal BCP routes. `<Link>`, `navigate()`, `router.push()`, `router.replace()`, history navigation and `router.refresh()` request `/_bcp/navigation`; the server executes the target loader inside a fresh target-page request context and returns current loader data with the route payload. Same-origin loader redirects continue through the router while preserving `Set-Cookie` headers. Superseded navigations are aborted and sequence-checked so stale responses cannot update the active route. Loader pages remain excluded from the production response-cache manifest by default because their output may depend on session, cookie, request identity or user-specific database state.
|
|
307
|
+
|
|
308
|
+
See [Server Data Loaders](docs/server-data-loaders.md) for serialization rules, authentication patterns, redirect behavior, SPA navigation, cache safety and request-context semantics.
|
|
309
|
+
|
|
310
|
+
## Protected routes and auth guards
|
|
311
|
+
|
|
312
|
+
The `0.1.10` release target adds scoped `guard.ts` / `guard.tsx` files for page authorization. A guard protects the pages in its directory and descendant route directories, runs before the page loader, and can use the same request/session APIs as a loader.
|
|
313
|
+
|
|
314
|
+
```text
|
|
315
|
+
app/dashboard/
|
|
316
|
+
├─ guard.ts
|
|
317
|
+
├─ page.tsx
|
|
318
|
+
└─ users/
|
|
319
|
+
└─ [id]/
|
|
320
|
+
├─ loader.ts
|
|
321
|
+
└─ page.tsx
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
// app/dashboard/guard.ts
|
|
326
|
+
import {
|
|
327
|
+
getSession,
|
|
328
|
+
redirect,
|
|
329
|
+
} from "bcp/server";
|
|
330
|
+
|
|
331
|
+
export async function guard() {
|
|
332
|
+
const session =
|
|
333
|
+
await getSession<{
|
|
334
|
+
userId: number;
|
|
335
|
+
email: string;
|
|
336
|
+
role: string;
|
|
337
|
+
}>();
|
|
338
|
+
|
|
339
|
+
if (!session) {
|
|
340
|
+
return redirect(
|
|
341
|
+
"/login",
|
|
342
|
+
303
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return {
|
|
347
|
+
session,
|
|
348
|
+
role:
|
|
349
|
+
session.role,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
Descendant loaders receive the merged result as `guardData`, so they do not need to repeat `getSession()`:
|
|
355
|
+
|
|
356
|
+
```ts
|
|
357
|
+
export async function loader({
|
|
358
|
+
params,
|
|
359
|
+
guardData,
|
|
360
|
+
}) {
|
|
361
|
+
return {
|
|
362
|
+
id:
|
|
363
|
+
params.id,
|
|
364
|
+
user:
|
|
365
|
+
guardData.session,
|
|
366
|
+
role:
|
|
367
|
+
guardData.role,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
A page can consume the same authorization data with `useGuardData<T>()`:
|
|
373
|
+
|
|
374
|
+
```tsx
|
|
375
|
+
"use client";
|
|
376
|
+
|
|
377
|
+
import {
|
|
378
|
+
useGuardData,
|
|
379
|
+
} from "bcp";
|
|
380
|
+
|
|
381
|
+
export default function DashboardPage() {
|
|
382
|
+
const guard =
|
|
383
|
+
useGuardData<{
|
|
384
|
+
session: {
|
|
385
|
+
email: string;
|
|
386
|
+
};
|
|
387
|
+
role: string;
|
|
388
|
+
}>();
|
|
389
|
+
|
|
390
|
+
return (
|
|
391
|
+
<main>
|
|
392
|
+
{guard.session.email}
|
|
393
|
+
</main>
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
Nested guards execute from root to child and receive ancestor output as `parentData`. Guard redirects and response cookies work for both direct document requests and SPA navigation. Guarded pages are excluded from the automatic production response cache, and standalone production strips user-supplied internal guard transport headers before evaluating authorization.
|
|
399
|
+
|
|
400
|
+
See [Protected Route Guards](docs/route-guards.md) for nested role policies, serialization rules, middleware ordering, cookie behavior and production hardening.
|
|
401
|
+
|
|
199
402
|
## JWT cookie sessions
|
|
200
403
|
|
|
201
404
|
BCP 0.1.8 adds HS256 JWT cookie sessions directly to `bcp/server`. Configure a server-only secret of at least 32 bytes:
|
|
@@ -335,7 +538,7 @@ import {
|
|
|
335
538
|
} from "bcp/cache";
|
|
336
539
|
```
|
|
337
540
|
|
|
338
|
-
The current cache implementation is process-local and intentionally does not provide distributed invalidation across multiple Node.js instances.
|
|
541
|
+
The current cache implementation is process-local and intentionally does not provide distributed invalidation across multiple Node.js instances. Loader-backed and route-guarded pages are excluded from the automatic production response-cache manifest because their output may depend on request/session identity. Cache server data explicitly only when the application has a safe user-aware cache key and invalidation strategy.
|
|
339
542
|
|
|
340
543
|
## Middleware
|
|
341
544
|
|
|
@@ -360,6 +563,8 @@ export function middleware(
|
|
|
360
563
|
}
|
|
361
564
|
```
|
|
362
565
|
|
|
566
|
+
Use middleware for request-wide interception and `guard.ts` for page-subtree authorization that needs to feed identity/role data into loaders and pages. In standalone production, project middleware runs before route guards.
|
|
567
|
+
|
|
363
568
|
## Configuration
|
|
364
569
|
|
|
365
570
|
```ts
|
|
@@ -411,10 +616,13 @@ The standalone output is generated under:
|
|
|
411
616
|
└─ server/
|
|
412
617
|
├─ server.mjs
|
|
413
618
|
├─ middleware.mjs
|
|
619
|
+
├─ guards.mjs
|
|
414
620
|
├─ cache-manifest.json
|
|
415
621
|
└─ config.json
|
|
416
622
|
```
|
|
417
623
|
|
|
624
|
+
`guards.mjs` is generated only when the application contains protected route guards.
|
|
625
|
+
|
|
418
626
|
## Package preparation
|
|
419
627
|
|
|
420
628
|
The development monorepo stays private. Publishable artifacts are produced separately:
|
|
@@ -445,7 +653,10 @@ No real npm publish command is run automatically by the repository.
|
|
|
445
653
|
- [Getting Started](docs/getting-started.md)
|
|
446
654
|
- [Application Modules](docs/application-modules.md)
|
|
447
655
|
- [Server Request APIs](docs/server-request-apis.md)
|
|
656
|
+
- [Server Data Loaders](docs/server-data-loaders.md)
|
|
657
|
+
- [Protected Route Guards](docs/route-guards.md)
|
|
448
658
|
- [JWT Cookie Sessions](docs/session-auth.md)
|
|
659
|
+
- [Updating BCP Framework](docs/updating.md)
|
|
449
660
|
- [Routing](docs/routing.md)
|
|
450
661
|
- [Configuration](docs/configuration.md)
|
|
451
662
|
- [Caching](docs/caching.md)
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "@/lib/database";
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
The generated `tsconfig.json` maps `@/*` to the project root. BCP also installs a Node.js resolver during development so the same alias works in SSR and API route modules. Production builds resolve the alias through the application bundler.
|
|
11
|
+
The generated `tsconfig.json` maps `@/*` to the project root. BCP also installs a Node.js resolver during development so the same alias works in SSR, loader and API route modules. Production builds resolve the alias through the application bundler.
|
|
12
12
|
|
|
13
13
|
## Client modules
|
|
14
14
|
|
|
@@ -79,7 +79,7 @@ import {
|
|
|
79
79
|
} from "@/lib/database";
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
For browser-driven data operations, put the database operation behind an API route:
|
|
83
83
|
|
|
84
84
|
```ts
|
|
85
85
|
// app/api/users/route.ts
|
|
@@ -111,6 +111,66 @@ const result =
|
|
|
111
111
|
await response.json();
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
+
## Server data loaders
|
|
115
|
+
|
|
116
|
+
BCP 0.1.9 adds a server-only page data path. A `loader.ts` next to `page.tsx` is not part of the hydrated page graph and may import server-only database helpers directly.
|
|
117
|
+
|
|
118
|
+
```text
|
|
119
|
+
app/users/
|
|
120
|
+
├─ loader.ts
|
|
121
|
+
└─ page.tsx
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
// app/users/loader.ts
|
|
126
|
+
import {
|
|
127
|
+
db,
|
|
128
|
+
} from "@/lib/database";
|
|
129
|
+
|
|
130
|
+
export async function loader() {
|
|
131
|
+
const [rows] =
|
|
132
|
+
await db.query(
|
|
133
|
+
"SELECT id, name FROM users"
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
users: rows,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The page consumes only the serializable result:
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
"use client";
|
|
146
|
+
|
|
147
|
+
import {
|
|
148
|
+
useLoaderData,
|
|
149
|
+
} from "bcp";
|
|
150
|
+
|
|
151
|
+
export default function UsersPage() {
|
|
152
|
+
const data =
|
|
153
|
+
useLoaderData<{
|
|
154
|
+
users: Array<{
|
|
155
|
+
id: number;
|
|
156
|
+
name: string;
|
|
157
|
+
}>;
|
|
158
|
+
}>();
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<pre>
|
|
162
|
+
{JSON.stringify(
|
|
163
|
+
data.users,
|
|
164
|
+
null,
|
|
165
|
+
2
|
|
166
|
+
)}
|
|
167
|
+
</pre>
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The loader itself stays server-only; only its validated JSON-safe result is serialized for hydration. See [Server Data Loaders](server-data-loaders.md) for request context, authentication, redirects and cache behavior.
|
|
173
|
+
|
|
114
174
|
## Current boundary model
|
|
115
175
|
|
|
116
|
-
BCP 0.1.x is not a React Server Components implementation. Pages and layouts can participate in browser hydration, so server-only dependencies must remain behind API routes or other server
|
|
176
|
+
BCP 0.1.x is not a React Server Components implementation. Pages and layouts can participate in browser hydration, so server-only dependencies must remain behind explicit server execution paths: API routes, route-level server data loaders, middleware, or other framework server runtimes. The boundary checks are designed to prevent accidental database or secret-bearing code from entering client bundles.
|
package/docs/releasing.md
CHANGED
|
@@ -18,7 +18,7 @@ Application source continues importing from `bcp`. `create-bcp-app` stores the s
|
|
|
18
18
|
Use the version helper instead of editing package metadata manually:
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
npm run version:set -- 0.1.
|
|
21
|
+
npm run version:set -- 0.1.10
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
It synchronizes the release version across:
|
|
@@ -187,24 +187,29 @@ and the executable:
|
|
|
187
187
|
bcp
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
-
A generated application's `package.json`
|
|
190
|
+
A newly generated application's `package.json` pins the selected framework release exactly so a later plain package-manager install cannot silently move BCP to a different release:
|
|
191
191
|
|
|
192
192
|
```json
|
|
193
193
|
{
|
|
194
|
+
"scripts": {
|
|
195
|
+
"update": "bcp update"
|
|
196
|
+
},
|
|
194
197
|
"dependencies": {
|
|
195
|
-
"bcp": "npm:@chidchanun/bcp
|
|
198
|
+
"bcp": "npm:@chidchanun/bcp@0.1.10"
|
|
196
199
|
}
|
|
197
200
|
}
|
|
198
201
|
```
|
|
199
202
|
|
|
203
|
+
The explicit updater is responsible for resolving and installing later framework releases.
|
|
204
|
+
|
|
200
205
|
## 8. Create the release tag
|
|
201
206
|
|
|
202
207
|
Only after `npm run rc:check` passes and `CHANGELOG.md` is ready:
|
|
203
208
|
|
|
204
209
|
```bash
|
|
205
210
|
git status
|
|
206
|
-
git tag -a v0.1.
|
|
207
|
-
git push origin v0.1.
|
|
211
|
+
git tag -a v0.1.10 -m "BCP Framework v0.1.10"
|
|
212
|
+
git push origin v0.1.10
|
|
208
213
|
```
|
|
209
214
|
|
|
210
215
|
Use the actual version from `package.json` in the tag.
|
|
@@ -231,19 +236,13 @@ The command refuses to publish unless all of these conditions are true:
|
|
|
231
236
|
- staged package names and versions match the selected release
|
|
232
237
|
- the target version has not already been accepted by npm
|
|
233
238
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
```text
|
|
237
|
-
next
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
For `1.x` and later it defaults to:
|
|
239
|
+
Stable BCP releases use this npm dist-tag by default, including stable `0.x` releases:
|
|
241
240
|
|
|
242
241
|
```text
|
|
243
242
|
latest
|
|
244
243
|
```
|
|
245
244
|
|
|
246
|
-
|
|
245
|
+
Use `BCP_DIST_TAG` only when intentionally publishing a separate channel such as `next` or `beta`:
|
|
247
246
|
|
|
248
247
|
```bash
|
|
249
248
|
BCP_DIST_TAG=beta npm run release:publish:yes
|
|
@@ -258,6 +257,8 @@ npm run release:publish:yes
|
|
|
258
257
|
|
|
259
258
|
The framework publishes first. After `npm publish` succeeds, the release script accepts either normal version visibility or the selected dist-tag pointing at the new version. This prevents npm registry/security-processing delays from being misclassified as a failed publish.
|
|
260
259
|
|
|
260
|
+
Using `latest` for stable releases is also part of the updater contract: `bcp update` resolves `@chidchanun/bcp@latest` by default.
|
|
261
|
+
|
|
261
262
|
## 10. Recover from a partial publish
|
|
262
263
|
|
|
263
264
|
If the framework package was accepted by npm but publishing `create-bcp-app` failed, fix the external issue without changing that release commit or tag, then use:
|
|
@@ -270,18 +271,32 @@ Resume mode intentionally does not run `release:version-check` or `npm publish -
|
|
|
270
271
|
|
|
271
272
|
Do not use resume mode to overwrite or replace an existing npm version; npm versions are immutable.
|
|
272
273
|
|
|
273
|
-
## 11. Install the
|
|
274
|
+
## 11. Install or update the stable release
|
|
275
|
+
|
|
276
|
+
The recommended new-project path is:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
npx create-bcp-app@latest my-app
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
A generated application keeps the documented `bcp` import name through an npm alias and pins the selected framework version exactly.
|
|
283
|
+
|
|
284
|
+
For an existing project already on an updater-capable release:
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
npm run update
|
|
288
|
+
```
|
|
274
289
|
|
|
275
|
-
|
|
290
|
+
For a project on BCP 0.1.9 or older, bootstrap the updater once with:
|
|
276
291
|
|
|
277
292
|
```bash
|
|
278
|
-
npx
|
|
293
|
+
npx @chidchanun/bcp@latest update
|
|
279
294
|
```
|
|
280
295
|
|
|
281
|
-
|
|
296
|
+
A manual install that preserves the `bcp` import name is:
|
|
282
297
|
|
|
283
298
|
```bash
|
|
284
|
-
npm install bcp@npm:@chidchanun/bcp@
|
|
299
|
+
npm install bcp@npm:@chidchanun/bcp@latest react react-dom
|
|
285
300
|
```
|
|
286
301
|
|
|
287
302
|
Application code then continues using:
|
|
@@ -292,7 +307,7 @@ import {
|
|
|
292
307
|
} from "bcp";
|
|
293
308
|
```
|
|
294
309
|
|
|
295
|
-
The scoped package can also be installed directly as `@chidchanun/bcp@
|
|
310
|
+
The scoped package can also be installed directly as `@chidchanun/bcp@latest`, but applications using the framework's documented `bcp` import path should prefer the alias form above.
|
|
296
311
|
|
|
297
312
|
## 12. Trusted publishing
|
|
298
313
|
|