create-bcp-app 0.2.12 → 0.2.14

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
@@ -69,17 +69,17 @@ Select storage provider:
69
69
 
70
70
  New projects include `bcp.project.json`.
71
71
 
72
- Example for the `0.2.12` target:
72
+ Example for the `0.2.14` target:
73
73
 
74
74
  ```json
75
75
  {
76
76
  "schemaVersion": 1,
77
77
  "framework": "bcp",
78
78
  "projectName": "my-app",
79
- "frameworkPackage": "npm:@chidchanun/bcp@0.2.12",
79
+ "frameworkPackage": "npm:@chidchanun/bcp@0.2.14",
80
80
  "createdWith": {
81
81
  "package": "create-bcp-app",
82
- "version": "0.2.12"
82
+ "version": "0.2.14"
83
83
  },
84
84
  "packageManager": "npm",
85
85
  "presets": {
@@ -167,26 +167,6 @@ export const onboarding =
167
167
  Applications using the SQL Database Platform can persist integration events in the same transaction as business data:
168
168
 
169
169
  ```ts
170
- import {
171
- db,
172
- } from "bcp/database";
173
-
174
- import {
175
- createSqlOutboxStore,
176
- createTransactionalOutbox,
177
- } from "bcp/events";
178
-
179
- const outboxStore =
180
- createSqlOutboxStore({
181
- database: db,
182
- driver: "mysql",
183
- });
184
-
185
- const outbox =
186
- createTransactionalOutbox({
187
- store: outboxStore,
188
- });
189
-
190
170
  await db.transaction(
191
171
  async tx => {
192
172
  await tx.execute(
@@ -204,42 +184,135 @@ await db.transaction(
204
184
  );
205
185
  ```
206
186
 
207
- Create migration SQL with:
187
+ After commit, `createOutboxDispatcher()` can hand off events to durable jobs/custom publishers.
188
+
189
+ ## Realtime Platform — 0.2.13+
190
+
191
+ Generated applications can add server-side realtime channels without changing the scaffold preset model:
208
192
 
209
193
  ```ts
210
194
  import {
211
- createOutboxMigrationSql,
212
- } from "bcp/events";
195
+ createRealtime,
196
+ } from "bcp/realtime";
213
197
 
214
- const migrationSql =
215
- createOutboxMigrationSql(
216
- "mysql"
217
- );
198
+ export const realtime =
199
+ createRealtime();
200
+ ```
201
+
202
+ Channel/room usage:
203
+
204
+ ```ts
205
+ const connection =
206
+ await realtime.connect();
207
+
208
+ await connection.join(
209
+ "orders:42"
210
+ );
211
+
212
+ await realtime.broadcast(
213
+ "orders:42",
214
+ "order.updated",
215
+ {
216
+ status: "paid",
217
+ }
218
+ );
218
219
  ```
219
220
 
220
- After commit, dispatch to the durable job queue:
221
+ BCP does not install a WebSocket library. Adapt your selected provider to `RealtimeSocket`. SSE is available directly through `realtime.sse()`.
222
+
223
+ The memory broker/presence store are local-only. Multi-instance production deployments should provide shared `RealtimeBroker` and `RealtimePresenceStore` implementations.
224
+
225
+ ## Testing Platform — 0.2.14+
226
+
227
+ `bcp/testing` adds framework-native test helpers without requiring a specific test runner.
228
+
229
+ Request/route example:
221
230
 
222
231
  ```ts
223
232
  import {
224
- createOutboxDispatcher,
225
- } from "bcp/events";
233
+ createRouteTestHandler,
234
+ createTestApp,
235
+ expectResponse,
236
+ } from "bcp/testing";
237
+
238
+ const app =
239
+ createTestApp({
240
+ handler:
241
+ createRouteTestHandler({
242
+ GET() {
243
+ return {
244
+ ok: true,
245
+ };
246
+ },
247
+ }),
248
+ });
226
249
 
227
- const dispatcher =
228
- createOutboxDispatcher({
229
- store: outboxStore,
230
- queue: jobs,
231
- ownerId: "outbox-a",
250
+ await expectResponse(
251
+ await app.get("/api/health")
252
+ )
253
+ .status(200)
254
+ .json({
255
+ ok: true,
232
256
  });
257
+ ```
258
+
259
+ Create a real signed BCP auth session for authenticated requests:
260
+
261
+ ```ts
262
+ import {
263
+ createTestAuthSession,
264
+ } from "bcp/testing";
265
+
266
+ const session =
267
+ await createTestAuthSession(
268
+ {
269
+ id: 42,
270
+ role: "admin",
271
+ },
272
+ {
273
+ secret:
274
+ process.env.BCP_SESSION_SECRET,
275
+ }
276
+ );
277
+
278
+ app.setCookie(
279
+ session.cookieName,
280
+ session.token
281
+ );
282
+ ```
233
283
 
234
- const runner =
235
- dispatcher.start();
284
+ Rollback database tests:
285
+
286
+ ```ts
287
+ import {
288
+ withTestTransaction,
289
+ } from "bcp/testing";
290
+
291
+ await withTestTransaction(
292
+ db,
293
+ async tx => {
294
+ await tx.execute(
295
+ "INSERT INTO users ..."
296
+ );
297
+ }
298
+ );
236
299
  ```
237
300
 
238
- Event type `order.created` is handed off to queue name `event.order.created`.
301
+ Infrastructure helpers include:
239
302
 
240
- The outbox dispatcher supports leases, stale recovery, retry/backoff, custom publishers, a local EventBus, cleanup and statistics.
303
+ ```text
304
+ createJobTestHarness()
305
+ createWorkflowTestHarness()
306
+ createOutboxTestHarness()
307
+ createRealtimeTestSocket()
308
+ createRealtimeTestHarness()
309
+ readSseEvents()
310
+ createFakeClock()
311
+ createSequenceIdFactory()
312
+ runTestMiddleware()
313
+ ```
241
314
 
242
- `bcp/events` is server-only. The SQL outbox protects the database-commit/external-publish boundary, but downstream delivery remains at-least-once, so non-repeatable side effects should use idempotency protection.
315
+ `bcp/testing` is server-only. It can be used with Node `node:test`, Vitest, Jest or another runner; BCP does not install those runners as framework dependencies.
243
316
 
244
317
  ## Storage providers
245
318
 
@@ -279,5 +352,5 @@ npm run generate -- migration create_users
279
352
  For prerelease/local package verification:
280
353
 
281
354
  ```bash
282
- npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.12.tgz
355
+ npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.14.tgz
283
356
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-bcp-app",
3
- "version": "0.2.12",
3
+ "version": "0.2.14",
4
4
  "description": "Create a new BCP Framework application.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -112,26 +112,6 @@ Workflows support sequential/parallel steps, retries, persisted delays, compensa
112
112
  Use `bcp/events` when application data and an integration event must commit atomically in the same SQL transaction.
113
113
 
114
114
  ```ts
115
- import {
116
- db,
117
- } from "bcp/database";
118
-
119
- import {
120
- createSqlOutboxStore,
121
- createTransactionalOutbox,
122
- } from "bcp/events";
123
-
124
- const outboxStore =
125
- createSqlOutboxStore({
126
- database: db,
127
- driver: "mysql",
128
- });
129
-
130
- const outbox =
131
- createTransactionalOutbox({
132
- store: outboxStore,
133
- });
134
-
135
115
  await db.transaction(
136
116
  async tx => {
137
117
  await tx.execute(
@@ -149,42 +129,120 @@ await db.transaction(
149
129
  );
150
130
  ```
151
131
 
152
- Generate the required table SQL:
132
+ After commit, `createOutboxDispatcher()` can deliver through durable jobs or a custom publisher.
133
+
134
+ ## Realtime Platform — BCP 0.2.13+
135
+
136
+ Create a server-side realtime hub:
153
137
 
154
138
  ```ts
155
139
  import {
156
- createOutboxMigrationSql,
157
- } from "bcp/events";
140
+ createRealtime,
141
+ } from "bcp/realtime";
158
142
 
159
- const sql =
160
- createOutboxMigrationSql(
161
- "mysql"
162
- );
143
+ export const realtime =
144
+ createRealtime();
163
145
  ```
164
146
 
165
- Dispatch committed events to the durable queue:
147
+ Channels/rooms:
148
+
149
+ ```ts
150
+ const connection =
151
+ await realtime.connect();
152
+
153
+ await connection.join(
154
+ "orders:42"
155
+ );
156
+
157
+ await realtime.broadcast(
158
+ "orders:42",
159
+ "order.updated",
160
+ {
161
+ status: "paid",
162
+ }
163
+ );
164
+ ```
165
+
166
+ BCP does not install a WebSocket server dependency. Adapt the selected provider to `RealtimeSocket`. SSE is built in through `realtime.sse()`.
167
+
168
+ For multi-instance deployment, replace the memory broker/presence store with shared `RealtimeBroker` and `RealtimePresenceStore` implementations.
169
+
170
+ ## Testing Platform — BCP 0.2.14+
171
+
172
+ Use server-only `bcp/testing` to exercise framework contracts without adding a BCP-specific test runner.
166
173
 
167
174
  ```ts
168
175
  import {
169
- createOutboxDispatcher,
170
- } from "bcp/events";
176
+ createRouteTestHandler,
177
+ createTestApp,
178
+ expectResponse,
179
+ } from "bcp/testing";
180
+
181
+ const app =
182
+ createTestApp({
183
+ handler:
184
+ createRouteTestHandler({
185
+ GET() {
186
+ return {
187
+ ok: true,
188
+ };
189
+ },
190
+ }),
191
+ });
171
192
 
172
- const dispatcher =
173
- createOutboxDispatcher({
174
- store: outboxStore,
175
- queue: jobs,
176
- ownerId: "outbox-a",
193
+ await expectResponse(
194
+ await app.get("/api/health")
195
+ )
196
+ .status(200)
197
+ .json({
198
+ ok: true,
177
199
  });
200
+ ```
201
+
202
+ Authentication tests can create a real signed BCP session:
178
203
 
179
- const runner =
180
- dispatcher.start();
204
+ ```ts
205
+ import {
206
+ createTestAuthSession,
207
+ } from "bcp/testing";
208
+
209
+ const session =
210
+ await createTestAuthSession(
211
+ {
212
+ id: 42,
213
+ },
214
+ {
215
+ secret:
216
+ process.env.BCP_SESSION_SECRET,
217
+ }
218
+ );
219
+
220
+ app.setCookie(
221
+ session.cookieName,
222
+ session.token
223
+ );
181
224
  ```
182
225
 
183
- Event `order.created` is queued as `event.order.created`.
226
+ Database tests can force rollback after assertions:
227
+
228
+ ```ts
229
+ import {
230
+ withTestTransaction,
231
+ } from "bcp/testing";
232
+
233
+ await withTestTransaction(
234
+ db,
235
+ async tx => {
236
+ await tx.execute(
237
+ "INSERT INTO users ..."
238
+ );
239
+ }
240
+ );
241
+ ```
184
242
 
185
- The dispatcher supports leases, stale recovery, retry/backoff, custom publishers, local EventBus delivery, retention cleanup and statistics.
243
+ Additional helpers include job/workflow/outbox harnesses, `runTestMiddleware()`, fake clocks and IDs, a fake `RealtimeSocket`, realtime event assertions and `readSseEvents()`.
186
244
 
187
- `bcp/events` is server-only. Outbox delivery remains at-least-once, so non-repeatable downstream side effects should use idempotency protection.
245
+ BCP does not require Jest or Vitest; these helpers work with Node `node:test` or another runner.
188
246
 
189
247
  ## Generate framework files
190
248