@chidchanun/bcp 0.1.25 → 0.1.26
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 +169 -263
- package/docs/README.md +148 -210
- package/docs/file-upload.md +194 -32
- package/docs/releases/0.1.26.md +281 -0
- package/docs/s3-storage.md +276 -0
- package/docs/storage.md +278 -162
- package/package.json +5 -2
- package/packages/client/src/database.mjs +236 -0
- package/packages/client/src/server.ts +22 -0
- package/packages/server/src/file-delivery.ts +8 -24
- package/packages/server/src/storage-s3.ts +1159 -0
- package/packages/server/src/storage.ts +740 -54
- package/packages/server/src/upload-stream.ts +846 -0
package/README.md
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
# BCP Framework
|
|
2
2
|
|
|
3
|
-
BCP Framework is a React full-stack framework focused on file-based routing,
|
|
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.
|
|
4
4
|
|
|
5
|
-
> **
|
|
5
|
+
> **Release candidate target:** `0.1.26`
|
|
6
6
|
>
|
|
7
|
-
> BCP is
|
|
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
8
|
|
|
9
9
|
## Overview
|
|
10
10
|
|
|
11
|
-
BCP
|
|
11
|
+
BCP keeps React pages and their server behavior close to the route that owns them:
|
|
12
12
|
|
|
13
13
|
```text
|
|
14
14
|
Browser
|
|
15
15
|
↓
|
|
16
|
-
BCP middleware /
|
|
16
|
+
BCP security / middleware / cache
|
|
17
17
|
↓
|
|
18
18
|
Route guard
|
|
19
19
|
↓
|
|
@@ -24,7 +24,7 @@ React SSR
|
|
|
24
24
|
Hydration / SPA navigation
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
A typical route can colocate its page, loader, guard and actions:
|
|
28
28
|
|
|
29
29
|
```text
|
|
30
30
|
app/
|
|
@@ -57,8 +57,8 @@ app/
|
|
|
57
57
|
| Error handling | HTTP error helpers and consistent error responses |
|
|
58
58
|
| Database | MySQL pool/query helpers, transactions and migrations |
|
|
59
59
|
| Logging | Structured logger, request logger and request IDs |
|
|
60
|
-
| Uploads |
|
|
61
|
-
| Storage |
|
|
60
|
+
| Uploads | Buffered multipart helpers and production multipart streaming |
|
|
61
|
+
| Storage | Local + S3-compatible adapters, streaming I/O and ranged delivery |
|
|
62
62
|
| Caching | Response cache and revalidation primitives |
|
|
63
63
|
| Developer tools | `doctor`, `inspect`, updater and route inspection |
|
|
64
64
|
| Production | Standalone server build with production middleware pipeline |
|
|
@@ -73,8 +73,6 @@ Database features currently target MySQL.
|
|
|
73
73
|
|
|
74
74
|
## Quick start
|
|
75
75
|
|
|
76
|
-
Create a new application:
|
|
77
|
-
|
|
78
76
|
```bash
|
|
79
77
|
npx create-bcp-app@latest my-app
|
|
80
78
|
cd my-app
|
|
@@ -87,7 +85,7 @@ Default development URL:
|
|
|
87
85
|
http://localhost:3000
|
|
88
86
|
```
|
|
89
87
|
|
|
90
|
-
|
|
88
|
+
Generated projects normally include:
|
|
91
89
|
|
|
92
90
|
```json
|
|
93
91
|
{
|
|
@@ -96,7 +94,8 @@ A generated project normally exposes scripts such as:
|
|
|
96
94
|
"build": "bcp build",
|
|
97
95
|
"start": "bcp start",
|
|
98
96
|
"routes": "bcp routes",
|
|
99
|
-
"update": "bcp update"
|
|
97
|
+
"update": "bcp update",
|
|
98
|
+
"typecheck": "tsc --noEmit"
|
|
100
99
|
}
|
|
101
100
|
}
|
|
102
101
|
```
|
|
@@ -109,13 +108,7 @@ The public framework package is published as:
|
|
|
109
108
|
@chidchanun/bcp
|
|
110
109
|
```
|
|
111
110
|
|
|
112
|
-
Applications normally consume it through the dependency key:
|
|
113
|
-
|
|
114
|
-
```text
|
|
115
|
-
bcp
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
This keeps imports concise:
|
|
111
|
+
Applications normally consume it through the dependency key `bcp`, keeping imports concise:
|
|
119
112
|
|
|
120
113
|
```ts
|
|
121
114
|
import {
|
|
@@ -125,7 +118,7 @@ import {
|
|
|
125
118
|
} from "bcp";
|
|
126
119
|
```
|
|
127
120
|
|
|
128
|
-
Server-only APIs use dedicated entrypoints
|
|
121
|
+
Server-only APIs use dedicated entrypoints:
|
|
129
122
|
|
|
130
123
|
```ts
|
|
131
124
|
import {
|
|
@@ -137,8 +130,6 @@ import {
|
|
|
137
130
|
|
|
138
131
|
## Project structure
|
|
139
132
|
|
|
140
|
-
A typical application can grow into this layout:
|
|
141
|
-
|
|
142
133
|
```text
|
|
143
134
|
app/
|
|
144
135
|
├─ layout.tsx
|
|
@@ -168,11 +159,9 @@ package.json
|
|
|
168
159
|
tsconfig.json
|
|
169
160
|
```
|
|
170
161
|
|
|
171
|
-
BCP keeps page rendering, route authorization, server data and route mutations close together without requiring one large application router configuration file.
|
|
172
|
-
|
|
173
162
|
## Routing
|
|
174
163
|
|
|
175
|
-
Page routes are discovered from `app/**/page.tsx
|
|
164
|
+
Page routes are discovered from `app/**/page.tsx`:
|
|
176
165
|
|
|
177
166
|
```text
|
|
178
167
|
app/page.tsx /
|
|
@@ -196,15 +185,13 @@ Read more: [Routing](docs/routing.md)
|
|
|
196
185
|
|
|
197
186
|
## Layouts and metadata
|
|
198
187
|
|
|
199
|
-
Routes
|
|
200
|
-
|
|
201
|
-
Document metadata is route-aware and can be generated alongside the page tree.
|
|
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.
|
|
202
189
|
|
|
203
190
|
Read more: [Routing](docs/routing.md)
|
|
204
191
|
|
|
205
192
|
## Server data loaders
|
|
206
193
|
|
|
207
|
-
Place `loader.ts` next to a page when the route needs server-side data
|
|
194
|
+
Place `loader.ts` next to a page when the route needs server-side data:
|
|
208
195
|
|
|
209
196
|
```ts
|
|
210
197
|
// app/users/[id]/loader.ts
|
|
@@ -218,7 +205,7 @@ export async function loader({
|
|
|
218
205
|
}
|
|
219
206
|
```
|
|
220
207
|
|
|
221
|
-
Consume
|
|
208
|
+
Consume serializable loader data from a client page:
|
|
222
209
|
|
|
223
210
|
```tsx
|
|
224
211
|
"use client";
|
|
@@ -233,11 +220,7 @@ export default function UserPage() {
|
|
|
233
220
|
id: string;
|
|
234
221
|
}>();
|
|
235
222
|
|
|
236
|
-
return
|
|
237
|
-
<main>
|
|
238
|
-
User {data.id}
|
|
239
|
-
</main>
|
|
240
|
-
);
|
|
223
|
+
return <main>User {data.id}</main>;
|
|
241
224
|
}
|
|
242
225
|
```
|
|
243
226
|
|
|
@@ -245,9 +228,7 @@ Read more: [Server Data Loaders](docs/server-data-loaders.md)
|
|
|
245
228
|
|
|
246
229
|
## Route guards
|
|
247
230
|
|
|
248
|
-
A route tree can define `guard.ts` to authorize access before
|
|
249
|
-
|
|
250
|
-
Authentication-aware guards are available through `bcp/auth`:
|
|
231
|
+
A route tree can define `guard.ts` to authorize access before rendering:
|
|
251
232
|
|
|
252
233
|
```ts
|
|
253
234
|
import {
|
|
@@ -267,16 +248,12 @@ Read more:
|
|
|
267
248
|
|
|
268
249
|
## Form actions
|
|
269
250
|
|
|
270
|
-
Route-owned mutations live in `actions.ts` and can be invoked through the public `<Form>` API.
|
|
271
|
-
|
|
272
|
-
This supports both progressive form submission and SPA action transport while keeping mutation logic server-only.
|
|
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.
|
|
273
252
|
|
|
274
253
|
Read more: [Form Actions](docs/form-actions.md)
|
|
275
254
|
|
|
276
255
|
## Server request APIs
|
|
277
256
|
|
|
278
|
-
Request-scoped APIs are exposed through `bcp/server`:
|
|
279
|
-
|
|
280
257
|
```ts
|
|
281
258
|
import {
|
|
282
259
|
bearerToken,
|
|
@@ -289,13 +266,13 @@ import {
|
|
|
289
266
|
} from "bcp/server";
|
|
290
267
|
```
|
|
291
268
|
|
|
292
|
-
`requestId()`
|
|
269
|
+
`requestId()` accepts a valid incoming `X-Request-Id` or generates a stable UUID for the active request.
|
|
293
270
|
|
|
294
271
|
Read more: [Server Request APIs](docs/server-request-apis.md)
|
|
295
272
|
|
|
296
273
|
## Authentication and sessions
|
|
297
274
|
|
|
298
|
-
High-level authentication helpers
|
|
275
|
+
High-level authentication helpers:
|
|
299
276
|
|
|
300
277
|
```ts
|
|
301
278
|
import {
|
|
@@ -305,7 +282,7 @@ import {
|
|
|
305
282
|
} from "bcp/auth";
|
|
306
283
|
```
|
|
307
284
|
|
|
308
|
-
Lower-level JWT cookie session primitives
|
|
285
|
+
Lower-level JWT cookie session primitives:
|
|
309
286
|
|
|
310
287
|
```ts
|
|
311
288
|
import {
|
|
@@ -317,7 +294,7 @@ import {
|
|
|
317
294
|
} from "bcp/server";
|
|
318
295
|
```
|
|
319
296
|
|
|
320
|
-
Authentication is
|
|
297
|
+
Authentication is separated from application-specific credential lookup so projects can connect their own user table or identity provider.
|
|
321
298
|
|
|
322
299
|
Read more:
|
|
323
300
|
|
|
@@ -346,16 +323,12 @@ export async function middleware(
|
|
|
346
323
|
}
|
|
347
324
|
```
|
|
348
325
|
|
|
349
|
-
This allows middleware to run logic both before and after downstream route execution.
|
|
350
|
-
|
|
351
326
|
Existing middleware v1 behavior remains supported for compatibility.
|
|
352
327
|
|
|
353
328
|
Read more: [Middleware](docs/middleware.md)
|
|
354
329
|
|
|
355
330
|
## Validation
|
|
356
331
|
|
|
357
|
-
BCP includes typed validation primitives:
|
|
358
|
-
|
|
359
332
|
```ts
|
|
360
333
|
import {
|
|
361
334
|
v,
|
|
@@ -363,14 +336,10 @@ import {
|
|
|
363
336
|
} from "bcp/validation";
|
|
364
337
|
```
|
|
365
338
|
|
|
366
|
-
Validation can be shared by API routes and form actions without coupling application schemas to the rendering layer.
|
|
367
|
-
|
|
368
339
|
Read more: [Validation](docs/validation.md)
|
|
369
340
|
|
|
370
341
|
## Error handling
|
|
371
342
|
|
|
372
|
-
Structured HTTP error helpers are exposed through `bcp/error`:
|
|
373
|
-
|
|
374
343
|
```ts
|
|
375
344
|
import {
|
|
376
345
|
badRequest,
|
|
@@ -397,23 +366,13 @@ Read more: [Error Handling](docs/error-handling.md)
|
|
|
397
366
|
|
|
398
367
|
## Database
|
|
399
368
|
|
|
400
|
-
Database helpers are exposed through:
|
|
401
|
-
|
|
402
369
|
```ts
|
|
403
370
|
import {
|
|
404
371
|
db,
|
|
405
372
|
} from "bcp/database";
|
|
406
373
|
```
|
|
407
374
|
|
|
408
|
-
The database layer provides
|
|
409
|
-
|
|
410
|
-
- lazy MySQL pool creation,
|
|
411
|
-
- prepared execution,
|
|
412
|
-
- query helpers,
|
|
413
|
-
- transactions,
|
|
414
|
-
- migration status and rollback support.
|
|
415
|
-
|
|
416
|
-
Migration commands:
|
|
375
|
+
The database layer provides a lazy MySQL pool, prepared execution, query helpers, transactions and migrations.
|
|
417
376
|
|
|
418
377
|
```bash
|
|
419
378
|
bcp db create create_users
|
|
@@ -429,8 +388,6 @@ Read more:
|
|
|
429
388
|
|
|
430
389
|
## Logging and observability
|
|
431
390
|
|
|
432
|
-
Structured server logging is available through `bcp/server`:
|
|
433
|
-
|
|
434
391
|
```ts
|
|
435
392
|
import {
|
|
436
393
|
logger,
|
|
@@ -446,26 +403,6 @@ logger.info(
|
|
|
446
403
|
);
|
|
447
404
|
```
|
|
448
405
|
|
|
449
|
-
Request-scoped logging can automatically include request identity:
|
|
450
|
-
|
|
451
|
-
```ts
|
|
452
|
-
export async function loader() {
|
|
453
|
-
const log =
|
|
454
|
-
await requestLogger({
|
|
455
|
-
feature:
|
|
456
|
-
"categories",
|
|
457
|
-
});
|
|
458
|
-
|
|
459
|
-
log.info(
|
|
460
|
-
"Loading categories"
|
|
461
|
-
);
|
|
462
|
-
|
|
463
|
-
return {
|
|
464
|
-
items: [],
|
|
465
|
-
};
|
|
466
|
-
}
|
|
467
|
-
```
|
|
468
|
-
|
|
469
406
|
Environment controls:
|
|
470
407
|
|
|
471
408
|
```env
|
|
@@ -473,28 +410,13 @@ BCP_LOG_LEVEL=debug
|
|
|
473
410
|
BCP_LOG_FORMAT=json
|
|
474
411
|
```
|
|
475
412
|
|
|
476
|
-
Supported levels
|
|
477
|
-
|
|
478
|
-
```text
|
|
479
|
-
debug
|
|
480
|
-
info
|
|
481
|
-
warn
|
|
482
|
-
error
|
|
483
|
-
silent
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
Supported formats:
|
|
487
|
-
|
|
488
|
-
```text
|
|
489
|
-
pretty
|
|
490
|
-
json
|
|
491
|
-
```
|
|
413
|
+
Supported levels are `debug`, `info`, `warn`, `error` and `silent`. Formats are `pretty` and `json`.
|
|
492
414
|
|
|
493
415
|
Read more: [Logging and Observability](docs/development-logging.md)
|
|
494
416
|
|
|
495
|
-
## File
|
|
417
|
+
## File uploads
|
|
496
418
|
|
|
497
|
-
BCP
|
|
419
|
+
BCP keeps the buffered multipart API for small forms:
|
|
498
420
|
|
|
499
421
|
```ts
|
|
500
422
|
import {
|
|
@@ -503,90 +425,78 @@ import {
|
|
|
503
425
|
saveUploadedFile,
|
|
504
426
|
} from "bcp/server";
|
|
505
427
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
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:
|
|
454
|
+
|
|
455
|
+
```ts
|
|
456
|
+
import {
|
|
457
|
+
storeMultipartFile,
|
|
458
|
+
} from "bcp/server";
|
|
459
|
+
|
|
460
|
+
const stored =
|
|
461
|
+
await storeMultipartFile(
|
|
462
|
+
request,
|
|
463
|
+
{
|
|
464
|
+
storage,
|
|
465
|
+
fieldName:
|
|
466
|
+
"file",
|
|
467
|
+
key:
|
|
468
|
+
"documents/report.pdf",
|
|
469
|
+
maxBytes:
|
|
470
|
+
100 * 1024 * 1024,
|
|
471
|
+
constraints: {
|
|
523
472
|
maxBytes:
|
|
524
|
-
|
|
473
|
+
80 * 1024 * 1024,
|
|
525
474
|
allowedTypes: [
|
|
526
|
-
"
|
|
527
|
-
"image/jpeg",
|
|
528
|
-
"image/webp",
|
|
475
|
+
"application/pdf",
|
|
529
476
|
],
|
|
530
477
|
allowedExtensions: [
|
|
531
|
-
".
|
|
532
|
-
".jpg",
|
|
533
|
-
".jpeg",
|
|
534
|
-
".webp",
|
|
478
|
+
".pdf",
|
|
535
479
|
],
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
return Response.json(
|
|
540
|
-
await saveUploadedFile(
|
|
541
|
-
file,
|
|
542
|
-
{
|
|
543
|
-
directory:
|
|
544
|
-
"./uploads",
|
|
545
|
-
}
|
|
546
|
-
)
|
|
480
|
+
},
|
|
481
|
+
}
|
|
547
482
|
);
|
|
548
|
-
}
|
|
549
483
|
```
|
|
550
484
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
- multipart validation,
|
|
554
|
-
- total request and per-file size limits,
|
|
555
|
-
- MIME and extension allowlists,
|
|
556
|
-
- required/optional file fields,
|
|
557
|
-
- safe UUID-based storage names,
|
|
558
|
-
- filename sanitization,
|
|
559
|
-
- path traversal protection,
|
|
560
|
-
- no-overwrite-by-default persistence,
|
|
561
|
-
- SHA-256 checksum metadata.
|
|
562
|
-
|
|
563
|
-
The security gateway applies `server.bodyLimit` / `BCP_BODY_LIMIT` before application upload parsing. Applications accepting larger files must raise that outer limit explicitly.
|
|
564
|
-
|
|
565
|
-
```ts
|
|
566
|
-
import {
|
|
567
|
-
defineConfig,
|
|
568
|
-
} from "bcp/config";
|
|
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.
|
|
569
486
|
|
|
570
|
-
|
|
571
|
-
server: {
|
|
572
|
-
bodyLimit:
|
|
573
|
-
10 * 1024 * 1024,
|
|
574
|
-
},
|
|
575
|
-
});
|
|
576
|
-
```
|
|
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.
|
|
577
488
|
|
|
578
|
-
MIME type and extension validation are metadata checks, not content-signature verification.
|
|
489
|
+
MIME type and extension validation are metadata checks, not content-signature verification.
|
|
579
490
|
|
|
580
491
|
Read more: [File Upload](docs/file-upload.md)
|
|
581
492
|
|
|
582
493
|
## Storage adapters
|
|
583
494
|
|
|
584
|
-
|
|
495
|
+
### Local filesystem
|
|
585
496
|
|
|
586
497
|
```ts
|
|
587
498
|
import {
|
|
588
499
|
createLocalStorage,
|
|
589
|
-
storeUploadedFile,
|
|
590
500
|
} from "bcp/server";
|
|
591
501
|
|
|
592
502
|
const storage =
|
|
@@ -594,46 +504,76 @@ const storage =
|
|
|
594
504
|
directory:
|
|
595
505
|
"./uploads",
|
|
596
506
|
});
|
|
507
|
+
```
|
|
597
508
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
509
|
+
### S3-compatible storage
|
|
510
|
+
|
|
511
|
+
BCP `0.1.26` adds an S3-compatible backend:
|
|
512
|
+
|
|
513
|
+
```ts
|
|
514
|
+
import {
|
|
515
|
+
createS3Storage,
|
|
516
|
+
} from "bcp/server";
|
|
517
|
+
|
|
518
|
+
const storage =
|
|
519
|
+
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,
|
|
530
|
+
});
|
|
607
531
|
```
|
|
608
532
|
|
|
609
|
-
|
|
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.
|
|
536
|
+
|
|
537
|
+
Read more: [S3-Compatible Storage](docs/s3-storage.md)
|
|
538
|
+
|
|
539
|
+
### Streaming storage
|
|
540
|
+
|
|
541
|
+
The `StorageAdapter` contract keeps its original buffered methods and adds optional streaming capabilities:
|
|
610
542
|
|
|
611
543
|
```text
|
|
612
544
|
put
|
|
545
|
+
putStream? ← 0.1.26
|
|
613
546
|
stat
|
|
614
547
|
read
|
|
548
|
+
readStream? ← 0.1.26
|
|
615
549
|
exists
|
|
616
550
|
delete
|
|
617
551
|
```
|
|
618
552
|
|
|
619
|
-
|
|
553
|
+
Use generic helpers so legacy and native-streaming adapters can share application code:
|
|
620
554
|
|
|
621
|
-
|
|
555
|
+
```ts
|
|
556
|
+
import {
|
|
557
|
+
getStorageCapabilities,
|
|
558
|
+
putStorageStream,
|
|
559
|
+
readStorageStream,
|
|
560
|
+
} from "bcp/server";
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
Both built-in `0.1.26` adapters support native streaming reads, streaming writes and byte ranges.
|
|
622
564
|
|
|
623
|
-
|
|
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.
|
|
624
566
|
|
|
625
567
|
Read more: [Storage and File Delivery](docs/storage.md)
|
|
626
568
|
|
|
627
569
|
## Production file delivery
|
|
628
570
|
|
|
629
|
-
Storage objects can be returned through a hardened HTTP response helper:
|
|
630
|
-
|
|
631
571
|
```ts
|
|
632
572
|
import {
|
|
633
573
|
createStorageResponse,
|
|
634
574
|
} from "bcp/server";
|
|
635
575
|
|
|
636
|
-
export
|
|
576
|
+
export function GET(
|
|
637
577
|
request: Request
|
|
638
578
|
) {
|
|
639
579
|
return createStorageResponse(
|
|
@@ -650,41 +590,36 @@ export async function GET(
|
|
|
650
590
|
}
|
|
651
591
|
```
|
|
652
592
|
|
|
653
|
-
`createStorageResponse()` supports:
|
|
593
|
+
`createStorageResponse()` uses storage streaming and supports:
|
|
654
594
|
|
|
655
|
-
- `GET`,
|
|
656
|
-
-
|
|
657
|
-
- `ETag`,
|
|
658
|
-
- `Last-Modified`,
|
|
659
|
-
- `If-None-Match`,
|
|
660
|
-
- `If-Modified-Since`,
|
|
595
|
+
- `GET` / `HEAD`,
|
|
596
|
+
- ETag / Last-Modified validators,
|
|
661
597
|
- `If-Range`,
|
|
662
598
|
- single byte ranges with `206 Partial Content`,
|
|
663
599
|
- `304 Not Modified`,
|
|
664
600
|
- `416 Range Not Satisfiable`,
|
|
665
|
-
- safe `Content-Disposition` filenames
|
|
601
|
+
- safe `Content-Disposition` filenames,
|
|
602
|
+
- configurable cache control.
|
|
666
603
|
|
|
667
|
-
The default cache policy
|
|
604
|
+
The default cache policy remains:
|
|
668
605
|
|
|
669
606
|
```text
|
|
670
607
|
private, max-age=0, must-revalidate
|
|
671
608
|
```
|
|
672
609
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
Multiple byte ranges are intentionally not supported in `0.1.25`.
|
|
610
|
+
Multiple byte ranges remain intentionally unsupported in `0.1.26`.
|
|
676
611
|
|
|
677
612
|
Read more: [Storage and File Delivery](docs/storage.md)
|
|
678
613
|
|
|
679
614
|
## Caching
|
|
680
615
|
|
|
681
|
-
BCP includes
|
|
616
|
+
BCP includes response caching and revalidation primitives used by development and standalone production runtimes.
|
|
682
617
|
|
|
683
618
|
Read more: [Caching](docs/caching.md)
|
|
684
619
|
|
|
685
620
|
## Security
|
|
686
621
|
|
|
687
|
-
The framework security layer includes request body limits and production request handling defaults. Application authorization
|
|
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.
|
|
688
623
|
|
|
689
624
|
Storage keys, filenames and MIME metadata must not be treated as authorization decisions.
|
|
690
625
|
|
|
@@ -698,60 +633,48 @@ Application configuration lives in:
|
|
|
698
633
|
bcp.config.ts
|
|
699
634
|
```
|
|
700
635
|
|
|
701
|
-
Public environment variables use
|
|
636
|
+
Public environment variables use:
|
|
702
637
|
|
|
703
638
|
```text
|
|
704
639
|
BCP_PUBLIC_
|
|
705
640
|
```
|
|
706
641
|
|
|
707
|
-
Server-only
|
|
642
|
+
Server-only values remain server-side and are not emitted into browser bundles.
|
|
708
643
|
|
|
709
644
|
Read more: [Configuration](docs/configuration.md)
|
|
710
645
|
|
|
711
646
|
## Developer tools
|
|
712
647
|
|
|
713
|
-
BCP includes project diagnostics:
|
|
714
|
-
|
|
715
648
|
```bash
|
|
716
649
|
bcp doctor
|
|
717
650
|
bcp inspect
|
|
718
651
|
```
|
|
719
652
|
|
|
720
|
-
`bcp doctor` checks
|
|
653
|
+
`bcp doctor` checks project structure, BCP/React installation parity, duplicate framework copies, environment/config loading, route conflicts and client/server boundaries.
|
|
721
654
|
|
|
722
|
-
|
|
723
|
-
- BCP installation,
|
|
724
|
-
- React / ReactDOM compatibility,
|
|
725
|
-
- duplicate framework copies,
|
|
726
|
-
- environment/config loading,
|
|
727
|
-
- route conflicts,
|
|
728
|
-
- client/server boundaries.
|
|
729
|
-
|
|
730
|
-
`bcp inspect` reports resolved configuration, environment sources, dependencies and discovered routes.
|
|
655
|
+
`bcp inspect` reports resolved configuration, environment sources, dependency versions and discovered routes.
|
|
731
656
|
|
|
732
657
|
Read more: [Developer Tools](docs/developer-tools.md)
|
|
733
658
|
|
|
734
659
|
## Windows CLI
|
|
735
660
|
|
|
736
|
-
Microsoft SQL Server
|
|
737
|
-
|
|
738
|
-
BCP therefore publishes the collision-free alias:
|
|
739
|
-
|
|
740
|
-
```text
|
|
741
|
-
bcp-framework
|
|
742
|
-
```
|
|
661
|
+
Microsoft SQL Server can install another executable named `bcp.exe`. BCP therefore publishes the collision-free alias `bcp-framework`.
|
|
743
662
|
|
|
744
|
-
Inside
|
|
663
|
+
Inside npm scripts, `bcp` is safe because npm prepends the project's `node_modules/.bin` to `PATH`.
|
|
745
664
|
|
|
746
|
-
For direct PowerShell usage,
|
|
665
|
+
For direct PowerShell usage, use the project-local CLI:
|
|
747
666
|
|
|
748
667
|
```powershell
|
|
668
|
+
npm exec -- bcp-framework --version
|
|
749
669
|
npm exec -- bcp-framework doctor
|
|
750
670
|
npm exec -- bcp-framework inspect
|
|
671
|
+
npm exec -- bcp-framework routes
|
|
751
672
|
npm exec -- bcp-framework dev
|
|
752
673
|
npm exec -- bcp-framework build
|
|
753
674
|
```
|
|
754
675
|
|
|
676
|
+
This keeps the CLI version aligned with the framework installed by the application.
|
|
677
|
+
|
|
755
678
|
## CLI reference
|
|
756
679
|
|
|
757
680
|
```bash
|
|
@@ -774,9 +697,7 @@ bcp db rollback
|
|
|
774
697
|
|
|
775
698
|
## Development behavior
|
|
776
699
|
|
|
777
|
-
BCP includes Fast Refresh and deterministic development hydration behavior.
|
|
778
|
-
|
|
779
|
-
Recent stabilization work also covers:
|
|
700
|
+
BCP includes Fast Refresh and deterministic development hydration behavior. Recent stabilization work covers:
|
|
780
701
|
|
|
781
702
|
- Windows line-ending parity,
|
|
782
703
|
- multiline JSX hydration parity,
|
|
@@ -784,25 +705,16 @@ Recent stabilization work also covers:
|
|
|
784
705
|
- automatic page-route/client-bundle graph resynchronization,
|
|
785
706
|
- standalone authentication guard request-context parity.
|
|
786
707
|
|
|
787
|
-
A development topology change should no longer require manually deleting `.bcp-framework` to recover a missing client route bundle.
|
|
788
|
-
|
|
789
708
|
Read more: [Hydration](docs/hydration.md)
|
|
790
709
|
|
|
791
710
|
## Production build
|
|
792
711
|
|
|
793
|
-
Build an application:
|
|
794
|
-
|
|
795
712
|
```bash
|
|
796
713
|
npm run build
|
|
797
|
-
```
|
|
798
|
-
|
|
799
|
-
Start the generated standalone runtime:
|
|
800
|
-
|
|
801
|
-
```bash
|
|
802
714
|
npm run start
|
|
803
715
|
```
|
|
804
716
|
|
|
805
|
-
Production output
|
|
717
|
+
Production output:
|
|
806
718
|
|
|
807
719
|
```text
|
|
808
720
|
.bcp-framework/build/
|
|
@@ -814,7 +726,7 @@ Production output is written under:
|
|
|
814
726
|
|
|
815
727
|
The standalone runtime composes production middleware, security, cache, actions, guards, loaders and page rendering into the final HTTP pipeline.
|
|
816
728
|
|
|
817
|
-
Runtime hostname/port overrides can be supplied to `bcp start` without rebuilding
|
|
729
|
+
Runtime hostname/port overrides can be supplied to `bcp start` without rebuilding.
|
|
818
730
|
|
|
819
731
|
Read more: [Deployment](docs/deployment.md)
|
|
820
732
|
|
|
@@ -824,11 +736,11 @@ Read more: [Deployment](docs/deployment.md)
|
|
|
824
736
|
bcp update
|
|
825
737
|
bcp update --check
|
|
826
738
|
bcp update --dry-run
|
|
827
|
-
bcp update 0.1.
|
|
739
|
+
bcp update 0.1.26
|
|
828
740
|
bcp update next
|
|
829
741
|
```
|
|
830
742
|
|
|
831
|
-
Projects created before the updater was introduced can bootstrap it once
|
|
743
|
+
Projects created before the updater was introduced can bootstrap it once with:
|
|
832
744
|
|
|
833
745
|
```bash
|
|
834
746
|
npx @chidchanun/bcp@latest update
|
|
@@ -836,14 +748,15 @@ npx @chidchanun/bcp@latest update
|
|
|
836
748
|
|
|
837
749
|
Read more: [Updating](docs/updating.md)
|
|
838
750
|
|
|
839
|
-
## Framework development
|
|
751
|
+
## Framework development and release validation
|
|
840
752
|
|
|
841
|
-
|
|
753
|
+
Inside the BCP Framework repository:
|
|
842
754
|
|
|
843
755
|
```bash
|
|
844
756
|
npm install
|
|
845
757
|
npm run typecheck
|
|
846
758
|
npm run test:unit
|
|
759
|
+
npm run test:integration
|
|
847
760
|
npm run test:e2e
|
|
848
761
|
npm run test:package
|
|
849
762
|
```
|
|
@@ -854,13 +767,13 @@ Full release-candidate validation:
|
|
|
854
767
|
npm run rc:check
|
|
855
768
|
```
|
|
856
769
|
|
|
857
|
-
A version must not be tagged or published until
|
|
770
|
+
A version must not be tagged or published until RC and packed-package verification pass.
|
|
858
771
|
|
|
859
772
|
Read more: [Releasing](docs/releasing.md)
|
|
860
773
|
|
|
861
774
|
## Documentation source
|
|
862
775
|
|
|
863
|
-
The `docs/` directory is the source content
|
|
776
|
+
The `docs/` directory is the source content for the future **`bcp-docs-web`** documentation website.
|
|
864
777
|
|
|
865
778
|
Start with:
|
|
866
779
|
|
|
@@ -877,6 +790,7 @@ Start with:
|
|
|
877
790
|
- [Error Handling](docs/error-handling.md)
|
|
878
791
|
- [File Upload](docs/file-upload.md)
|
|
879
792
|
- [Storage and File Delivery](docs/storage.md)
|
|
793
|
+
- [S3-Compatible Storage](docs/s3-storage.md)
|
|
880
794
|
- [Authentication](docs/authentication.md)
|
|
881
795
|
- [Auth Route Guards](docs/auth-route-guards.md)
|
|
882
796
|
- [JWT Sessions](docs/session-auth.md)
|
|
@@ -892,9 +806,7 @@ Start with:
|
|
|
892
806
|
- [Updating](docs/updating.md)
|
|
893
807
|
- [Releasing](docs/releasing.md)
|
|
894
808
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
When `bcp-docs-web` is built, the recommended top-level information architecture is:
|
|
809
|
+
Recommended `bcp-docs-web` top-level navigation:
|
|
898
810
|
|
|
899
811
|
```text
|
|
900
812
|
Getting Started
|
|
@@ -902,21 +814,14 @@ Routing & Data
|
|
|
902
814
|
Authentication
|
|
903
815
|
Database
|
|
904
816
|
Runtime & Infrastructure
|
|
817
|
+
Storage & Uploads
|
|
905
818
|
API Reference
|
|
906
819
|
Releases
|
|
907
820
|
```
|
|
908
821
|
|
|
909
|
-
`docs/README.md` contains the proposed route-to-source mapping for that website.
|
|
910
|
-
|
|
911
822
|
## Release history
|
|
912
823
|
|
|
913
|
-
Release notes
|
|
914
|
-
|
|
915
|
-
```text
|
|
916
|
-
docs/releases/
|
|
917
|
-
```
|
|
918
|
-
|
|
919
|
-
Recent milestones:
|
|
824
|
+
Release notes live under `docs/releases/`.
|
|
920
825
|
|
|
921
826
|
| Version | Milestone |
|
|
922
827
|
| --- | --- |
|
|
@@ -926,17 +831,18 @@ Recent milestones:
|
|
|
926
831
|
| `0.1.23` | Logging and observability |
|
|
927
832
|
| `0.1.24` | File Upload Foundation |
|
|
928
833
|
| `0.1.25` | Storage Adapters and File Delivery |
|
|
834
|
+
| `0.1.26` | S3-Compatible Storage and Production Streaming |
|
|
929
835
|
|
|
930
|
-
##
|
|
836
|
+
## Next direction
|
|
931
837
|
|
|
932
|
-
|
|
838
|
+
After `0.1.26`, the recommended direction is:
|
|
933
839
|
|
|
934
|
-
1.
|
|
935
|
-
2.
|
|
936
|
-
3.
|
|
937
|
-
4.
|
|
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.
|
|
938
844
|
|
|
939
|
-
|
|
845
|
+
These are roadmap items, not `0.1.26` API guarantees.
|
|
940
846
|
|
|
941
847
|
## License
|
|
942
848
|
|