@chidchanun/bcp 0.3.0 → 0.3.1

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.
@@ -1,142 +1,263 @@
1
- # Migrating to BCP Framework 0.3.0
1
+ # Migrating to BCP Framework 0.3.x
2
2
 
3
- BCP Framework `0.3.0` establishes the Application Platform baseline while preserving the public entrypoints frozen in `0.2.19`.
3
+ BCP Framework `0.3.0` established the Application Platform baseline. `0.3.1` extends it additively with typed dependency injection through `bcp/container`.
4
4
 
5
- > **Release state:** unreleased until RC validation, tagging and npm publication complete.
5
+ ## Compatibility
6
6
 
7
- ## Compatibility goal
7
+ Current target:
8
8
 
9
- `0.3.0` intentionally adds one public server-only package entrypoint:
9
+ ```text
10
+ 0.3.1 — Dependency Injection & Service Container
11
+ ```
12
+
13
+ Previous baseline:
10
14
 
11
15
  ```text
12
- bcp/application
16
+ 0.3.0
13
17
  ```
14
18
 
15
- No `0.2.19` public entrypoint is intentionally removed. Existing applications do not have to adopt the new application runtime immediately.
19
+ Intentional breaking changes:
16
20
 
17
- ## Upgrade
21
+ ```text
22
+ false
23
+ ```
24
+
25
+ Existing `0.3.0` applications do not have to adopt dependency injection immediately.
18
26
 
19
- After `0.3.0` is published:
27
+ ## Upgrade to 0.3.1
28
+
29
+ After publication:
20
30
 
21
31
  ```powershell
22
32
  npm exec -- bcp-framework update --check
23
- npm run update -- 0.3.0
33
+ npm run update -- 0.3.1
24
34
  ```
25
35
 
26
- Then rebuild the application:
36
+ Then validate the application:
27
37
 
28
38
  ```powershell
29
39
  npm run typecheck
30
40
  npm run build
41
+ npm exec -- bcp-framework routes
31
42
  npm exec -- bcp-framework doctor
32
43
  ```
33
44
 
34
- Do not reuse a `.bcp-framework/build` directory produced by `0.2.x`.
45
+ ## Existing Application Platform code remains valid
35
46
 
36
- ## Existing 0.2.x composition remains valid
37
-
38
- These imports remain public:
47
+ This remains supported:
39
48
 
40
49
  ```ts
41
- import { db } from "bcp/database";
42
- import { createAuth } from "bcp/auth";
43
- import { createJobQueue } from "bcp/jobs";
44
- import { createWorkflow } from "bcp/workflow";
45
- import { createTransactionalOutbox } from "bcp/events";
46
- import { createRealtime } from "bcp/realtime";
47
- import { createCacheStore } from "bcp/cache";
48
- import { createPluginHost } from "bcp/plugins";
49
- import { createTracer } from "bcp/observability";
50
- import { createDeploymentRuntime } from "bcp/deployment";
50
+ import {
51
+ createApp,
52
+ } from "bcp/application";
53
+
54
+ const app =
55
+ createApp({
56
+ name: "my-app",
57
+ });
58
+
59
+ app.provide(
60
+ "database",
61
+ database
62
+ );
51
63
  ```
52
64
 
53
- You can continue owning lifecycle manually if that is already appropriate for the project.
65
+ `app.services` and `context.services` continue to use the Plugin Platform registry.
54
66
 
55
- ## Optional migration to createApp
67
+ ## Optional migration to typed DI
56
68
 
57
- New or gradually modernized applications can centralize composition:
69
+ New typed dependencies can use `bcp/container`:
58
70
 
59
71
  ```ts
60
72
  import {
61
- createApp,
62
- } from "bcp/application";
73
+ createServiceToken,
74
+ provideValue,
75
+ } from "bcp/container";
63
76
 
64
- export const app =
77
+ const databaseToken =
78
+ createServiceToken<typeof database>(
79
+ "database"
80
+ );
81
+
82
+ const app =
65
83
  createApp({
66
84
  name: "my-app",
67
- version: "1.0.0",
85
+ providers: [
86
+ provideValue(
87
+ databaseToken,
88
+ database
89
+ ),
90
+ ],
68
91
  });
69
92
  ```
70
93
 
71
- Register shared service instances before startup:
94
+ Then resolve from application hooks or server composition code:
72
95
 
73
96
  ```ts
74
- app.provide("database", database);
75
- app.provide("cache", cache);
76
- app.provide("jobs", jobs);
97
+ const database =
98
+ await app.container.resolve(
99
+ databaseToken
100
+ );
77
101
  ```
78
102
 
79
- Register lifecycle-owned resources:
103
+ You do not need to migrate every plugin service at once.
104
+
105
+ ## Factory dependencies
106
+
107
+ Replace manual service construction:
80
108
 
81
109
  ```ts
82
- app.addResource({
83
- name: "database",
84
- start: () => database.connect(),
85
- stop: () => database.close(),
86
- });
110
+ const repository =
111
+ createRepository(
112
+ database,
113
+ logger
114
+ );
87
115
  ```
88
116
 
89
- Then:
117
+ with explicit typed provider dependencies when useful:
90
118
 
91
119
  ```ts
92
- await app.start();
120
+ const repositoryProvider =
121
+ provideFactory(
122
+ repositoryToken,
123
+ [
124
+ databaseToken,
125
+ loggerToken,
126
+ ] as const,
127
+ (
128
+ _context,
129
+ [database, logger]
130
+ ) =>
131
+ createRepository(
132
+ database,
133
+ logger
134
+ )
135
+ );
93
136
  ```
94
137
 
95
- ## Lifecycle ownership
138
+ No decorators or reflection metadata are required.
139
+
140
+ ## Request/job/test scopes
96
141
 
97
- Do not allow both the application runtime and separate application code to independently start/stop the same resource.
142
+ Use child scopes for dependencies that should not be application singletons:
143
+
144
+ ```ts
145
+ const requestScope =
146
+ app.createScope({
147
+ name: `request:${requestId}`,
148
+ });
98
149
 
99
- Choose one lifecycle owner for each database pool, worker, scheduler, broker or other long-running resource.
150
+ try {
151
+ const service =
152
+ await requestScope.resolve(
153
+ requestServiceToken
154
+ );
155
+ } finally {
156
+ await requestScope.dispose();
157
+ }
158
+ ```
100
159
 
101
- The Application Platform starts:
160
+ Testing overrides:
161
+
162
+ ```ts
163
+ const testScope =
164
+ app.createScope({
165
+ name: "test",
166
+ overrides: [
167
+ provideValue(
168
+ mailerToken,
169
+ fakeMailer
170
+ ),
171
+ ],
172
+ });
173
+ ```
174
+
175
+ ## Lifetimes
176
+
177
+ Provider lifetimes are:
102
178
 
103
179
  ```text
104
- plugins
105
- resources
106
- application hook
180
+ singleton
181
+ scoped
182
+ transient
107
183
  ```
108
184
 
109
- and stops them in reverse dependency order.
185
+ The default is `singleton`.
186
+
187
+ A common mapping is:
188
+
189
+ ```text
190
+ database pool singleton
191
+ cache client singleton
192
+ repository scoped or singleton depending on state
193
+ request context scoped
194
+ small stateless factory output transient when required
195
+ ```
110
196
 
111
- ## Plugins and modules
197
+ ## Disposal ownership
112
198
 
113
- Existing `definePlugin()` and `defineModule()` values work directly:
199
+ If the DI container owns a resource through a provider `dispose()` callback, avoid also registering an independent shutdown owner for the same instance unless the cleanup operation is explicitly idempotent.
200
+
201
+ Example:
114
202
 
115
203
  ```ts
116
- const app =
117
- createApp({
118
- name: "my-app",
119
- modules: [
120
- backendModule,
121
- ],
122
- });
204
+ provideFactory(
205
+ databaseToken,
206
+ [] as const,
207
+ createDatabase,
208
+ {
209
+ dispose(database) {
210
+ return database.close();
211
+ },
212
+ }
213
+ );
214
+ ```
215
+
216
+ The Application Platform keeps the container alive until application resources/plugins stop, then disposes injected services in reverse creation order.
217
+
218
+ ## Application resource lifecycle
219
+
220
+ Long-running components can still use `app.addResource()`:
221
+
222
+ ```ts
223
+ app.addResource({
224
+ name: "worker",
225
+ start: () => worker.start(),
226
+ stop: () => worker.stop(),
227
+ });
123
228
  ```
124
229
 
125
- No plugin rewrite is required for `0.3.0`.
230
+ DI and Deployment resources solve different concerns:
231
+
232
+ ```text
233
+ container provider -> construct/resolve/dispose dependencies
234
+ application resource -> start/readiness/stop long-running runtime components
235
+ ```
236
+
237
+ A provider may construct the worker while an application resource starts/stops it.
126
238
 
127
239
  ## Server-only boundary
128
240
 
129
- `bcp/application` owns process lifecycle and infrastructure composition. Do not import it from React client pages or islands.
241
+ Both entrypoints are server-only:
242
+
243
+ ```text
244
+ bcp/container
245
+ bcp/application
246
+ ```
130
247
 
131
- Use it from server bootstrap/application composition modules.
248
+ Do not import them into React client pages/islands.
132
249
 
133
250
  ## API baseline
134
251
 
135
- `0.2.19` remains the previous compatibility baseline. The reviewed `0.3.0` API snapshot adds `bcp/application` and becomes the new release contract used by `npm run api:check`.
252
+ `0.3.1` adds one public entrypoint over `0.3.0`:
253
+
254
+ ```text
255
+ bcp/container
256
+ ```
136
257
 
137
- ## Validation checklist
258
+ The reviewed API snapshot records the new `container.mjs` prepared runtime and browser poison boundary.
138
259
 
139
- For framework development:
260
+ ## Framework validation checklist
140
261
 
141
262
  ```powershell
142
263
  npm run typecheck
@@ -149,7 +270,7 @@ npm run release:readiness
149
270
  npm run rc:check
150
271
  ```
151
272
 
152
- For an application upgrading from `0.2.19`:
273
+ For application upgrades:
153
274
 
154
275
  ```powershell
155
276
  npm run typecheck
@@ -2,7 +2,7 @@
2
2
 
3
3
  BCP Framework exposes an explicit, machine-readable application-platform contract rather than relying on private repository structure.
4
4
 
5
- The current development baseline is **`0.3.0BCP Application Platform`** and remains unreleased until the complete RC sequence passes, the exact release commit is tagged and npm publication completes.
5
+ The current development baseline is **`0.3.1Dependency Injection & Service Container`** and remains unreleased until the complete RC sequence passes, the exact release commit is tagged and npm publication completes.
6
6
 
7
7
  ## Sources of truth
8
8
 
@@ -20,11 +20,11 @@ docs/docs-web-manifest.json
20
20
  -> documentation routes and release navigation
21
21
  ```
22
22
 
23
- Framework source and tests remain authoritative for runtime behavior. The manifests make the supported surface testable during release validation.
23
+ Framework source and tests remain authoritative for runtime behavior.
24
24
 
25
25
  ## Public entrypoints
26
26
 
27
- The `0.3.0` baseline supports:
27
+ The `0.3.1` baseline supports:
28
28
 
29
29
  ```text
30
30
  bcp
@@ -43,43 +43,57 @@ bcp/testing
43
43
  bcp/plugins
44
44
  bcp/observability
45
45
  bcp/deployment
46
+ bcp/container
46
47
  bcp/application
47
48
  bcp/server
48
49
  bcp/server-only
49
50
  bcp/middleware
50
51
  ```
51
52
 
52
- `bcp/application` is the one new entrypoint relative to the `0.2.19` baseline. No existing `0.2.19` public entrypoint is intentionally removed.
53
+ `bcp/container` is the new entrypoint relative to `0.3.0`. No `0.3.0` public entrypoint is intentionally removed.
53
54
 
54
- Application code should use these entrypoints instead of private `packages/*` implementation paths.
55
+ The prepared package also exposes `./package.json`; it is part of package-export snapshot validation but is not an application API module.
55
56
 
56
- The prepared npm package also exposes `./package.json`; that package export is included in the API snapshot even though it is not an application API module.
57
+ ## Application and DI baseline
57
58
 
58
- ## Application Platform baseline
59
+ `bcp/application` remains the composition root while `bcp/container` adds typed dependency injection:
59
60
 
60
- `bcp/application` adds a server-only composition root:
61
+ ```text
62
+ ServiceToken<T>
63
+ value providers
64
+ factory providers
65
+ class providers
66
+ singleton/scoped/transient lifetimes
67
+ child/request scopes
68
+ test overrides
69
+ dependency graph diagnostics
70
+ circular dependency detection
71
+ reverse disposal
72
+ ```
73
+
74
+ Application integration exposes:
61
75
 
62
- ```ts
63
- import {
64
- createApp,
65
- defineApp,
66
- } from "bcp/application";
76
+ ```text
77
+ app.container
78
+ app.context.container
79
+ app.register(provider)
80
+ app.createScope(options)
67
81
  ```
68
82
 
69
- The Application Platform reuses the existing Plugin and Deployment platforms for:
83
+ The existing Plugin Platform registry remains available through `app.services` / `context.services` for compatibility.
84
+
85
+ ## Lifecycle contract
86
+
87
+ Application deployment resources start in this order:
70
88
 
71
89
  ```text
72
- typed application config
73
- shared services and hooks
74
- plugins/modules
75
- resource lifecycle
76
- startup rollback
77
- readiness/diagnostics
78
- signal handling
79
- graceful shutdown
90
+ bcp:container
91
+ bcp:plugins
92
+ application resources
93
+ bcp:application
80
94
  ```
81
95
 
82
- It does not replace existing database, jobs, cache, events, realtime or other subsystem APIs. Applications may use those independently or compose selected instances through the application root.
96
+ Shutdown reverses that order. This keeps injected dependencies available while workers/resources/plugins stop, then disposes injected services before final application disposal.
83
97
 
84
98
  ## CLI baseline
85
99
 
@@ -112,21 +126,25 @@ build target: standalone-node
112
126
  package target: standalone-node
113
127
  ```
114
128
 
115
- Prepared server/runtime entrypoints resolve to compiled ESM where required by the package contract. `0.3.0` adds compiled `application.mjs`.
129
+ Prepared npm packages expose compiled server ESM. `0.3.1` adds:
130
+
131
+ ```text
132
+ bcp/container -> container.mjs
133
+ ```
134
+
135
+ and preserves compiled `application.mjs` from `0.3.0`.
116
136
 
117
137
  ## Compatibility policy
118
138
 
119
- For `0.3.0`:
139
+ For `0.3.1`:
120
140
 
121
141
  ```text
122
- previous baseline: 0.2.19
142
+ previous baseline: 0.3.0
123
143
  intentional breaking changes: false
124
- baseline: application-platform
144
+ baseline: dependency-injection-service-container
125
145
  ```
126
146
 
127
- `0.2.19` remains the historical freeze point for `0.2.x`. `0.3.0` intentionally advances the reviewed API snapshot by adding `bcp/application` and becomes the next compatibility baseline.
128
-
129
- Bug fixes must not silently remove a documented public entrypoint or change its prepared package-resolution/browser-boundary contract.
147
+ Bug fixes must not silently remove a documented entrypoint or change its prepared package-resolution/browser-boundary contract.
130
148
 
131
149
  ## API compatibility gate
132
150
 
@@ -134,16 +152,14 @@ Bug fixes must not silently remove a documented public entrypoint or change its
134
152
  npm run api:check
135
153
  ```
136
154
 
137
- The gate prepares the publish package, regenerates the current contract in memory and compares it to `docs/api-freeze-snapshot.json`.
155
+ The gate prepares the publish package, regenerates the current contract in memory and compares it with `docs/api-freeze-snapshot.json`.
138
156
 
139
- To intentionally regenerate the snapshot for a reviewed platform-baseline change:
157
+ Regenerate the snapshot only for an intentional reviewed baseline change:
140
158
 
141
159
  ```bash
142
160
  npm run api:snapshot
143
161
  ```
144
162
 
145
- Do not regenerate the snapshot merely to silence an unexpected compatibility failure.
146
-
147
163
  ## Release readiness
148
164
 
149
165
  ```bash
@@ -151,11 +167,11 @@ npm run release:readiness
151
167
  npm run release:readiness:report
152
168
  ```
153
169
 
154
- The readiness gate checks version/lock/manifests parity, compatibility metadata, application entrypoint ownership, API snapshot parity, release docs and Application Platform capability flags. The optional report is written to `.bcp-framework/release-readiness.json`.
170
+ The readiness gate checks package/lock/manifests parity, the `0.3.0` previous baseline, public entrypoint/API snapshot parity, container/application ownership, release docs and DI/Application capability flags.
155
171
 
156
172
  ## Release validation
157
173
 
158
- Before `0.3.0` is tagged or published:
174
+ Before `0.3.1` is tagged or published:
159
175
 
160
176
  ```bash
161
177
  npm run typecheck
@@ -170,4 +186,4 @@ npm run rc:check
170
186
 
171
187
  `rc:check` must pass on the exact commit used for the release tag.
172
188
 
173
- See [Application Platform](application-platform.md), [Migrating to 0.3.0](migration-0.3.md), and the historical [Stability & API Freeze](stability-api-freeze.md).
189
+ See [Dependency Injection & Service Container](service-container.md), [Application Platform](application-platform.md), [Migrating to 0.3.x](migration-0.3.md), and the historical [Stability & API Freeze](stability-api-freeze.md).
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "framework": "bcp",
4
- "version": "0.3.0",
4
+ "version": "0.3.1",
5
5
  "releaseState": "unreleased",
6
- "baseline": "application-platform",
6
+ "baseline": "dependency-injection-service-container",
7
7
  "runtime": {
8
8
  "node": ">=24.11.0",
9
9
  "react": "19",
@@ -27,6 +27,7 @@
27
27
  "bcp/plugins",
28
28
  "bcp/observability",
29
29
  "bcp/deployment",
30
+ "bcp/container",
30
31
  "bcp/application",
31
32
  "bcp/server",
32
33
  "bcp/server-only",
@@ -109,6 +110,21 @@
109
110
  "applicationLifecycleRollback": true,
110
111
  "applicationLifecycleIdempotency": true,
111
112
  "compiledApplicationRuntime": true,
113
+ "dependencyInjectionContainer": true,
114
+ "typedServiceTokens": true,
115
+ "serviceValueProviders": true,
116
+ "serviceFactoryProviders": true,
117
+ "serviceClassProviders": true,
118
+ "serviceSingletonLifetime": true,
119
+ "serviceScopedLifetime": true,
120
+ "serviceTransientLifetime": true,
121
+ "serviceChildScopes": true,
122
+ "serviceScopeOverrides": true,
123
+ "serviceDependencyGraph": true,
124
+ "serviceCircularDependencyDetection": true,
125
+ "serviceReverseDisposal": true,
126
+ "applicationServiceContainer": true,
127
+ "compiledContainerRuntime": true,
112
128
  "stabilityApiFreeze": true,
113
129
  "apiFreezeSnapshot": true,
114
130
  "apiCompatibilityGate": true,
@@ -244,7 +260,7 @@
244
260
  "s3-compatible"
245
261
  ],
246
262
  "compatibility": {
247
- "previousBaseline": "0.2.19",
263
+ "previousBaseline": "0.3.0",
248
264
  "intentionalBreakingChangesFromPreviousBaseline": false,
249
265
  "migrationGuide": "migration-0.3.md"
250
266
  },
@@ -258,6 +274,7 @@
258
274
  "apiReference": "api-reference.md",
259
275
  "stabilityApiFreeze": "stability-api-freeze.md",
260
276
  "applicationPlatform": "application-platform.md",
277
+ "serviceContainer": "service-container.md",
261
278
  "environmentValidation": "environment-validation.md",
262
279
  "applicationPackaging": "application-packaging.md",
263
280
  "authentication": "authentication.md",
@@ -276,6 +293,6 @@
276
293
  "pluginModulePlatform": "plugin-module-platform.md",
277
294
  "cachePlatformV2": "cache-platform-v2.md",
278
295
  "migrationGuide": "migration-0.3.md",
279
- "releaseNotes": "releases/0.3.0.md"
296
+ "releaseNotes": "releases/0.3.1.md"
280
297
  }
281
298
  }