create-bcp-app 0.2.7 → 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.
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.7",
95
+ "frameworkPackage": "npm:@chidchanun/bcp@0.2.9",
96
96
  "createdWith": {
97
97
  "package": "create-bcp-app",
98
- "version": "0.2.7"
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,87 +193,104 @@ 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:
209
+ Generated applications can use permission guards and resource policies from `bcp/auth`, plus same-origin and CSRF protection from `bcp/server`.
210
+
211
+ Authorization and CSRF checks must remain on the server; hiding UI controls in client code is not an authorization boundary.
212
+
213
+ ## Observability — 0.2.7+
214
+
215
+ Generated projects can opt into process-local metrics and health/readiness without adding another dependency:
305
216
 
306
217
  ```ts
307
218
  import {
308
- createPermissionGuard,
309
- hasPermission,
310
- } from "bcp/auth";
219
+ createHealthRegistry,
220
+ createMetricsRegistry,
221
+ createRequestMetricsMiddleware,
222
+ } from "bcp/observability";
311
223
  ```
312
224
 
313
- For resource-specific decisions, use `defineAuthorizationPolicy()`, `can()` or `authorize()`.
225
+ `bcp/observability` is server-only. Protect metrics and operational health detail with an appropriate network or authorization boundary when needed.
226
+
227
+ ## Background jobs — 0.2.8+
314
228
 
315
- Cookie-authenticated mutation routes can opt into same-origin and CSRF protection through `bcp/server`:
229
+ Generated projects can create a server-only background job queue without adding another package:
316
230
 
317
231
  ```ts
318
232
  import {
319
- createCsrfToken,
320
- requireCsrfRequest,
321
- requireSameOriginRequest,
322
- } from "bcp/server";
323
- ```
233
+ createJobQueue,
234
+ } from "bcp/jobs";
324
235
 
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.
236
+ export const jobs =
237
+ createJobQueue();
238
+ ```
326
239
 
327
- Authorization and CSRF checks must remain on the server; hiding UI controls in client code is not an authorization boundary.
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.
328
241
 
329
- ## Observability — 0.2.7+
242
+ ## Job scheduling — 0.2.9+
330
243
 
331
- Generated projects can opt into process-local metrics and health/readiness without adding another dependency:
244
+ Recurring schedules use the same `bcp/jobs` entrypoint:
332
245
 
333
246
  ```ts
334
247
  import {
335
- createHealthRegistry,
336
- createMetricsRegistry,
337
- createRequestMetricsMiddleware,
338
- } from "bcp/observability";
248
+ createJobScheduler,
249
+ } from "bcp/jobs";
250
+
251
+ export const scheduler =
252
+ createJobScheduler({
253
+ queue: jobs,
254
+ });
255
+ ```
256
+
257
+ Interval schedule:
339
258
 
340
- export const metrics =
341
- createMetricsRegistry();
259
+ ```ts
260
+ await scheduler.schedule(
261
+ "cache.cleanup",
262
+ {},
263
+ {
264
+ everyMs: 300_000,
265
+ }
266
+ );
267
+ ```
342
268
 
343
- export const health =
344
- createHealthRegistry();
269
+ UTC cron schedule:
345
270
 
346
- export const requestMetrics =
347
- createRequestMetricsMiddleware(
348
- metrics
349
- );
271
+ ```ts
272
+ await scheduler.schedule(
273
+ "report.weekday",
274
+ {},
275
+ {
276
+ cron: "30 9 * * 1-5",
277
+ }
278
+ );
350
279
  ```
351
280
 
352
- Expose metrics from an application API route with `createMetricsResponse(metrics)`. The response uses Prometheus-compatible text format.
281
+ Start the scheduler loop:
353
282
 
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.
283
+ ```ts
284
+ const runner =
285
+ scheduler.start({
286
+ pollIntervalMs: 1_000,
287
+ leaseMs: 30_000,
288
+ });
289
+ ```
355
290
 
356
- The default HTTP request metrics use `method` and `status` labels only. Raw paths are intentionally excluded to avoid high-cardinality metric series.
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`.
357
292
 
358
- `bcp/observability` is server-only. Protect metrics and operational health detail with an appropriate network or authorization boundary when needed.
293
+ `bcp/jobs` is server-only and must not be imported into page/client bundles.
359
294
 
360
295
  ## Application Packaging — 0.2.4+
361
296
 
@@ -365,32 +300,8 @@ Generated projects include:
365
300
  npm run package
366
301
  ```
367
302
 
368
- This runs the BCP `standalone-node` application packaging flow and writes:
369
-
370
- ```text
371
- .bcp-framework/package/
372
- ├─ client/
373
- ├─ server/
374
- ├─ public/ # when present
375
- ├─ package.json
376
- ├─ package-lock.json # when a safe production lock can be derived
377
- ├─ bcp.package.json
378
- ├─ bcp.deployment.json
379
- ├─ bcp.env.json
380
- ├─ Dockerfile
381
- └─ README.md
382
- ```
383
-
384
303
  The deployment package excludes application `devDependencies` and project `.env` values. Supply real secrets through the deployment environment.
385
304
 
386
- For a package with a generated production lockfile:
387
-
388
- ```bash
389
- cd .bcp-framework/package
390
- npm ci --omit=dev
391
- npm start
392
- ```
393
-
394
305
  ## Project generators after creation
395
306
 
396
307
  ```bash
@@ -418,25 +329,13 @@ bcp generate migration create_users
418
329
  --database <database> none | mysql | postgresql | sqlite | mongodb
419
330
  --auth <preset> none | jwt-cookie
420
331
  --storage <provider> none | local | amazon-s3 | cloudflare-r2
421
- -y, --yes Accept defaults (Tailwind enabled, no database, no auth, no storage)
332
+ -y, --yes Accept defaults
422
333
  --bcp <specifier> Override dependencies.bcp
423
334
  -h, --help Show help
424
335
  ```
425
336
 
426
- Examples:
427
-
428
- ```bash
429
- npx create-bcp-app my-app --tailwind --database mysql --auth jwt-cookie --storage local
430
- npx create-bcp-app my-app --database postgresql
431
- npx create-bcp-app my-app --database sqlite
432
- npx create-bcp-app my-app --storage amazon-s3
433
- npx create-bcp-app my-app --storage cloudflare-r2
434
- npx create-bcp-app my-app --no-tailwind --database mongodb
435
- npx create-bcp-app my-app --yes
436
- ```
437
-
438
337
  The `--bcp` option is mainly for prerelease/local package verification:
439
338
 
440
339
  ```bash
441
- npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.7.tgz
340
+ npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.9.tgz
442
341
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-bcp-app",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "Create a new BCP Framework application.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -43,87 +43,117 @@ 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:
46
+ BCP Authentication Platform v2 can opt into revocable server-side session state with `createAuth()` and `AuthSessionStore`.
47
47
 
48
- ```ts
49
- import {
50
- createAuth,
51
- createMemoryAuthSessionStore,
52
- } from "bcp/auth";
48
+ The memory store is intended for local development/tests. Use a shared durable `AuthSessionStore` implementation for multi-process or multi-container production deployments.
53
49
 
54
- const sessionStore =
55
- createMemoryAuthSessionStore();
50
+ ## Authorization & request security — BCP 0.2.6+
56
51
 
57
- export const appAuth =
58
- createAuth({
59
- store: sessionStore,
60
- idleTimeout: 60 * 30,
61
- });
62
- ```
52
+ Use permission guards and resource policies from `bcp/auth`, and same-origin/CSRF protection from `bcp/server`.
63
53
 
64
- The memory store is intended for local development/tests. Use a shared durable `AuthSessionStore` implementation for multi-process or multi-container production deployments.
54
+ Authorization must always be enforced server-side. Client UI visibility is not a security boundary.
65
55
 
66
- ## Authorization & request security — BCP 0.2.6+
56
+ ## Observability — BCP 0.2.7+
67
57
 
68
- Server-side permission guards:
58
+ Create process-local metrics and health/readiness registries:
69
59
 
70
60
  ```ts
71
61
  import {
72
- createPermissionGuard,
73
- } from "bcp/auth";
74
-
75
- export const guard =
76
- createPermissionGuard(
77
- "dashboard.read"
78
- );
62
+ createHealthRegistry,
63
+ createMetricsRegistry,
64
+ createRequestMetricsMiddleware,
65
+ } from "bcp/observability";
79
66
  ```
80
67
 
81
- For ownership or resource-specific rules, use `defineAuthorizationPolicy()`, `can()` and `authorize()` from `bcp/auth`.
68
+ Protect operational endpoints when their contents should not be public.
69
+
70
+ ## Background jobs — BCP 0.2.8+
82
71
 
83
- Cookie-authenticated mutation routes can validate browser origin and CSRF state:
72
+ Create a server-only background queue:
84
73
 
85
74
  ```ts
86
75
  import {
87
- createCsrfToken,
88
- requireCsrfRequest,
89
- requireSameOriginRequest,
90
- } from "bcp/server";
76
+ createJobQueue,
77
+ } from "bcp/jobs";
78
+
79
+ export const jobs =
80
+ createJobQueue();
91
81
  ```
92
82
 
93
- `createCsrfToken()` uses `BCP_CSRF_SECRET` when configured and otherwise falls back to `BCP_SESSION_SECRET`.
83
+ Register typed work:
94
84
 
95
- Authorization must always be enforced server-side. Client UI visibility is not a security boundary.
85
+ ```ts
86
+ jobs.register<{
87
+ userId: number;
88
+ }>(
89
+ "email.welcome",
90
+ async ({ payload }) => {
91
+ await sendWelcomeEmail(
92
+ payload.userId
93
+ );
94
+ }
95
+ );
96
+ ```
96
97
 
97
- ## Observability BCP 0.2.7+
98
+ Workers support delayed jobs, retry/backoff, cancellation and configurable concurrency.
98
99
 
99
- Create process-local metrics and health/readiness registries:
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:
100
105
 
101
106
  ```ts
102
107
  import {
103
- createHealthRegistry,
104
- createMetricsRegistry,
105
- createRequestMetricsMiddleware,
106
- } from "bcp/observability";
108
+ createJobScheduler,
109
+ } from "bcp/jobs";
107
110
 
108
- export const metrics =
109
- createMetricsRegistry();
111
+ export const scheduler =
112
+ createJobScheduler({
113
+ queue: jobs,
114
+ });
115
+ ```
110
116
 
111
- export const health =
112
- createHealthRegistry();
117
+ Interval schedule:
113
118
 
114
- export const requestMetrics =
115
- createRequestMetricsMiddleware(
116
- metrics
117
- );
119
+ ```ts
120
+ await scheduler.schedule(
121
+ "cache.cleanup",
122
+ {},
123
+ {
124
+ everyMs: 300_000,
125
+ }
126
+ );
118
127
  ```
119
128
 
120
- Expose Prometheus-compatible metrics with `createMetricsResponse(metrics)` from a server API route.
129
+ UTC cron schedule:
121
130
 
122
- Use `health.response()` for readiness endpoints. It returns HTTP `200` when all checks pass and `503` when a check fails or times out.
131
+ ```ts
132
+ await scheduler.schedule(
133
+ "report.weekday",
134
+ {},
135
+ {
136
+ cron: "30 9 * * 1-5",
137
+ }
138
+ );
139
+ ```
123
140
 
124
- The default request metrics use bounded `method` and `status` labels and do not include raw paths.
141
+ Start and stop the scheduler lifecycle:
125
142
 
126
- Protect operational endpoints when their contents should not be public.
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`.
155
+
156
+ `bcp/jobs` is server-only and cannot be imported into page/client bundles.
127
157
 
128
158
  ## Generate framework files
129
159
 
@@ -170,39 +200,15 @@ npm exec -- bcp-framework build
170
200
  npm exec -- bcp-framework package
171
201
  ```
172
202
 
173
- You can also execute the Windows command shim explicitly:
174
-
175
- ```powershell
176
- .\node_modules\.bin\bcp-framework.cmd --version
177
- ```
178
-
179
203
  Microsoft SQL Server can install another Windows executable named `bcp.exe`, so the `bcp-framework` alias avoids that command-name collision.
180
204
 
181
- Use this convention:
182
-
183
- ```text
184
- Inside npm scripts -> bcp ...
185
- Direct PowerShell usage -> npm exec -- bcp-framework ...
186
- ```
187
-
188
205
  ## Project diagnostics
189
206
 
190
- Run:
191
-
192
207
  ```powershell
193
208
  npm exec -- bcp-framework doctor
194
209
  npm exec -- bcp-framework inspect
195
210
  ```
196
211
 
197
- Machine-readable reports:
198
-
199
- ```powershell
200
- npm exec -- bcp-framework doctor --json
201
- npm exec -- bcp-framework inspect --json
202
- ```
203
-
204
- Doctor checks common project/runtime problems while Inspect shows the resolved configuration, routes, dependencies and project metadata BCP sees.
205
-
206
212
  ## Production build
207
213
 
208
214
  Create the raw standalone production build:
@@ -217,8 +223,6 @@ Start it with:
217
223
  npm start
218
224
  ```
219
225
 
220
- The production build is written to `.bcp-framework/build` and runs as a standalone Node.js server.
221
-
222
226
  ## Deployment package — BCP 0.2.4+
223
227
 
224
228
  Create a fresh production build and deployment-oriented package:
@@ -227,22 +231,6 @@ Create a fresh production build and deployment-oriented package:
227
231
  npm run package
228
232
  ```
229
233
 
230
- The output is written to:
231
-
232
- ```text
233
- .bcp-framework/package/
234
- ```
235
-
236
- 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.
237
235
 
238
236
  BCP intentionally excludes project `.env` files and application `devDependencies` from the deployment package. Provide secrets through your deployment environment.
239
-
240
- For a package with a generated production lockfile:
241
-
242
- ```bash
243
- cd .bcp-framework/package
244
- npm ci --omit=dev
245
- npm start
246
- ```
247
-
248
- If `bcp.package.json` reports that no lockfile was included, use the install command recorded in that manifest instead.