@chidchanun/bcp 0.2.11 → 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 +228 -401
- package/docs/README.md +51 -68
- package/docs/api-manifest.json +31 -63
- package/docs/api-reference.md +103 -118
- package/docs/docs-web-manifest.json +9 -5
- package/docs/platform-manifest.json +27 -4
- package/docs/realtime-platform.md +447 -0
- package/docs/releases/0.2.12.md +147 -0
- package/docs/releases/0.2.13.md +122 -0
- package/docs/transactional-outbox-events.md +465 -0
- package/package.json +11 -1
- package/packages/bundler/src/client-boundary.ts +2 -0
- package/packages/client/src/events.mjs +889 -0
- package/packages/client/src/events.ts +31 -0
- package/packages/client/src/realtime.mjs +936 -0
- package/packages/client/src/realtime.ts +31 -0
- package/packages/server/src/events.ts +1416 -0
- package/packages/server/src/realtime.ts +1464 -0
package/README.md
CHANGED
|
@@ -1,55 +1,36 @@
|
|
|
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,
|
|
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.
|
|
5
|
+
> **Development target:** `0.2.13 — Realtime Platform`
|
|
6
6
|
>
|
|
7
|
-
> `0.2.
|
|
7
|
+
> `0.2.13` remains unreleased until local validation, RC checks, tagging and npm publication complete.
|
|
8
8
|
|
|
9
|
-
##
|
|
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, `0.2.8` added Background Jobs Platform, `0.2.9` added recurring scheduling, `0.2.10` added durable worker leases/DLQ/Redis adapters, and `0.2.11` adds persistent multi-step workflow orchestration.
|
|
12
|
-
|
|
13
|
-
Machine-readable platform contracts:
|
|
14
|
-
|
|
15
|
-
```text
|
|
16
|
-
docs/platform-manifest.json
|
|
17
|
-
-> runtime target, capabilities and compatibility
|
|
18
|
-
|
|
19
|
-
docs/docs-web-manifest.json
|
|
20
|
-
-> documentation navigation, routes and releases
|
|
21
|
-
|
|
22
|
-
docs/api-manifest.json
|
|
23
|
-
-> public package entrypoints and guide ownership
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Current capabilities
|
|
9
|
+
## Current platform
|
|
27
10
|
|
|
28
11
|
| Area | Capability |
|
|
29
12
|
| --- | --- |
|
|
30
13
|
| Application | React SSR, hydration, layouts, metadata and SPA navigation |
|
|
31
14
|
| Routing | Static, dynamic, catch-all, optional catch-all and route groups |
|
|
32
|
-
| Server data | Route
|
|
33
|
-
| Mutations | Route-owned
|
|
34
|
-
| Authentication | JWT cookie sessions, optional server-side
|
|
35
|
-
| Authorization | Auth/guest/role/permission
|
|
36
|
-
|
|
|
15
|
+
| Server data | Route loaders and request-scoped server APIs |
|
|
16
|
+
| Mutations | Route-owned actions and `<Form>` |
|
|
17
|
+
| Authentication | JWT cookie sessions, optional server-side stores, revocation, logout-all and idle timeout |
|
|
18
|
+
| Authorization | Auth/guest/role/permission guards and resource-aware policies |
|
|
19
|
+
| Security | Same-origin validation and signed CSRF tokens |
|
|
37
20
|
| Middleware | Middleware System v2 with onion execution |
|
|
38
|
-
|
|
|
39
|
-
|
|
|
40
|
-
|
|
|
41
|
-
|
|
|
42
|
-
|
|
|
43
|
-
|
|
|
44
|
-
|
|
|
45
|
-
|
|
|
46
|
-
| Uploads |
|
|
47
|
-
| Storage | Local + S3-compatible storage, streaming, list/copy/move, metadata, bulk delete and signed URLs |
|
|
21
|
+
| Database | MySQL, PostgreSQL and SQLite adapters, transactions, lifecycle and migrations |
|
|
22
|
+
| Background jobs | Delay, retry/backoff, cancellation and concurrent workers |
|
|
23
|
+
| Scheduling | Interval/UTC cron schedules and scheduler leases |
|
|
24
|
+
| Durable jobs | Redis-compatible queue/schedule adapters, visibility timeout, heartbeat, stale recovery and DLQ |
|
|
25
|
+
| Workflows | Sequential/parallel steps, retries, persisted delays, compensation and run leases |
|
|
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 |
|
|
28
|
+
| Observability | Structured logs, metrics, Prometheus output and health/readiness checks |
|
|
29
|
+
| Uploads & storage | Multipart streaming, Local/S3-compatible storage and signed URLs |
|
|
48
30
|
| Caching | Response cache and revalidation primitives |
|
|
49
|
-
| Configuration | Typed
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
| Documentation | Manifest-driven docs navigation, platform metadata and public API reference |
|
|
31
|
+
| Configuration | Typed config/environment validation and diagnostics |
|
|
32
|
+
| Production | Standalone Node.js build, packaging, dependency pruning, Docker starter and graceful shutdown |
|
|
33
|
+
| Documentation | Manifest-driven docs, platform metadata and API reference |
|
|
53
34
|
|
|
54
35
|
## Requirements
|
|
55
36
|
|
|
@@ -57,7 +38,7 @@ docs/api-manifest.json
|
|
|
57
38
|
- React `19`
|
|
58
39
|
- npm
|
|
59
40
|
|
|
60
|
-
|
|
41
|
+
Optional SQL drivers:
|
|
61
42
|
|
|
62
43
|
```text
|
|
63
44
|
MySQL mysql2
|
|
@@ -73,7 +54,7 @@ cd my-app
|
|
|
73
54
|
npm run dev
|
|
74
55
|
```
|
|
75
56
|
|
|
76
|
-
Generated projects normally
|
|
57
|
+
Generated projects normally use one framework dependency:
|
|
77
58
|
|
|
78
59
|
```json
|
|
79
60
|
{
|
|
@@ -83,314 +64,39 @@ Generated projects normally keep one framework dependency key:
|
|
|
83
64
|
}
|
|
84
65
|
```
|
|
85
66
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
## Configuration & environment
|
|
89
|
-
|
|
90
|
-
Framework configuration stays in one of:
|
|
91
|
-
|
|
92
|
-
```text
|
|
93
|
-
bcp.config.ts
|
|
94
|
-
bcp.config.mts
|
|
95
|
-
bcp.config.js
|
|
96
|
-
bcp.config.mjs
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
Application environment validation can be declared in:
|
|
100
|
-
|
|
101
|
-
```text
|
|
102
|
-
bcp.environment.ts
|
|
103
|
-
bcp.environment.mts
|
|
104
|
-
bcp.environment.js
|
|
105
|
-
bcp.environment.mjs
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
Configuration precedence is:
|
|
109
|
-
|
|
110
|
-
```text
|
|
111
|
-
CLI override
|
|
112
|
-
↓
|
|
113
|
-
BCP_* environment
|
|
114
|
-
↓
|
|
115
|
-
bcp.config.*
|
|
116
|
-
↓
|
|
117
|
-
framework defaults
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
Validate configuration and declared environment values with:
|
|
121
|
-
|
|
122
|
-
```bash
|
|
123
|
-
bcp config check
|
|
124
|
-
bcp config check --json
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Variables beginning with `BCP_PUBLIC_` may be embedded in browser output. Never expose application secrets through public-prefixed variables.
|
|
128
|
-
|
|
129
|
-
Read more:
|
|
130
|
-
|
|
131
|
-
- [Configuration](docs/configuration.md)
|
|
132
|
-
- [Environment Validation](docs/environment-validation.md)
|
|
133
|
-
|
|
134
|
-
## Database Platform v2 — 0.2.3
|
|
67
|
+
## Core backend entrypoints
|
|
135
68
|
|
|
136
69
|
```ts
|
|
137
|
-
import {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
} from "bcp/
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
```text
|
|
146
|
-
mysql
|
|
147
|
-
postgresql
|
|
148
|
-
sqlite
|
|
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";
|
|
149
77
|
```
|
|
150
78
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
```bash
|
|
154
|
-
bcp db create create_users
|
|
155
|
-
bcp db migrate
|
|
156
|
-
bcp db status
|
|
157
|
-
bcp db rollback
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
Read more:
|
|
161
|
-
|
|
162
|
-
- [Database](docs/database.md)
|
|
163
|
-
- [Database Migrations](docs/database-migrations.md)
|
|
164
|
-
|
|
165
|
-
## Application Packaging — 0.2.4
|
|
166
|
-
|
|
167
|
-
Create a fresh production build and deployment package:
|
|
168
|
-
|
|
169
|
-
```bash
|
|
170
|
-
bcp package
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
Output is written under:
|
|
174
|
-
|
|
175
|
-
```text
|
|
176
|
-
.bcp-framework/package/
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
Read more:
|
|
180
|
-
|
|
181
|
-
- [Application Packaging](docs/application-packaging.md)
|
|
182
|
-
- [Deployment](docs/deployment.md)
|
|
183
|
-
|
|
184
|
-
## Authentication Platform v2 — 0.2.5
|
|
185
|
-
|
|
186
|
-
```ts
|
|
187
|
-
import {
|
|
188
|
-
auth,
|
|
189
|
-
createAuth,
|
|
190
|
-
createMemoryAuthSessionStore,
|
|
191
|
-
login,
|
|
192
|
-
logout,
|
|
193
|
-
} from "bcp/auth";
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
Stateless signed JWT-cookie authentication remains supported. Applications that need centralized revocation can configure an `AuthSessionStore`.
|
|
197
|
-
|
|
198
|
-
Read more:
|
|
199
|
-
|
|
200
|
-
- [Authentication](docs/authentication.md)
|
|
201
|
-
- [Auth Session Stores](docs/auth-session-store.md)
|
|
202
|
-
- [Auth Route Guards](docs/auth-route-guards.md)
|
|
203
|
-
|
|
204
|
-
## Authorization & Security v2 — 0.2.6
|
|
205
|
-
|
|
206
|
-
```ts
|
|
207
|
-
import {
|
|
208
|
-
authorize,
|
|
209
|
-
hasPermission,
|
|
210
|
-
requirePermission,
|
|
211
|
-
} from "bcp/auth";
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
Request-security helpers are exposed from `bcp/server`:
|
|
215
|
-
|
|
216
|
-
```ts
|
|
217
|
-
import {
|
|
218
|
-
createCsrfToken,
|
|
219
|
-
requireCsrfRequest,
|
|
220
|
-
requireSameOriginRequest,
|
|
221
|
-
} from "bcp/server";
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
Read more: [Authorization & Security v2](docs/authorization-security.md)
|
|
225
|
-
|
|
226
|
-
## Observability Platform v2 — 0.2.7
|
|
227
|
-
|
|
228
|
-
```ts
|
|
229
|
-
import {
|
|
230
|
-
createHealthRegistry,
|
|
231
|
-
createMetricsRegistry,
|
|
232
|
-
createMetricsResponse,
|
|
233
|
-
} from "bcp/observability";
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
Read more: [Observability Platform v2](docs/observability.md)
|
|
237
|
-
|
|
238
|
-
## Background Jobs Platform — 0.2.8
|
|
79
|
+
## Durable jobs and scheduling
|
|
239
80
|
|
|
240
81
|
```ts
|
|
241
82
|
import {
|
|
242
83
|
createJobQueue,
|
|
243
|
-
} from "bcp/jobs";
|
|
244
|
-
|
|
245
|
-
export const jobs =
|
|
246
|
-
createJobQueue();
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
Register work:
|
|
250
|
-
|
|
251
|
-
```ts
|
|
252
|
-
jobs.register<{
|
|
253
|
-
userId: number;
|
|
254
|
-
}>(
|
|
255
|
-
"email.welcome",
|
|
256
|
-
async ({ payload }) => {
|
|
257
|
-
await sendWelcomeEmail(
|
|
258
|
-
payload.userId
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
);
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
Enqueue work:
|
|
265
|
-
|
|
266
|
-
```ts
|
|
267
|
-
await jobs.enqueue(
|
|
268
|
-
"email.welcome",
|
|
269
|
-
{
|
|
270
|
-
userId: 42,
|
|
271
|
-
},
|
|
272
|
-
{
|
|
273
|
-
delayMs: 5_000,
|
|
274
|
-
maxAttempts: 5,
|
|
275
|
-
}
|
|
276
|
-
);
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
Read more: [Background Jobs Platform](docs/background-jobs.md)
|
|
280
|
-
|
|
281
|
-
## Job Scheduling Platform — 0.2.9
|
|
282
|
-
|
|
283
|
-
```ts
|
|
284
|
-
import {
|
|
285
84
|
createJobScheduler,
|
|
286
85
|
} from "bcp/jobs";
|
|
287
86
|
|
|
288
|
-
export const scheduler =
|
|
289
|
-
createJobScheduler({
|
|
290
|
-
queue: jobs,
|
|
291
|
-
});
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
Interval schedule:
|
|
295
|
-
|
|
296
|
-
```ts
|
|
297
|
-
await scheduler.schedule(
|
|
298
|
-
"cache.cleanup",
|
|
299
|
-
{},
|
|
300
|
-
{
|
|
301
|
-
id: "cache-cleanup",
|
|
302
|
-
everyMs: 5 * 60 * 1000,
|
|
303
|
-
}
|
|
304
|
-
);
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
UTC cron schedule:
|
|
308
|
-
|
|
309
|
-
```ts
|
|
310
|
-
await scheduler.schedule(
|
|
311
|
-
"report.weekday",
|
|
312
|
-
{},
|
|
313
|
-
{
|
|
314
|
-
cron: "30 9 * * 1-5",
|
|
315
|
-
}
|
|
316
|
-
);
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
Read more: [Job Scheduling Platform](docs/job-scheduling.md)
|
|
320
|
-
|
|
321
|
-
## Durable Jobs Platform — 0.2.10
|
|
322
|
-
|
|
323
|
-
Workers support visibility leases, heartbeat renewal and stale-running recovery when the configured adapter implements those capabilities:
|
|
324
|
-
|
|
325
|
-
```ts
|
|
326
|
-
const worker =
|
|
327
|
-
jobs.startWorker({
|
|
328
|
-
workerId: "email-worker",
|
|
329
|
-
concurrency: 4,
|
|
330
|
-
visibilityTimeoutMs: 30_000,
|
|
331
|
-
heartbeatIntervalMs: 10_000,
|
|
332
|
-
pollIntervalMs: 250,
|
|
333
|
-
});
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
Retry-exhausted jobs can be inspected and requeued:
|
|
337
|
-
|
|
338
|
-
```ts
|
|
339
|
-
const failed =
|
|
340
|
-
await jobs.deadLetters();
|
|
341
|
-
|
|
342
|
-
await jobs.requeueDeadLetter(
|
|
343
|
-
failed[0].id,
|
|
344
|
-
{
|
|
345
|
-
delayMs: 5_000,
|
|
346
|
-
resetAttempts: true,
|
|
347
|
-
}
|
|
348
|
-
);
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
Redis-compatible durable adapters:
|
|
352
|
-
|
|
353
|
-
```ts
|
|
354
|
-
import {
|
|
355
|
-
createJobQueue,
|
|
356
|
-
createJobScheduler,
|
|
357
|
-
createRedisJobQueueAdapter,
|
|
358
|
-
createRedisJobScheduleStore,
|
|
359
|
-
} from "bcp/jobs";
|
|
360
|
-
|
|
361
|
-
const queueAdapter =
|
|
362
|
-
createRedisJobQueueAdapter({
|
|
363
|
-
client: redisCommandClient,
|
|
364
|
-
namespace: "my-app:{jobs}",
|
|
365
|
-
});
|
|
366
|
-
|
|
367
87
|
export const jobs =
|
|
368
|
-
createJobQueue(
|
|
369
|
-
adapter: queueAdapter,
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
const scheduleStore =
|
|
373
|
-
createRedisJobScheduleStore({
|
|
374
|
-
client: redisCommandClient,
|
|
375
|
-
namespace: "my-app:{jobs}",
|
|
376
|
-
});
|
|
88
|
+
createJobQueue();
|
|
377
89
|
|
|
378
90
|
export const scheduler =
|
|
379
91
|
createJobScheduler({
|
|
380
92
|
queue: jobs,
|
|
381
|
-
store: scheduleStore,
|
|
382
|
-
ownerId: "scheduler-a",
|
|
383
93
|
});
|
|
384
94
|
```
|
|
385
95
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
Read more: [Durable Jobs Platform](docs/durable-jobs.md)
|
|
96
|
+
Production adapters can provide Redis-compatible durable queue/schedule storage without BCP owning the Redis connection.
|
|
389
97
|
|
|
390
98
|
## Workflow Orchestration — 0.2.11
|
|
391
99
|
|
|
392
|
-
Create a server-only workflow with typed input:
|
|
393
|
-
|
|
394
100
|
```ts
|
|
395
101
|
import {
|
|
396
102
|
createWorkflow,
|
|
@@ -404,11 +110,7 @@ export const onboarding =
|
|
|
404
110
|
workflow => {
|
|
405
111
|
workflow.step(
|
|
406
112
|
"profile",
|
|
407
|
-
|
|
408
|
-
await createProfile(
|
|
409
|
-
input.userId
|
|
410
|
-
);
|
|
411
|
-
}
|
|
113
|
+
createProfile
|
|
412
114
|
);
|
|
413
115
|
|
|
414
116
|
workflow.parallel(
|
|
@@ -433,66 +135,199 @@ export const onboarding =
|
|
|
433
135
|
);
|
|
434
136
|
```
|
|
435
137
|
|
|
436
|
-
|
|
138
|
+
Workflows support retries, compensation, persisted delays and optional durable queue execution.
|
|
139
|
+
|
|
140
|
+
## Transactional Outbox & Events — 0.2.12
|
|
141
|
+
|
|
142
|
+
Use the same SQL transaction for business data and its outbox event:
|
|
437
143
|
|
|
438
144
|
```ts
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
145
|
+
await db.transaction(
|
|
146
|
+
async tx => {
|
|
147
|
+
await tx.execute(
|
|
148
|
+
"INSERT INTO orders ..."
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
await outbox.publish(
|
|
152
|
+
tx,
|
|
153
|
+
"order.created",
|
|
154
|
+
{
|
|
155
|
+
orderId: 42,
|
|
156
|
+
}
|
|
157
|
+
);
|
|
447
158
|
}
|
|
448
159
|
);
|
|
449
160
|
```
|
|
450
161
|
|
|
451
|
-
|
|
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:
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
import {
|
|
174
|
+
createRealtime,
|
|
175
|
+
} from "bcp/realtime";
|
|
176
|
+
|
|
177
|
+
export const realtime =
|
|
178
|
+
createRealtime();
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Channels / rooms
|
|
452
182
|
|
|
453
183
|
```ts
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
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",
|
|
457
194
|
{
|
|
458
|
-
|
|
459
|
-
releaseStock,
|
|
195
|
+
status: "paid",
|
|
460
196
|
}
|
|
461
197
|
);
|
|
462
198
|
```
|
|
463
199
|
|
|
464
|
-
|
|
200
|
+
Rooms are represented by channel names. Connections receive broadcasts only for channels they joined.
|
|
201
|
+
|
|
202
|
+
### Presence
|
|
465
203
|
|
|
466
204
|
```ts
|
|
467
|
-
await
|
|
468
|
-
|
|
205
|
+
await connection.join(
|
|
206
|
+
"project:7",
|
|
207
|
+
{
|
|
208
|
+
presence: {
|
|
209
|
+
status: "online",
|
|
210
|
+
},
|
|
211
|
+
}
|
|
469
212
|
);
|
|
213
|
+
|
|
214
|
+
const members =
|
|
215
|
+
await realtime.members(
|
|
216
|
+
"project:7"
|
|
217
|
+
);
|
|
470
218
|
```
|
|
471
219
|
|
|
472
|
-
|
|
220
|
+
The built-in memory presence store is process-local. Multi-instance deployments should provide a shared `RealtimePresenceStore`.
|
|
221
|
+
|
|
222
|
+
### Authentication and private channels
|
|
473
223
|
|
|
474
224
|
```ts
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
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
|
+
),
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### WebSocket provider contract
|
|
250
|
+
|
|
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,
|
|
479
259
|
{
|
|
480
|
-
|
|
481
|
-
store:
|
|
482
|
-
workflowStore,
|
|
260
|
+
request,
|
|
483
261
|
}
|
|
484
262
|
);
|
|
485
263
|
```
|
|
486
264
|
|
|
487
|
-
|
|
265
|
+
The JSON socket protocol supports `join`, `leave`, `event` and `ping` messages.
|
|
488
266
|
|
|
489
|
-
|
|
267
|
+
### Server-Sent Events
|
|
490
268
|
|
|
491
|
-
|
|
269
|
+
SSE is built in through Web `Response`:
|
|
492
270
|
|
|
493
|
-
|
|
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
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
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.
|
|
288
|
+
|
|
289
|
+
```text
|
|
290
|
+
Browser A -> App A ----\
|
|
291
|
+
Shared Broker
|
|
292
|
+
Browser B -> App B ----/
|
|
293
|
+
| |
|
|
294
|
+
+---- Shared Presence Store
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Heartbeat
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
const heartbeat =
|
|
301
|
+
realtime.startHeartbeat({
|
|
302
|
+
intervalMs: 20_000,
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// shutdown
|
|
306
|
+
await heartbeat.stop();
|
|
307
|
+
await realtime.close();
|
|
308
|
+
```
|
|
494
309
|
|
|
495
|
-
|
|
310
|
+
`realtime.ping` / `realtime.pong` and `sweepStale()` provide connection liveness cleanup.
|
|
311
|
+
|
|
312
|
+
### Jobs / workflows / events integration
|
|
313
|
+
|
|
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
|
+
```
|
|
325
|
+
|
|
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.
|
|
327
|
+
|
|
328
|
+
Read more: [Realtime Platform](docs/realtime-platform.md)
|
|
329
|
+
|
|
330
|
+
## Public entrypoints
|
|
496
331
|
|
|
497
332
|
```text
|
|
498
333
|
bcp
|
|
@@ -505,24 +340,18 @@ bcp/database
|
|
|
505
340
|
bcp/auth
|
|
506
341
|
bcp/jobs
|
|
507
342
|
bcp/workflow
|
|
343
|
+
bcp/events
|
|
344
|
+
bcp/realtime
|
|
508
345
|
bcp/observability
|
|
509
346
|
bcp/server
|
|
510
347
|
bcp/server-only
|
|
511
348
|
bcp/middleware
|
|
512
349
|
```
|
|
513
350
|
|
|
514
|
-
Application code should use public entrypoints instead of
|
|
515
|
-
|
|
516
|
-
See:
|
|
517
|
-
|
|
518
|
-
- [API Reference](docs/api-reference.md)
|
|
519
|
-
- [Platform Manifest](docs/platform-manifest.json)
|
|
520
|
-
- [API Manifest](docs/api-manifest.json)
|
|
351
|
+
Application code should use public entrypoints instead of private `packages/*` implementation files.
|
|
521
352
|
|
|
522
353
|
## CLI
|
|
523
354
|
|
|
524
|
-
Core commands:
|
|
525
|
-
|
|
526
355
|
```bash
|
|
527
356
|
bcp dev
|
|
528
357
|
bcp build
|
|
@@ -545,7 +374,7 @@ bcp db status
|
|
|
545
374
|
bcp db rollback
|
|
546
375
|
```
|
|
547
376
|
|
|
548
|
-
|
|
377
|
+
Generators:
|
|
549
378
|
|
|
550
379
|
```bash
|
|
551
380
|
bcp generate page dashboard/users
|
|
@@ -557,27 +386,24 @@ bcp generate migration create_users
|
|
|
557
386
|
## Production model
|
|
558
387
|
|
|
559
388
|
```text
|
|
560
|
-
Browser / API clients
|
|
561
|
-
|
|
562
|
-
security +
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
shared jobs + scheduler
|
|
572
|
-
↓
|
|
573
|
-
workers + structured logs + metrics + health/readiness
|
|
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
|
|
574
400
|
```
|
|
575
401
|
|
|
576
|
-
|
|
402
|
+
## Packaging
|
|
577
403
|
|
|
578
404
|
```bash
|
|
579
405
|
npm run build
|
|
580
|
-
npm
|
|
406
|
+
npm start
|
|
581
407
|
```
|
|
582
408
|
|
|
583
409
|
Deployment package:
|
|
@@ -588,33 +414,30 @@ bcp package
|
|
|
588
414
|
|
|
589
415
|
## Documentation Platform
|
|
590
416
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
`bcp-docs-web` consumes:
|
|
417
|
+
Machine-readable contracts:
|
|
594
418
|
|
|
595
419
|
```text
|
|
596
|
-
docs/docs-web-manifest.json
|
|
597
420
|
docs/platform-manifest.json
|
|
421
|
+
docs/docs-web-manifest.json
|
|
598
422
|
docs/api-manifest.json
|
|
599
423
|
```
|
|
600
424
|
|
|
601
425
|
## Release validation
|
|
602
426
|
|
|
603
|
-
|
|
427
|
+
Before publishing `0.2.13`:
|
|
604
428
|
|
|
605
429
|
```bash
|
|
606
|
-
npm install
|
|
607
430
|
npm run typecheck
|
|
608
431
|
npm run test:unit
|
|
609
432
|
npm run test:integration
|
|
610
|
-
npm run test:package
|
|
611
433
|
npm run test:e2e
|
|
434
|
+
npm run test:package
|
|
612
435
|
npm run rc:check
|
|
613
436
|
```
|
|
614
437
|
|
|
615
|
-
`0.2.
|
|
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.
|
|
616
439
|
|
|
617
|
-
Do not tag or publish until the final release commit passes the
|
|
440
|
+
Do not tag or publish until the exact final release commit passes the full RC sequence.
|
|
618
441
|
|
|
619
442
|
## Release history
|
|
620
443
|
|
|
@@ -638,12 +461,16 @@ Do not tag or publish until the final release commit passes the complete RC sequ
|
|
|
638
461
|
| `0.2.9` | Job Scheduling Platform |
|
|
639
462
|
| `0.2.10` | Durable Jobs Platform |
|
|
640
463
|
| `0.2.11` | Workflow Orchestration |
|
|
464
|
+
| `0.2.12` | Transactional Outbox & Events |
|
|
465
|
+
| `0.2.13` | Realtime Platform |
|
|
641
466
|
|
|
642
467
|
## Roadmap
|
|
643
468
|
|
|
644
|
-
`0.2.
|
|
469
|
+
`0.2.13` establishes provider-neutral live delivery on top of the durable database/outbox/jobs/workflow stack.
|
|
470
|
+
|
|
471
|
+
The next logical milestone is **`0.2.14 — Testing Platform`**, focused on framework-native request/route/auth/database/jobs/workflow/realtime testing utilities and application test harnesses.
|
|
645
472
|
|
|
646
|
-
|
|
473
|
+
Native desktop/mobile compilation remains later roadmap work.
|
|
647
474
|
|
|
648
475
|
## License
|
|
649
476
|
|