create-bcp-app 0.2.15 → 0.2.17
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 +103 -121
- package/package.json +1 -1
- package/template/README.md +138 -45
package/README.md
CHANGED
|
@@ -34,7 +34,6 @@ For direct PowerShell usage, prefer the collision-free local alias:
|
|
|
34
34
|
npm exec -- bcp-framework --version
|
|
35
35
|
npm exec -- bcp-framework doctor
|
|
36
36
|
npm exec -- bcp-framework inspect
|
|
37
|
-
npm exec -- bcp-framework generate page dashboard/users
|
|
38
37
|
npm exec -- bcp-framework routes
|
|
39
38
|
npm exec -- bcp-framework dev
|
|
40
39
|
npm exec -- bcp-framework build
|
|
@@ -45,8 +44,6 @@ Microsoft SQL Server can install another Windows executable named `bcp.exe`, so
|
|
|
45
44
|
|
|
46
45
|
## Interactive choices
|
|
47
46
|
|
|
48
|
-
The generator asks for optional application presets:
|
|
49
|
-
|
|
50
47
|
```text
|
|
51
48
|
Use Tailwind CSS?
|
|
52
49
|
Select a database:
|
|
@@ -69,17 +66,17 @@ Select storage provider:
|
|
|
69
66
|
|
|
70
67
|
New projects include `bcp.project.json`.
|
|
71
68
|
|
|
72
|
-
Example for the `0.2.
|
|
69
|
+
Example for the `0.2.17` target:
|
|
73
70
|
|
|
74
71
|
```json
|
|
75
72
|
{
|
|
76
73
|
"schemaVersion": 1,
|
|
77
74
|
"framework": "bcp",
|
|
78
75
|
"projectName": "my-app",
|
|
79
|
-
"frameworkPackage": "npm:@chidchanun/bcp@0.2.
|
|
76
|
+
"frameworkPackage": "npm:@chidchanun/bcp@0.2.17",
|
|
80
77
|
"createdWith": {
|
|
81
78
|
"package": "create-bcp-app",
|
|
82
|
-
"version": "0.2.
|
|
79
|
+
"version": "0.2.17"
|
|
83
80
|
},
|
|
84
81
|
"packageManager": "npm",
|
|
85
82
|
"presets": {
|
|
@@ -109,15 +106,6 @@ For MySQL, PostgreSQL and SQLite, generated `lib/database.ts` exposes BCP databa
|
|
|
109
106
|
|
|
110
107
|
The JWT Cookie preset creates `lib/auth.ts` and starter auth routes. BCP `0.2.5+` supports optional revocable server-side auth state, while `0.2.6+` adds permission/policy authorization plus same-origin/CSRF helpers.
|
|
111
108
|
|
|
112
|
-
## Observability
|
|
113
|
-
|
|
114
|
-
```ts
|
|
115
|
-
import {
|
|
116
|
-
createHealthRegistry,
|
|
117
|
-
createMetricsRegistry,
|
|
118
|
-
} from "bcp/observability";
|
|
119
|
-
```
|
|
120
|
-
|
|
121
109
|
## Background jobs and scheduling
|
|
122
110
|
|
|
123
111
|
```ts
|
|
@@ -160,12 +148,8 @@ export const onboarding =
|
|
|
160
148
|
);
|
|
161
149
|
```
|
|
162
150
|
|
|
163
|
-
`bcp/workflow` supports sequential/parallel steps, retry, persisted delays, compensation and optional execution through `bcp/jobs`.
|
|
164
|
-
|
|
165
151
|
## Transactional Outbox & Events — 0.2.12+
|
|
166
152
|
|
|
167
|
-
Applications using the SQL Database Platform can persist integration events in the same transaction as business data:
|
|
168
|
-
|
|
169
153
|
```ts
|
|
170
154
|
await db.transaction(
|
|
171
155
|
async tx => {
|
|
@@ -184,12 +168,8 @@ await db.transaction(
|
|
|
184
168
|
);
|
|
185
169
|
```
|
|
186
170
|
|
|
187
|
-
After commit, `createOutboxDispatcher()` can hand off events to durable jobs/custom publishers.
|
|
188
|
-
|
|
189
171
|
## Realtime Platform — 0.2.13+
|
|
190
172
|
|
|
191
|
-
Generated applications can add server-side realtime channels without changing the scaffold preset model:
|
|
192
|
-
|
|
193
173
|
```ts
|
|
194
174
|
import {
|
|
195
175
|
createRealtime,
|
|
@@ -199,35 +179,10 @@ export const realtime =
|
|
|
199
179
|
createRealtime();
|
|
200
180
|
```
|
|
201
181
|
|
|
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
|
-
);
|
|
219
|
-
```
|
|
220
|
-
|
|
221
182
|
BCP does not install a WebSocket library. Adapt your selected provider to `RealtimeSocket`. SSE is available directly through `realtime.sse()`.
|
|
222
183
|
|
|
223
|
-
The memory broker/presence store are local-only. Multi-instance production deployments should provide shared `RealtimeBroker` and `RealtimePresenceStore` implementations.
|
|
224
|
-
|
|
225
184
|
## Testing Platform — 0.2.14+
|
|
226
185
|
|
|
227
|
-
`bcp/testing` adds framework-native test helpers without requiring a specific test runner.
|
|
228
|
-
|
|
229
|
-
Request/route example:
|
|
230
|
-
|
|
231
186
|
```ts
|
|
232
187
|
import {
|
|
233
188
|
createRouteTestHandler,
|
|
@@ -256,72 +211,13 @@ await expectResponse(
|
|
|
256
211
|
});
|
|
257
212
|
```
|
|
258
213
|
|
|
259
|
-
|
|
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
|
-
```
|
|
283
|
-
|
|
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.
|
|
214
|
+
BCP testing helpers are runner-neutral and can be used with Node `node:test`, Vitest, Jest or another runner.
|
|
316
215
|
|
|
317
216
|
## Plugin & Module Platform — 0.2.15+
|
|
318
217
|
|
|
319
|
-
Use `bcp/plugins` to compose reusable server-side application modules with explicit lifecycle and dependencies.
|
|
320
|
-
|
|
321
218
|
```ts
|
|
322
219
|
import {
|
|
323
220
|
createPluginHost,
|
|
324
|
-
defineModule,
|
|
325
221
|
definePlugin,
|
|
326
222
|
} from "bcp/plugins";
|
|
327
223
|
|
|
@@ -344,28 +240,114 @@ const jobsPlugin =
|
|
|
344
240
|
],
|
|
345
241
|
});
|
|
346
242
|
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
name: "backend",
|
|
243
|
+
export const plugins =
|
|
244
|
+
createPluginHost({
|
|
350
245
|
plugins: [
|
|
351
|
-
databasePlugin,
|
|
352
246
|
jobsPlugin,
|
|
247
|
+
databasePlugin,
|
|
353
248
|
],
|
|
354
249
|
});
|
|
250
|
+
```
|
|
355
251
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
252
|
+
## Cache Platform v2 — 0.2.16+
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
import {
|
|
256
|
+
createCacheStore,
|
|
257
|
+
createRedisCacheAdapter,
|
|
258
|
+
createRedisCacheLockAdapter,
|
|
259
|
+
} from "bcp/cache";
|
|
260
|
+
|
|
261
|
+
export const cache =
|
|
262
|
+
createCacheStore({
|
|
263
|
+
adapter:
|
|
264
|
+
createRedisCacheAdapter({
|
|
265
|
+
client: redisClient,
|
|
266
|
+
}),
|
|
267
|
+
lock:
|
|
268
|
+
createRedisCacheLockAdapter({
|
|
269
|
+
client: redisClient,
|
|
270
|
+
}),
|
|
361
271
|
});
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
BCP does not install or own the Redis client. Applications remain responsible for credentials, TLS, Cluster/Sentinel configuration, reconnect behavior and connection shutdown.
|
|
362
275
|
|
|
363
|
-
|
|
276
|
+
## Observability Platform v3 — 0.2.17+
|
|
277
|
+
|
|
278
|
+
Metrics and health remain available through the same entrypoint:
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
import {
|
|
282
|
+
createHealthRegistry,
|
|
283
|
+
createMetricsRegistry,
|
|
284
|
+
createTracer,
|
|
285
|
+
} from "bcp/observability";
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Create a tracer:
|
|
289
|
+
|
|
290
|
+
```ts
|
|
291
|
+
export const tracer =
|
|
292
|
+
createTracer({
|
|
293
|
+
serviceName: "my-app",
|
|
294
|
+
});
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Trace incoming HTTP requests with Middleware System v2:
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
import {
|
|
301
|
+
createRequestTracingMiddleware,
|
|
302
|
+
} from "bcp/observability";
|
|
303
|
+
|
|
304
|
+
export const middleware =
|
|
305
|
+
createRequestTracingMiddleware(
|
|
306
|
+
tracer
|
|
307
|
+
);
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
The middleware understands W3C `traceparent`, preserves `x-correlation-id`, creates a server span and returns the current trace headers on the response.
|
|
311
|
+
|
|
312
|
+
For jobs/workflows/events/realtime payloads use explicit trace carriers:
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
import {
|
|
316
|
+
createTraceCarrier,
|
|
317
|
+
runWithTraceCarrier,
|
|
318
|
+
} from "bcp/observability";
|
|
319
|
+
|
|
320
|
+
const trace =
|
|
321
|
+
createTraceCarrier();
|
|
322
|
+
|
|
323
|
+
await jobs.enqueue(
|
|
324
|
+
"order.process",
|
|
325
|
+
{
|
|
326
|
+
orderId,
|
|
327
|
+
trace,
|
|
328
|
+
}
|
|
329
|
+
);
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Consumer:
|
|
333
|
+
|
|
334
|
+
```ts
|
|
335
|
+
await runWithTraceCarrier(
|
|
336
|
+
payload.trace,
|
|
337
|
+
() =>
|
|
338
|
+
tracer.withSpan(
|
|
339
|
+
"job order.process",
|
|
340
|
+
handler,
|
|
341
|
+
{
|
|
342
|
+
kind: "consumer",
|
|
343
|
+
}
|
|
344
|
+
)
|
|
345
|
+
);
|
|
364
346
|
```
|
|
365
347
|
|
|
366
|
-
|
|
348
|
+
Use `getTraceLogFields()` to add `traceId`, `spanId` and `correlationId` to structured logs.
|
|
367
349
|
|
|
368
|
-
`
|
|
350
|
+
BCP does not install OpenTelemetry or a vendor APM package. Implement `TraceSpanExporter` when production spans need to be sent to an external collector.
|
|
369
351
|
|
|
370
352
|
## Storage providers
|
|
371
353
|
|
|
@@ -405,5 +387,5 @@ npm run generate -- migration create_users
|
|
|
405
387
|
For prerelease/local package verification:
|
|
406
388
|
|
|
407
389
|
```bash
|
|
408
|
-
npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.
|
|
390
|
+
npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.17.tgz
|
|
409
391
|
```
|
package/package.json
CHANGED
package/template/README.md
CHANGED
|
@@ -199,49 +199,6 @@ await expectResponse(
|
|
|
199
199
|
});
|
|
200
200
|
```
|
|
201
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
|
-
},
|
|
214
|
-
{
|
|
215
|
-
secret:
|
|
216
|
-
process.env.BCP_SESSION_SECRET,
|
|
217
|
-
}
|
|
218
|
-
);
|
|
219
|
-
|
|
220
|
-
app.setCookie(
|
|
221
|
-
session.cookieName,
|
|
222
|
-
session.token
|
|
223
|
-
);
|
|
224
|
-
```
|
|
225
|
-
|
|
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
202
|
BCP does not require Jest or Vitest; these helpers work with Node `node:test` or another runner.
|
|
246
203
|
|
|
247
204
|
## Plugin & Module Platform — BCP 0.2.15+
|
|
@@ -284,9 +241,145 @@ export const plugins =
|
|
|
284
241
|
|
|
285
242
|
Plugin startup follows dependency order and shutdown reverses it. Plugins can use `setup/start/stop/dispose`, config parsers, shared services and async hooks.
|
|
286
243
|
|
|
287
|
-
|
|
244
|
+
## Cache Platform v2 — BCP 0.2.16+
|
|
245
|
+
|
|
246
|
+
Use `createCacheStore()` for async cache-aside loading, shared adapters and distributed cache-fill coordination.
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
import {
|
|
250
|
+
createCacheStore,
|
|
251
|
+
} from "bcp/cache";
|
|
252
|
+
|
|
253
|
+
export const cache =
|
|
254
|
+
createCacheStore();
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
const user =
|
|
259
|
+
await cache.getOrSet(
|
|
260
|
+
"user:42",
|
|
261
|
+
() => loadUser(42),
|
|
262
|
+
{
|
|
263
|
+
ttlMs: 60_000,
|
|
264
|
+
tags: ["users"],
|
|
265
|
+
paths: ["/users/42"],
|
|
266
|
+
}
|
|
267
|
+
);
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
For multiple instances, connect a shared cache and lock provider:
|
|
271
|
+
|
|
272
|
+
```ts
|
|
273
|
+
import {
|
|
274
|
+
createRedisCacheAdapter,
|
|
275
|
+
createRedisCacheLockAdapter,
|
|
276
|
+
} from "bcp/cache";
|
|
277
|
+
|
|
278
|
+
const redisCache =
|
|
279
|
+
createRedisCacheAdapter({
|
|
280
|
+
client: redisClient,
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const redisLock =
|
|
284
|
+
createRedisCacheLockAdapter({
|
|
285
|
+
client: redisClient,
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
export const cache =
|
|
289
|
+
createCacheStore({
|
|
290
|
+
adapter: redisCache,
|
|
291
|
+
lock: redisLock,
|
|
292
|
+
});
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
BCP does not install or own a Redis client. The default adapter namespace is `bcp:{cache}`. The original `cache()` and `dedupe()` APIs remain available for backward-compatible process-local caching.
|
|
296
|
+
|
|
297
|
+
## Observability Platform v3 — BCP 0.2.17+
|
|
298
|
+
|
|
299
|
+
Use the existing `bcp/observability` entrypoint for tracing as well as metrics and health.
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
import {
|
|
303
|
+
createTracer,
|
|
304
|
+
} from "bcp/observability";
|
|
305
|
+
|
|
306
|
+
export const tracer =
|
|
307
|
+
createTracer({
|
|
308
|
+
serviceName: "my-app",
|
|
309
|
+
});
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Trace incoming Middleware System v2 requests:
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
import {
|
|
316
|
+
createRequestTracingMiddleware,
|
|
317
|
+
} from "bcp/observability";
|
|
318
|
+
|
|
319
|
+
export const middleware =
|
|
320
|
+
createRequestTracingMiddleware(
|
|
321
|
+
tracer
|
|
322
|
+
);
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
The middleware continues valid W3C `traceparent` headers, preserves `x-correlation-id`, creates a server span and includes active trace headers in the response.
|
|
326
|
+
|
|
327
|
+
Create child spans for application work:
|
|
328
|
+
|
|
329
|
+
```ts
|
|
330
|
+
await tracer.withSpan(
|
|
331
|
+
"order.checkout",
|
|
332
|
+
async () => {
|
|
333
|
+
await tracer.withSpan(
|
|
334
|
+
"database.order.insert",
|
|
335
|
+
createOrder,
|
|
336
|
+
{
|
|
337
|
+
kind: "client",
|
|
338
|
+
}
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
);
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
For jobs, workflows, events and realtime payloads, propagate context explicitly:
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
import {
|
|
348
|
+
createTraceCarrier,
|
|
349
|
+
runWithTraceCarrier,
|
|
350
|
+
} from "bcp/observability";
|
|
351
|
+
|
|
352
|
+
const trace =
|
|
353
|
+
createTraceCarrier();
|
|
354
|
+
|
|
355
|
+
await jobs.enqueue(
|
|
356
|
+
"order.process",
|
|
357
|
+
{
|
|
358
|
+
orderId,
|
|
359
|
+
trace,
|
|
360
|
+
}
|
|
361
|
+
);
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Consumer:
|
|
365
|
+
|
|
366
|
+
```ts
|
|
367
|
+
await runWithTraceCarrier(
|
|
368
|
+
payload.trace,
|
|
369
|
+
() =>
|
|
370
|
+
tracer.withSpan(
|
|
371
|
+
"job order.process",
|
|
372
|
+
handler,
|
|
373
|
+
{
|
|
374
|
+
kind: "consumer",
|
|
375
|
+
}
|
|
376
|
+
)
|
|
377
|
+
);
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Use `getTraceLogFields()` to attach `traceId`, `spanId` and `correlationId` to structured logs.
|
|
288
381
|
|
|
289
|
-
|
|
382
|
+
BCP does not install OpenTelemetry or a vendor APM SDK. Production collector integration is application-owned through `TraceSpanExporter`.
|
|
290
383
|
|
|
291
384
|
## Generate framework files
|
|
292
385
|
|