create-bcp-app 0.2.13 → 0.2.15

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.
Files changed (3) hide show
  1. package/README.md +137 -27
  2. package/package.json +1 -1
  3. package/template/README.md +114 -13
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.13` target:
72
+ Example for the `0.2.15` 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.13",
79
+ "frameworkPackage": "npm:@chidchanun/bcp@0.2.15",
80
80
  "createdWith": {
81
81
  "package": "create-bcp-app",
82
- "version": "0.2.13"
82
+ "version": "0.2.15"
83
83
  },
84
84
  "packageManager": "npm",
85
85
  "presets": {
@@ -218,44 +218,154 @@ await realtime.broadcast(
218
218
  );
219
219
  ```
220
220
 
221
- Presence metadata can be attached during `join()` and read with `realtime.members(channel)`.
221
+ BCP does not install a WebSocket library. Adapt your selected provider to `RealtimeSocket`. SSE is available directly through `realtime.sse()`.
222
222
 
223
- For private channels, configure `authenticate`, `getUserId` and `authorizeChannel` on `createRealtime()`.
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+
224
226
 
225
- ### WebSocket integration
227
+ `bcp/testing` adds framework-native test helpers without requiring a specific test runner.
226
228
 
227
- BCP does not install a WebSocket library. Adapt your selected provider to `RealtimeSocket` and pass it to:
229
+ Request/route example:
228
230
 
229
231
  ```ts
230
- await realtime.attachSocket(
231
- socketAdapter,
232
- {
233
- request,
234
- }
235
- );
236
- ```
232
+ import {
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
+ });
237
249
 
238
- ### Server-Sent Events
250
+ await expectResponse(
251
+ await app.get("/api/health")
252
+ )
253
+ .status(200)
254
+ .json({
255
+ ok: true,
256
+ });
257
+ ```
239
258
 
240
- SSE is available without another dependency:
259
+ Create a real signed BCP auth session for authenticated requests:
241
260
 
242
261
  ```ts
243
- export function GET(
244
- request: Request
245
- ) {
246
- return realtime.sse(
247
- "jobs:42",
262
+ import {
263
+ createTestAuthSession,
264
+ } from "bcp/testing";
265
+
266
+ const session =
267
+ await createTestAuthSession(
248
268
  {
249
- signal:
250
- request.signal,
269
+ id: 42,
270
+ role: "admin",
271
+ },
272
+ {
273
+ secret:
274
+ process.env.BCP_SESSION_SECRET,
251
275
  }
252
276
  );
253
- }
277
+
278
+ app.setCookie(
279
+ session.cookieName,
280
+ session.token
281
+ );
254
282
  ```
255
283
 
256
- The memory broker/presence store are local-only. Multi-instance production deployments should provide shared `RealtimeBroker` and `RealtimePresenceStore` implementations.
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
+ );
299
+ ```
300
+
301
+ Infrastructure helpers include:
302
+
303
+ ```text
304
+ createJobTestHarness()
305
+ createWorkflowTestHarness()
306
+ createOutboxTestHarness()
307
+ createRealtimeTestSocket()
308
+ createRealtimeTestHarness()
309
+ readSseEvents()
310
+ createFakeClock()
311
+ createSequenceIdFactory()
312
+ runTestMiddleware()
313
+ ```
314
+
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.
316
+
317
+ ## Plugin & Module Platform — 0.2.15+
318
+
319
+ Use `bcp/plugins` to compose reusable server-side application modules with explicit lifecycle and dependencies.
320
+
321
+ ```ts
322
+ import {
323
+ createPluginHost,
324
+ defineModule,
325
+ definePlugin,
326
+ } from "bcp/plugins";
327
+
328
+ const databasePlugin =
329
+ definePlugin({
330
+ name: "database",
331
+ setup(context) {
332
+ context.services.provide(
333
+ "database",
334
+ db
335
+ );
336
+ },
337
+ });
338
+
339
+ const jobsPlugin =
340
+ definePlugin({
341
+ name: "jobs",
342
+ requires: [
343
+ "database",
344
+ ],
345
+ });
346
+
347
+ const backendModule =
348
+ defineModule({
349
+ name: "backend",
350
+ plugins: [
351
+ databasePlugin,
352
+ jobsPlugin,
353
+ ],
354
+ });
355
+
356
+ const host =
357
+ createPluginHost({
358
+ modules: [
359
+ backendModule,
360
+ ],
361
+ });
362
+
363
+ await host.start();
364
+ ```
365
+
366
+ Plugins can use `setup/start/stop/dispose`, typed config parsers, a shared service registry and an awaited in-process hook bus. Required dependencies start first; shutdown runs in reverse order.
257
367
 
258
- `bcp/realtime` is server-only and cannot be imported into page/client bundles.
368
+ `bcp/plugins` is server-only and cannot be imported into page/client bundles.
259
369
 
260
370
  ## Storage providers
261
371
 
@@ -295,5 +405,5 @@ npm run generate -- migration create_users
295
405
  For prerelease/local package verification:
296
406
 
297
407
  ```bash
298
- npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.13.tgz
408
+ npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.15.tgz
299
409
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-bcp-app",
3
- "version": "0.2.13",
3
+ "version": "0.2.15",
4
4
  "description": "Create a new BCP Framework application.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -163,29 +163,130 @@ await realtime.broadcast(
163
163
  );
164
164
  ```
165
165
 
166
- Presence metadata can be supplied during `join()` and queried with `realtime.members(channel)`.
166
+ BCP does not install a WebSocket server dependency. Adapt the selected provider to `RealtimeSocket`. SSE is built in through `realtime.sse()`.
167
167
 
168
- BCP does not install a WebSocket server dependency. Adapt the selected provider to `RealtimeSocket` and call `realtime.attachSocket(socketAdapter, { request })`.
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+
169
171
 
170
- SSE is built in:
172
+ Use server-only `bcp/testing` to exercise framework contracts without adding a BCP-specific test runner.
171
173
 
172
174
  ```ts
173
- export function GET(
174
- request: Request
175
- ) {
176
- return realtime.sse(
177
- "jobs:42",
175
+ import {
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
+ });
192
+
193
+ await expectResponse(
194
+ await app.get("/api/health")
195
+ )
196
+ .status(200)
197
+ .json({
198
+ ok: true,
199
+ });
200
+ ```
201
+
202
+ Authentication tests can create a real signed BCP session:
203
+
204
+ ```ts
205
+ import {
206
+ createTestAuthSession,
207
+ } from "bcp/testing";
208
+
209
+ const session =
210
+ await createTestAuthSession(
211
+ {
212
+ id: 42,
213
+ },
178
214
  {
179
- signal:
180
- request.signal,
215
+ secret:
216
+ process.env.BCP_SESSION_SECRET,
181
217
  }
182
218
  );
183
- }
219
+
220
+ app.setCookie(
221
+ session.cookieName,
222
+ session.token
223
+ );
184
224
  ```
185
225
 
186
- For multi-instance deployment, replace the memory broker/presence store with shared `RealtimeBroker` and `RealtimePresenceStore` implementations.
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
+ ```
242
+
243
+ Additional helpers include job/workflow/outbox harnesses, `runTestMiddleware()`, page loader/guard/action helpers, fake clocks and IDs, a fake `RealtimeSocket`, realtime event assertions and `readSseEvents()`.
244
+
245
+ BCP does not require Jest or Vitest; these helpers work with Node `node:test` or another runner.
246
+
247
+ ## Plugin & Module Platform — BCP 0.2.15+
248
+
249
+ Use `bcp/plugins` to compose reusable server-only application services with explicit dependencies.
250
+
251
+ ```ts
252
+ import {
253
+ createPluginHost,
254
+ definePlugin,
255
+ } from "bcp/plugins";
256
+
257
+ const databasePlugin =
258
+ definePlugin({
259
+ name: "database",
260
+ setup(context) {
261
+ context.services.provide(
262
+ "database",
263
+ db
264
+ );
265
+ },
266
+ });
267
+
268
+ const jobsPlugin =
269
+ definePlugin({
270
+ name: "jobs",
271
+ requires: [
272
+ "database",
273
+ ],
274
+ });
275
+
276
+ export const plugins =
277
+ createPluginHost({
278
+ plugins: [
279
+ jobsPlugin,
280
+ databasePlugin,
281
+ ],
282
+ });
283
+ ```
284
+
285
+ Plugin startup follows dependency order and shutdown reverses it. Plugins can use `setup/start/stop/dispose`, config parsers, shared services and async hooks.
286
+
287
+ Use `defineModule()` when a reusable package needs to bundle multiple plugin definitions into one named module.
187
288
 
188
- `bcp/realtime` is server-only and cannot be imported into page/client bundles.
289
+ `bcp/plugins` is server-only and cannot be imported from page/client bundles.
189
290
 
190
291
  ## Generate framework files
191
292