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.
- package/README.md +137 -27
- package/package.json +1 -1
- 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.
|
|
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.
|
|
79
|
+
"frameworkPackage": "npm:@chidchanun/bcp@0.2.15",
|
|
80
80
|
"createdWith": {
|
|
81
81
|
"package": "create-bcp-app",
|
|
82
|
-
"version": "0.2.
|
|
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
|
-
|
|
221
|
+
BCP does not install a WebSocket library. Adapt your selected provider to `RealtimeSocket`. SSE is available directly through `realtime.sse()`.
|
|
222
222
|
|
|
223
|
-
|
|
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
|
-
|
|
227
|
+
`bcp/testing` adds framework-native test helpers without requiring a specific test runner.
|
|
226
228
|
|
|
227
|
-
|
|
229
|
+
Request/route example:
|
|
228
230
|
|
|
229
231
|
```ts
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
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
|
-
|
|
250
|
+
await expectResponse(
|
|
251
|
+
await app.get("/api/health")
|
|
252
|
+
)
|
|
253
|
+
.status(200)
|
|
254
|
+
.json({
|
|
255
|
+
ok: true,
|
|
256
|
+
});
|
|
257
|
+
```
|
|
239
258
|
|
|
240
|
-
|
|
259
|
+
Create a real signed BCP auth session for authenticated requests:
|
|
241
260
|
|
|
242
261
|
```ts
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
262
|
+
import {
|
|
263
|
+
createTestAuthSession,
|
|
264
|
+
} from "bcp/testing";
|
|
265
|
+
|
|
266
|
+
const session =
|
|
267
|
+
await createTestAuthSession(
|
|
248
268
|
{
|
|
249
|
-
|
|
250
|
-
|
|
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
|
-
|
|
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/
|
|
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.
|
|
408
|
+
npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.15.tgz
|
|
299
409
|
```
|
package/package.json
CHANGED
package/template/README.md
CHANGED
|
@@ -163,29 +163,130 @@ await realtime.broadcast(
|
|
|
163
163
|
);
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
-
|
|
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
|
-
|
|
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
|
-
|
|
172
|
+
Use server-only `bcp/testing` to exercise framework contracts without adding a BCP-specific test runner.
|
|
171
173
|
|
|
172
174
|
```ts
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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
|
-
|
|
180
|
-
|
|
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
|
-
|
|
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/
|
|
289
|
+
`bcp/plugins` is server-only and cannot be imported from page/client bundles.
|
|
189
290
|
|
|
190
291
|
## Generate framework files
|
|
191
292
|
|