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 +95 -42
- package/package.json +1 -1
- package/template/README.md +98 -62
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.
|
|
95
|
+
"frameworkPackage": "npm:@chidchanun/bcp@0.2.10",
|
|
96
96
|
"createdWith": {
|
|
97
97
|
"package": "create-bcp-app",
|
|
98
|
-
"version": "0.2.
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
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
|
-
|
|
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.
|
|
393
|
+
npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.10.tgz
|
|
341
394
|
```
|
package/package.json
CHANGED
package/template/README.md
CHANGED
|
@@ -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`.
|
|
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
|
-
|
|
101
|
+
Example UTC cron schedule:
|
|
118
102
|
|
|
119
103
|
```ts
|
|
120
104
|
await scheduler.schedule(
|
|
121
|
-
"
|
|
105
|
+
"report.weekday",
|
|
122
106
|
{},
|
|
123
107
|
{
|
|
124
|
-
|
|
108
|
+
cron: "30 9 * * 1-5",
|
|
125
109
|
}
|
|
126
110
|
);
|
|
127
111
|
```
|
|
128
112
|
|
|
129
|
-
|
|
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
|
-
|
|
133
|
-
|
|
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
|
-
|
|
136
|
+
resetAttempts: true,
|
|
137
137
|
}
|
|
138
138
|
);
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
-
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
-
|
|
151
|
-
|
|
199
|
+
export const scheduler =
|
|
200
|
+
createJobScheduler({
|
|
201
|
+
queue: jobs,
|
|
202
|
+
store,
|
|
203
|
+
ownerId: "scheduler-a",
|
|
204
|
+
});
|
|
152
205
|
```
|
|
153
206
|
|
|
154
|
-
|
|
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
|
|
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.
|
|
241
|
+
BCP Framework is installed as a project-local dependency.
|
|
189
242
|
|
|
190
|
-
PowerShell
|
|
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
|
```
|