@chidchanun/bcp 0.2.8 → 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 +164 -163
- package/docs/README.md +48 -139
- package/docs/api-manifest.json +4 -2
- package/docs/api-reference.md +92 -242
- package/docs/docs-web-manifest.json +7 -3
- package/docs/durable-jobs.md +359 -0
- package/docs/job-scheduling.md +357 -0
- package/docs/platform-manifest.json +23 -4
- package/docs/releases/0.2.10.md +148 -0
- package/docs/releases/0.2.9.md +162 -0
- package/package.json +2 -2
- package/packages/client/src/jobs.mjs +2289 -0
- package/packages/client/src/jobs.ts +34 -0
- package/packages/server/src/job-scheduler.ts +1144 -0
- package/packages/server/src/jobs-redis.ts +1226 -0
- package/packages/server/src/jobs.ts +768 -128
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# BCP Framework
|
|
2
2
|
|
|
3
|
-
BCP Framework is a React full-stack framework for file-based routing, SSR, SPA navigation, server data loading, guarded application flows, API routes, authentication, authorization, database access, background jobs, observability, validation, uploads, storage and standalone Node.js production deployment.
|
|
3
|
+
BCP Framework is a React full-stack framework for file-based routing, SSR, SPA navigation, server data loading, guarded application flows, API routes, authentication, authorization, database access, background jobs, recurring scheduling, observability, validation, uploads, storage and standalone Node.js production deployment.
|
|
4
4
|
|
|
5
|
-
> **Development target:** `0.2.
|
|
5
|
+
> **Development target:** `0.2.10 — Durable Jobs Platform`
|
|
6
6
|
>
|
|
7
|
-
> `0.2.
|
|
7
|
+
> `0.2.10` is an unreleased development target until local validation, RC checks, tagging and npm publication complete.
|
|
8
8
|
|
|
9
9
|
## 0.2 platform
|
|
10
10
|
|
|
11
|
-
`0.2.0` established the Framework Platform baseline, `0.2.1` added the Documentation Platform, `0.2.2` added Configuration & Environment v2, `0.2.3` added Database Platform v2, `0.2.4` added Application Packaging, `0.2.5` added Authentication Platform v2, `0.2.6` added Authorization & Security v2, `0.2.7` added Observability Platform v2,
|
|
11
|
+
`0.2.0` established the Framework Platform baseline, `0.2.1` added the Documentation Platform, `0.2.2` added Configuration & Environment v2, `0.2.3` added Database Platform v2, `0.2.4` added Application Packaging, `0.2.5` added Authentication Platform v2, `0.2.6` added Authorization & Security v2, `0.2.7` added Observability Platform v2, `0.2.8` added Background Jobs Platform, `0.2.9` added recurring scheduling, and `0.2.10` adds durable worker leases, DLQ maintenance and Redis-compatible queue/scheduler adapters.
|
|
12
12
|
|
|
13
13
|
Machine-readable platform contracts:
|
|
14
14
|
|
|
@@ -35,7 +35,9 @@ docs/api-manifest.json
|
|
|
35
35
|
| Authorization | Auth/guest/role/permission route guards, flat permissions and resource-aware policies |
|
|
36
36
|
| Request security | Same-origin validation and signed CSRF tokens for unsafe mutations |
|
|
37
37
|
| Middleware | Middleware System v2 with onion execution |
|
|
38
|
-
| Background jobs |
|
|
38
|
+
| Background jobs | Delayed jobs, retries/backoff, cancellation, concurrent workers, visibility leases, heartbeat, stale recovery and DLQ |
|
|
39
|
+
| Scheduling | Recurring interval jobs, UTC cron, schedule-store leases and deterministic scheduled run IDs |
|
|
40
|
+
| Durable jobs | Redis-compatible queue/schedule adapters, retention cleanup, requeue and queue statistics |
|
|
39
41
|
| Observability | Structured logs, counters/gauges/histograms, Prometheus output, request metrics and health/readiness checks |
|
|
40
42
|
| Validation | Typed validators and structured validation errors |
|
|
41
43
|
| Error handling | HTTP error helpers and consistent error responses |
|
|
@@ -130,8 +132,6 @@ Read more:
|
|
|
130
132
|
|
|
131
133
|
## Database Platform v2 — 0.2.3
|
|
132
134
|
|
|
133
|
-
Application code uses one server-only database entrypoint across supported SQL providers:
|
|
134
|
-
|
|
135
135
|
```ts
|
|
136
136
|
import {
|
|
137
137
|
db,
|
|
@@ -147,16 +147,6 @@ postgresql
|
|
|
147
147
|
sqlite
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
-
Lifecycle control:
|
|
151
|
-
|
|
152
|
-
```ts
|
|
153
|
-
await db.connect();
|
|
154
|
-
|
|
155
|
-
// application work
|
|
156
|
-
|
|
157
|
-
await db.disconnect();
|
|
158
|
-
```
|
|
159
|
-
|
|
160
150
|
Migration CLI:
|
|
161
151
|
|
|
162
152
|
```bash
|
|
@@ -179,23 +169,10 @@ Create a fresh production build and deployment package:
|
|
|
179
169
|
bcp package
|
|
180
170
|
```
|
|
181
171
|
|
|
182
|
-
Output:
|
|
172
|
+
Output is written under:
|
|
183
173
|
|
|
184
174
|
```text
|
|
185
175
|
.bcp-framework/package/
|
|
186
|
-
├─ client/
|
|
187
|
-
├─ server/
|
|
188
|
-
│ └─ server.mjs
|
|
189
|
-
├─ public/ # when present
|
|
190
|
-
├─ manifest.json
|
|
191
|
-
├─ package.json
|
|
192
|
-
├─ package-lock.json # when a safe npm v3 production lock can be derived
|
|
193
|
-
├─ bcp.package.json
|
|
194
|
-
├─ bcp.deployment.json
|
|
195
|
-
├─ bcp.env.json
|
|
196
|
-
├─ Dockerfile
|
|
197
|
-
├─ .dockerignore
|
|
198
|
-
└─ README.md
|
|
199
176
|
```
|
|
200
177
|
|
|
201
178
|
Read more:
|
|
@@ -205,35 +182,17 @@ Read more:
|
|
|
205
182
|
|
|
206
183
|
## Authentication Platform v2 — 0.2.5
|
|
207
184
|
|
|
208
|
-
Stateless signed JWT-cookie authentication remains supported:
|
|
209
|
-
|
|
210
185
|
```ts
|
|
211
186
|
import {
|
|
212
187
|
auth,
|
|
213
|
-
login,
|
|
214
|
-
logout,
|
|
215
|
-
} from "bcp/auth";
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
Applications that need centralized revocation can add a server-side session store:
|
|
219
|
-
|
|
220
|
-
```ts
|
|
221
|
-
import {
|
|
222
188
|
createAuth,
|
|
223
189
|
createMemoryAuthSessionStore,
|
|
190
|
+
login,
|
|
191
|
+
logout,
|
|
224
192
|
} from "bcp/auth";
|
|
225
|
-
|
|
226
|
-
const sessionStore =
|
|
227
|
-
createMemoryAuthSessionStore();
|
|
228
|
-
|
|
229
|
-
export const appAuth =
|
|
230
|
-
createAuth({
|
|
231
|
-
store: sessionStore,
|
|
232
|
-
idleTimeout: 60 * 30,
|
|
233
|
-
});
|
|
234
193
|
```
|
|
235
194
|
|
|
236
|
-
|
|
195
|
+
Stateless signed JWT-cookie authentication remains supported. Applications that need centralized revocation can configure an `AuthSessionStore`.
|
|
237
196
|
|
|
238
197
|
Read more:
|
|
239
198
|
|
|
@@ -243,55 +202,12 @@ Read more:
|
|
|
243
202
|
|
|
244
203
|
## Authorization & Security v2 — 0.2.6
|
|
245
204
|
|
|
246
|
-
Use flat permissions directly from `bcp/auth`:
|
|
247
|
-
|
|
248
205
|
```ts
|
|
249
206
|
import {
|
|
207
|
+
authorize,
|
|
250
208
|
hasPermission,
|
|
251
209
|
requirePermission,
|
|
252
210
|
} from "bcp/auth";
|
|
253
|
-
|
|
254
|
-
hasPermission(
|
|
255
|
-
user,
|
|
256
|
-
"users.read"
|
|
257
|
-
);
|
|
258
|
-
|
|
259
|
-
await requirePermission(
|
|
260
|
-
[
|
|
261
|
-
"users.read",
|
|
262
|
-
"users.write",
|
|
263
|
-
],
|
|
264
|
-
{
|
|
265
|
-
match: "all",
|
|
266
|
-
}
|
|
267
|
-
);
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
Resource-aware policies:
|
|
271
|
-
|
|
272
|
-
```ts
|
|
273
|
-
import {
|
|
274
|
-
authorize,
|
|
275
|
-
defineAuthorizationPolicy,
|
|
276
|
-
} from "bcp/auth";
|
|
277
|
-
|
|
278
|
-
const updateProject =
|
|
279
|
-
defineAuthorizationPolicy(
|
|
280
|
-
({
|
|
281
|
-
user,
|
|
282
|
-
resource,
|
|
283
|
-
}) =>
|
|
284
|
-
resource.ownerId ===
|
|
285
|
-
user.id
|
|
286
|
-
);
|
|
287
|
-
|
|
288
|
-
await authorize(
|
|
289
|
-
updateProject,
|
|
290
|
-
{
|
|
291
|
-
user,
|
|
292
|
-
resource: project,
|
|
293
|
-
}
|
|
294
|
-
);
|
|
295
211
|
```
|
|
296
212
|
|
|
297
213
|
Request-security helpers are exposed from `bcp/server`:
|
|
@@ -308,56 +224,18 @@ Read more: [Authorization & Security v2](docs/authorization-security.md)
|
|
|
308
224
|
|
|
309
225
|
## Observability Platform v2 — 0.2.7
|
|
310
226
|
|
|
311
|
-
Create one application metrics registry:
|
|
312
|
-
|
|
313
227
|
```ts
|
|
314
228
|
import {
|
|
229
|
+
createHealthRegistry,
|
|
315
230
|
createMetricsRegistry,
|
|
316
|
-
} from "bcp/observability";
|
|
317
|
-
|
|
318
|
-
export const metrics =
|
|
319
|
-
createMetricsRegistry();
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
Supported metric types:
|
|
323
|
-
|
|
324
|
-
```text
|
|
325
|
-
counter
|
|
326
|
-
gauge
|
|
327
|
-
histogram
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
Expose Prometheus-compatible text:
|
|
331
|
-
|
|
332
|
-
```ts
|
|
333
|
-
import {
|
|
334
231
|
createMetricsResponse,
|
|
335
232
|
} from "bcp/observability";
|
|
336
|
-
|
|
337
|
-
export function GET() {
|
|
338
|
-
return createMetricsResponse(
|
|
339
|
-
metrics
|
|
340
|
-
);
|
|
341
|
-
}
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
Health/readiness registry:
|
|
345
|
-
|
|
346
|
-
```ts
|
|
347
|
-
import {
|
|
348
|
-
createHealthRegistry,
|
|
349
|
-
} from "bcp/observability";
|
|
350
|
-
|
|
351
|
-
export const health =
|
|
352
|
-
createHealthRegistry();
|
|
353
233
|
```
|
|
354
234
|
|
|
355
235
|
Read more: [Observability Platform v2](docs/observability.md)
|
|
356
236
|
|
|
357
237
|
## Background Jobs Platform — 0.2.8
|
|
358
238
|
|
|
359
|
-
Create a server-side queue:
|
|
360
|
-
|
|
361
239
|
```ts
|
|
362
240
|
import {
|
|
363
241
|
createJobQueue,
|
|
@@ -367,7 +245,7 @@ export const jobs =
|
|
|
367
245
|
createJobQueue();
|
|
368
246
|
```
|
|
369
247
|
|
|
370
|
-
Register
|
|
248
|
+
Register work:
|
|
371
249
|
|
|
372
250
|
```ts
|
|
373
251
|
jobs.register<{
|
|
@@ -382,7 +260,7 @@ jobs.register<{
|
|
|
382
260
|
);
|
|
383
261
|
```
|
|
384
262
|
|
|
385
|
-
Enqueue
|
|
263
|
+
Enqueue work:
|
|
386
264
|
|
|
387
265
|
```ts
|
|
388
266
|
await jobs.enqueue(
|
|
@@ -397,24 +275,153 @@ await jobs.enqueue(
|
|
|
397
275
|
);
|
|
398
276
|
```
|
|
399
277
|
|
|
400
|
-
|
|
278
|
+
Read more: [Background Jobs Platform](docs/background-jobs.md)
|
|
279
|
+
|
|
280
|
+
## Job Scheduling Platform — 0.2.9
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
import {
|
|
284
|
+
createJobScheduler,
|
|
285
|
+
} from "bcp/jobs";
|
|
286
|
+
|
|
287
|
+
export const scheduler =
|
|
288
|
+
createJobScheduler({
|
|
289
|
+
queue: jobs,
|
|
290
|
+
});
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Interval schedule:
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
await scheduler.schedule(
|
|
297
|
+
"cache.cleanup",
|
|
298
|
+
{},
|
|
299
|
+
{
|
|
300
|
+
id: "cache-cleanup",
|
|
301
|
+
everyMs: 5 * 60 * 1000,
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
UTC cron schedule:
|
|
307
|
+
|
|
308
|
+
```ts
|
|
309
|
+
await scheduler.schedule(
|
|
310
|
+
"report.weekday",
|
|
311
|
+
{},
|
|
312
|
+
{
|
|
313
|
+
cron: "30 9 * * 1-5",
|
|
314
|
+
}
|
|
315
|
+
);
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Read more: [Job Scheduling Platform](docs/job-scheduling.md)
|
|
319
|
+
|
|
320
|
+
## Durable Jobs Platform — 0.2.10
|
|
321
|
+
|
|
322
|
+
Workers now support visibility leases, heartbeat renewal and stale-running recovery when the configured adapter implements those capabilities:
|
|
401
323
|
|
|
402
324
|
```ts
|
|
403
325
|
const worker =
|
|
404
326
|
jobs.startWorker({
|
|
327
|
+
workerId: "email-worker",
|
|
405
328
|
concurrency: 4,
|
|
329
|
+
visibilityTimeoutMs: 30_000,
|
|
330
|
+
heartbeatIntervalMs: 10_000,
|
|
406
331
|
pollIntervalMs: 250,
|
|
407
332
|
});
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Retry-exhausted jobs can be inspected and requeued:
|
|
336
|
+
|
|
337
|
+
```ts
|
|
338
|
+
const failed =
|
|
339
|
+
await jobs.deadLetters();
|
|
340
|
+
|
|
341
|
+
await jobs.requeueDeadLetter(
|
|
342
|
+
failed[0].id,
|
|
343
|
+
{
|
|
344
|
+
delayMs: 5_000,
|
|
345
|
+
resetAttempts: true,
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Operational helpers:
|
|
351
|
+
|
|
352
|
+
```ts
|
|
353
|
+
await jobs.recoverStale({
|
|
354
|
+
limit: 100,
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
const stats =
|
|
358
|
+
await jobs.stats();
|
|
359
|
+
|
|
360
|
+
await jobs.cleanup({
|
|
361
|
+
before:
|
|
362
|
+
Date.now() -
|
|
363
|
+
7 * 24 * 60 * 60 * 1000,
|
|
364
|
+
});
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Redis-compatible durable queue
|
|
368
|
+
|
|
369
|
+
BCP does not install a Redis client library. Supply an application-owned client that implements:
|
|
370
|
+
|
|
371
|
+
```ts
|
|
372
|
+
interface RedisCommandClient {
|
|
373
|
+
sendCommand(
|
|
374
|
+
command: string[]
|
|
375
|
+
): Promise<unknown>;
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Then create the adapters:
|
|
380
|
+
|
|
381
|
+
```ts
|
|
382
|
+
import {
|
|
383
|
+
createJobQueue,
|
|
384
|
+
createJobScheduler,
|
|
385
|
+
createRedisJobQueueAdapter,
|
|
386
|
+
createRedisJobScheduleStore,
|
|
387
|
+
} from "bcp/jobs";
|
|
388
|
+
|
|
389
|
+
const queueAdapter =
|
|
390
|
+
createRedisJobQueueAdapter({
|
|
391
|
+
client: redisCommandClient,
|
|
392
|
+
namespace: "my-app:{jobs}",
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
export const jobs =
|
|
396
|
+
createJobQueue({
|
|
397
|
+
adapter: queueAdapter,
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
const scheduleStore =
|
|
401
|
+
createRedisJobScheduleStore({
|
|
402
|
+
client: redisCommandClient,
|
|
403
|
+
namespace: "my-app:{jobs}",
|
|
404
|
+
});
|
|
408
405
|
|
|
409
|
-
|
|
410
|
-
|
|
406
|
+
export const scheduler =
|
|
407
|
+
createJobScheduler({
|
|
408
|
+
queue: jobs,
|
|
409
|
+
store: scheduleStore,
|
|
410
|
+
ownerId: "scheduler-a",
|
|
411
|
+
});
|
|
411
412
|
```
|
|
412
413
|
|
|
413
|
-
The
|
|
414
|
+
The Redis reference adapters use atomic Lua operations for reservations, visibility leases, heartbeat, stale recovery, DLQ requeue and scheduler leasing. The default namespace is `bcp:{jobs}` so keys share one Redis Cluster hash slot.
|
|
414
415
|
|
|
415
|
-
|
|
416
|
+
A typical application may configure its Redis client with:
|
|
416
417
|
|
|
417
|
-
|
|
418
|
+
```dotenv
|
|
419
|
+
REDIS_URL=redis://localhost:6379
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
BCP does not read `REDIS_URL` automatically; connection creation, TLS/Cluster settings and credentials remain application-owned.
|
|
423
|
+
|
|
424
|
+
Read more: [Durable Jobs Platform](docs/durable-jobs.md)
|
|
418
425
|
|
|
419
426
|
## Public entrypoints
|
|
420
427
|
|
|
@@ -479,27 +486,21 @@ bcp generate middleware
|
|
|
479
486
|
bcp generate migration create_users
|
|
480
487
|
```
|
|
481
488
|
|
|
482
|
-
##
|
|
489
|
+
## Production model
|
|
483
490
|
|
|
484
491
|
```text
|
|
485
|
-
Browser
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
↓
|
|
493
|
-
React SSR
|
|
494
|
-
↓
|
|
495
|
-
Hydration / SPA navigation
|
|
492
|
+
Browser / API clients
|
|
493
|
+
↓
|
|
494
|
+
security + middleware + auth
|
|
495
|
+
↓
|
|
496
|
+
loaders / actions / API routes
|
|
497
|
+
↓
|
|
498
|
+
SSR / application responses
|
|
496
499
|
|
|
497
500
|
Operational side channels:
|
|
498
|
-
|
|
501
|
+
shared jobs + scheduler + structured logs + metrics + health/readiness
|
|
499
502
|
```
|
|
500
503
|
|
|
501
|
-
## Production build
|
|
502
|
-
|
|
503
504
|
Raw standalone build:
|
|
504
505
|
|
|
505
506
|
```bash
|
|
@@ -513,8 +514,6 @@ Deployment package:
|
|
|
513
514
|
bcp package
|
|
514
515
|
```
|
|
515
516
|
|
|
516
|
-
Both current targets remain Node.js `standalone-node` applications.
|
|
517
|
-
|
|
518
517
|
## Documentation Platform
|
|
519
518
|
|
|
520
519
|
The framework repository is the documentation source of truth.
|
|
@@ -541,7 +540,7 @@ npm run test:e2e
|
|
|
541
540
|
npm run rc:check
|
|
542
541
|
```
|
|
543
542
|
|
|
544
|
-
`0.2.
|
|
543
|
+
`0.2.10` adds Durable Jobs Platform unit and prepared-package smoke checks covering visibility leases, heartbeat renewal, stale recovery, DLQ/requeue, retention/statistics, Redis queue/scheduler command contracts and the compiled `bcp/jobs` runtime.
|
|
545
544
|
|
|
546
545
|
Do not tag or publish until the final release commit passes the complete RC sequence.
|
|
547
546
|
|
|
@@ -564,12 +563,14 @@ Do not tag or publish until the final release commit passes the complete RC sequ
|
|
|
564
563
|
| `0.2.6` | Authorization & Security v2 |
|
|
565
564
|
| `0.2.7` | Observability Platform v2 |
|
|
566
565
|
| `0.2.8` | Background Jobs Platform |
|
|
566
|
+
| `0.2.9` | Job Scheduling Platform |
|
|
567
|
+
| `0.2.10` | Durable Jobs Platform |
|
|
567
568
|
|
|
568
569
|
## Roadmap
|
|
569
570
|
|
|
570
|
-
`0.2.
|
|
571
|
+
`0.2.10 — Durable Jobs Platform` establishes shared production queue/scheduler adapters and worker recovery semantics while keeping the provider-neutral `bcp/jobs` contract.
|
|
571
572
|
|
|
572
|
-
Later `0.2.x` work can add
|
|
573
|
+
Later `0.2.x` work can add workflow orchestration, transactional outbox helpers or additional durable providers without changing the base queue/scheduler model. Native `.exe`, desktop and mobile compilation remain later roadmap work.
|
|
573
574
|
|
|
574
575
|
## License
|
|
575
576
|
|