create-bcp-app 0.2.9 → 0.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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.9",
95
+ "frameworkPackage": "npm:@chidchanun/bcp@0.2.10",
96
96
  "createdWith": {
97
97
  "package": "create-bcp-app",
98
- "version": "0.2.9"
98
+ "version": "0.2.10"
99
99
  },
100
100
  "packageManager": "npm",
101
101
  "presets": {
@@ -107,9 +107,7 @@ Example:
107
107
  }
108
108
  ```
109
109
 
110
- This manifest records scaffold identity only. It is intended for framework diagnostics, update/migration tooling and project-aware documentation. It must not contain secrets.
111
-
112
- The file should normally be committed to source control.
110
+ This manifest records scaffold identity only. It must not contain secrets and should normally be committed to source control.
113
111
 
114
112
  ## Generated application defaults
115
113
 
@@ -157,24 +155,6 @@ The database choice adds starter configuration and the matching driver:
157
155
 
158
156
  For **MySQL**, **PostgreSQL** and **SQLite**, generated `lib/database.ts` exposes framework database primitives through `bcp/database`.
159
157
 
160
- Generated examples:
161
-
162
- ```dotenv
163
- DB_HOST=localhost
164
- DB_PORT=3306
165
- DB_USER=
166
- DB_PASSWORD=
167
- DB_NAME=bcp_app
168
- ```
169
-
170
- ```dotenv
171
- DATABASE_URL=postgresql://postgres:password@localhost:5432/bcp_app
172
- ```
173
-
174
- ```dotenv
175
- DATABASE_URL=./data/bcp.sqlite
176
- ```
177
-
178
158
  The generator intentionally does not force an ORM.
179
159
 
180
160
  ## Storage providers
@@ -193,16 +173,7 @@ BCP_SESSION_SECRET=
193
173
 
194
174
  Set this to a cryptographically random secret of at least 32 bytes before real authentication use.
195
175
 
196
- BCP `0.2.5+` can opt into revocable server-side auth state:
197
-
198
- ```ts
199
- import {
200
- createAuth,
201
- createMemoryAuthSessionStore,
202
- } from "bcp/auth";
203
- ```
204
-
205
- The memory store is intended for development/tests. Multi-process production deployments should implement `AuthSessionStore` using shared durable storage.
176
+ BCP `0.2.5+` can opt into revocable server-side auth state through `AuthSessionStore`.
206
177
 
207
178
  ## Authorization & request security — 0.2.6+
208
179
 
@@ -226,7 +197,7 @@ import {
226
197
 
227
198
  ## Background jobs — 0.2.8+
228
199
 
229
- Generated projects can create a server-only background job queue without adding another package:
200
+ Generated projects can create a server-only background job queue:
230
201
 
231
202
  ```ts
232
203
  import {
@@ -237,7 +208,7 @@ export const jobs =
237
208
  createJobQueue();
238
209
  ```
239
210
 
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.
211
+ Workers support concurrency, delayed jobs, retry/backoff and cancellation.
241
212
 
242
213
  ## Job scheduling — 0.2.9+
243
214
 
@@ -278,17 +249,99 @@ await scheduler.schedule(
278
249
  );
279
250
  ```
280
251
 
281
- Start the scheduler loop:
252
+ ## Durable jobs — 0.2.10+
253
+
254
+ BCP `0.2.10` adds worker visibility leases, heartbeat renewal, stale-running recovery, DLQ/requeue, retention cleanup and queue statistics.
255
+
256
+ ```ts
257
+ const worker =
258
+ jobs.startWorker({
259
+ workerId: "worker-a",
260
+ concurrency: 4,
261
+ visibilityTimeoutMs: 30_000,
262
+ heartbeatIntervalMs: 10_000,
263
+ });
264
+ ```
265
+
266
+ Inspect failed jobs:
267
+
268
+ ```ts
269
+ const deadLetters =
270
+ await jobs.deadLetters();
271
+ ```
272
+
273
+ Requeue:
274
+
275
+ ```ts
276
+ await jobs.requeueDeadLetter(
277
+ deadLetters[0].id,
278
+ {
279
+ resetAttempts: true,
280
+ }
281
+ );
282
+ ```
283
+
284
+ ### Redis-compatible durable adapters
285
+
286
+ BCP intentionally does not install a Redis client library. Applications own the Redis connection and pass a minimal command client to BCP:
287
+
288
+ ```ts
289
+ interface RedisCommandClient {
290
+ sendCommand(
291
+ command: string[]
292
+ ): Promise<unknown>;
293
+ }
294
+ ```
295
+
296
+ Queue adapter:
297
+
298
+ ```ts
299
+ import {
300
+ createJobQueue,
301
+ createRedisJobQueueAdapter,
302
+ } from "bcp/jobs";
303
+
304
+ const adapter =
305
+ createRedisJobQueueAdapter({
306
+ client: redisCommandClient,
307
+ namespace: "my-app:{jobs}",
308
+ });
309
+
310
+ export const jobs =
311
+ createJobQueue({
312
+ adapter,
313
+ });
314
+ ```
315
+
316
+ Scheduler store:
282
317
 
283
318
  ```ts
284
- const runner =
285
- scheduler.start({
286
- pollIntervalMs: 1_000,
287
- leaseMs: 30_000,
319
+ import {
320
+ createJobScheduler,
321
+ createRedisJobScheduleStore,
322
+ } from "bcp/jobs";
323
+
324
+ const store =
325
+ createRedisJobScheduleStore({
326
+ client: redisCommandClient,
327
+ namespace: "my-app:{jobs}",
328
+ });
329
+
330
+ export const scheduler =
331
+ createJobScheduler({
332
+ queue: jobs,
333
+ store,
334
+ ownerId: "scheduler-a",
288
335
  });
289
336
  ```
290
337
 
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`.
338
+ A typical application may configure its Redis client with:
339
+
340
+ ```dotenv
341
+ REDIS_URL=redis://localhost:6379
342
+ ```
343
+
344
+ BCP does not read `REDIS_URL` automatically. Redis credentials, TLS/Cluster/Sentinel configuration and connection lifecycle stay application-owned.
292
345
 
293
346
  `bcp/jobs` is server-only and must not be imported into page/client bundles.
294
347
 
@@ -337,5 +390,5 @@ bcp generate migration create_users
337
390
  The `--bcp` option is mainly for prerelease/local package verification:
338
391
 
339
392
  ```bash
340
- npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.9.tgz
393
+ npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.10.tgz
341
394
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-bcp-app",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
4
4
  "description": "Create a new BCP Framework application.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -25,17 +25,11 @@ npm start
25
25
  npm run update
26
26
  ```
27
27
 
28
- The generated scripts call commands such as `bcp dev`, `bcp generate`, `bcp build`, `bcp package` and `bcp start`. npm automatically adds the project's `node_modules/.bin` directory to `PATH` while an npm script is running.
28
+ The generated scripts call commands such as `bcp dev`, `bcp generate`, `bcp build`, `bcp package` and `bcp start`.
29
29
 
30
30
  ## Project metadata
31
31
 
32
- Projects created with BCP `0.1.29+` include:
33
-
34
- ```text
35
- bcp.project.json
36
- ```
37
-
38
- It records non-secret scaffold choices such as Tailwind, database, authentication and storage presets so BCP diagnostics/tooling can understand the project without guessing configuration from source files.
32
+ Projects created with BCP `0.1.29+` include `bcp.project.json` with non-secret scaffold metadata.
39
33
 
40
34
  Commit this file with the project. Do not put passwords, access keys, session secrets or tokens in it.
41
35
 
@@ -45,8 +39,6 @@ Projects created with the `JWT Cookie` preset remain stateless by default and us
45
39
 
46
40
  BCP Authentication Platform v2 can opt into revocable server-side session state with `createAuth()` and `AuthSessionStore`.
47
41
 
48
- The memory store is intended for local development/tests. Use a shared durable `AuthSessionStore` implementation for multi-process or multi-container production deployments.
49
-
50
42
  ## Authorization & request security — BCP 0.2.6+
51
43
 
52
44
  Use permission guards and resource policies from `bcp/auth`, and same-origin/CSRF protection from `bcp/server`.
@@ -55,8 +47,6 @@ Authorization must always be enforced server-side. Client UI visibility is not a
55
47
 
56
48
  ## Observability — BCP 0.2.7+
57
49
 
58
- Create process-local metrics and health/readiness registries:
59
-
60
50
  ```ts
61
51
  import {
62
52
  createHealthRegistry,
@@ -95,14 +85,8 @@ jobs.register<{
95
85
  );
96
86
  ```
97
87
 
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
88
  ## Job scheduling — BCP 0.2.9+
103
89
 
104
- Add recurring schedules on top of the same queue:
105
-
106
90
  ```ts
107
91
  import {
108
92
  createJobScheduler,
@@ -114,51 +98,126 @@ export const scheduler =
114
98
  });
115
99
  ```
116
100
 
117
- Interval schedule:
101
+ Example UTC cron schedule:
118
102
 
119
103
  ```ts
120
104
  await scheduler.schedule(
121
- "cache.cleanup",
105
+ "report.weekday",
122
106
  {},
123
107
  {
124
- everyMs: 300_000,
108
+ cron: "30 9 * * 1-5",
125
109
  }
126
110
  );
127
111
  ```
128
112
 
129
- UTC cron schedule:
113
+ ## Durable jobs — BCP 0.2.10+
114
+
115
+ Workers can use visibility leases, heartbeat renewal and stale-running recovery:
130
116
 
131
117
  ```ts
132
- await scheduler.schedule(
133
- "report.weekday",
134
- {},
118
+ const worker =
119
+ jobs.startWorker({
120
+ workerId: "worker-a",
121
+ concurrency: 4,
122
+ visibilityTimeoutMs: 30_000,
123
+ heartbeatIntervalMs: 10_000,
124
+ });
125
+ ```
126
+
127
+ Retry-exhausted jobs are available through the adapter DLQ contract:
128
+
129
+ ```ts
130
+ const deadLetters =
131
+ await jobs.deadLetters();
132
+
133
+ await jobs.requeueDeadLetter(
134
+ deadLetters[0].id,
135
135
  {
136
- cron: "30 9 * * 1-5",
136
+ resetAttempts: true,
137
137
  }
138
138
  );
139
139
  ```
140
140
 
141
- Start and stop the scheduler lifecycle:
141
+ Operational helpers:
142
+
143
+ ```ts
144
+ await jobs.recoverStale();
145
+ const stats = await jobs.stats();
146
+ await jobs.cleanup({
147
+ before:
148
+ Date.now() -
149
+ 7 * 24 * 60 * 60 * 1000,
150
+ });
151
+ ```
152
+
153
+ ### Redis-compatible adapters
154
+
155
+ BCP does not install a Redis library. Supply an application-owned command client:
156
+
157
+ ```ts
158
+ interface RedisCommandClient {
159
+ sendCommand(
160
+ command: string[]
161
+ ): Promise<unknown>;
162
+ }
163
+ ```
164
+
165
+ Create a durable queue:
166
+
167
+ ```ts
168
+ import {
169
+ createJobQueue,
170
+ createRedisJobQueueAdapter,
171
+ } from "bcp/jobs";
172
+
173
+ const adapter =
174
+ createRedisJobQueueAdapter({
175
+ client: redisCommandClient,
176
+ namespace: "my-app:{jobs}",
177
+ });
178
+
179
+ export const jobs =
180
+ createJobQueue({
181
+ adapter,
182
+ });
183
+ ```
184
+
185
+ Create a shared schedule store:
142
186
 
143
187
  ```ts
144
- const schedulerRunner =
145
- scheduler.start({
146
- pollIntervalMs: 1_000,
147
- leaseMs: 30_000,
188
+ import {
189
+ createJobScheduler,
190
+ createRedisJobScheduleStore,
191
+ } from "bcp/jobs";
192
+
193
+ const store =
194
+ createRedisJobScheduleStore({
195
+ client: redisCommandClient,
196
+ namespace: "my-app:{jobs}",
148
197
  });
149
198
 
150
- await schedulerRunner.stop();
151
- await scheduler.close();
199
+ export const scheduler =
200
+ createJobScheduler({
201
+ queue: jobs,
202
+ store,
203
+ ownerId: "scheduler-a",
204
+ });
152
205
  ```
153
206
 
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`.
207
+ A typical deployment may use:
208
+
209
+ ```dotenv
210
+ REDIS_URL=redis://localhost:6379
211
+ ```
212
+
213
+ BCP does not read this variable automatically. The application owns Redis connection creation, credentials, TLS/Cluster configuration and shutdown.
214
+
215
+ The processing model is at-least-once, so side-effecting job handlers should be idempotent when duplicate execution is unsafe.
155
216
 
156
217
  `bcp/jobs` is server-only and cannot be imported into page/client bundles.
157
218
 
158
219
  ## Generate framework files
159
220
 
160
- BCP can generate common project files:
161
-
162
221
  ```bash
163
222
  npm run generate -- page dashboard/users
164
223
  npm run generate -- api users
@@ -166,7 +225,7 @@ npm run generate -- middleware
166
225
  npm run generate -- migration create_users
167
226
  ```
168
227
 
169
- Equivalent direct BCP CLI commands are:
228
+ Equivalent direct commands:
170
229
 
171
230
  ```bash
172
231
  bcp generate page dashboard/users
@@ -177,23 +236,16 @@ bcp generate migration create_users
177
236
 
178
237
  Existing page/API/middleware targets are not replaced unless `--force` is supplied explicitly.
179
238
 
180
- After generating routes, inspect them with:
181
-
182
- ```bash
183
- npm run routes
184
- ```
185
-
186
239
  ## Direct CLI usage
187
240
 
188
- BCP Framework is installed as a project-local dependency. It is not installed globally by `create-bcp-app`.
241
+ BCP Framework is installed as a project-local dependency.
189
242
 
190
- PowerShell does not automatically add `node_modules/.bin` to its normal command search path, so use `npm exec` for direct commands:
243
+ For PowerShell direct usage:
191
244
 
192
245
  ```powershell
193
246
  npm exec -- bcp-framework --version
194
247
  npm exec -- bcp-framework doctor
195
248
  npm exec -- bcp-framework inspect
196
- npm exec -- bcp-framework generate page dashboard/users
197
249
  npm exec -- bcp-framework routes
198
250
  npm exec -- bcp-framework dev
199
251
  npm exec -- bcp-framework build
@@ -202,31 +254,15 @@ npm exec -- bcp-framework package
202
254
 
203
255
  Microsoft SQL Server can install another Windows executable named `bcp.exe`, so the `bcp-framework` alias avoids that command-name collision.
204
256
 
205
- ## Project diagnostics
206
-
207
- ```powershell
208
- npm exec -- bcp-framework doctor
209
- npm exec -- bcp-framework inspect
210
- ```
211
-
212
257
  ## Production build
213
258
 
214
- Create the raw standalone production build:
215
-
216
259
  ```bash
217
260
  npm run build
218
- ```
219
-
220
- Start it with:
221
-
222
- ```bash
223
261
  npm start
224
262
  ```
225
263
 
226
264
  ## Deployment package — BCP 0.2.4+
227
265
 
228
- Create a fresh production build and deployment-oriented package:
229
-
230
266
  ```bash
231
267
  npm run package
232
268
  ```