create-bcp-app 0.2.17 → 0.2.18
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 +90 -189
- package/package.json +1 -1
- package/template/README.md +79 -289
package/README.md
CHANGED
|
@@ -10,9 +10,7 @@ npm run dev
|
|
|
10
10
|
|
|
11
11
|
## Project-local BCP CLI
|
|
12
12
|
|
|
13
|
-
`create-bcp-app` installs BCP Framework as a project-local dependency.
|
|
14
|
-
|
|
15
|
-
Generated npm scripts use `bcp` because npm places `node_modules/.bin` on the script `PATH`:
|
|
13
|
+
`create-bcp-app` installs BCP Framework as a project-local dependency. Generated npm scripts use the local CLI:
|
|
16
14
|
|
|
17
15
|
```json
|
|
18
16
|
{
|
|
@@ -28,7 +26,7 @@ Generated npm scripts use `bcp` because npm places `node_modules/.bin` on the sc
|
|
|
28
26
|
}
|
|
29
27
|
```
|
|
30
28
|
|
|
31
|
-
For direct PowerShell usage, prefer the collision-free
|
|
29
|
+
For direct PowerShell usage, prefer the collision-free alias:
|
|
32
30
|
|
|
33
31
|
```powershell
|
|
34
32
|
npm exec -- bcp-framework --version
|
|
@@ -66,17 +64,17 @@ Select storage provider:
|
|
|
66
64
|
|
|
67
65
|
New projects include `bcp.project.json`.
|
|
68
66
|
|
|
69
|
-
Example for the `0.2.
|
|
67
|
+
Example for the `0.2.18` target:
|
|
70
68
|
|
|
71
69
|
```json
|
|
72
70
|
{
|
|
73
71
|
"schemaVersion": 1,
|
|
74
72
|
"framework": "bcp",
|
|
75
73
|
"projectName": "my-app",
|
|
76
|
-
"frameworkPackage": "npm:@chidchanun/bcp@0.2.
|
|
74
|
+
"frameworkPackage": "npm:@chidchanun/bcp@0.2.18",
|
|
77
75
|
"createdWith": {
|
|
78
76
|
"package": "create-bcp-app",
|
|
79
|
-
"version": "0.2.
|
|
77
|
+
"version": "0.2.18"
|
|
80
78
|
},
|
|
81
79
|
"packageManager": "npm",
|
|
82
80
|
"presets": {
|
|
@@ -88,7 +86,7 @@ Example for the `0.2.17` target:
|
|
|
88
86
|
}
|
|
89
87
|
```
|
|
90
88
|
|
|
91
|
-
This manifest records scaffold identity only.
|
|
89
|
+
This manifest records scaffold identity only. Do not place secrets in it.
|
|
92
90
|
|
|
93
91
|
## Database presets
|
|
94
92
|
|
|
@@ -104,71 +102,23 @@ For MySQL, PostgreSQL and SQLite, generated `lib/database.ts` exposes BCP databa
|
|
|
104
102
|
|
|
105
103
|
## Authentication and security
|
|
106
104
|
|
|
107
|
-
The JWT Cookie preset creates
|
|
105
|
+
The JWT Cookie preset creates starter authentication code. BCP supports revocable session stores, permission/policy authorization, route guards and same-origin/CSRF helpers.
|
|
108
106
|
|
|
109
|
-
## Background jobs and
|
|
107
|
+
## Background jobs, workflows and events
|
|
110
108
|
|
|
111
109
|
```ts
|
|
112
110
|
import {
|
|
113
111
|
createJobQueue,
|
|
114
112
|
createJobScheduler,
|
|
115
113
|
} from "bcp/jobs";
|
|
116
|
-
|
|
117
|
-
export const jobs =
|
|
118
|
-
createJobQueue();
|
|
119
|
-
|
|
120
|
-
export const scheduler =
|
|
121
|
-
createJobScheduler({
|
|
122
|
-
queue: jobs,
|
|
123
|
-
});
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
`0.2.10+` adds visibility leases, heartbeat renewal, stale-running recovery, DLQ/requeue, retention cleanup and Redis-compatible durable adapters.
|
|
127
|
-
|
|
128
|
-
## Workflow orchestration — 0.2.11+
|
|
129
|
-
|
|
130
|
-
```ts
|
|
131
114
|
import {
|
|
132
115
|
createWorkflow,
|
|
133
116
|
} from "bcp/workflow";
|
|
134
|
-
|
|
135
|
-
export const onboarding =
|
|
136
|
-
createWorkflow(
|
|
137
|
-
"user.onboarding",
|
|
138
|
-
workflow => {
|
|
139
|
-
workflow.step(
|
|
140
|
-
"profile",
|
|
141
|
-
createProfile
|
|
142
|
-
);
|
|
143
|
-
workflow.delay(
|
|
144
|
-
"cooldown",
|
|
145
|
-
1_000
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
);
|
|
149
117
|
```
|
|
150
118
|
|
|
151
|
-
|
|
119
|
+
Durable Redis-compatible queues/schedules, workflow orchestration and transactional outbox/event delivery are available without forcing a Redis client dependency.
|
|
152
120
|
|
|
153
|
-
|
|
154
|
-
await db.transaction(
|
|
155
|
-
async tx => {
|
|
156
|
-
await tx.execute(
|
|
157
|
-
"INSERT INTO orders ..."
|
|
158
|
-
);
|
|
159
|
-
|
|
160
|
-
await outbox.publish(
|
|
161
|
-
tx,
|
|
162
|
-
"order.created",
|
|
163
|
-
{
|
|
164
|
-
orderId: 42,
|
|
165
|
-
}
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
);
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
## Realtime Platform — 0.2.13+
|
|
121
|
+
## Realtime
|
|
172
122
|
|
|
173
123
|
```ts
|
|
174
124
|
import {
|
|
@@ -179,187 +129,138 @@ export const realtime =
|
|
|
179
129
|
createRealtime();
|
|
180
130
|
```
|
|
181
131
|
|
|
182
|
-
BCP does not install a WebSocket library.
|
|
183
|
-
|
|
184
|
-
## Testing Platform — 0.2.14+
|
|
185
|
-
|
|
186
|
-
```ts
|
|
187
|
-
import {
|
|
188
|
-
createRouteTestHandler,
|
|
189
|
-
createTestApp,
|
|
190
|
-
expectResponse,
|
|
191
|
-
} from "bcp/testing";
|
|
192
|
-
|
|
193
|
-
const app =
|
|
194
|
-
createTestApp({
|
|
195
|
-
handler:
|
|
196
|
-
createRouteTestHandler({
|
|
197
|
-
GET() {
|
|
198
|
-
return {
|
|
199
|
-
ok: true,
|
|
200
|
-
};
|
|
201
|
-
},
|
|
202
|
-
}),
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
await expectResponse(
|
|
206
|
-
await app.get("/api/health")
|
|
207
|
-
)
|
|
208
|
-
.status(200)
|
|
209
|
-
.json({
|
|
210
|
-
ok: true,
|
|
211
|
-
});
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
BCP testing helpers are runner-neutral and can be used with Node `node:test`, Vitest, Jest or another runner.
|
|
132
|
+
BCP does not install a WebSocket server library. Applications adapt their provider to `RealtimeSocket`; SSE is built in.
|
|
215
133
|
|
|
216
|
-
##
|
|
134
|
+
## Testing
|
|
217
135
|
|
|
218
|
-
|
|
219
|
-
import {
|
|
220
|
-
createPluginHost,
|
|
221
|
-
definePlugin,
|
|
222
|
-
} from "bcp/plugins";
|
|
223
|
-
|
|
224
|
-
const databasePlugin =
|
|
225
|
-
definePlugin({
|
|
226
|
-
name: "database",
|
|
227
|
-
setup(context) {
|
|
228
|
-
context.services.provide(
|
|
229
|
-
"database",
|
|
230
|
-
db
|
|
231
|
-
);
|
|
232
|
-
},
|
|
233
|
-
});
|
|
136
|
+
`bcp/testing` provides request/route/page/auth/database/middleware/jobs/workflow/outbox/realtime test harnesses and does not require Jest or Vitest.
|
|
234
137
|
|
|
235
|
-
|
|
236
|
-
definePlugin({
|
|
237
|
-
name: "jobs",
|
|
238
|
-
requires: [
|
|
239
|
-
"database",
|
|
240
|
-
],
|
|
241
|
-
});
|
|
138
|
+
## Plugins
|
|
242
139
|
|
|
243
|
-
|
|
244
|
-
createPluginHost({
|
|
245
|
-
plugins: [
|
|
246
|
-
jobsPlugin,
|
|
247
|
-
databasePlugin,
|
|
248
|
-
],
|
|
249
|
-
});
|
|
250
|
-
```
|
|
140
|
+
`bcp/plugins` provides dependency ordering, module composition, lifecycle hooks, config parsing, shared services and async hooks.
|
|
251
141
|
|
|
252
|
-
## Cache Platform v2
|
|
142
|
+
## Cache Platform v2
|
|
253
143
|
|
|
254
144
|
```ts
|
|
255
145
|
import {
|
|
256
146
|
createCacheStore,
|
|
257
|
-
createRedisCacheAdapter,
|
|
258
|
-
createRedisCacheLockAdapter,
|
|
259
147
|
} from "bcp/cache";
|
|
260
148
|
|
|
261
149
|
export const cache =
|
|
262
|
-
createCacheStore(
|
|
263
|
-
adapter:
|
|
264
|
-
createRedisCacheAdapter({
|
|
265
|
-
client: redisClient,
|
|
266
|
-
}),
|
|
267
|
-
lock:
|
|
268
|
-
createRedisCacheLockAdapter({
|
|
269
|
-
client: redisClient,
|
|
270
|
-
}),
|
|
271
|
-
});
|
|
150
|
+
createCacheStore();
|
|
272
151
|
```
|
|
273
152
|
|
|
274
|
-
|
|
153
|
+
Multi-instance applications can use Redis-compatible cache and lock adapters for distributed cache-fill coordination.
|
|
275
154
|
|
|
276
|
-
## Observability Platform v3
|
|
277
|
-
|
|
278
|
-
Metrics and health remain available through the same entrypoint:
|
|
155
|
+
## Observability Platform v3
|
|
279
156
|
|
|
280
157
|
```ts
|
|
281
158
|
import {
|
|
282
|
-
createHealthRegistry,
|
|
283
|
-
createMetricsRegistry,
|
|
284
159
|
createTracer,
|
|
285
160
|
} from "bcp/observability";
|
|
286
|
-
```
|
|
287
161
|
|
|
288
|
-
Create a tracer:
|
|
289
|
-
|
|
290
|
-
```ts
|
|
291
162
|
export const tracer =
|
|
292
163
|
createTracer({
|
|
293
164
|
serviceName: "my-app",
|
|
294
165
|
});
|
|
295
166
|
```
|
|
296
167
|
|
|
297
|
-
|
|
168
|
+
Tracing supports W3C `traceparent`, correlation IDs, request middleware, explicit carriers for jobs/workflows/events/realtime and provider-neutral exporters.
|
|
169
|
+
|
|
170
|
+
## Deployment Platform v2 — 0.2.18+
|
|
171
|
+
|
|
172
|
+
Use `bcp/deployment` to coordinate application resources in production:
|
|
298
173
|
|
|
299
174
|
```ts
|
|
300
175
|
import {
|
|
301
|
-
|
|
302
|
-
} from "bcp/
|
|
176
|
+
createDeploymentRuntime,
|
|
177
|
+
} from "bcp/deployment";
|
|
303
178
|
|
|
304
|
-
export const
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
);
|
|
179
|
+
export const deployment =
|
|
180
|
+
createDeploymentRuntime({
|
|
181
|
+
serviceName: "my-app",
|
|
182
|
+
});
|
|
308
183
|
```
|
|
309
184
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
For jobs/workflows/events/realtime payloads use explicit trace carriers:
|
|
185
|
+
Register shared dependencies before components that use them:
|
|
313
186
|
|
|
314
187
|
```ts
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
188
|
+
deployment.addResource({
|
|
189
|
+
name: "database",
|
|
190
|
+
|
|
191
|
+
async start() {
|
|
192
|
+
await db.connect();
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
ready() {
|
|
196
|
+
return db.status === "ready";
|
|
197
|
+
},
|
|
319
198
|
|
|
320
|
-
|
|
321
|
-
|
|
199
|
+
async stop() {
|
|
200
|
+
await db.close();
|
|
201
|
+
},
|
|
202
|
+
});
|
|
322
203
|
|
|
323
|
-
|
|
324
|
-
"
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
329
|
-
|
|
204
|
+
deployment.addResource({
|
|
205
|
+
name: "workers",
|
|
206
|
+
|
|
207
|
+
start() {
|
|
208
|
+
worker = jobs.startWorker();
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
async stop() {
|
|
212
|
+
await worker.stop();
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
await deployment.start();
|
|
330
217
|
```
|
|
331
218
|
|
|
332
|
-
|
|
219
|
+
Startup follows registration order and shutdown reverses it. This naturally stops workers before database/cache/Redis connections.
|
|
220
|
+
|
|
221
|
+
Readiness endpoint:
|
|
333
222
|
|
|
334
223
|
```ts
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
)
|
|
345
|
-
);
|
|
224
|
+
import {
|
|
225
|
+
createDeploymentReadinessResponse,
|
|
226
|
+
} from "bcp/deployment";
|
|
227
|
+
|
|
228
|
+
export function GET() {
|
|
229
|
+
return createDeploymentReadinessResponse(
|
|
230
|
+
deployment
|
|
231
|
+
);
|
|
232
|
+
}
|
|
346
233
|
```
|
|
347
234
|
|
|
348
|
-
|
|
235
|
+
Runtime identity can use:
|
|
349
236
|
|
|
350
|
-
|
|
237
|
+
```text
|
|
238
|
+
BCP_DEPLOYMENT_ID
|
|
239
|
+
BCP_INSTANCE_ID
|
|
240
|
+
BCP_RELEASE
|
|
241
|
+
NODE_ENV
|
|
242
|
+
BCP_SHUTDOWN_TIMEOUT_MS
|
|
243
|
+
```
|
|
351
244
|
|
|
352
|
-
|
|
245
|
+
Install graceful signal handling with:
|
|
353
246
|
|
|
354
|
-
|
|
247
|
+
```ts
|
|
248
|
+
const removeSignals =
|
|
249
|
+
deployment.installSignalHandlers();
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Default signals are `SIGTERM` and `SIGINT`.
|
|
355
253
|
|
|
356
254
|
## Application packaging
|
|
357
255
|
|
|
358
256
|
```bash
|
|
257
|
+
npm run build
|
|
359
258
|
npm run package
|
|
360
259
|
```
|
|
361
260
|
|
|
362
|
-
The deployment package excludes application `devDependencies` and project `.env` values. Supply
|
|
261
|
+
The deployment package excludes application `devDependencies` and project `.env` values. Supply secrets through the deployment environment.
|
|
262
|
+
|
|
263
|
+
BCP `0.2.18` prepared framework packages use compiled ESM runtime files for the main server entrypoints including config, auth, observability, deployment, server and middleware.
|
|
363
264
|
|
|
364
265
|
## Project generators
|
|
365
266
|
|
|
@@ -387,5 +288,5 @@ npm run generate -- migration create_users
|
|
|
387
288
|
For prerelease/local package verification:
|
|
388
289
|
|
|
389
290
|
```bash
|
|
390
|
-
npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.
|
|
291
|
+
npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.18.tgz
|
|
391
292
|
```
|
package/package.json
CHANGED
package/template/README.md
CHANGED
|
@@ -27,113 +27,33 @@ npm run update
|
|
|
27
27
|
|
|
28
28
|
Generated projects include `bcp.project.json` with non-secret scaffold metadata. Commit it with the project, but never put passwords, tokens or access keys in it.
|
|
29
29
|
|
|
30
|
-
## Authentication
|
|
30
|
+
## Authentication and authorization
|
|
31
31
|
|
|
32
|
-
JWT Cookie projects can
|
|
32
|
+
JWT Cookie projects can use `createAuth()` and optional `AuthSessionStore` revocation. Permission guards/resource policies live in `bcp/auth`; same-origin/CSRF helpers live in `bcp/server`.
|
|
33
33
|
|
|
34
|
-
##
|
|
34
|
+
## Database
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
MySQL, PostgreSQL and SQLite projects expose the BCP database platform through `bcp/database`.
|
|
37
37
|
|
|
38
|
-
##
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
import {
|
|
42
|
-
createHealthRegistry,
|
|
43
|
-
createMetricsRegistry,
|
|
44
|
-
} from "bcp/observability";
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Background jobs — BCP 0.2.8+
|
|
38
|
+
## Jobs, scheduling and workflows
|
|
48
39
|
|
|
49
40
|
```ts
|
|
50
41
|
import {
|
|
51
42
|
createJobQueue,
|
|
52
|
-
} from "bcp/jobs";
|
|
53
|
-
|
|
54
|
-
export const jobs =
|
|
55
|
-
createJobQueue();
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## Job scheduling — BCP 0.2.9+
|
|
59
|
-
|
|
60
|
-
```ts
|
|
61
|
-
import {
|
|
62
43
|
createJobScheduler,
|
|
63
44
|
} from "bcp/jobs";
|
|
64
|
-
|
|
65
|
-
export const scheduler =
|
|
66
|
-
createJobScheduler({
|
|
67
|
-
queue: jobs,
|
|
68
|
-
});
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## Durable jobs — BCP 0.2.10+
|
|
72
|
-
|
|
73
|
-
Workers can use visibility leases, heartbeat renewal, stale recovery and DLQ/requeue. Redis-compatible adapters are available without forcing a Redis client dependency.
|
|
74
|
-
|
|
75
|
-
```ts
|
|
76
|
-
const worker =
|
|
77
|
-
jobs.startWorker({
|
|
78
|
-
workerId: "worker-a",
|
|
79
|
-
concurrency: 4,
|
|
80
|
-
visibilityTimeoutMs: 30_000,
|
|
81
|
-
heartbeatIntervalMs: 10_000,
|
|
82
|
-
});
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Workflow orchestration — BCP 0.2.11+
|
|
86
|
-
|
|
87
|
-
```ts
|
|
88
45
|
import {
|
|
89
46
|
createWorkflow,
|
|
90
47
|
} from "bcp/workflow";
|
|
91
|
-
|
|
92
|
-
export const onboarding =
|
|
93
|
-
createWorkflow(
|
|
94
|
-
"user.onboarding",
|
|
95
|
-
workflow => {
|
|
96
|
-
workflow.step(
|
|
97
|
-
"profile",
|
|
98
|
-
createProfile
|
|
99
|
-
);
|
|
100
|
-
workflow.delay(
|
|
101
|
-
"cooldown",
|
|
102
|
-
1_000
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
);
|
|
106
48
|
```
|
|
107
49
|
|
|
108
|
-
Workflows support sequential/parallel steps, retries, persisted delays
|
|
50
|
+
Durable jobs support leases, heartbeat, stale recovery and DLQ. Workflows support sequential/parallel steps, retries, persisted delays and compensation.
|
|
109
51
|
|
|
110
|
-
## Transactional
|
|
52
|
+
## Transactional events
|
|
111
53
|
|
|
112
|
-
Use `bcp/events` when
|
|
54
|
+
Use `bcp/events` when business data and an integration event must commit in the same SQL transaction. The outbox dispatcher can deliver through durable jobs or an application publisher after commit.
|
|
113
55
|
|
|
114
|
-
|
|
115
|
-
await db.transaction(
|
|
116
|
-
async tx => {
|
|
117
|
-
await tx.execute(
|
|
118
|
-
"INSERT INTO orders ..."
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
await outbox.publish(
|
|
122
|
-
tx,
|
|
123
|
-
"order.created",
|
|
124
|
-
{
|
|
125
|
-
orderId: 42,
|
|
126
|
-
}
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
);
|
|
130
|
-
```
|
|
131
|
-
|
|
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:
|
|
56
|
+
## Realtime
|
|
137
57
|
|
|
138
58
|
```ts
|
|
139
59
|
import {
|
|
@@ -144,252 +64,137 @@ export const realtime =
|
|
|
144
64
|
createRealtime();
|
|
145
65
|
```
|
|
146
66
|
|
|
147
|
-
|
|
67
|
+
BCP does not install a WebSocket server library. Adapt the selected provider through `RealtimeSocket`; SSE is built in.
|
|
148
68
|
|
|
149
|
-
|
|
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
|
-
```
|
|
69
|
+
## Testing
|
|
165
70
|
|
|
166
|
-
|
|
71
|
+
`bcp/testing` provides request/route/page/auth/database/middleware/jobs/workflow/outbox/realtime/SSE test helpers without requiring Jest or Vitest.
|
|
167
72
|
|
|
168
|
-
|
|
73
|
+
## Plugins
|
|
169
74
|
|
|
170
|
-
|
|
75
|
+
`bcp/plugins` provides reusable server-side plugins/modules, dependency ordering, lifecycle hooks, config parsing, shared services and awaited hooks.
|
|
171
76
|
|
|
172
|
-
|
|
77
|
+
## Cache Platform v2
|
|
173
78
|
|
|
174
79
|
```ts
|
|
175
80
|
import {
|
|
176
|
-
|
|
177
|
-
|
|
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
|
-
});
|
|
81
|
+
createCacheStore,
|
|
82
|
+
} from "bcp/cache";
|
|
192
83
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
)
|
|
196
|
-
.status(200)
|
|
197
|
-
.json({
|
|
198
|
-
ok: true,
|
|
199
|
-
});
|
|
84
|
+
export const cache =
|
|
85
|
+
createCacheStore();
|
|
200
86
|
```
|
|
201
87
|
|
|
202
|
-
|
|
88
|
+
Use Redis-compatible cache/lock adapters for multi-instance cache-fill coordination when needed.
|
|
203
89
|
|
|
204
|
-
##
|
|
205
|
-
|
|
206
|
-
Use `bcp/plugins` to compose reusable server-only application services with explicit dependencies.
|
|
90
|
+
## Observability Platform v3
|
|
207
91
|
|
|
208
92
|
```ts
|
|
209
93
|
import {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
} from "bcp/plugins";
|
|
213
|
-
|
|
214
|
-
const databasePlugin =
|
|
215
|
-
definePlugin({
|
|
216
|
-
name: "database",
|
|
217
|
-
setup(context) {
|
|
218
|
-
context.services.provide(
|
|
219
|
-
"database",
|
|
220
|
-
db
|
|
221
|
-
);
|
|
222
|
-
},
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
const jobsPlugin =
|
|
226
|
-
definePlugin({
|
|
227
|
-
name: "jobs",
|
|
228
|
-
requires: [
|
|
229
|
-
"database",
|
|
230
|
-
],
|
|
231
|
-
});
|
|
94
|
+
createTracer,
|
|
95
|
+
} from "bcp/observability";
|
|
232
96
|
|
|
233
|
-
export const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
jobsPlugin,
|
|
237
|
-
databasePlugin,
|
|
238
|
-
],
|
|
97
|
+
export const tracer =
|
|
98
|
+
createTracer({
|
|
99
|
+
serviceName: "bcp-app",
|
|
239
100
|
});
|
|
240
101
|
```
|
|
241
102
|
|
|
242
|
-
|
|
103
|
+
Tracing supports AsyncLocalStorage context, W3C `traceparent`, correlation IDs, request tracing, trace carriers and provider-neutral exporters.
|
|
243
104
|
|
|
244
|
-
##
|
|
105
|
+
## Deployment Platform v2 — BCP 0.2.18+
|
|
245
106
|
|
|
246
|
-
Use `
|
|
107
|
+
Use `bcp/deployment` to manage production resource lifecycle:
|
|
247
108
|
|
|
248
109
|
```ts
|
|
249
110
|
import {
|
|
250
|
-
|
|
251
|
-
} from "bcp/
|
|
111
|
+
createDeploymentRuntime,
|
|
112
|
+
} from "bcp/deployment";
|
|
252
113
|
|
|
253
|
-
export const
|
|
254
|
-
|
|
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
|
-
);
|
|
114
|
+
export const deployment =
|
|
115
|
+
createDeploymentRuntime({
|
|
116
|
+
serviceName: "bcp-app",
|
|
117
|
+
});
|
|
268
118
|
```
|
|
269
119
|
|
|
270
|
-
|
|
120
|
+
Register dependencies first:
|
|
271
121
|
|
|
272
122
|
```ts
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
createRedisCacheLockAdapter,
|
|
276
|
-
} from "bcp/cache";
|
|
123
|
+
deployment.addResource({
|
|
124
|
+
name: "database",
|
|
277
125
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
});
|
|
126
|
+
async start() {
|
|
127
|
+
await db.connect();
|
|
128
|
+
},
|
|
282
129
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
});
|
|
130
|
+
ready() {
|
|
131
|
+
return db.status === "ready";
|
|
132
|
+
},
|
|
287
133
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
});
|
|
134
|
+
async stop() {
|
|
135
|
+
await db.close();
|
|
136
|
+
},
|
|
137
|
+
});
|
|
293
138
|
```
|
|
294
139
|
|
|
295
|
-
|
|
140
|
+
Register workers/realtime services afterward so reverse-order shutdown stops them before their shared database/cache/Redis dependencies.
|
|
296
141
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
Use the existing `bcp/observability` entrypoint for tracing as well as metrics and health.
|
|
142
|
+
Start runtime:
|
|
300
143
|
|
|
301
144
|
```ts
|
|
302
|
-
|
|
303
|
-
createTracer,
|
|
304
|
-
} from "bcp/observability";
|
|
305
|
-
|
|
306
|
-
export const tracer =
|
|
307
|
-
createTracer({
|
|
308
|
-
serviceName: "my-app",
|
|
309
|
-
});
|
|
145
|
+
await deployment.start();
|
|
310
146
|
```
|
|
311
147
|
|
|
312
|
-
|
|
148
|
+
Readiness endpoint:
|
|
313
149
|
|
|
314
150
|
```ts
|
|
315
151
|
import {
|
|
316
|
-
|
|
317
|
-
} from "bcp/
|
|
152
|
+
createDeploymentReadinessResponse,
|
|
153
|
+
} from "bcp/deployment";
|
|
318
154
|
|
|
319
|
-
export
|
|
320
|
-
|
|
321
|
-
|
|
155
|
+
export function GET() {
|
|
156
|
+
return createDeploymentReadinessResponse(
|
|
157
|
+
deployment
|
|
322
158
|
);
|
|
159
|
+
}
|
|
323
160
|
```
|
|
324
161
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
Create child spans for application work:
|
|
162
|
+
Install graceful signal handling when the app owns process signals:
|
|
328
163
|
|
|
329
164
|
```ts
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
async () => {
|
|
333
|
-
await tracer.withSpan(
|
|
334
|
-
"database.order.insert",
|
|
335
|
-
createOrder,
|
|
336
|
-
{
|
|
337
|
-
kind: "client",
|
|
338
|
-
}
|
|
339
|
-
);
|
|
340
|
-
}
|
|
341
|
-
);
|
|
165
|
+
const removeSignals =
|
|
166
|
+
deployment.installSignalHandlers();
|
|
342
167
|
```
|
|
343
168
|
|
|
344
|
-
|
|
169
|
+
Default signals are `SIGTERM` and `SIGINT`.
|
|
345
170
|
|
|
346
|
-
|
|
347
|
-
import {
|
|
348
|
-
createTraceCarrier,
|
|
349
|
-
runWithTraceCarrier,
|
|
350
|
-
} from "bcp/observability";
|
|
171
|
+
Deployment identity can be supplied through:
|
|
351
172
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
orderId,
|
|
359
|
-
trace,
|
|
360
|
-
}
|
|
361
|
-
);
|
|
173
|
+
```text
|
|
174
|
+
BCP_DEPLOYMENT_ID
|
|
175
|
+
BCP_INSTANCE_ID
|
|
176
|
+
BCP_RELEASE
|
|
177
|
+
NODE_ENV
|
|
178
|
+
BCP_SHUTDOWN_TIMEOUT_MS
|
|
362
179
|
```
|
|
363
180
|
|
|
364
|
-
|
|
181
|
+
## Production build
|
|
365
182
|
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
() =>
|
|
370
|
-
tracer.withSpan(
|
|
371
|
-
"job order.process",
|
|
372
|
-
handler,
|
|
373
|
-
{
|
|
374
|
-
kind: "consumer",
|
|
375
|
-
}
|
|
376
|
-
)
|
|
377
|
-
);
|
|
183
|
+
```bash
|
|
184
|
+
npm run build
|
|
185
|
+
npm start
|
|
378
186
|
```
|
|
379
187
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
BCP does not install OpenTelemetry or a vendor APM SDK. Production collector integration is application-owned through `TraceSpanExporter`.
|
|
383
|
-
|
|
384
|
-
## Generate framework files
|
|
188
|
+
## Deployment package
|
|
385
189
|
|
|
386
190
|
```bash
|
|
387
|
-
npm run
|
|
388
|
-
npm run generate -- api users
|
|
389
|
-
npm run generate -- middleware
|
|
390
|
-
npm run generate -- migration create_users
|
|
191
|
+
npm run package
|
|
391
192
|
```
|
|
392
193
|
|
|
194
|
+
BCP excludes project `.env` files and application `devDependencies` from the deployment package. Supply secrets through the deployment environment.
|
|
195
|
+
|
|
196
|
+
BCP 0.2.18 prepared framework packages use compiled `.mjs` runtimes for the main server entrypoints, including config, auth, observability, deployment, server and middleware.
|
|
197
|
+
|
|
393
198
|
## Direct CLI usage
|
|
394
199
|
|
|
395
200
|
For PowerShell:
|
|
@@ -403,18 +208,3 @@ npm exec -- bcp-framework dev
|
|
|
403
208
|
npm exec -- bcp-framework build
|
|
404
209
|
npm exec -- bcp-framework package
|
|
405
210
|
```
|
|
406
|
-
|
|
407
|
-
## Production build
|
|
408
|
-
|
|
409
|
-
```bash
|
|
410
|
-
npm run build
|
|
411
|
-
npm start
|
|
412
|
-
```
|
|
413
|
-
|
|
414
|
-
## Deployment package
|
|
415
|
-
|
|
416
|
-
```bash
|
|
417
|
-
npm run package
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
BCP excludes project `.env` files and application `devDependencies` from the deployment package. Supply secrets through the deployment environment.
|