@chidchanun/bcp 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.
@@ -0,0 +1,449 @@
1
+ # Deployment Platform v2
2
+
3
+ BCP Framework `0.2.18` adds a server-only deployment lifecycle layer through `bcp/deployment` and hardens published production entrypoints so application runtime code does not need to execute framework TypeScript directly.
4
+
5
+ ## Goals
6
+
7
+ Deployment Platform v2 provides:
8
+
9
+ - application resource startup ordering;
10
+ - reverse-order graceful shutdown;
11
+ - startup rollback when a later resource fails;
12
+ - readiness checks for orchestrators/load balancers;
13
+ - runtime diagnostics and deployment identity;
14
+ - `SIGTERM` / `SIGINT` integration;
15
+ - integration with the existing BCP shutdown-hook registry;
16
+ - compiled production runtimes for key server entrypoints.
17
+
18
+ It does not replace Kubernetes, Docker, systemd, PM2 or another process orchestrator. BCP provides lifecycle primitives that those systems can drive.
19
+
20
+ ## Create a deployment runtime
21
+
22
+ ```ts
23
+ import {
24
+ createDeploymentRuntime,
25
+ } from "bcp/deployment";
26
+
27
+ export const deployment =
28
+ createDeploymentRuntime({
29
+ serviceName: "orders-api",
30
+ version: "1.4.0",
31
+ });
32
+ ```
33
+
34
+ Runtime states are:
35
+
36
+ ```text
37
+ idle
38
+ starting
39
+ ready
40
+ draining
41
+ stopped
42
+ failed
43
+ ```
44
+
45
+ ## Register resources
46
+
47
+ Resources are started in registration order and stopped in reverse order.
48
+
49
+ ```ts
50
+ deployment.addResource({
51
+ name: "database",
52
+
53
+ async start() {
54
+ await db.connect();
55
+ },
56
+
57
+ async ready() {
58
+ return {
59
+ ok:
60
+ db.status ===
61
+ "ready",
62
+ detail:
63
+ db.status,
64
+ };
65
+ },
66
+
67
+ async stop() {
68
+ await db.close();
69
+ },
70
+
71
+ diagnostics() {
72
+ return {
73
+ provider:
74
+ "postgresql",
75
+ };
76
+ },
77
+ });
78
+ ```
79
+
80
+ Then register dependent services later:
81
+
82
+ ```ts
83
+ deployment.addResource({
84
+ name: "jobs",
85
+
86
+ async start() {
87
+ workers.start();
88
+ },
89
+
90
+ async stop() {
91
+ await workers.stop();
92
+ },
93
+ });
94
+ ```
95
+
96
+ Starting:
97
+
98
+ ```ts
99
+ await deployment.start();
100
+ ```
101
+
102
+ produces:
103
+
104
+ ```text
105
+ database.start()
106
+
107
+ jobs.start()
108
+
109
+ state = ready
110
+ ```
111
+
112
+ Shutdown reverses the order:
113
+
114
+ ```text
115
+ jobs.stop()
116
+
117
+ database.stop()
118
+
119
+ state = stopped
120
+ ```
121
+
122
+ ## Startup rollback
123
+
124
+ If a resource fails during startup, already-started resources are stopped in reverse order.
125
+
126
+ ```text
127
+ database.start() ✅
128
+ jobs.start() ✅
129
+ realtime.start() ❌
130
+
131
+ rollback:
132
+
133
+ jobs.stop()
134
+ database.stop()
135
+ ```
136
+
137
+ The runtime moves to `failed` and `start()` rejects.
138
+
139
+ ## Resource context
140
+
141
+ Lifecycle callbacks receive:
142
+
143
+ ```ts
144
+ {
145
+ metadata,
146
+ signal,
147
+ }
148
+ ```
149
+
150
+ `signal` is aborted when shutdown begins. Long-running BCP/application components can use it to stop accepting new work or cancel background loops.
151
+
152
+ ## Readiness
153
+
154
+ ```ts
155
+ const report =
156
+ await deployment.readiness();
157
+ ```
158
+
159
+ A runtime is ready only when:
160
+
161
+ 1. runtime state is `ready`;
162
+ 2. all registered resources are in the started state;
163
+ 3. every resource readiness function reports success.
164
+
165
+ Create an HTTP response directly:
166
+
167
+ ```ts
168
+ import {
169
+ createDeploymentReadinessResponse,
170
+ } from "bcp/deployment";
171
+
172
+ export function GET() {
173
+ return createDeploymentReadinessResponse(
174
+ deployment
175
+ );
176
+ }
177
+ ```
178
+
179
+ Successful readiness returns HTTP `200`. A non-ready runtime returns `503`.
180
+
181
+ The response uses:
182
+
183
+ ```text
184
+ Cache-Control: no-store
185
+ ```
186
+
187
+ Recommended route:
188
+
189
+ ```text
190
+ /api/ready
191
+ ```
192
+
193
+ Do not place authentication/user data in this endpoint when it is consumed by infrastructure health probes.
194
+
195
+ ## Diagnostics
196
+
197
+ ```ts
198
+ const diagnostics =
199
+ await deployment.diagnostics();
200
+ ```
201
+
202
+ The report includes:
203
+
204
+ - service/deployment identity;
205
+ - process ID;
206
+ - Node version;
207
+ - platform/architecture;
208
+ - runtime state;
209
+ - uptime;
210
+ - lifecycle state for each registered resource;
211
+ - optional resource-specific diagnostic metadata.
212
+
213
+ An HTTP response helper is available:
214
+
215
+ ```ts
216
+ import {
217
+ createDeploymentDiagnosticsResponse,
218
+ } from "bcp/deployment";
219
+
220
+ export function GET() {
221
+ return createDeploymentDiagnosticsResponse(
222
+ deployment
223
+ );
224
+ }
225
+ ```
226
+
227
+ Diagnostics can reveal infrastructure details. Protect the route when exposing it outside a trusted operations network.
228
+
229
+ ## Deployment metadata
230
+
231
+ The runtime accepts explicit identifiers:
232
+
233
+ ```ts
234
+ createDeploymentRuntime({
235
+ serviceName:
236
+ "orders-api",
237
+ deploymentId:
238
+ "deploy-20260831-01",
239
+ instanceId:
240
+ "orders-api-7f5d9",
241
+ release:
242
+ "2026.08.31",
243
+ environmentName:
244
+ "production",
245
+ });
246
+ ```
247
+
248
+ Or resolve them from runtime environment variables:
249
+
250
+ ```text
251
+ BCP_DEPLOYMENT_ID
252
+ BCP_INSTANCE_ID
253
+ BCP_RELEASE
254
+ NODE_ENV
255
+ ```
256
+
257
+ If `BCP_DEPLOYMENT_ID` is not supplied, BCP generates a UUID for the process.
258
+
259
+ ## Shutdown timeout
260
+
261
+ Default shutdown timeout:
262
+
263
+ ```text
264
+ 10 seconds
265
+ ```
266
+
267
+ Configure it explicitly:
268
+
269
+ ```ts
270
+ createDeploymentRuntime({
271
+ serviceName: "orders-api",
272
+ shutdownTimeoutMs:
273
+ 30_000,
274
+ });
275
+ ```
276
+
277
+ or through:
278
+
279
+ ```dotenv
280
+ BCP_SHUTDOWN_TIMEOUT_MS=30000
281
+ ```
282
+
283
+ The timeout is shared by reverse-order resource shutdown. If a resource does not finish before the remaining deadline, shutdown records the failure and eventually rejects with `AggregateError`.
284
+
285
+ ## Signal handling
286
+
287
+ Install handlers:
288
+
289
+ ```ts
290
+ const removeSignals =
291
+ deployment.installSignalHandlers();
292
+ ```
293
+
294
+ Default signals:
295
+
296
+ ```text
297
+ SIGTERM
298
+ SIGINT
299
+ ```
300
+
301
+ The handlers start graceful shutdown and set `process.exitCode` rather than immediately calling `process.exit()`. This allows pending cleanup/microtasks to finish.
302
+
303
+ Remove handlers when ownership moves elsewhere:
304
+
305
+ ```ts
306
+ removeSignals();
307
+ ```
308
+
309
+ Custom signal set:
310
+
311
+ ```ts
312
+ deployment.installSignalHandlers({
313
+ signals: [
314
+ "SIGTERM",
315
+ ],
316
+ });
317
+ ```
318
+
319
+ ## Existing BCP shutdown hooks
320
+
321
+ Deployment runtime can participate in the existing production-hardening shutdown registry:
322
+
323
+ ```ts
324
+ const unregister =
325
+ deployment.registerShutdownHook();
326
+ ```
327
+
328
+ When the framework executes registered shutdown hooks, the deployment runtime drains its resources.
329
+
330
+ Use either direct signal ownership or integrate with an application-level signal coordinator. Avoid installing multiple independent handlers that all own the same resource lifecycle.
331
+
332
+ ## Recommended topology
333
+
334
+ ```text
335
+ Load balancer / orchestrator
336
+
337
+ ├── readiness probe
338
+ │ ↓
339
+ │ bcp/deployment
340
+
341
+ └── SIGTERM
342
+
343
+ state = draining
344
+
345
+ stop inbound/realtime
346
+
347
+ stop workers/jobs
348
+
349
+ close database
350
+
351
+ state = stopped
352
+ ```
353
+
354
+ ## Jobs and workflow workers
355
+
356
+ Register workers as resources so they stop before shared dependencies such as Redis or SQL connections:
357
+
358
+ ```ts
359
+ deployment.addResource({
360
+ name: "workers",
361
+
362
+ start() {
363
+ worker =
364
+ jobs.startWorker();
365
+ },
366
+
367
+ async stop() {
368
+ await worker.stop();
369
+ },
370
+ });
371
+ ```
372
+
373
+ Register database/cache connections before workers. Reverse-order shutdown then naturally stops workers before closing their dependencies.
374
+
375
+ ## Realtime
376
+
377
+ For realtime transports, mark the system not-ready before closing shared storage/transport resources. Runtime state changes to `draining` before resource stop hooks run, so readiness probes begin returning `503` while shutdown is in progress.
378
+
379
+ ## Observability
380
+
381
+ Deployment metadata can be attached to logs/traces:
382
+
383
+ ```ts
384
+ const metadata =
385
+ deployment.metadata;
386
+
387
+ logger.info(
388
+ "runtime ready",
389
+ {
390
+ deploymentId:
391
+ metadata.deploymentId,
392
+ instanceId:
393
+ metadata.instanceId,
394
+ release:
395
+ metadata.release,
396
+ }
397
+ );
398
+ ```
399
+
400
+ Use `bcp/observability` for trace/span correlation and `bcp/deployment` for process/deployment identity and lifecycle state.
401
+
402
+ ## Compiled server runtimes
403
+
404
+ Prepared `bcp` packages now compile these production entrypoints:
405
+
406
+ ```text
407
+ bcp/cache -> cache.mjs
408
+ bcp/config -> config.mjs
409
+ bcp/database -> database.mjs
410
+ bcp/auth -> auth.mjs
411
+ bcp/jobs -> jobs.mjs
412
+ bcp/workflow -> workflow.mjs
413
+ bcp/events -> events.mjs
414
+ bcp/realtime -> realtime.mjs
415
+ bcp/testing -> testing.mjs
416
+ bcp/plugins -> plugins.mjs
417
+ bcp/observability -> observability.mjs
418
+ bcp/deployment -> deployment.mjs
419
+ bcp/server -> server.mjs
420
+ bcp/middleware -> middleware.mjs
421
+ ```
422
+
423
+ Type declarations/source types remain available from the TypeScript source entrypoint while runtime resolution points to compiled ESM in prepared npm packages.
424
+
425
+ This reduces reliance on Node TypeScript stripping for server framework runtime entrypoints and provides a more deterministic production package.
426
+
427
+ ## Compatibility
428
+
429
+ `0.2.18` is intended to be backward compatible with `0.2.17`.
430
+
431
+ Existing:
432
+
433
+ ```text
434
+ bcp build
435
+ bcp package
436
+ npm start
437
+ registerShutdownHook()
438
+ ```
439
+
440
+ remain available. `bcp/deployment` is additive.
441
+
442
+ ## Related guides
443
+
444
+ - [Application Packaging](application-packaging.md)
445
+ - [Deployment](deployment.md)
446
+ - [Production Hardening](production-hardening.md)
447
+ - [Observability Platform v3](observability-v3.md)
448
+ - [Background Jobs](background-jobs.md)
449
+ - [Realtime Platform](realtime-platform.md)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "framework": "bcp",
4
- "versionTarget": "0.2.17",
4
+ "versionTarget": "0.2.18",
5
5
  "releaseState": "unreleased",
6
6
  "sections": [
7
7
  {
@@ -58,13 +58,14 @@
58
58
  {
59
59
  "id": "runtime",
60
60
  "title": "Runtime & Infrastructure",
61
- "description": "Middleware, jobs, scheduling, workflows, event delivery, realtime channels, observability, distributed caching, security and production hardening.",
61
+ "description": "Middleware, jobs, scheduling, workflows, event delivery, realtime channels, observability, deployment lifecycle, distributed caching, security and production hardening.",
62
62
  "pages": [
63
63
  { "route": "/docs/middleware", "source": "middleware.md", "title": "Middleware" },
64
64
  { "route": "/docs/hydration", "source": "hydration.md", "title": "Hydration" },
65
65
  { "route": "/docs/development-logging", "source": "development-logging.md", "title": "Logging" },
66
66
  { "route": "/docs/observability", "source": "observability.md", "title": "Observability Platform v2" },
67
67
  { "route": "/docs/observability-v3", "source": "observability-v3.md", "title": "Observability Platform v3" },
68
+ { "route": "/docs/deployment-platform-v2", "source": "deployment-platform-v2.md", "title": "Deployment Platform v2" },
68
69
  { "route": "/docs/background-jobs", "source": "background-jobs.md", "title": "Background Jobs Platform" },
69
70
  { "route": "/docs/job-scheduling", "source": "job-scheduling.md", "title": "Job Scheduling Platform" },
70
71
  { "route": "/docs/durable-jobs", "source": "durable-jobs.md", "title": "Durable Jobs Platform" },
@@ -118,7 +119,8 @@
118
119
  }
119
120
  ],
120
121
  "releases": [
121
- { "route": "/releases/0.2.17", "source": "releases/0.2.17.md", "version": "0.2.17", "state": "unreleased" },
122
+ { "route": "/releases/0.2.18", "source": "releases/0.2.18.md", "version": "0.2.18", "state": "unreleased" },
123
+ { "route": "/releases/0.2.17", "source": "releases/0.2.17.md", "version": "0.2.17" },
122
124
  { "route": "/releases/0.2.16", "source": "releases/0.2.16.md", "version": "0.2.16" },
123
125
  { "route": "/releases/0.2.15", "source": "releases/0.2.15.md", "version": "0.2.15" },
124
126
  { "route": "/releases/0.2.14", "source": "releases/0.2.14.md", "version": "0.2.14" },
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "framework": "bcp",
4
- "version": "0.2.17",
4
+ "version": "0.2.18",
5
5
  "releaseState": "unreleased",
6
- "baseline": "observability-platform-v3",
6
+ "baseline": "deployment-platform-v2",
7
7
  "runtime": {
8
8
  "node": ">=24.11.0",
9
9
  "react": "19",
@@ -26,6 +26,7 @@
26
26
  "bcp/testing",
27
27
  "bcp/plugins",
28
28
  "bcp/observability",
29
+ "bcp/deployment",
29
30
  "bcp/server",
30
31
  "bcp/server-only",
31
32
  "bcp/middleware"
@@ -82,6 +83,18 @@
82
83
  "traceMetricsExporter": true,
83
84
  "traceLogFields": true,
84
85
  "compiledObservabilityRuntime": true,
86
+ "deploymentPlatformV2": true,
87
+ "deploymentRuntimeLifecycle": true,
88
+ "deploymentResourceRegistry": true,
89
+ "deploymentReadiness": true,
90
+ "deploymentDiagnostics": true,
91
+ "deploymentSignalHandling": true,
92
+ "deploymentShutdownHooks": true,
93
+ "deploymentRuntimeMetadata": true,
94
+ "compiledConfigRuntime": true,
95
+ "compiledAuthRuntime": true,
96
+ "compiledServerRuntime": true,
97
+ "compiledMiddlewareRuntime": true,
85
98
  "backgroundJobsPlatform": true,
86
99
  "jobQueueAdapterContract": true,
87
100
  "inMemoryJobQueue": true,
@@ -211,7 +224,7 @@
211
224
  "s3-compatible"
212
225
  ],
213
226
  "compatibility": {
214
- "previousBaseline": "0.2.16",
227
+ "previousBaseline": "0.2.17",
215
228
  "intentionalBreakingChangesFromPreviousBaseline": false,
216
229
  "migrationGuide": "migration-0.2.md"
217
230
  },
@@ -229,6 +242,7 @@
229
242
  "authorizationSecurity": "authorization-security.md",
230
243
  "observability": "observability.md",
231
244
  "observabilityV3": "observability-v3.md",
245
+ "deploymentPlatformV2": "deployment-platform-v2.md",
232
246
  "backgroundJobs": "background-jobs.md",
233
247
  "jobScheduling": "job-scheduling.md",
234
248
  "durableJobs": "durable-jobs.md",
@@ -239,6 +253,6 @@
239
253
  "pluginModulePlatform": "plugin-module-platform.md",
240
254
  "cachePlatformV2": "cache-platform-v2.md",
241
255
  "migrationGuide": "migration-0.2.md",
242
- "releaseNotes": "releases/0.2.17.md"
256
+ "releaseNotes": "releases/0.2.18.md"
243
257
  }
244
258
  }
@@ -0,0 +1,136 @@
1
+ # BCP Framework 0.2.18 — Deployment Platform v2
2
+
3
+ Status: **unreleased**
4
+
5
+ `0.2.18` adds a framework-native deployment lifecycle and hardens prepared npm runtime entrypoints for standalone Node production use.
6
+
7
+ ## Highlights
8
+
9
+ ### New `bcp/deployment` entrypoint
10
+
11
+ ```ts
12
+ import {
13
+ createDeploymentRuntime,
14
+ } from "bcp/deployment";
15
+ ```
16
+
17
+ Deployment runtime provides:
18
+
19
+ - ordered resource startup;
20
+ - reverse-order graceful shutdown;
21
+ - startup rollback;
22
+ - readiness checks;
23
+ - deployment/process diagnostics;
24
+ - deployment/instance/release metadata;
25
+ - `SIGTERM` / `SIGINT` handling;
26
+ - integration with existing BCP shutdown hooks.
27
+
28
+ ### Readiness endpoints
29
+
30
+ ```ts
31
+ return createDeploymentReadinessResponse(
32
+ deployment
33
+ );
34
+ ```
35
+
36
+ Ready runtime returns `200`; non-ready/draining/failed runtime returns `503`.
37
+
38
+ ### Diagnostics
39
+
40
+ ```ts
41
+ return createDeploymentDiagnosticsResponse(
42
+ deployment
43
+ );
44
+ ```
45
+
46
+ Diagnostics include process/runtime identity, uptime and resource lifecycle state plus optional resource diagnostics.
47
+
48
+ ### Runtime identity
49
+
50
+ Supported runtime environment values:
51
+
52
+ ```text
53
+ BCP_DEPLOYMENT_ID
54
+ BCP_INSTANCE_ID
55
+ BCP_RELEASE
56
+ NODE_ENV
57
+ BCP_SHUTDOWN_TIMEOUT_MS
58
+ ```
59
+
60
+ ### Compiled production entrypoints
61
+
62
+ Prepared framework packages now use compiled ESM runtime files for additional server-side entrypoints:
63
+
64
+ ```text
65
+ bcp/config -> config.mjs
66
+ bcp/auth -> auth.mjs
67
+ bcp/deployment -> deployment.mjs
68
+ bcp/server -> server.mjs
69
+ bcp/middleware -> middleware.mjs
70
+ ```
71
+
72
+ Existing compiled server runtimes such as cache/database/jobs/workflow/events/realtime/testing/plugins/observability remain compiled as before.
73
+
74
+ This closes a packaging gap where several server entrypoints still resolved directly to TypeScript in the published package.
75
+
76
+ ## Public API additions
77
+
78
+ ```text
79
+ createDeploymentRuntime
80
+ createDeploymentReadinessResponse
81
+ createDeploymentDiagnosticsResponse
82
+
83
+ DeploymentRuntime
84
+ DeploymentRuntimeOptions
85
+ DeploymentRuntimeState
86
+ DeploymentResource
87
+ DeploymentResourceContext
88
+ DeploymentResourceStatus
89
+ DeploymentReadinessResult
90
+ DeploymentReadinessReport
91
+ DeploymentDiagnosticsReport
92
+ DeploymentMetadata
93
+ DeploymentSignalOptions
94
+ DeploymentShutdownOptions
95
+ ```
96
+
97
+ ## Lifecycle model
98
+
99
+ ```text
100
+ idle
101
+
102
+ starting
103
+
104
+ ready
105
+
106
+ draining
107
+
108
+ stopped
109
+ ```
110
+
111
+ Failures move the runtime to `failed`.
112
+
113
+ ## Compatibility
114
+
115
+ There are no intentional breaking changes from `0.2.17`.
116
+
117
+ Existing production hardening APIs, shutdown hooks, `bcp build`, `bcp package` and application package manifests remain supported.
118
+
119
+ `bcp/deployment` is additive.
120
+
121
+ ## Validation
122
+
123
+ Before tagging/publishing:
124
+
125
+ ```bash
126
+ npm run typecheck
127
+ npm run test:unit
128
+ npm run test:integration
129
+ npm run test:e2e
130
+ npm run test:package
131
+ npm run rc:check
132
+ ```
133
+
134
+ The `0.2.18` package smoke validates the compiled deployment runtime plus compiled config/auth/server/middleware entrypoints from the prepared `.package/bcp` staging directory.
135
+
136
+ Do not tag/publish until the final commit passes the complete RC sequence.