@chidchanun/bcp 0.1.26 → 0.1.27

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/README.md CHANGED
@@ -1,52 +1,16 @@
1
1
  # BCP Framework
2
2
 
3
- BCP Framework is a React full-stack framework focused on file-based routing, SSR, server data loading, guarded application flows, API routes, authentication, database access, validation, logging, uploads, storage adapters and standalone production deployment.
3
+ BCP Framework is a React full-stack framework focused on file-based routing, SSR, server data loading, guarded application flows, API routes, authentication, database access, validation, logging, uploads, storage and standalone production deployment.
4
4
 
5
- > **Release candidate target:** `0.1.26`
5
+ > **Development target:** `0.1.27`
6
6
  >
7
- > BCP is pre-1.0. The `0.1.26` source is complete for RC validation, but it must not be presented as a published npm release until the full release checks pass and the matching packages are published.
8
-
9
- ## Overview
10
-
11
- BCP keeps React pages and their server behavior close to the route that owns them:
12
-
13
- ```text
14
- Browser
15
-
16
- BCP security / middleware / cache
17
-
18
- Route guard
19
-
20
- Loader / action / API route
21
-
22
- React SSR
23
-
24
- Hydration / SPA navigation
25
- ```
26
-
27
- A typical route can colocate its page, loader, guard and actions:
28
-
29
- ```text
30
- app/
31
- ├─ layout.tsx
32
- ├─ page.tsx
33
- ├─ dashboard/
34
- │ ├─ guard.ts
35
- │ └─ users/
36
- │ └─ [id]/
37
- │ ├─ loader.ts
38
- │ ├─ actions.ts
39
- │ └─ page.tsx
40
- └─ api/
41
- └─ upload/
42
- └─ route.ts
43
- ```
7
+ > BCP is pre-1.0. The `0.1.27` source adds the Storage Ecosystem and remains an unreleased development target until local validation, RC checks, tagging and npm publication complete.
44
8
 
45
9
  ## Current capabilities
46
10
 
47
11
  | Area | Capability |
48
12
  | --- | --- |
49
- | Application | React SSR, hydration, layouts, metadata, SPA navigation |
13
+ | Application | React SSR, hydration, layouts, metadata and SPA navigation |
50
14
  | Routing | Static, dynamic, catch-all, optional catch-all and route groups |
51
15
  | Server data | `loader.ts`, request-scoped server APIs |
52
16
  | Mutations | Route-owned `actions.ts` and `<Form>` |
@@ -58,7 +22,7 @@ app/
58
22
  | Database | MySQL pool/query helpers, transactions and migrations |
59
23
  | Logging | Structured logger, request logger and request IDs |
60
24
  | Uploads | Buffered multipart helpers and production multipart streaming |
61
- | Storage | Local + S3-compatible adapters, streaming I/O and ranged delivery |
25
+ | Storage | Local + S3-compatible adapters, streaming, listing, copy/move, metadata, bulk delete and signed S3 URLs |
62
26
  | Caching | Response cache and revalidation primitives |
63
27
  | Developer tools | `doctor`, `inspect`, updater and route inspection |
64
28
  | Production | Standalone server build with production middleware pipeline |
@@ -79,16 +43,13 @@ cd my-app
79
43
  npm run dev
80
44
  ```
81
45
 
82
- Default development URL:
83
-
84
- ```text
85
- http://localhost:3000
86
- ```
87
-
88
- Generated projects normally include:
46
+ Generated projects normally use the application dependency key `bcp`:
89
47
 
90
48
  ```json
91
49
  {
50
+ "dependencies": {
51
+ "bcp": "npm:@chidchanun/bcp@latest"
52
+ },
92
53
  "scripts": {
93
54
  "dev": "bcp dev",
94
55
  "build": "bcp build",
@@ -100,68 +61,45 @@ Generated projects normally include:
100
61
  }
101
62
  ```
102
63
 
103
- ## Packages
64
+ Keep only one framework dependency named `bcp`. Installing both `bcp` and `@chidchanun/bcp` directly can load duplicate framework/React contexts.
104
65
 
105
- The public framework package is published as:
66
+ ## Application model
106
67
 
107
68
  ```text
108
- @chidchanun/bcp
109
- ```
110
-
111
- Applications normally consume it through the dependency key `bcp`, keeping imports concise:
112
-
113
- ```ts
114
- import {
115
- Form,
116
- Link,
117
- useLoaderData,
118
- } from "bcp";
119
- ```
120
-
121
- Server-only APIs use dedicated entrypoints:
122
-
123
- ```ts
124
- import {
125
- cookies,
126
- logger,
127
- requestId,
128
- } from "bcp/server";
69
+ Browser
70
+
71
+ BCP security / middleware / cache
72
+
73
+ Route guard
74
+
75
+ Loader / action / API route
76
+
77
+ React SSR
78
+
79
+ Hydration / SPA navigation
129
80
  ```
130
81
 
131
- ## Project structure
82
+ A route can keep page, loader, guard and actions together:
132
83
 
133
84
  ```text
134
85
  app/
135
86
  ├─ layout.tsx
136
87
  ├─ page.tsx
137
- ├─ login/
138
- │ └─ page.tsx
139
88
  ├─ dashboard/
140
89
  │ ├─ guard.ts
141
- │ ├─ page.tsx
142
90
  │ └─ users/
143
91
  │ └─ [id]/
144
92
  │ ├─ loader.ts
145
93
  │ ├─ actions.ts
146
94
  │ └─ page.tsx
147
95
  └─ api/
148
- ├─ auth/
149
- │ └─ login/
150
- │ └─ route.ts
151
96
  └─ upload/
152
97
  └─ route.ts
153
-
154
- lib/
155
- public/
156
- migrations/
157
- bcp.config.ts
158
- package.json
159
- tsconfig.json
160
98
  ```
161
99
 
162
100
  ## Routing
163
101
 
164
- Page routes are discovered from `app/**/page.tsx`:
102
+ Page routes are discovered from `app/**/page.tsx` and API routes from `app/**/route.ts`.
165
103
 
166
104
  ```text
167
105
  app/page.tsx /
@@ -170,65 +108,16 @@ app/users/[id]/page.tsx /users/:id
170
108
  app/docs/[...slug]/page.tsx /docs/*
171
109
  app/catalog/[[...slug]]/page.tsx /catalog and /catalog/*
172
110
  app/(admin)/settings/page.tsx /settings
173
- ```
174
-
175
- Static routes have priority over dynamic and catch-all routes.
176
-
177
- API routes use `route.ts`:
178
111
 
179
- ```text
180
- app/api/users/route.ts /api/users
181
- app/api/users/[id]/route.ts /api/users/:id
112
+ app/api/users/route.ts /api/users
113
+ app/api/users/[id]/route.ts /api/users/:id
182
114
  ```
183
115
 
184
116
  Read more: [Routing](docs/routing.md)
185
117
 
186
- ## Layouts and metadata
118
+ ## Server data, guards and actions
187
119
 
188
- Routes inherit layouts from parent directories. BCP resolves the layout chain in development and standalone production. Document metadata is route-aware and can be generated alongside the page tree.
189
-
190
- Read more: [Routing](docs/routing.md)
191
-
192
- ## Server data loaders
193
-
194
- Place `loader.ts` next to a page when the route needs server-side data:
195
-
196
- ```ts
197
- // app/users/[id]/loader.ts
198
- export async function loader({
199
- params,
200
- }) {
201
- return {
202
- id:
203
- params.id,
204
- };
205
- }
206
- ```
207
-
208
- Consume serializable loader data from a client page:
209
-
210
- ```tsx
211
- "use client";
212
-
213
- import {
214
- useLoaderData,
215
- } from "bcp";
216
-
217
- export default function UserPage() {
218
- const data =
219
- useLoaderData<{
220
- id: string;
221
- }>();
222
-
223
- return <main>User {data.id}</main>;
224
- }
225
- ```
226
-
227
- Read more: [Server Data Loaders](docs/server-data-loaders.md)
228
-
229
- ## Route guards
230
-
231
- A route tree can define `guard.ts` to authorize access before rendering:
120
+ Server loaders live next to their route in `loader.ts`. Route authorization can be defined in `guard.ts`, while route-owned mutations live in `actions.ts`.
232
121
 
233
122
  ```ts
234
123
  import {
@@ -239,40 +128,14 @@ export const guard =
239
128
  requireRole("admin");
240
129
  ```
241
130
 
242
- The standalone production pipeline preserves the same active request context used by authentication and server request APIs.
243
-
244
131
  Read more:
245
132
 
133
+ - [Server Data Loaders](docs/server-data-loaders.md)
246
134
  - [Route Guards](docs/route-guards.md)
247
135
  - [Auth Route Guards](docs/auth-route-guards.md)
136
+ - [Form Actions](docs/form-actions.md)
248
137
 
249
- ## Form actions
250
-
251
- Route-owned mutations live in `actions.ts` and can be invoked through the public `<Form>` API. BCP supports progressive form submission and SPA action transport while keeping mutation code server-only.
252
-
253
- Read more: [Form Actions](docs/form-actions.md)
254
-
255
- ## Server request APIs
256
-
257
- ```ts
258
- import {
259
- bearerToken,
260
- clientIp,
261
- cookies,
262
- headers,
263
- requestId,
264
- requestMethod,
265
- requestUrl,
266
- } from "bcp/server";
267
- ```
268
-
269
- `requestId()` accepts a valid incoming `X-Request-Id` or generates a stable UUID for the active request.
270
-
271
- Read more: [Server Request APIs](docs/server-request-apis.md)
272
-
273
- ## Authentication and sessions
274
-
275
- High-level authentication helpers:
138
+ ## Authentication and server APIs
276
139
 
277
140
  ```ts
278
141
  import {
@@ -280,89 +143,23 @@ import {
280
143
  requireAuth,
281
144
  requireRole,
282
145
  } from "bcp/auth";
283
- ```
284
-
285
- Lower-level JWT cookie session primitives:
286
146
 
287
- ```ts
288
147
  import {
289
- createSession,
290
- createSessionToken,
291
- destroySession,
292
- getSession,
293
- verifySessionToken,
148
+ cookies,
149
+ headers,
150
+ requestId,
151
+ requestMethod,
152
+ requestUrl,
294
153
  } from "bcp/server";
295
154
  ```
296
155
 
297
- Authentication is separated from application-specific credential lookup so projects can connect their own user table or identity provider.
156
+ BCP also exposes lower-level JWT cookie session primitives through `bcp/server`.
298
157
 
299
158
  Read more:
300
159
 
301
160
  - [Authentication](docs/authentication.md)
302
- - [JWT Cookie Sessions](docs/session-auth.md)
303
-
304
- ## Middleware
305
-
306
- Middleware System v2 uses onion-style execution:
307
-
308
- ```ts
309
- export async function middleware(
310
- request,
311
- context,
312
- next
313
- ) {
314
- const response =
315
- await next();
316
-
317
- response.headers.set(
318
- "x-app",
319
- "example"
320
- );
321
-
322
- return response;
323
- }
324
- ```
325
-
326
- Existing middleware v1 behavior remains supported for compatibility.
327
-
328
- Read more: [Middleware](docs/middleware.md)
329
-
330
- ## Validation
331
-
332
- ```ts
333
- import {
334
- v,
335
- validateFormData,
336
- } from "bcp/validation";
337
- ```
338
-
339
- Read more: [Validation](docs/validation.md)
340
-
341
- ## Error handling
342
-
343
- ```ts
344
- import {
345
- badRequest,
346
- forbidden,
347
- notFoundResponse,
348
- toErrorResponse,
349
- unauthorized,
350
- } from "bcp/error";
351
- ```
352
-
353
- The common error envelope is:
354
-
355
- ```json
356
- {
357
- "error": {
358
- "status": 400,
359
- "code": "BAD_REQUEST",
360
- "message": "Invalid request"
361
- }
362
- }
363
- ```
364
-
365
- Read more: [Error Handling](docs/error-handling.md)
161
+ - [JWT Sessions](docs/session-auth.md)
162
+ - [Server Request APIs](docs/server-request-apis.md)
366
163
 
367
164
  ## Database
368
165
 
@@ -372,7 +169,7 @@ import {
372
169
  } from "bcp/database";
373
170
  ```
374
171
 
375
- The database layer provides a lazy MySQL pool, prepared execution, query helpers, transactions and migrations.
172
+ The database layer provides lazy MySQL pool creation, prepared execution, query helpers, transactions and migrations.
376
173
 
377
174
  ```bash
378
175
  bcp db create create_users
@@ -386,71 +183,9 @@ Read more:
386
183
  - [Database](docs/database.md)
387
184
  - [Database Migrations](docs/database-migrations.md)
388
185
 
389
- ## Logging and observability
186
+ ## Uploads and streaming
390
187
 
391
- ```ts
392
- import {
393
- logger,
394
- requestLogger,
395
- } from "bcp/server";
396
-
397
- logger.info(
398
- "Application event",
399
- {
400
- feature:
401
- "catalog",
402
- }
403
- );
404
- ```
405
-
406
- Environment controls:
407
-
408
- ```env
409
- BCP_LOG_LEVEL=debug
410
- BCP_LOG_FORMAT=json
411
- ```
412
-
413
- Supported levels are `debug`, `info`, `warn`, `error` and `silent`. Formats are `pretty` and `json`.
414
-
415
- Read more: [Logging and Observability](docs/development-logging.md)
416
-
417
- ## File uploads
418
-
419
- BCP keeps the buffered multipart API for small forms:
420
-
421
- ```ts
422
- import {
423
- parseMultipartFormData,
424
- requireUploadedFile,
425
- saveUploadedFile,
426
- } from "bcp/server";
427
-
428
- const formData =
429
- await parseMultipartFormData(
430
- request,
431
- {
432
- maxBytes:
433
- 8 * 1024 * 1024,
434
- }
435
- );
436
-
437
- const file =
438
- requireUploadedFile(
439
- formData,
440
- "file",
441
- {
442
- maxBytes:
443
- 5 * 1024 * 1024,
444
- allowedTypes: [
445
- "image/png",
446
- "image/jpeg",
447
- "image/webp",
448
- ],
449
- }
450
- );
451
- ```
452
-
453
- BCP `0.1.26` adds direct multipart-to-storage streaming for larger production uploads:
188
+ BCP supports the original buffered multipart helpers as well as production multipart-to-storage streaming:
454
189
 
455
190
  ```ts
456
191
  import {
@@ -462,35 +197,24 @@ const stored =
462
197
  request,
463
198
  {
464
199
  storage,
465
- fieldName:
466
- "file",
467
- key:
468
- "documents/report.pdf",
469
- maxBytes:
470
- 100 * 1024 * 1024,
200
+ fieldName: "file",
201
+ key: "documents/report.pdf",
202
+ maxBytes: 100 * 1024 * 1024,
471
203
  constraints: {
472
- maxBytes:
473
- 80 * 1024 * 1024,
204
+ maxBytes: 80 * 1024 * 1024,
474
205
  allowedTypes: [
475
206
  "application/pdf",
476
207
  ],
477
- allowedExtensions: [
478
- ".pdf",
479
- ],
480
208
  },
481
209
  }
482
210
  );
483
211
  ```
484
212
 
485
- `storeMultipartFile()` parses `Request.body` incrementally and streams the selected file directly into the configured `StorageAdapter`. It does not call `request.formData()` for the target file.
486
-
487
- The security gateway still applies `server.bodyLimit` / `BCP_BODY_LIMIT` as the outer request limit. Streaming controls memory use; it does not bypass proxy/platform/body limits.
488
-
489
- MIME type and extension validation are metadata checks, not content-signature verification.
213
+ `storeMultipartFile()` consumes `Request.body` incrementally and streams the selected file directly into storage. Request/body infrastructure limits still apply.
490
214
 
491
215
  Read more: [File Upload](docs/file-upload.md)
492
216
 
493
- ## Storage adapters
217
+ ## Storage
494
218
 
495
219
  ### Local filesystem
496
220
 
@@ -501,14 +225,11 @@ import {
501
225
 
502
226
  const storage =
503
227
  createLocalStorage({
504
- directory:
505
- "./uploads",
228
+ directory: "./uploads",
506
229
  });
507
230
  ```
508
231
 
509
- ### S3-compatible storage
510
-
511
- BCP `0.1.26` adds an S3-compatible backend:
232
+ ### S3 / R2 / MinIO
512
233
 
513
234
  ```ts
514
235
  import {
@@ -517,40 +238,21 @@ import {
517
238
 
518
239
  const storage =
519
240
  createS3Storage({
520
- bucket:
521
- process.env.S3_BUCKET!,
522
- region:
523
- process.env.S3_REGION!,
524
- endpoint:
525
- process.env.S3_ENDPOINT,
526
- accessKeyId:
527
- process.env.S3_ACCESS_KEY_ID,
528
- secretAccessKey:
529
- process.env.S3_SECRET_ACCESS_KEY,
241
+ bucket: process.env.S3_BUCKET!,
242
+ region: process.env.S3_REGION!,
243
+ endpoint: process.env.S3_ENDPOINT,
244
+ accessKeyId: process.env.S3_ACCESS_KEY_ID,
245
+ secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
530
246
  });
531
247
  ```
532
248
 
533
- Custom endpoints and `forcePathStyle` allow use with S3-compatible services such as MinIO. Explicit credentials are optional; when omitted, the AWS SDK can use its normal server-side credential provider chain.
534
-
535
- Keep cloud credentials server-only. Never expose them through `BCP_PUBLIC_*` variables.
249
+ Custom endpoints and `forcePathStyle` support common S3-compatible deployments such as MinIO. Keep credentials server-only.
536
250
 
537
251
  Read more: [S3-Compatible Storage](docs/s3-storage.md)
538
252
 
539
253
  ### Streaming storage
540
254
 
541
- The `StorageAdapter` contract keeps its original buffered methods and adds optional streaming capabilities:
542
-
543
- ```text
544
- put
545
- putStream? ← 0.1.26
546
- stat
547
- read
548
- readStream? ← 0.1.26
549
- exists
550
- delete
551
- ```
552
-
553
- Use generic helpers so legacy and native-streaming adapters can share application code:
255
+ The stable minimum `StorageAdapter` retains its buffered API while adapters can expose optional `putStream()` and `readStream()` implementations.
554
256
 
555
257
  ```ts
556
258
  import {
@@ -560,152 +262,127 @@ import {
560
262
  } from "bcp/server";
561
263
  ```
562
264
 
563
- Both built-in `0.1.26` adapters support native streaming reads, streaming writes and byte ranges.
564
-
565
- Streaming writes support `maxBytes` and `AbortSignal`. Local incomplete objects are removed on failure; S3 multipart uploads are configured to clean up parts on failed completion.
265
+ Both built-in local and S3 adapters support streaming reads/writes and byte ranges.
566
266
 
567
267
  Read more: [Storage and File Delivery](docs/storage.md)
568
268
 
569
- ## Production file delivery
269
+ ### Storage Ecosystem — 0.1.27
270
+
271
+ BCP `0.1.27` adds a richer, additive object-storage API without invalidating older `StorageAdapter` implementations:
570
272
 
571
273
  ```ts
572
274
  import {
573
- createStorageResponse,
275
+ copyStorageObject,
276
+ createStorageSignedReadUrl,
277
+ createStorageSignedWriteUrl,
278
+ deleteStorageObjects,
279
+ getStorageEcosystemCapabilities,
280
+ getStorageMetadata,
281
+ listStorageObjects,
282
+ moveStorageObject,
283
+ setStorageMetadata,
574
284
  } from "bcp/server";
285
+ ```
575
286
 
576
- export function GET(
577
- request: Request
578
- ) {
579
- return createStorageResponse(
580
- request,
287
+ Listing supports prefix filtering, limits and opaque cursors:
288
+
289
+ ```ts
290
+ const page =
291
+ await listStorageObjects(
581
292
  storage,
582
- "documents/report.pdf",
583
293
  {
584
- disposition:
585
- "attachment",
586
- downloadName:
587
- "report.pdf",
294
+ prefix: "documents/",
295
+ limit: 50,
588
296
  }
589
297
  );
590
- }
591
- ```
592
-
593
- `createStorageResponse()` uses storage streaming and supports:
594
-
595
- - `GET` / `HEAD`,
596
- - ETag / Last-Modified validators,
597
- - `If-Range`,
598
- - single byte ranges with `206 Partial Content`,
599
- - `304 Not Modified`,
600
- - `416 Range Not Satisfiable`,
601
- - safe `Content-Disposition` filenames,
602
- - configurable cache control.
603
-
604
- The default cache policy remains:
605
-
606
- ```text
607
- private, max-age=0, must-revalidate
608
298
  ```
609
299
 
610
- Multiple byte ranges remain intentionally unsupported in `0.1.26`.
611
-
612
- Read more: [Storage and File Delivery](docs/storage.md)
613
-
614
- ## Caching
615
-
616
- BCP includes response caching and revalidation primitives used by development and standalone production runtimes.
617
-
618
- Read more: [Caching](docs/caching.md)
619
-
620
- ## Security
621
-
622
- The framework security layer includes request body limits and production request handling defaults. Application authorization remains the responsibility of route guards and application logic.
623
-
624
- Storage keys, filenames and MIME metadata must not be treated as authorization decisions.
625
-
626
- Read more: [Security](docs/security.md)
627
-
628
- ## Environment and configuration
300
+ Copy and move use native adapter operations when available, with portable fallback behavior where practical:
629
301
 
630
- Application configuration lives in:
302
+ ```ts
303
+ await copyStorageObject(
304
+ storage,
305
+ "incoming/report.pdf",
306
+ "archive/report.pdf"
307
+ );
631
308
 
632
- ```text
633
- bcp.config.ts
309
+ await moveStorageObject(
310
+ storage,
311
+ "tmp/avatar.webp",
312
+ "users/42/avatar.webp"
313
+ );
634
314
  ```
635
315
 
636
- Public environment variables use:
316
+ Portable user metadata is string-to-string metadata and is distinct from application authorization/business state:
637
317
 
638
- ```text
639
- BCP_PUBLIC_
318
+ ```ts
319
+ await setStorageMetadata(
320
+ storage,
321
+ "archive/report.pdf",
322
+ {
323
+ owner: "user-42",
324
+ status: "approved",
325
+ }
326
+ );
640
327
  ```
641
328
 
642
- Server-only values remain server-side and are not emitted into browser bundles.
329
+ S3-compatible storage also supports short-lived presigned direct-transfer URLs:
643
330
 
644
- Read more: [Configuration](docs/configuration.md)
645
-
646
- ## Developer tools
331
+ ```ts
332
+ const downloadUrl =
333
+ await createStorageSignedReadUrl(
334
+ storage,
335
+ "videos/demo.mp4",
336
+ {
337
+ expiresIn: 300,
338
+ }
339
+ );
647
340
 
648
- ```bash
649
- bcp doctor
650
- bcp inspect
341
+ const uploadUrl =
342
+ await createStorageSignedWriteUrl(
343
+ storage,
344
+ "uploads/demo.mp4",
345
+ {
346
+ expiresIn: 300,
347
+ contentType: "video/mp4",
348
+ }
349
+ );
651
350
  ```
652
351
 
653
- `bcp doctor` checks project structure, BCP/React installation parity, duplicate framework copies, environment/config loading, route conflicts and client/server boundaries.
654
-
655
- `bcp inspect` reports resolved configuration, environment sources, dependency versions and discovered routes.
656
-
657
- Read more: [Developer Tools](docs/developer-tools.md)
352
+ Local storage intentionally does not emulate signed URLs. Signed URLs are temporary credentials and should only be generated after application authorization.
658
353
 
659
- ## Windows CLI
354
+ Read more: [Storage Ecosystem](docs/storage-ecosystem.md)
660
355
 
661
- Microsoft SQL Server can install another executable named `bcp.exe`. BCP therefore publishes the collision-free alias `bcp-framework`.
356
+ ## File delivery
662
357
 
663
- Inside npm scripts, `bcp` is safe because npm prepends the project's `node_modules/.bin` to `PATH`.
358
+ `createStorageResponse()` serves local or cloud-backed objects through the same API with `GET`, `HEAD`, ETag/Last-Modified validators and single byte ranges.
664
359
 
665
- For direct PowerShell usage, use the project-local CLI:
360
+ ```ts
361
+ import {
362
+ createStorageResponse,
363
+ } from "bcp/server";
666
364
 
667
- ```powershell
668
- npm exec -- bcp-framework --version
669
- npm exec -- bcp-framework doctor
670
- npm exec -- bcp-framework inspect
671
- npm exec -- bcp-framework routes
672
- npm exec -- bcp-framework dev
673
- npm exec -- bcp-framework build
365
+ return createStorageResponse(
366
+ request,
367
+ storage,
368
+ "documents/report.pdf"
369
+ );
674
370
  ```
675
371
 
676
- This keeps the CLI version aligned with the framework installed by the application.
677
-
678
- ## CLI reference
679
-
680
- ```bash
681
- bcp dev
682
- bcp routes
683
- bcp build
684
- bcp start
685
- bcp doctor
686
- bcp doctor --json
687
- bcp inspect
688
- bcp inspect --json
689
- bcp update
690
- bcp version
691
-
692
- bcp db create create_users
693
- bcp db migrate
694
- bcp db status
695
- bcp db rollback
696
- ```
372
+ Read more: [Storage and File Delivery](docs/storage.md)
697
373
 
698
- ## Development behavior
374
+ ## Middleware, validation, errors and caching
699
375
 
700
- BCP includes Fast Refresh and deterministic development hydration behavior. Recent stabilization work covers:
376
+ BCP includes Middleware System v2, typed validation helpers, structured HTTP errors, structured logging and response caching/revalidation.
701
377
 
702
- - Windows line-ending parity,
703
- - multiline JSX hydration parity,
704
- - duplicate BCP installation detection,
705
- - automatic page-route/client-bundle graph resynchronization,
706
- - standalone authentication guard request-context parity.
378
+ Read more:
707
379
 
708
- Read more: [Hydration](docs/hydration.md)
380
+ - [Middleware](docs/middleware.md)
381
+ - [Validation](docs/validation.md)
382
+ - [Error Handling](docs/error-handling.md)
383
+ - [Logging and Observability](docs/development-logging.md)
384
+ - [Caching](docs/caching.md)
385
+ - [Security](docs/security.md)
709
386
 
710
387
  ## Production build
711
388
 
@@ -714,7 +391,7 @@ npm run build
714
391
  npm run start
715
392
  ```
716
393
 
717
- Production output:
394
+ Standalone output is written under:
718
395
 
719
396
  ```text
720
397
  .bcp-framework/build/
@@ -724,11 +401,26 @@ Production output:
724
401
  └─ server.mjs
725
402
  ```
726
403
 
727
- The standalone runtime composes production middleware, security, cache, actions, guards, loaders and page rendering into the final HTTP pipeline.
404
+ Read more: [Deployment](docs/deployment.md)
728
405
 
729
- Runtime hostname/port overrides can be supplied to `bcp start` without rebuilding.
406
+ ## Windows CLI
730
407
 
731
- Read more: [Deployment](docs/deployment.md)
408
+ Microsoft SQL Server can install another executable named `bcp.exe`. BCP publishes the collision-free alias `bcp-framework`.
409
+
410
+ Inside project npm scripts, `bcp` is safe because npm prepends `node_modules/.bin` to `PATH`.
411
+
412
+ For direct PowerShell usage:
413
+
414
+ ```powershell
415
+ npm exec -- bcp-framework --version
416
+ npm exec -- bcp-framework doctor
417
+ npm exec -- bcp-framework inspect
418
+ npm exec -- bcp-framework routes
419
+ npm exec -- bcp-framework dev
420
+ npm exec -- bcp-framework build
421
+ ```
422
+
423
+ Read more: [Developer Tools](docs/developer-tools.md)
732
424
 
733
425
  ## Updating BCP
734
426
 
@@ -736,22 +428,14 @@ Read more: [Deployment](docs/deployment.md)
736
428
  bcp update
737
429
  bcp update --check
738
430
  bcp update --dry-run
739
- bcp update 0.1.26
431
+ bcp update 0.1.27
740
432
  bcp update next
741
433
  ```
742
434
 
743
- Projects created before the updater was introduced can bootstrap it once with:
744
-
745
- ```bash
746
- npx @chidchanun/bcp@latest update
747
- ```
748
-
749
435
  Read more: [Updating](docs/updating.md)
750
436
 
751
437
  ## Framework development and release validation
752
438
 
753
- Inside the BCP Framework repository:
754
-
755
439
  ```bash
756
440
  npm install
757
441
  npm run typecheck
@@ -759,70 +443,40 @@ npm run test:unit
759
443
  npm run test:integration
760
444
  npm run test:e2e
761
445
  npm run test:package
762
- ```
763
-
764
- Full release-candidate validation:
765
-
766
- ```bash
767
446
  npm run rc:check
768
447
  ```
769
448
 
770
- A version must not be tagged or published until RC and packed-package verification pass.
449
+ A version must not be tagged or published until its RC and packed-package verification pass.
771
450
 
772
451
  Read more: [Releasing](docs/releasing.md)
773
452
 
774
453
  ## Documentation source
775
454
 
776
- The `docs/` directory is the source content for the future **`bcp-docs-web`** documentation website.
455
+ The `docs/` directory is the authored source for **`bcp-docs-web`**.
777
456
 
778
- Start with:
457
+ Recommended starting points:
779
458
 
780
459
  - [Documentation Source Map](docs/README.md)
781
460
  - [Getting Started](docs/getting-started.md)
782
461
  - [Configuration](docs/configuration.md)
783
- - [Application Modules](docs/application-modules.md)
784
462
  - [Routing](docs/routing.md)
785
463
  - [Server Data Loaders](docs/server-data-loaders.md)
786
464
  - [Route Guards](docs/route-guards.md)
787
465
  - [Form Actions](docs/form-actions.md)
788
466
  - [Server Request APIs](docs/server-request-apis.md)
789
- - [Validation](docs/validation.md)
790
- - [Error Handling](docs/error-handling.md)
791
467
  - [File Upload](docs/file-upload.md)
792
468
  - [Storage and File Delivery](docs/storage.md)
469
+ - [Storage Ecosystem](docs/storage-ecosystem.md)
793
470
  - [S3-Compatible Storage](docs/s3-storage.md)
794
471
  - [Authentication](docs/authentication.md)
795
- - [Auth Route Guards](docs/auth-route-guards.md)
796
- - [JWT Sessions](docs/session-auth.md)
797
472
  - [Database](docs/database.md)
798
- - [Database Migrations](docs/database-migrations.md)
799
473
  - [Middleware](docs/middleware.md)
800
- - [Hydration](docs/hydration.md)
801
474
  - [Developer Tools](docs/developer-tools.md)
802
- - [Logging and Observability](docs/development-logging.md)
803
- - [Caching](docs/caching.md)
804
- - [Security](docs/security.md)
805
475
  - [Deployment](docs/deployment.md)
806
- - [Updating](docs/updating.md)
807
476
  - [Releasing](docs/releasing.md)
808
477
 
809
- Recommended `bcp-docs-web` top-level navigation:
810
-
811
- ```text
812
- Getting Started
813
- Routing & Data
814
- Authentication
815
- Database
816
- Runtime & Infrastructure
817
- Storage & Uploads
818
- API Reference
819
- Releases
820
- ```
821
-
822
478
  ## Release history
823
479
 
824
- Release notes live under `docs/releases/`.
825
-
826
480
  | Version | Milestone |
827
481
  | --- | --- |
828
482
  | `0.1.20` | Hydration line-ending stabilization |
@@ -832,17 +486,21 @@ Release notes live under `docs/releases/`.
832
486
  | `0.1.24` | File Upload Foundation |
833
487
  | `0.1.25` | Storage Adapters and File Delivery |
834
488
  | `0.1.26` | S3-Compatible Storage and Production Streaming |
489
+ | `0.1.27` | Storage Ecosystem |
835
490
 
836
491
  ## Next direction
837
492
 
838
- After `0.1.26`, the recommended direction is:
493
+ After `0.1.27`, the planned milestone is **`0.1.28 — Production Hardening`**:
839
494
 
840
- 1. signed storage URLs where needed,
841
- 2. object listing/copy/move capabilities,
842
- 3. broader production hardening and graceful shutdown,
843
- 4. stronger storage/provider diagnostics.
495
+ 1. graceful HTTP shutdown and active-request draining,
496
+ 2. database/S3 resource cleanup,
497
+ 3. trusted proxy and forwarded-header handling,
498
+ 4. request/server timeout controls,
499
+ 5. security hardening,
500
+ 6. Docker and standalone-runtime regression coverage,
501
+ 7. stronger startup/runtime diagnostics.
844
502
 
845
- These are roadmap items, not `0.1.26` API guarantees.
503
+ These are roadmap items, not `0.1.27` guarantees.
846
504
 
847
505
  ## License
848
506