@chidchanun/bcp 0.2.12 → 0.2.13

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
@@ -1,15 +1,13 @@
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, API routes, authentication, authorization, SQL databases, background jobs, scheduling, workflow orchestration, transactional events, observability, uploads, storage and standalone Node.js deployment.
3
+ BCP Framework is a React full-stack framework for file-based routing, SSR, SPA navigation, server data loading, API routes, authentication, authorization, SQL databases, background jobs, scheduling, workflow orchestration, transactional events, realtime delivery, observability, uploads, storage and standalone Node.js deployment.
4
4
 
5
- > **Development target:** `0.2.12Transactional Outbox & Events`
5
+ > **Development target:** `0.2.13Realtime Platform`
6
6
  >
7
- > `0.2.12` remains unreleased until local validation, RC checks, tagging and npm publication complete.
7
+ > `0.2.13` remains unreleased until local validation, RC checks, tagging and npm publication complete.
8
8
 
9
9
  ## Current platform
10
10
 
11
- BCP `0.2.x` currently includes:
12
-
13
11
  | Area | Capability |
14
12
  | --- | --- |
15
13
  | Application | React SSR, hydration, layouts, metadata and SPA navigation |
@@ -26,6 +24,7 @@ BCP `0.2.x` currently includes:
26
24
  | Durable jobs | Redis-compatible queue/schedule adapters, visibility timeout, heartbeat, stale recovery and DLQ |
27
25
  | Workflows | Sequential/parallel steps, retries, persisted delays, compensation and run leases |
28
26
  | Events | Transactional outbox, SQL persistence, dispatcher leases, retries, event bus and durable queue handoff |
27
+ | Realtime | Channels/rooms, presence, broker delivery, WebSocket adapter contract, SSE and heartbeat |
29
28
  | Observability | Structured logs, metrics, Prometheus output and health/readiness checks |
30
29
  | Uploads & storage | Multipart streaming, Local/S3-compatible storage and signed URLs |
31
30
  | Caching | Response cache and revalidation primitives |
@@ -65,86 +64,28 @@ Generated projects normally use one framework dependency:
65
64
  }
66
65
  ```
67
66
 
68
- ## Database Platform
67
+ ## Core backend entrypoints
69
68
 
70
69
  ```ts
71
- import {
72
- db,
73
- createDatabase,
74
- } from "bcp/database";
70
+ import { db } from "bcp/database";
71
+ import { createAuth } from "bcp/auth";
72
+ import { createJobQueue } from "bcp/jobs";
73
+ import { createWorkflow } from "bcp/workflow";
74
+ import { createTransactionalOutbox } from "bcp/events";
75
+ import { createRealtime } from "bcp/realtime";
76
+ import { createMetricsRegistry } from "bcp/observability";
75
77
  ```
76
78
 
77
- Migration CLI:
78
-
79
- ```bash
80
- bcp db create create_users
81
- bcp db migrate
82
- bcp db status
83
- bcp db rollback
84
- ```
85
-
86
- ## Authentication & authorization
87
-
88
- ```ts
89
- import {
90
- createAuth,
91
- createMemoryAuthSessionStore,
92
- requirePermission,
93
- } from "bcp/auth";
94
- ```
95
-
96
- Request security is available from `bcp/server`:
97
-
98
- ```ts
99
- import {
100
- createCsrfToken,
101
- requireCsrfRequest,
102
- requireSameOriginRequest,
103
- } from "bcp/server";
104
- ```
105
-
106
- ## Observability
107
-
108
- ```ts
109
- import {
110
- createHealthRegistry,
111
- createMetricsRegistry,
112
- createMetricsResponse,
113
- } from "bcp/observability";
114
- ```
115
-
116
- ## Background jobs
79
+ ## Durable jobs and scheduling
117
80
 
118
81
  ```ts
119
82
  import {
120
83
  createJobQueue,
84
+ createJobScheduler,
121
85
  } from "bcp/jobs";
122
86
 
123
87
  export const jobs =
124
88
  createJobQueue();
125
- ```
126
-
127
- Register typed work:
128
-
129
- ```ts
130
- jobs.register<{
131
- userId: number;
132
- }>(
133
- "email.welcome",
134
- async ({ payload }) => {
135
- await sendWelcomeEmail(
136
- payload.userId
137
- );
138
- }
139
- );
140
- ```
141
-
142
- ## Job scheduling
143
-
144
- ```ts
145
- import {
146
- createJobScheduler,
147
- } from "bcp/jobs";
148
89
 
149
90
  export const scheduler =
150
91
  createJobScheduler({
@@ -152,33 +93,7 @@ export const scheduler =
152
93
  });
153
94
  ```
154
95
 
155
- UTC cron example:
156
-
157
- ```ts
158
- await scheduler.schedule(
159
- "report.weekday",
160
- {},
161
- {
162
- cron: "30 9 * * 1-5",
163
- }
164
- );
165
- ```
166
-
167
- ## Durable Jobs Platform — 0.2.10
168
-
169
- Workers support visibility leases, heartbeat renewal and stale-running recovery:
170
-
171
- ```ts
172
- const worker =
173
- jobs.startWorker({
174
- workerId: "email-worker",
175
- concurrency: 4,
176
- visibilityTimeoutMs: 30_000,
177
- heartbeatIntervalMs: 10_000,
178
- });
179
- ```
180
-
181
- Redis-compatible adapters are available from `bcp/jobs`. BCP does not install or own the Redis client; applications provide a command client and manage credentials/TLS/Cluster/lifecycle themselves.
96
+ Production adapters can provide Redis-compatible durable queue/schedule storage without BCP owning the Redis connection.
182
97
 
183
98
  ## Workflow Orchestration — 0.2.11
184
99
 
@@ -220,45 +135,13 @@ export const onboarding =
220
135
  );
221
136
  ```
222
137
 
223
- Workflows support retries, compensation and optional execution through the durable job queue.
138
+ Workflows support retries, compensation, persisted delays and optional durable queue execution.
224
139
 
225
140
  ## Transactional Outbox & Events — 0.2.12
226
141
 
227
- `0.2.12` adds the server-only `bcp/events` entrypoint.
228
-
229
- The problem it solves:
230
-
231
- ```text
232
- DB commit succeeds
233
- +
234
- external publish fails
235
- =
236
- missing integration event
237
- ```
238
-
239
- The outbox writes the event in the **same SQL transaction** as the business data:
142
+ Use the same SQL transaction for business data and its outbox event:
240
143
 
241
144
  ```ts
242
- import {
243
- db,
244
- } from "bcp/database";
245
-
246
- import {
247
- createSqlOutboxStore,
248
- createTransactionalOutbox,
249
- } from "bcp/events";
250
-
251
- const outboxStore =
252
- createSqlOutboxStore({
253
- database: db,
254
- driver: "postgresql",
255
- });
256
-
257
- const outbox =
258
- createTransactionalOutbox({
259
- store: outboxStore,
260
- });
261
-
262
145
  await db.transaction(
263
146
  async tx => {
264
147
  await tx.execute(
@@ -270,108 +153,182 @@ await db.transaction(
270
153
  "order.created",
271
154
  {
272
155
  orderId: 42,
273
- },
274
- {
275
- aggregateId: "42",
276
- correlationId: requestId,
277
156
  }
278
157
  );
279
158
  }
280
159
  );
281
160
  ```
282
161
 
283
- Generate the outbox table migration for the configured provider:
162
+ After commit, an outbox dispatcher can deliver through `bcp/jobs`, a custom publisher or the local event bus.
163
+
164
+ Read more: [Transactional Outbox & Events](docs/transactional-outbox-events.md)
165
+
166
+ ## Realtime Platform — 0.2.13
167
+
168
+ `0.2.13` adds the server-only `bcp/realtime` public entrypoint.
169
+
170
+ Create a hub:
284
171
 
285
172
  ```ts
286
173
  import {
287
- createOutboxMigrationSql,
288
- } from "bcp/events";
174
+ createRealtime,
175
+ } from "bcp/realtime";
289
176
 
290
- const sql =
291
- createOutboxMigrationSql(
292
- "postgresql"
293
- );
177
+ export const realtime =
178
+ createRealtime();
294
179
  ```
295
180
 
296
- Supported providers:
181
+ ### Channels / rooms
297
182
 
298
- ```text
299
- mysql
300
- postgresql
301
- sqlite
183
+ ```ts
184
+ const connection =
185
+ await realtime.connect();
186
+
187
+ await connection.join(
188
+ "orders:42"
189
+ );
190
+
191
+ await realtime.broadcast(
192
+ "orders:42",
193
+ "order.updated",
194
+ {
195
+ status: "paid",
196
+ }
197
+ );
302
198
  ```
303
199
 
304
- ### Dispatcher
200
+ Rooms are represented by channel names. Connections receive broadcasts only for channels they joined.
305
201
 
306
- After the SQL transaction commits, a dispatcher claims due events and delivers them:
202
+ ### Presence
307
203
 
308
204
  ```ts
309
- import {
310
- createOutboxDispatcher,
311
- } from "bcp/events";
205
+ await connection.join(
206
+ "project:7",
207
+ {
208
+ presence: {
209
+ status: "online",
210
+ },
211
+ }
212
+ );
312
213
 
313
- export const dispatcher =
314
- createOutboxDispatcher({
315
- store: outboxStore,
316
- queue: jobs,
317
- ownerId: "outbox-a",
318
- leaseMs: 30_000,
319
- batchSize: 100,
320
- pollIntervalMs: 1_000,
214
+ const members =
215
+ await realtime.members(
216
+ "project:7"
217
+ );
218
+ ```
219
+
220
+ The built-in memory presence store is process-local. Multi-instance deployments should provide a shared `RealtimePresenceStore`.
221
+
222
+ ### Authentication and private channels
223
+
224
+ ```ts
225
+ const realtime =
226
+ createRealtime({
227
+ authenticate:
228
+ async ({ request }) =>
229
+ request
230
+ ? loadRealtimeUser(
231
+ request
232
+ )
233
+ : null,
234
+
235
+ getUserId:
236
+ user => user.id,
237
+
238
+ authorizeChannel:
239
+ ({ connection, channel }) =>
240
+ !channel.startsWith(
241
+ "private:"
242
+ ) ||
243
+ Boolean(
244
+ connection.user
245
+ ),
321
246
  });
247
+ ```
248
+
249
+ ### WebSocket provider contract
322
250
 
323
- const runner =
324
- dispatcher.start();
251
+ BCP intentionally does not install `ws`, Socket.IO or another WebSocket server dependency.
252
+
253
+ Adapt the selected server/provider to `RealtimeSocket`, then attach it:
254
+
255
+ ```ts
256
+ const connection =
257
+ await realtime.attachSocket(
258
+ socketAdapter,
259
+ {
260
+ request,
261
+ }
262
+ );
325
263
  ```
326
264
 
327
- With `queue: jobs`, event type:
265
+ The JSON socket protocol supports `join`, `leave`, `event` and `ping` messages.
328
266
 
329
- ```text
330
- order.created
267
+ ### Server-Sent Events
268
+
269
+ SSE is built in through Web `Response`:
270
+
271
+ ```ts
272
+ export function GET(
273
+ request: Request
274
+ ) {
275
+ return realtime.sse(
276
+ "workflow:42",
277
+ {
278
+ signal:
279
+ request.signal,
280
+ }
281
+ );
282
+ }
331
283
  ```
332
284
 
333
- is handed off as:
285
+ ### Cross-instance delivery
286
+
287
+ `RealtimeBroker` is the provider-neutral pub/sub boundary. The built-in memory broker supports same-process hubs; production applications can implement shared Redis/NATS/etc. brokers without changing hub APIs.
334
288
 
335
289
  ```text
336
- event.order.created
290
+ Browser A -> App A ----\
291
+ Shared Broker
292
+ Browser B -> App B ----/
293
+ | |
294
+ +---- Shared Presence Store
337
295
  ```
338
296
 
339
- Register its durable consumer:
297
+ ### Heartbeat
340
298
 
341
299
  ```ts
342
- jobs.register(
343
- "event.order.created",
344
- async ({ payload }) => {
345
- await handleOrderCreated(
346
- payload
347
- );
348
- }
349
- );
300
+ const heartbeat =
301
+ realtime.startHeartbeat({
302
+ intervalMs: 20_000,
303
+ });
304
+
305
+ // shutdown
306
+ await heartbeat.stop();
307
+ await realtime.close();
350
308
  ```
351
309
 
352
- Dispatcher features include:
310
+ `realtime.ping` / `realtime.pong` and `sweepStale()` provide connection liveness cleanup.
353
311
 
354
- - batched claims,
355
- - lease ownership,
356
- - stale lease recovery,
357
- - retry/backoff,
358
- - terminal failed state,
359
- - queue delivery,
360
- - custom publisher callbacks,
361
- - local `EventBus`,
362
- - retention cleanup,
363
- - outbox statistics.
312
+ ### Jobs / workflows / events integration
364
313
 
365
- `published` means the configured destination accepted the event. For queue delivery, it means enqueue succeeded; it does not mean the downstream job handler has completed.
314
+ Realtime is the transient delivery edge for durable backend state:
315
+
316
+ ```ts
317
+ await realtime.broadcast(
318
+ `jobs:${job.id}`,
319
+ "job.progress",
320
+ {
321
+ progress: 60,
322
+ }
323
+ );
324
+ ```
366
325
 
367
- Delivery remains **at-least-once**, so consumers that perform non-idempotent side effects should use stable event IDs/idempotency controls.
326
+ Important business facts should remain in database/outbox/jobs/workflows. Realtime delivery is transient, so reconnecting clients should refetch durable state/history when catch-up is required.
368
327
 
369
- Read more: [Transactional Outbox & Events](docs/transactional-outbox-events.md)
328
+ Read more: [Realtime Platform](docs/realtime-platform.md)
370
329
 
371
330
  ## Public entrypoints
372
331
 
373
- The current documented platform surface is:
374
-
375
332
  ```text
376
333
  bcp
377
334
  bcp/island
@@ -384,13 +341,14 @@ bcp/auth
384
341
  bcp/jobs
385
342
  bcp/workflow
386
343
  bcp/events
344
+ bcp/realtime
387
345
  bcp/observability
388
346
  bcp/server
389
347
  bcp/server-only
390
348
  bcp/middleware
391
349
  ```
392
350
 
393
- Application code should use public entrypoints instead of importing private `packages/*` implementation files.
351
+ Application code should use public entrypoints instead of private `packages/*` implementation files.
394
352
 
395
353
  ## CLI
396
354
 
@@ -407,6 +365,15 @@ bcp inspect
407
365
  bcp version
408
366
  ```
409
367
 
368
+ Database migrations:
369
+
370
+ ```bash
371
+ bcp db create create_users
372
+ bcp db migrate
373
+ bcp db status
374
+ bcp db rollback
375
+ ```
376
+
410
377
  Generators:
411
378
 
412
379
  ```bash
@@ -419,32 +386,21 @@ bcp generate migration create_users
419
386
  ## Production model
420
387
 
421
388
  ```text
422
- Browser / API
423
- |
424
- security + auth + middleware
425
- |
426
- loaders / actions / API routes
427
- |
428
- Database transaction
429
- |\
430
- | +--> transactional outbox
431
- | |
432
- | dispatcher
433
- | |
434
- | durable jobs
435
- | |
436
- | workers
437
- |
438
- SSR / response
439
-
440
- Workflow + scheduler + logs + metrics + health
441
- operate alongside the request path.
389
+ Browser / API / Realtime clients
390
+ |
391
+ security + auth
392
+ |
393
+ application APIs
394
+ / | \
395
+ database workflows realtime
396
+ | | ^
397
+ outbox jobs |
398
+ \__________|_________/
399
+ durable state
442
400
  ```
443
401
 
444
402
  ## Packaging
445
403
 
446
- Raw production build:
447
-
448
404
  ```bash
449
405
  npm run build
450
406
  npm start
@@ -458,8 +414,6 @@ bcp package
458
414
 
459
415
  ## Documentation Platform
460
416
 
461
- The framework repository is the documentation source of truth.
462
-
463
417
  Machine-readable contracts:
464
418
 
465
419
  ```text
@@ -470,7 +424,7 @@ docs/api-manifest.json
470
424
 
471
425
  ## Release validation
472
426
 
473
- Before publishing `0.2.12`:
427
+ Before publishing `0.2.13`:
474
428
 
475
429
  ```bash
476
430
  npm run typecheck
@@ -481,7 +435,7 @@ npm run test:package
481
435
  npm run rc:check
482
436
  ```
483
437
 
484
- `0.2.12` adds unit and prepared-package smoke coverage for transaction-bound outbox writes, dispatcher queue handoff, retry/failure behavior, stale lease recovery, SQL migration generation, public export/runtime compilation and browser boundary enforcement.
438
+ `0.2.13` adds unit and prepared-package smoke coverage for broker broadcasts, channel membership, presence, authentication/channel authorization, socket protocol, heartbeat cleanup, SSE streaming, public runtime compilation and browser boundary enforcement.
485
439
 
486
440
  Do not tag or publish until the exact final release commit passes the full RC sequence.
487
441
 
@@ -508,12 +462,13 @@ Do not tag or publish until the exact final release commit passes the full RC se
508
462
  | `0.2.10` | Durable Jobs Platform |
509
463
  | `0.2.11` | Workflow Orchestration |
510
464
  | `0.2.12` | Transactional Outbox & Events |
465
+ | `0.2.13` | Realtime Platform |
511
466
 
512
467
  ## Roadmap
513
468
 
514
- `0.2.12` closes the database-commit / external-publish gap and establishes a provider-neutral event-delivery boundary on top of Database + Durable Jobs.
469
+ `0.2.13` establishes provider-neutral live delivery on top of the durable database/outbox/jobs/workflow stack.
515
470
 
516
- The next logical milestone is **`0.2.13Realtime Platform`**, adding WebSocket/SSE channels, rooms/presence, authenticated realtime connections and live delivery for workflow/job/event progress without changing the current outbox/job contracts.
471
+ The next logical milestone is **`0.2.14Testing Platform`**, focused on framework-native request/route/auth/database/jobs/workflow/realtime testing utilities and application test harnesses.
517
472
 
518
473
  Native desktop/mobile compilation remains later roadmap work.
519
474