@chidchanun/bcp 0.3.0 → 0.3.2

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