create-bcp-app 0.2.8 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +53 -191
  2. package/package.json +1 -1
  3. package/template/README.md +59 -110
package/README.md CHANGED
@@ -92,10 +92,10 @@ Example:
92
92
  "schemaVersion": 1,
93
93
  "framework": "bcp",
94
94
  "projectName": "my-app",
95
- "frameworkPackage": "npm:@chidchanun/bcp@0.2.8",
95
+ "frameworkPackage": "npm:@chidchanun/bcp@0.2.9",
96
96
  "createdWith": {
97
97
  "package": "create-bcp-app",
98
- "version": "0.2.8"
98
+ "version": "0.2.9"
99
99
  },
100
100
  "packageManager": "npm",
101
101
  "presets": {
@@ -133,14 +133,7 @@ npm exec -- bcp-framework update --check
133
133
 
134
134
  ## Tailwind CSS
135
135
 
136
- When Tailwind is enabled, the project includes:
137
-
138
- - `tailwindcss`
139
- - `@tailwindcss/cli`
140
- - `concurrently`
141
- - `app/globals.css`
142
- - `/bcp.css` stylesheet setup
143
- - starter utility classes
136
+ When Tailwind is enabled, the project includes `tailwindcss`, `@tailwindcss/cli`, `concurrently`, `app/globals.css`, `/bcp.css` stylesheet setup and starter utility classes.
144
137
 
145
138
  Generated commands include:
146
139
 
@@ -162,9 +155,9 @@ The database choice adds starter configuration and the matching driver:
162
155
  - MongoDB: `mongodb`
163
156
  - None: no database dependency
164
157
 
165
- For **MySQL**, **PostgreSQL** and **SQLite**, generated `lib/database.ts` exposes the framework database primitives through `bcp/database`. Provider connections are managed behind Database Platform v2 instead of being created directly in generated application code.
158
+ For **MySQL**, **PostgreSQL** and **SQLite**, generated `lib/database.ts` exposes framework database primitives through `bcp/database`.
166
159
 
167
- Generated MySQL environment variables:
160
+ Generated examples:
168
161
 
169
162
  ```dotenv
170
163
  DB_HOST=localhost
@@ -174,100 +167,25 @@ DB_PASSWORD=
174
167
  DB_NAME=bcp_app
175
168
  ```
176
169
 
177
- Generated PostgreSQL environment variable:
178
-
179
170
  ```dotenv
180
171
  DATABASE_URL=postgresql://postgres:password@localhost:5432/bcp_app
181
172
  ```
182
173
 
183
- Generated SQLite environment variable:
184
-
185
174
  ```dotenv
186
175
  DATABASE_URL=./data/bcp.sqlite
187
176
  ```
188
177
 
189
- `bcp/database` infers PostgreSQL from `postgres://` or `postgresql://` connection URLs. SQLite is inferred from `:memory:`, `sqlite:` / `file:` locations and common `.sqlite`, `.sqlite3` or `.db` file paths. Applications may also configure `DB_DRIVER` explicitly.
190
-
191
- Placeholder syntax follows the selected provider:
192
-
193
- ```text
194
- MySQL ?
195
- SQLite ?
196
- PostgreSQL $1, $2, ...
197
- ```
198
-
199
178
  The generator intentionally does not force an ORM.
200
179
 
201
180
  ## Storage providers
202
181
 
203
- Selecting a storage provider creates `lib/storage.ts` and adds provider-specific environment settings.
204
-
205
- ### Local Server
206
-
207
- ```bash
208
- npx create-bcp-app my-app --storage local
209
- ```
210
-
211
- Environment:
212
-
213
- ```dotenv
214
- STORAGE_LOCAL_DIRECTORY=./storage
215
- ```
216
-
217
- The generated helper uses `createLocalStorage()`.
218
-
219
- ### Amazon S3
220
-
221
- ```bash
222
- npx create-bcp-app my-app --storage amazon-s3
223
- ```
224
-
225
- Generated environment settings:
226
-
227
- ```dotenv
228
- AWS_S3_BUCKET=
229
- AWS_REGION=ap-southeast-1
230
- AWS_ACCESS_KEY_ID=
231
- AWS_SECRET_ACCESS_KEY=
232
- AWS_SESSION_TOKEN=
233
- AWS_S3_PREFIX=
234
- ```
235
-
236
- The helper uses `createS3Storage()`. Explicit credentials can remain unset when deployment uses the AWS SDK server-side credential chain, such as an IAM role.
237
-
238
- ### Cloudflare R2
239
-
240
- ```bash
241
- npx create-bcp-app my-app --storage cloudflare-r2
242
- ```
243
-
244
- Generated environment settings:
245
-
246
- ```dotenv
247
- R2_ACCOUNT_ID=
248
- R2_BUCKET=
249
- R2_ACCESS_KEY_ID=
250
- R2_SECRET_ACCESS_KEY=
251
- R2_PREFIX=
252
- ```
182
+ Selecting a storage provider creates `lib/storage.ts` and provider-specific environment settings. Supported presets are Local Server, Amazon S3 and Cloudflare R2.
253
183
 
254
184
  Storage credentials are server-only. Do not expose them through `BCP_PUBLIC_*` variables.
255
185
 
256
186
  ## JWT Cookie authentication
257
187
 
258
- Selecting `JWT Cookie` creates:
259
-
260
- ```text
261
- lib/
262
- └─ auth.ts
263
-
264
- app/api/auth/
265
- ├─ login/route.ts
266
- ├─ logout/route.ts
267
- └─ me/route.ts
268
- ```
269
-
270
- and adds:
188
+ Selecting `JWT Cookie` creates `lib/auth.ts` and starter `/api/auth/login`, `/logout` and `/me` routes, and adds:
271
189
 
272
190
  ```dotenv
273
191
  BCP_SESSION_SECRET=
@@ -275,54 +193,20 @@ BCP_SESSION_SECRET=
275
193
 
276
194
  Set this to a cryptographically random secret of at least 32 bytes before real authentication use.
277
195
 
278
- The generated `authenticateCredentials(email, password)` returns `null` until the application connects it to its own user store and password-hash verification.
279
-
280
- Generated auth stays in backward-compatible stateless JWT-cookie mode by default.
281
-
282
- BCP `0.2.5+` can opt into revocable server-side auth state without changing the generated auth route structure:
196
+ BCP `0.2.5+` can opt into revocable server-side auth state:
283
197
 
284
198
  ```ts
285
199
  import {
286
200
  createAuth,
287
201
  createMemoryAuthSessionStore,
288
202
  } from "bcp/auth";
289
-
290
- const sessionStore =
291
- createMemoryAuthSessionStore();
292
-
293
- const frameworkAuth =
294
- createAuth<AuthenticatedUser>({
295
- store: sessionStore,
296
- idleTimeout: 60 * 30,
297
- });
298
203
  ```
299
204
 
300
205
  The memory store is intended for development/tests. Multi-process production deployments should implement `AuthSessionStore` using shared durable storage.
301
206
 
302
207
  ## Authorization & request security — 0.2.6+
303
208
 
304
- Generated applications can add permissions to their application user shape and use server-side permission guards without changing the auth preset routes:
305
-
306
- ```ts
307
- import {
308
- createPermissionGuard,
309
- hasPermission,
310
- } from "bcp/auth";
311
- ```
312
-
313
- For resource-specific decisions, use `defineAuthorizationPolicy()`, `can()` or `authorize()`.
314
-
315
- Cookie-authenticated mutation routes can opt into same-origin and CSRF protection through `bcp/server`:
316
-
317
- ```ts
318
- import {
319
- createCsrfToken,
320
- requireCsrfRequest,
321
- requireSameOriginRequest,
322
- } from "bcp/server";
323
- ```
324
-
325
- `createCsrfToken()` uses `BCP_CSRF_SECRET` when configured and otherwise falls back to `BCP_SESSION_SECRET`, so the generated JWT auth preset does not require another environment variable to get started. Production applications may define a separate `BCP_CSRF_SECRET` for independent key rotation.
209
+ Generated applications can use permission guards and resource policies from `bcp/auth`, plus same-origin and CSRF protection from `bcp/server`.
326
210
 
327
211
  Authorization and CSRF checks must remain on the server; hiding UI controls in client code is not an authorization boundary.
328
212
 
@@ -336,25 +220,8 @@ import {
336
220
  createMetricsRegistry,
337
221
  createRequestMetricsMiddleware,
338
222
  } from "bcp/observability";
339
-
340
- export const metrics =
341
- createMetricsRegistry();
342
-
343
- export const health =
344
- createHealthRegistry();
345
-
346
- export const requestMetrics =
347
- createRequestMetricsMiddleware(
348
- metrics
349
- );
350
223
  ```
351
224
 
352
- Expose metrics from an application API route with `createMetricsResponse(metrics)`. The response uses Prometheus-compatible text format.
353
-
354
- Health endpoints can return `health.response()`, which uses HTTP `200` when all checks pass and `503` when any dependency check fails or times out.
355
-
356
- The default HTTP request metrics use `method` and `status` labels only. Raw paths are intentionally excluded to avoid high-cardinality metric series.
357
-
358
225
  `bcp/observability` is server-only. Protect metrics and operational health detail with an appropriate network or authorization boundary when needed.
359
226
 
360
227
  ## Background jobs — 0.2.8+
@@ -370,27 +237,58 @@ export const jobs =
370
237
  createJobQueue();
371
238
  ```
372
239
 
373
- Register handlers and enqueue work:
240
+ Workers support concurrency, delayed jobs, retry/backoff and cancellation. The default memory adapter is process-local and should be replaced with a durable `JobQueueAdapter` for production workloads that must survive restarts or coordinate across instances.
241
+
242
+ ## Job scheduling — 0.2.9+
243
+
244
+ Recurring schedules use the same `bcp/jobs` entrypoint:
245
+
246
+ ```ts
247
+ import {
248
+ createJobScheduler,
249
+ } from "bcp/jobs";
250
+
251
+ export const scheduler =
252
+ createJobScheduler({
253
+ queue: jobs,
254
+ });
255
+ ```
256
+
257
+ Interval schedule:
374
258
 
375
259
  ```ts
376
- jobs.register(
377
- "email.welcome",
378
- async ({ payload }) => {
379
- await sendWelcomeEmail(
380
- payload.userId
381
- );
260
+ await scheduler.schedule(
261
+ "cache.cleanup",
262
+ {},
263
+ {
264
+ everyMs: 300_000,
382
265
  }
383
266
  );
267
+ ```
268
+
269
+ UTC cron schedule:
384
270
 
385
- await jobs.enqueue(
386
- "email.welcome",
271
+ ```ts
272
+ await scheduler.schedule(
273
+ "report.weekday",
274
+ {},
387
275
  {
388
- userId: 42,
276
+ cron: "30 9 * * 1-5",
389
277
  }
390
278
  );
391
279
  ```
392
280
 
393
- Workers support concurrency, delayed jobs, retry/backoff and cancellation. The default memory adapter is process-local and should be replaced with a durable `JobQueueAdapter` for multi-process/container production workloads that must survive restarts.
281
+ Start the scheduler loop:
282
+
283
+ ```ts
284
+ const runner =
285
+ scheduler.start({
286
+ pollIntervalMs: 1_000,
287
+ leaseMs: 30_000,
288
+ });
289
+ ```
290
+
291
+ The default schedule store is process-local. Multi-instance production deployments should implement a shared durable `JobScheduleStore`; its `acquireDue()` operation must atomically lease due schedules. A durable scheduler deployment normally also uses a shared durable `JobQueueAdapter`.
394
292
 
395
293
  `bcp/jobs` is server-only and must not be imported into page/client bundles.
396
294
 
@@ -402,32 +300,8 @@ Generated projects include:
402
300
  npm run package
403
301
  ```
404
302
 
405
- This runs the BCP `standalone-node` application packaging flow and writes:
406
-
407
- ```text
408
- .bcp-framework/package/
409
- ├─ client/
410
- ├─ server/
411
- ├─ public/ # when present
412
- ├─ package.json
413
- ├─ package-lock.json # when a safe production lock can be derived
414
- ├─ bcp.package.json
415
- ├─ bcp.deployment.json
416
- ├─ bcp.env.json
417
- ├─ Dockerfile
418
- └─ README.md
419
- ```
420
-
421
303
  The deployment package excludes application `devDependencies` and project `.env` values. Supply real secrets through the deployment environment.
422
304
 
423
- For a package with a generated production lockfile:
424
-
425
- ```bash
426
- cd .bcp-framework/package
427
- npm ci --omit=dev
428
- npm start
429
- ```
430
-
431
305
  ## Project generators after creation
432
306
 
433
307
  ```bash
@@ -455,25 +329,13 @@ bcp generate migration create_users
455
329
  --database <database> none | mysql | postgresql | sqlite | mongodb
456
330
  --auth <preset> none | jwt-cookie
457
331
  --storage <provider> none | local | amazon-s3 | cloudflare-r2
458
- -y, --yes Accept defaults (Tailwind enabled, no database, no auth, no storage)
332
+ -y, --yes Accept defaults
459
333
  --bcp <specifier> Override dependencies.bcp
460
334
  -h, --help Show help
461
335
  ```
462
336
 
463
- Examples:
464
-
465
- ```bash
466
- npx create-bcp-app my-app --tailwind --database mysql --auth jwt-cookie --storage local
467
- npx create-bcp-app my-app --database postgresql
468
- npx create-bcp-app my-app --database sqlite
469
- npx create-bcp-app my-app --storage amazon-s3
470
- npx create-bcp-app my-app --storage cloudflare-r2
471
- npx create-bcp-app my-app --no-tailwind --database mongodb
472
- npx create-bcp-app my-app --yes
473
- ```
474
-
475
337
  The `--bcp` option is mainly for prerelease/local package verification:
476
338
 
477
339
  ```bash
478
- npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.8.tgz
340
+ npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.9.tgz
479
341
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-bcp-app",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "Create a new BCP Framework application.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -43,54 +43,13 @@ Commit this file with the project. Do not put passwords, access keys, session se
43
43
 
44
44
  Projects created with the `JWT Cookie` preset remain stateless by default and use the generated `lib/auth.ts` helpers.
45
45
 
46
- BCP Authentication Platform v2 can opt into revocable server-side session state:
47
-
48
- ```ts
49
- import {
50
- createAuth,
51
- createMemoryAuthSessionStore,
52
- } from "bcp/auth";
53
-
54
- const sessionStore =
55
- createMemoryAuthSessionStore();
56
-
57
- export const appAuth =
58
- createAuth({
59
- store: sessionStore,
60
- idleTimeout: 60 * 30,
61
- });
62
- ```
46
+ BCP Authentication Platform v2 can opt into revocable server-side session state with `createAuth()` and `AuthSessionStore`.
63
47
 
64
48
  The memory store is intended for local development/tests. Use a shared durable `AuthSessionStore` implementation for multi-process or multi-container production deployments.
65
49
 
66
50
  ## Authorization & request security — BCP 0.2.6+
67
51
 
68
- Server-side permission guards:
69
-
70
- ```ts
71
- import {
72
- createPermissionGuard,
73
- } from "bcp/auth";
74
-
75
- export const guard =
76
- createPermissionGuard(
77
- "dashboard.read"
78
- );
79
- ```
80
-
81
- For ownership or resource-specific rules, use `defineAuthorizationPolicy()`, `can()` and `authorize()` from `bcp/auth`.
82
-
83
- Cookie-authenticated mutation routes can validate browser origin and CSRF state:
84
-
85
- ```ts
86
- import {
87
- createCsrfToken,
88
- requireCsrfRequest,
89
- requireSameOriginRequest,
90
- } from "bcp/server";
91
- ```
92
-
93
- `createCsrfToken()` uses `BCP_CSRF_SECRET` when configured and otherwise falls back to `BCP_SESSION_SECRET`.
52
+ Use permission guards and resource policies from `bcp/auth`, and same-origin/CSRF protection from `bcp/server`.
94
53
 
95
54
  Authorization must always be enforced server-side. Client UI visibility is not a security boundary.
96
55
 
@@ -104,25 +63,8 @@ import {
104
63
  createMetricsRegistry,
105
64
  createRequestMetricsMiddleware,
106
65
  } from "bcp/observability";
107
-
108
- export const metrics =
109
- createMetricsRegistry();
110
-
111
- export const health =
112
- createHealthRegistry();
113
-
114
- export const requestMetrics =
115
- createRequestMetricsMiddleware(
116
- metrics
117
- );
118
66
  ```
119
67
 
120
- Expose Prometheus-compatible metrics with `createMetricsResponse(metrics)` from a server API route.
121
-
122
- Use `health.response()` for readiness endpoints. It returns HTTP `200` when all checks pass and `503` when a check fails or times out.
123
-
124
- The default request metrics use bounded `method` and `status` labels and do not include raw paths.
125
-
126
68
  Protect operational endpoints when their contents should not be public.
127
69
 
128
70
  ## Background jobs — BCP 0.2.8+
@@ -138,10 +80,12 @@ export const jobs =
138
80
  createJobQueue();
139
81
  ```
140
82
 
141
- Register and enqueue work:
83
+ Register typed work:
142
84
 
143
85
  ```ts
144
- jobs.register(
86
+ jobs.register<{
87
+ userId: number;
88
+ }>(
145
89
  "email.welcome",
146
90
  async ({ payload }) => {
147
91
  await sendWelcomeEmail(
@@ -149,18 +93,65 @@ jobs.register(
149
93
  );
150
94
  }
151
95
  );
96
+ ```
152
97
 
153
- await jobs.enqueue(
154
- "email.welcome",
98
+ Workers support delayed jobs, retry/backoff, cancellation and configurable concurrency.
99
+
100
+ The default memory adapter is process-local and not durable. For production jobs that must survive restarts or run across multiple processes/containers, implement `JobQueueAdapter` with shared durable infrastructure.
101
+
102
+ ## Job scheduling — BCP 0.2.9+
103
+
104
+ Add recurring schedules on top of the same queue:
105
+
106
+ ```ts
107
+ import {
108
+ createJobScheduler,
109
+ } from "bcp/jobs";
110
+
111
+ export const scheduler =
112
+ createJobScheduler({
113
+ queue: jobs,
114
+ });
115
+ ```
116
+
117
+ Interval schedule:
118
+
119
+ ```ts
120
+ await scheduler.schedule(
121
+ "cache.cleanup",
122
+ {},
155
123
  {
156
- userId: 42,
124
+ everyMs: 300_000,
157
125
  }
158
126
  );
159
127
  ```
160
128
 
161
- Workers support delayed jobs, retry/backoff, cancellation and configurable concurrency.
129
+ UTC cron schedule:
162
130
 
163
- The default memory adapter is process-local and not durable. For production jobs that must survive restarts or run across multiple processes/containers, implement `JobQueueAdapter` with shared durable infrastructure.
131
+ ```ts
132
+ await scheduler.schedule(
133
+ "report.weekday",
134
+ {},
135
+ {
136
+ cron: "30 9 * * 1-5",
137
+ }
138
+ );
139
+ ```
140
+
141
+ Start and stop the scheduler lifecycle:
142
+
143
+ ```ts
144
+ const schedulerRunner =
145
+ scheduler.start({
146
+ pollIntervalMs: 1_000,
147
+ leaseMs: 30_000,
148
+ });
149
+
150
+ await schedulerRunner.stop();
151
+ await scheduler.close();
152
+ ```
153
+
154
+ The default `createMemoryJobScheduleStore()` is process-local. Multi-instance production deployments should implement a shared durable `JobScheduleStore` whose `acquireDue()` atomically leases due schedules. Durable deployments normally also use a shared `JobQueueAdapter`.
164
155
 
165
156
  `bcp/jobs` is server-only and cannot be imported into page/client bundles.
166
157
 
@@ -209,39 +200,15 @@ npm exec -- bcp-framework build
209
200
  npm exec -- bcp-framework package
210
201
  ```
211
202
 
212
- You can also execute the Windows command shim explicitly:
213
-
214
- ```powershell
215
- .\node_modules\.bin\bcp-framework.cmd --version
216
- ```
217
-
218
203
  Microsoft SQL Server can install another Windows executable named `bcp.exe`, so the `bcp-framework` alias avoids that command-name collision.
219
204
 
220
- Use this convention:
221
-
222
- ```text
223
- Inside npm scripts -> bcp ...
224
- Direct PowerShell usage -> npm exec -- bcp-framework ...
225
- ```
226
-
227
205
  ## Project diagnostics
228
206
 
229
- Run:
230
-
231
207
  ```powershell
232
208
  npm exec -- bcp-framework doctor
233
209
  npm exec -- bcp-framework inspect
234
210
  ```
235
211
 
236
- Machine-readable reports:
237
-
238
- ```powershell
239
- npm exec -- bcp-framework doctor --json
240
- npm exec -- bcp-framework inspect --json
241
- ```
242
-
243
- Doctor checks common project/runtime problems while Inspect shows the resolved configuration, routes, dependencies and project metadata BCP sees.
244
-
245
212
  ## Production build
246
213
 
247
214
  Create the raw standalone production build:
@@ -256,8 +223,6 @@ Start it with:
256
223
  npm start
257
224
  ```
258
225
 
259
- The production build is written to `.bcp-framework/build` and runs as a standalone Node.js server.
260
-
261
226
  ## Deployment package — BCP 0.2.4+
262
227
 
263
228
  Create a fresh production build and deployment-oriented package:
@@ -266,22 +231,6 @@ Create a fresh production build and deployment-oriented package:
266
231
  npm run package
267
232
  ```
268
233
 
269
- The output is written to:
270
-
271
- ```text
272
- .bcp-framework/package/
273
- ```
274
-
275
- It contains the standalone client/server output, a production-only dependency manifest, deployment/environment metadata, file integrity hashes and a starter Dockerfile.
234
+ The output is written to `.bcp-framework/package/` and contains standalone output, production dependency metadata, deployment/environment manifests, integrity hashes and a starter Dockerfile.
276
235
 
277
236
  BCP intentionally excludes project `.env` files and application `devDependencies` from the deployment package. Provide secrets through your deployment environment.
278
-
279
- For a package with a generated production lockfile:
280
-
281
- ```bash
282
- cd .bcp-framework/package
283
- npm ci --omit=dev
284
- npm start
285
- ```
286
-
287
- If `bcp.package.json` reports that no lockfile was included, use the install command recorded in that manifest instead.