create-bcp-app 0.2.10 → 0.2.12
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 +91 -202
- package/package.json +1 -1
- package/template/README.md +81 -128
package/README.md
CHANGED
|
@@ -28,16 +28,6 @@ Generated npm scripts use `bcp` because npm places `node_modules/.bin` on the sc
|
|
|
28
28
|
}
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
When Tailwind CSS is selected, the generated packaging script preserves the production CSS step:
|
|
32
|
-
|
|
33
|
-
```json
|
|
34
|
-
{
|
|
35
|
-
"scripts": {
|
|
36
|
-
"package": "npm run css:build:prod && bcp package"
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
31
|
For direct PowerShell usage, prefer the collision-free local alias:
|
|
42
32
|
|
|
43
33
|
```powershell
|
|
@@ -75,27 +65,21 @@ Select storage provider:
|
|
|
75
65
|
Cloudflare R2
|
|
76
66
|
```
|
|
77
67
|
|
|
78
|
-
Equivalent non-interactive flags are available for CI/scaffolding automation.
|
|
79
|
-
|
|
80
68
|
## Generated project metadata
|
|
81
69
|
|
|
82
|
-
New projects include
|
|
83
|
-
|
|
84
|
-
```text
|
|
85
|
-
bcp.project.json
|
|
86
|
-
```
|
|
70
|
+
New projects include `bcp.project.json`.
|
|
87
71
|
|
|
88
|
-
Example:
|
|
72
|
+
Example for the `0.2.12` target:
|
|
89
73
|
|
|
90
74
|
```json
|
|
91
75
|
{
|
|
92
76
|
"schemaVersion": 1,
|
|
93
77
|
"framework": "bcp",
|
|
94
78
|
"projectName": "my-app",
|
|
95
|
-
"frameworkPackage": "npm:@chidchanun/bcp@0.2.
|
|
79
|
+
"frameworkPackage": "npm:@chidchanun/bcp@0.2.12",
|
|
96
80
|
"createdWith": {
|
|
97
81
|
"package": "create-bcp-app",
|
|
98
|
-
"version": "0.2.
|
|
82
|
+
"version": "0.2.12"
|
|
99
83
|
},
|
|
100
84
|
"packageManager": "npm",
|
|
101
85
|
"presets": {
|
|
@@ -109,43 +93,9 @@ Example:
|
|
|
109
93
|
|
|
110
94
|
This manifest records scaffold identity only. It must not contain secrets and should normally be committed to source control.
|
|
111
95
|
|
|
112
|
-
## Generated application defaults
|
|
113
|
-
|
|
114
|
-
Generated applications include the project-root `@/` alias and TypeScript settings compatible with the BCP bundler.
|
|
115
|
-
|
|
116
|
-
Modules that use React client hooks such as `useState` or `useEffect` must declare `"use client"` at the top of the module.
|
|
117
|
-
|
|
118
|
-
The generated BCP dependency is pinned to the exact framework release selected by the generator.
|
|
119
|
-
|
|
120
|
-
Update later with:
|
|
121
|
-
|
|
122
|
-
```bash
|
|
123
|
-
npm run update
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
Check without modifying files:
|
|
127
|
-
|
|
128
|
-
```powershell
|
|
129
|
-
npm exec -- bcp-framework update --check
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
## Tailwind CSS
|
|
133
|
-
|
|
134
|
-
When Tailwind is enabled, the project includes `tailwindcss`, `@tailwindcss/cli`, `concurrently`, `app/globals.css`, `/bcp.css` stylesheet setup and starter utility classes.
|
|
135
|
-
|
|
136
|
-
Generated commands include:
|
|
137
|
-
|
|
138
|
-
```text
|
|
139
|
-
npm run css:build
|
|
140
|
-
npm run css:watch
|
|
141
|
-
npm run css:build:prod
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
`npm run build` and `npm run package` create the production stylesheet before the BCP production build/package flow.
|
|
145
|
-
|
|
146
96
|
## Database presets
|
|
147
97
|
|
|
148
|
-
|
|
98
|
+
Database choices add starter configuration and the matching driver:
|
|
149
99
|
|
|
150
100
|
- MySQL: `mysql2`
|
|
151
101
|
- PostgreSQL: `pg`
|
|
@@ -153,71 +103,31 @@ The database choice adds starter configuration and the matching driver:
|
|
|
153
103
|
- MongoDB: `mongodb`
|
|
154
104
|
- None: no database dependency
|
|
155
105
|
|
|
156
|
-
For
|
|
106
|
+
For MySQL, PostgreSQL and SQLite, generated `lib/database.ts` exposes BCP database primitives through `bcp/database`.
|
|
157
107
|
|
|
158
|
-
|
|
108
|
+
## Authentication and security
|
|
159
109
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
Selecting a storage provider creates `lib/storage.ts` and provider-specific environment settings. Supported presets are Local Server, Amazon S3 and Cloudflare R2.
|
|
163
|
-
|
|
164
|
-
Storage credentials are server-only. Do not expose them through `BCP_PUBLIC_*` variables.
|
|
165
|
-
|
|
166
|
-
## JWT Cookie authentication
|
|
167
|
-
|
|
168
|
-
Selecting `JWT Cookie` creates `lib/auth.ts` and starter `/api/auth/login`, `/logout` and `/me` routes, and adds:
|
|
169
|
-
|
|
170
|
-
```dotenv
|
|
171
|
-
BCP_SESSION_SECRET=
|
|
172
|
-
```
|
|
110
|
+
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.
|
|
173
111
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
BCP `0.2.5+` can opt into revocable server-side auth state through `AuthSessionStore`.
|
|
177
|
-
|
|
178
|
-
## Authorization & request security — 0.2.6+
|
|
179
|
-
|
|
180
|
-
Generated applications can use permission guards and resource policies from `bcp/auth`, plus same-origin and CSRF protection from `bcp/server`.
|
|
181
|
-
|
|
182
|
-
Authorization and CSRF checks must remain on the server; hiding UI controls in client code is not an authorization boundary.
|
|
183
|
-
|
|
184
|
-
## Observability — 0.2.7+
|
|
185
|
-
|
|
186
|
-
Generated projects can opt into process-local metrics and health/readiness without adding another dependency:
|
|
112
|
+
## Observability
|
|
187
113
|
|
|
188
114
|
```ts
|
|
189
115
|
import {
|
|
190
116
|
createHealthRegistry,
|
|
191
117
|
createMetricsRegistry,
|
|
192
|
-
createRequestMetricsMiddleware,
|
|
193
118
|
} from "bcp/observability";
|
|
194
119
|
```
|
|
195
120
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
## Background jobs — 0.2.8+
|
|
199
|
-
|
|
200
|
-
Generated projects can create a server-only background job queue:
|
|
121
|
+
## Background jobs and scheduling
|
|
201
122
|
|
|
202
123
|
```ts
|
|
203
124
|
import {
|
|
204
125
|
createJobQueue,
|
|
126
|
+
createJobScheduler,
|
|
205
127
|
} from "bcp/jobs";
|
|
206
128
|
|
|
207
129
|
export const jobs =
|
|
208
130
|
createJobQueue();
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
Workers support concurrency, delayed jobs, retry/backoff and cancellation.
|
|
212
|
-
|
|
213
|
-
## Job scheduling — 0.2.9+
|
|
214
|
-
|
|
215
|
-
Recurring schedules use the same `bcp/jobs` entrypoint:
|
|
216
|
-
|
|
217
|
-
```ts
|
|
218
|
-
import {
|
|
219
|
-
createJobScheduler,
|
|
220
|
-
} from "bcp/jobs";
|
|
221
131
|
|
|
222
132
|
export const scheduler =
|
|
223
133
|
createJobScheduler({
|
|
@@ -225,129 +135,117 @@ export const scheduler =
|
|
|
225
135
|
});
|
|
226
136
|
```
|
|
227
137
|
|
|
228
|
-
|
|
138
|
+
`0.2.10+` adds visibility leases, heartbeat renewal, stale-running recovery, DLQ/requeue, retention cleanup and Redis-compatible durable adapters.
|
|
229
139
|
|
|
230
|
-
|
|
231
|
-
await scheduler.schedule(
|
|
232
|
-
"cache.cleanup",
|
|
233
|
-
{},
|
|
234
|
-
{
|
|
235
|
-
everyMs: 300_000,
|
|
236
|
-
}
|
|
237
|
-
);
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
UTC cron schedule:
|
|
140
|
+
## Workflow orchestration — 0.2.11+
|
|
241
141
|
|
|
242
142
|
```ts
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
143
|
+
import {
|
|
144
|
+
createWorkflow,
|
|
145
|
+
} from "bcp/workflow";
|
|
146
|
+
|
|
147
|
+
export const onboarding =
|
|
148
|
+
createWorkflow(
|
|
149
|
+
"user.onboarding",
|
|
150
|
+
workflow => {
|
|
151
|
+
workflow.step(
|
|
152
|
+
"profile",
|
|
153
|
+
createProfile
|
|
154
|
+
);
|
|
155
|
+
workflow.delay(
|
|
156
|
+
"cooldown",
|
|
157
|
+
1_000
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
);
|
|
250
161
|
```
|
|
251
162
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
BCP `0.2.10` adds worker visibility leases, heartbeat renewal, stale-running recovery, DLQ/requeue, retention cleanup and queue statistics.
|
|
163
|
+
`bcp/workflow` supports sequential/parallel steps, retry, persisted delays, compensation and optional execution through `bcp/jobs`.
|
|
255
164
|
|
|
256
|
-
|
|
257
|
-
const worker =
|
|
258
|
-
jobs.startWorker({
|
|
259
|
-
workerId: "worker-a",
|
|
260
|
-
concurrency: 4,
|
|
261
|
-
visibilityTimeoutMs: 30_000,
|
|
262
|
-
heartbeatIntervalMs: 10_000,
|
|
263
|
-
});
|
|
264
|
-
```
|
|
165
|
+
## Transactional Outbox & Events — 0.2.12+
|
|
265
166
|
|
|
266
|
-
|
|
167
|
+
Applications using the SQL Database Platform can persist integration events in the same transaction as business data:
|
|
267
168
|
|
|
268
169
|
```ts
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
170
|
+
import {
|
|
171
|
+
db,
|
|
172
|
+
} from "bcp/database";
|
|
173
|
+
|
|
174
|
+
import {
|
|
175
|
+
createSqlOutboxStore,
|
|
176
|
+
createTransactionalOutbox,
|
|
177
|
+
} from "bcp/events";
|
|
178
|
+
|
|
179
|
+
const outboxStore =
|
|
180
|
+
createSqlOutboxStore({
|
|
181
|
+
database: db,
|
|
182
|
+
driver: "mysql",
|
|
183
|
+
});
|
|
272
184
|
|
|
273
|
-
|
|
185
|
+
const outbox =
|
|
186
|
+
createTransactionalOutbox({
|
|
187
|
+
store: outboxStore,
|
|
188
|
+
});
|
|
274
189
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
190
|
+
await db.transaction(
|
|
191
|
+
async tx => {
|
|
192
|
+
await tx.execute(
|
|
193
|
+
"INSERT INTO orders ..."
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
await outbox.publish(
|
|
197
|
+
tx,
|
|
198
|
+
"order.created",
|
|
199
|
+
{
|
|
200
|
+
orderId: 42,
|
|
201
|
+
}
|
|
202
|
+
);
|
|
280
203
|
}
|
|
281
204
|
);
|
|
282
205
|
```
|
|
283
206
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
BCP intentionally does not install a Redis client library. Applications own the Redis connection and pass a minimal command client to BCP:
|
|
287
|
-
|
|
288
|
-
```ts
|
|
289
|
-
interface RedisCommandClient {
|
|
290
|
-
sendCommand(
|
|
291
|
-
command: string[]
|
|
292
|
-
): Promise<unknown>;
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
Queue adapter:
|
|
207
|
+
Create migration SQL with:
|
|
297
208
|
|
|
298
209
|
```ts
|
|
299
210
|
import {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
} from "bcp/jobs";
|
|
303
|
-
|
|
304
|
-
const adapter =
|
|
305
|
-
createRedisJobQueueAdapter({
|
|
306
|
-
client: redisCommandClient,
|
|
307
|
-
namespace: "my-app:{jobs}",
|
|
308
|
-
});
|
|
211
|
+
createOutboxMigrationSql,
|
|
212
|
+
} from "bcp/events";
|
|
309
213
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
214
|
+
const migrationSql =
|
|
215
|
+
createOutboxMigrationSql(
|
|
216
|
+
"mysql"
|
|
217
|
+
);
|
|
314
218
|
```
|
|
315
219
|
|
|
316
|
-
|
|
220
|
+
After commit, dispatch to the durable job queue:
|
|
317
221
|
|
|
318
222
|
```ts
|
|
319
223
|
import {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
} from "bcp/jobs";
|
|
323
|
-
|
|
324
|
-
const store =
|
|
325
|
-
createRedisJobScheduleStore({
|
|
326
|
-
client: redisCommandClient,
|
|
327
|
-
namespace: "my-app:{jobs}",
|
|
328
|
-
});
|
|
224
|
+
createOutboxDispatcher,
|
|
225
|
+
} from "bcp/events";
|
|
329
226
|
|
|
330
|
-
|
|
331
|
-
|
|
227
|
+
const dispatcher =
|
|
228
|
+
createOutboxDispatcher({
|
|
229
|
+
store: outboxStore,
|
|
332
230
|
queue: jobs,
|
|
333
|
-
|
|
334
|
-
ownerId: "scheduler-a",
|
|
231
|
+
ownerId: "outbox-a",
|
|
335
232
|
});
|
|
233
|
+
|
|
234
|
+
const runner =
|
|
235
|
+
dispatcher.start();
|
|
336
236
|
```
|
|
337
237
|
|
|
338
|
-
|
|
238
|
+
Event type `order.created` is handed off to queue name `event.order.created`.
|
|
339
239
|
|
|
340
|
-
|
|
341
|
-
REDIS_URL=redis://localhost:6379
|
|
342
|
-
```
|
|
240
|
+
The outbox dispatcher supports leases, stale recovery, retry/backoff, custom publishers, a local EventBus, cleanup and statistics.
|
|
343
241
|
|
|
344
|
-
|
|
242
|
+
`bcp/events` is server-only. The SQL outbox protects the database-commit/external-publish boundary, but downstream delivery remains at-least-once, so non-repeatable side effects should use idempotency protection.
|
|
345
243
|
|
|
346
|
-
|
|
244
|
+
## Storage providers
|
|
347
245
|
|
|
348
|
-
|
|
246
|
+
Supported presets are Local Server, Amazon S3 and Cloudflare R2. Storage credentials are server-only and must not use `BCP_PUBLIC_*` variables.
|
|
349
247
|
|
|
350
|
-
|
|
248
|
+
## Application packaging
|
|
351
249
|
|
|
352
250
|
```bash
|
|
353
251
|
npm run package
|
|
@@ -355,7 +253,7 @@ npm run package
|
|
|
355
253
|
|
|
356
254
|
The deployment package excludes application `devDependencies` and project `.env` values. Supply real secrets through the deployment environment.
|
|
357
255
|
|
|
358
|
-
## Project generators
|
|
256
|
+
## Project generators
|
|
359
257
|
|
|
360
258
|
```bash
|
|
361
259
|
npm run generate -- page dashboard/users
|
|
@@ -364,15 +262,6 @@ npm run generate -- middleware
|
|
|
364
262
|
npm run generate -- migration create_users
|
|
365
263
|
```
|
|
366
264
|
|
|
367
|
-
Equivalent direct CLI:
|
|
368
|
-
|
|
369
|
-
```bash
|
|
370
|
-
bcp generate page dashboard/users
|
|
371
|
-
bcp generate api users
|
|
372
|
-
bcp generate middleware
|
|
373
|
-
bcp generate migration create_users
|
|
374
|
-
```
|
|
375
|
-
|
|
376
265
|
## Options
|
|
377
266
|
|
|
378
267
|
```text
|
|
@@ -387,8 +276,8 @@ bcp generate migration create_users
|
|
|
387
276
|
-h, --help Show help
|
|
388
277
|
```
|
|
389
278
|
|
|
390
|
-
|
|
279
|
+
For prerelease/local package verification:
|
|
391
280
|
|
|
392
281
|
```bash
|
|
393
|
-
npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.
|
|
282
|
+
npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.12.tgz
|
|
394
283
|
```
|
package/package.json
CHANGED
package/template/README.md
CHANGED
|
@@ -12,8 +12,6 @@ Open `http://localhost:3000`.
|
|
|
12
12
|
|
|
13
13
|
## Project commands
|
|
14
14
|
|
|
15
|
-
Generated projects use the project-local BCP Framework CLI through npm scripts:
|
|
16
|
-
|
|
17
15
|
```bash
|
|
18
16
|
npm run dev
|
|
19
17
|
npm run routes
|
|
@@ -25,25 +23,17 @@ npm start
|
|
|
25
23
|
npm run update
|
|
26
24
|
```
|
|
27
25
|
|
|
28
|
-
The generated scripts call commands such as `bcp dev`, `bcp generate`, `bcp build`, `bcp package` and `bcp start`.
|
|
29
|
-
|
|
30
26
|
## Project metadata
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
Commit this file with the project. Do not put passwords, access keys, session secrets or tokens in it.
|
|
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.
|
|
35
29
|
|
|
36
30
|
## Authentication — BCP 0.2.5+
|
|
37
31
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
BCP Authentication Platform v2 can opt into revocable server-side session state with `createAuth()` and `AuthSessionStore`.
|
|
32
|
+
JWT Cookie projects can opt into revocable server-side session state with `createAuth()` and `AuthSessionStore`.
|
|
41
33
|
|
|
42
34
|
## Authorization & request security — BCP 0.2.6+
|
|
43
35
|
|
|
44
|
-
Use permission guards
|
|
45
|
-
|
|
46
|
-
Authorization must always be enforced server-side. Client UI visibility is not a security boundary.
|
|
36
|
+
Use permission guards/resource policies from `bcp/auth`, and same-origin/CSRF protection from `bcp/server`. Authorization must remain server-side.
|
|
47
37
|
|
|
48
38
|
## Observability — BCP 0.2.7+
|
|
49
39
|
|
|
@@ -51,16 +41,11 @@ Authorization must always be enforced server-side. Client UI visibility is not a
|
|
|
51
41
|
import {
|
|
52
42
|
createHealthRegistry,
|
|
53
43
|
createMetricsRegistry,
|
|
54
|
-
createRequestMetricsMiddleware,
|
|
55
44
|
} from "bcp/observability";
|
|
56
45
|
```
|
|
57
46
|
|
|
58
|
-
Protect operational endpoints when their contents should not be public.
|
|
59
|
-
|
|
60
47
|
## Background jobs — BCP 0.2.8+
|
|
61
48
|
|
|
62
|
-
Create a server-only background queue:
|
|
63
|
-
|
|
64
49
|
```ts
|
|
65
50
|
import {
|
|
66
51
|
createJobQueue,
|
|
@@ -70,21 +55,6 @@ export const jobs =
|
|
|
70
55
|
createJobQueue();
|
|
71
56
|
```
|
|
72
57
|
|
|
73
|
-
Register typed work:
|
|
74
|
-
|
|
75
|
-
```ts
|
|
76
|
-
jobs.register<{
|
|
77
|
-
userId: number;
|
|
78
|
-
}>(
|
|
79
|
-
"email.welcome",
|
|
80
|
-
async ({ payload }) => {
|
|
81
|
-
await sendWelcomeEmail(
|
|
82
|
-
payload.userId
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
);
|
|
86
|
-
```
|
|
87
|
-
|
|
88
58
|
## Job scheduling — BCP 0.2.9+
|
|
89
59
|
|
|
90
60
|
```ts
|
|
@@ -98,21 +68,9 @@ export const scheduler =
|
|
|
98
68
|
});
|
|
99
69
|
```
|
|
100
70
|
|
|
101
|
-
Example UTC cron schedule:
|
|
102
|
-
|
|
103
|
-
```ts
|
|
104
|
-
await scheduler.schedule(
|
|
105
|
-
"report.weekday",
|
|
106
|
-
{},
|
|
107
|
-
{
|
|
108
|
-
cron: "30 9 * * 1-5",
|
|
109
|
-
}
|
|
110
|
-
);
|
|
111
|
-
```
|
|
112
|
-
|
|
113
71
|
## Durable jobs — BCP 0.2.10+
|
|
114
72
|
|
|
115
|
-
Workers can use visibility leases, heartbeat renewal and
|
|
73
|
+
Workers can use visibility leases, heartbeat renewal, stale recovery and DLQ/requeue. Redis-compatible adapters are available without forcing a Redis client dependency.
|
|
116
74
|
|
|
117
75
|
```ts
|
|
118
76
|
const worker =
|
|
@@ -124,97 +82,109 @@ const worker =
|
|
|
124
82
|
});
|
|
125
83
|
```
|
|
126
84
|
|
|
127
|
-
|
|
85
|
+
## Workflow orchestration — BCP 0.2.11+
|
|
128
86
|
|
|
129
87
|
```ts
|
|
130
|
-
|
|
131
|
-
|
|
88
|
+
import {
|
|
89
|
+
createWorkflow,
|
|
90
|
+
} from "bcp/workflow";
|
|
132
91
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
+
);
|
|
139
106
|
```
|
|
140
107
|
|
|
141
|
-
|
|
108
|
+
Workflows support sequential/parallel steps, retries, persisted delays, compensation, run leases and optional durable queue execution.
|
|
109
|
+
|
|
110
|
+
## Transactional Outbox & Events — BCP 0.2.12+
|
|
111
|
+
|
|
112
|
+
Use `bcp/events` when application data and an integration event must commit atomically in the same SQL transaction.
|
|
142
113
|
|
|
143
114
|
```ts
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
115
|
+
import {
|
|
116
|
+
db,
|
|
117
|
+
} from "bcp/database";
|
|
118
|
+
|
|
119
|
+
import {
|
|
120
|
+
createSqlOutboxStore,
|
|
121
|
+
createTransactionalOutbox,
|
|
122
|
+
} from "bcp/events";
|
|
123
|
+
|
|
124
|
+
const outboxStore =
|
|
125
|
+
createSqlOutboxStore({
|
|
126
|
+
database: db,
|
|
127
|
+
driver: "mysql",
|
|
128
|
+
});
|
|
152
129
|
|
|
153
|
-
|
|
130
|
+
const outbox =
|
|
131
|
+
createTransactionalOutbox({
|
|
132
|
+
store: outboxStore,
|
|
133
|
+
});
|
|
154
134
|
|
|
155
|
-
|
|
135
|
+
await db.transaction(
|
|
136
|
+
async tx => {
|
|
137
|
+
await tx.execute(
|
|
138
|
+
"INSERT INTO orders ..."
|
|
139
|
+
);
|
|
156
140
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
141
|
+
await outbox.publish(
|
|
142
|
+
tx,
|
|
143
|
+
"order.created",
|
|
144
|
+
{
|
|
145
|
+
orderId: 42,
|
|
146
|
+
}
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
);
|
|
163
150
|
```
|
|
164
151
|
|
|
165
|
-
|
|
152
|
+
Generate the required table SQL:
|
|
166
153
|
|
|
167
154
|
```ts
|
|
168
155
|
import {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
} from "bcp/jobs";
|
|
172
|
-
|
|
173
|
-
const adapter =
|
|
174
|
-
createRedisJobQueueAdapter({
|
|
175
|
-
client: redisCommandClient,
|
|
176
|
-
namespace: "my-app:{jobs}",
|
|
177
|
-
});
|
|
156
|
+
createOutboxMigrationSql,
|
|
157
|
+
} from "bcp/events";
|
|
178
158
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
159
|
+
const sql =
|
|
160
|
+
createOutboxMigrationSql(
|
|
161
|
+
"mysql"
|
|
162
|
+
);
|
|
183
163
|
```
|
|
184
164
|
|
|
185
|
-
|
|
165
|
+
Dispatch committed events to the durable queue:
|
|
186
166
|
|
|
187
167
|
```ts
|
|
188
168
|
import {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
} from "bcp/jobs";
|
|
169
|
+
createOutboxDispatcher,
|
|
170
|
+
} from "bcp/events";
|
|
192
171
|
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
namespace: "my-app:{jobs}",
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
export const scheduler =
|
|
200
|
-
createJobScheduler({
|
|
172
|
+
const dispatcher =
|
|
173
|
+
createOutboxDispatcher({
|
|
174
|
+
store: outboxStore,
|
|
201
175
|
queue: jobs,
|
|
202
|
-
|
|
203
|
-
ownerId: "scheduler-a",
|
|
176
|
+
ownerId: "outbox-a",
|
|
204
177
|
});
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
A typical deployment may use:
|
|
208
178
|
|
|
209
|
-
|
|
210
|
-
|
|
179
|
+
const runner =
|
|
180
|
+
dispatcher.start();
|
|
211
181
|
```
|
|
212
182
|
|
|
213
|
-
|
|
183
|
+
Event `order.created` is queued as `event.order.created`.
|
|
214
184
|
|
|
215
|
-
The
|
|
185
|
+
The dispatcher supports leases, stale recovery, retry/backoff, custom publishers, local EventBus delivery, retention cleanup and statistics.
|
|
216
186
|
|
|
217
|
-
`bcp/
|
|
187
|
+
`bcp/events` is server-only. Outbox delivery remains at-least-once, so non-repeatable downstream side effects should use idempotency protection.
|
|
218
188
|
|
|
219
189
|
## Generate framework files
|
|
220
190
|
|
|
@@ -225,22 +195,9 @@ npm run generate -- middleware
|
|
|
225
195
|
npm run generate -- migration create_users
|
|
226
196
|
```
|
|
227
197
|
|
|
228
|
-
Equivalent direct commands:
|
|
229
|
-
|
|
230
|
-
```bash
|
|
231
|
-
bcp generate page dashboard/users
|
|
232
|
-
bcp generate api users
|
|
233
|
-
bcp generate middleware
|
|
234
|
-
bcp generate migration create_users
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
Existing page/API/middleware targets are not replaced unless `--force` is supplied explicitly.
|
|
238
|
-
|
|
239
198
|
## Direct CLI usage
|
|
240
199
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
For PowerShell direct usage:
|
|
200
|
+
For PowerShell:
|
|
244
201
|
|
|
245
202
|
```powershell
|
|
246
203
|
npm exec -- bcp-framework --version
|
|
@@ -252,8 +209,6 @@ npm exec -- bcp-framework build
|
|
|
252
209
|
npm exec -- bcp-framework package
|
|
253
210
|
```
|
|
254
211
|
|
|
255
|
-
Microsoft SQL Server can install another Windows executable named `bcp.exe`, so the `bcp-framework` alias avoids that command-name collision.
|
|
256
|
-
|
|
257
212
|
## Production build
|
|
258
213
|
|
|
259
214
|
```bash
|
|
@@ -261,12 +216,10 @@ npm run build
|
|
|
261
216
|
npm start
|
|
262
217
|
```
|
|
263
218
|
|
|
264
|
-
## Deployment package
|
|
219
|
+
## Deployment package
|
|
265
220
|
|
|
266
221
|
```bash
|
|
267
222
|
npm run package
|
|
268
223
|
```
|
|
269
224
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
BCP intentionally excludes project `.env` files and application `devDependencies` from the deployment package. Provide secrets through your deployment environment.
|
|
225
|
+
BCP excludes project `.env` files and application `devDependencies` from the deployment package. Supply secrets through the deployment environment.
|