create-bcp-app 0.2.11 → 0.2.13
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 +100 -195
- package/package.json +1 -1
- package/template/README.md +74 -198
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.13` 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.13",
|
|
96
80
|
"createdWith": {
|
|
97
81
|
"package": "create-bcp-app",
|
|
98
|
-
"version": "0.2.
|
|
82
|
+
"version": "0.2.13"
|
|
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
|
|
157
|
-
|
|
158
|
-
The generator intentionally does not force an ORM.
|
|
159
|
-
|
|
160
|
-
## Storage providers
|
|
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.
|
|
106
|
+
For MySQL, PostgreSQL and SQLite, generated `lib/database.ts` exposes BCP database primitives through `bcp/database`.
|
|
165
107
|
|
|
166
|
-
##
|
|
108
|
+
## Authentication and security
|
|
167
109
|
|
|
168
|
-
|
|
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,82 +135,23 @@ export const scheduler =
|
|
|
225
135
|
});
|
|
226
136
|
```
|
|
227
137
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
```ts
|
|
231
|
-
await scheduler.schedule(
|
|
232
|
-
"cache.cleanup",
|
|
233
|
-
{},
|
|
234
|
-
{
|
|
235
|
-
everyMs: 300_000,
|
|
236
|
-
}
|
|
237
|
-
);
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
UTC cron schedule:
|
|
241
|
-
|
|
242
|
-
```ts
|
|
243
|
-
await scheduler.schedule(
|
|
244
|
-
"report.weekday",
|
|
245
|
-
{},
|
|
246
|
-
{
|
|
247
|
-
cron: "30 9 * * 1-5",
|
|
248
|
-
}
|
|
249
|
-
);
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
## Durable jobs — 0.2.10+
|
|
253
|
-
|
|
254
|
-
BCP `0.2.10` adds worker visibility leases, heartbeat renewal, stale-running recovery, DLQ/requeue, retention cleanup and queue statistics.
|
|
255
|
-
|
|
256
|
-
```ts
|
|
257
|
-
const worker =
|
|
258
|
-
jobs.startWorker({
|
|
259
|
-
workerId: "worker-a",
|
|
260
|
-
concurrency: 4,
|
|
261
|
-
visibilityTimeoutMs: 30_000,
|
|
262
|
-
heartbeatIntervalMs: 10_000,
|
|
263
|
-
});
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
BCP intentionally does not install a Redis client library. Applications own the Redis connection and can pass a minimal `RedisCommandClient` to `createRedisJobQueueAdapter()` and `createRedisJobScheduleStore()`.
|
|
267
|
-
|
|
268
|
-
`bcp/jobs` is server-only and must not be imported into page/client bundles.
|
|
138
|
+
`0.2.10+` adds visibility leases, heartbeat renewal, stale-running recovery, DLQ/requeue, retention cleanup and Redis-compatible durable adapters.
|
|
269
139
|
|
|
270
140
|
## Workflow orchestration — 0.2.11+
|
|
271
141
|
|
|
272
|
-
Generated applications can define persistent backend workflows with the new server-only `bcp/workflow` entrypoint:
|
|
273
|
-
|
|
274
142
|
```ts
|
|
275
143
|
import {
|
|
276
144
|
createWorkflow,
|
|
277
145
|
} from "bcp/workflow";
|
|
278
146
|
|
|
279
147
|
export const onboarding =
|
|
280
|
-
createWorkflow
|
|
281
|
-
userId: number;
|
|
282
|
-
}>(
|
|
148
|
+
createWorkflow(
|
|
283
149
|
"user.onboarding",
|
|
284
150
|
workflow => {
|
|
285
151
|
workflow.step(
|
|
286
152
|
"profile",
|
|
287
153
|
createProfile
|
|
288
154
|
);
|
|
289
|
-
|
|
290
|
-
workflow.parallel(
|
|
291
|
-
"initialize",
|
|
292
|
-
parallel => {
|
|
293
|
-
parallel.step(
|
|
294
|
-
"preferences",
|
|
295
|
-
createPreferences
|
|
296
|
-
);
|
|
297
|
-
parallel.step(
|
|
298
|
-
"workspace",
|
|
299
|
-
createWorkspace
|
|
300
|
-
);
|
|
301
|
-
}
|
|
302
|
-
);
|
|
303
|
-
|
|
304
155
|
workflow.delay(
|
|
305
156
|
"cooldown",
|
|
306
157
|
1_000
|
|
@@ -309,45 +160,108 @@ export const onboarding =
|
|
|
309
160
|
);
|
|
310
161
|
```
|
|
311
162
|
|
|
312
|
-
|
|
163
|
+
`bcp/workflow` supports sequential/parallel steps, retry, persisted delays, compensation and optional execution through `bcp/jobs`.
|
|
164
|
+
|
|
165
|
+
## Transactional Outbox & Events — 0.2.12+
|
|
166
|
+
|
|
167
|
+
Applications using the SQL Database Platform can persist integration events in the same transaction as business data:
|
|
313
168
|
|
|
314
169
|
```ts
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
170
|
+
await db.transaction(
|
|
171
|
+
async tx => {
|
|
172
|
+
await tx.execute(
|
|
173
|
+
"INSERT INTO orders ..."
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
await outbox.publish(
|
|
177
|
+
tx,
|
|
178
|
+
"order.created",
|
|
179
|
+
{
|
|
180
|
+
orderId: 42,
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
After commit, `createOutboxDispatcher()` can hand off events to durable jobs/custom publishers.
|
|
188
|
+
|
|
189
|
+
## Realtime Platform — 0.2.13+
|
|
190
|
+
|
|
191
|
+
Generated applications can add server-side realtime channels without changing the scaffold preset model:
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
import {
|
|
195
|
+
createRealtime,
|
|
196
|
+
} from "bcp/realtime";
|
|
197
|
+
|
|
198
|
+
export const realtime =
|
|
199
|
+
createRealtime();
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Channel/room usage:
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
const connection =
|
|
206
|
+
await realtime.connect();
|
|
207
|
+
|
|
208
|
+
await connection.join(
|
|
209
|
+
"orders:42"
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
await realtime.broadcast(
|
|
213
|
+
"orders:42",
|
|
214
|
+
"order.updated",
|
|
318
215
|
{
|
|
319
|
-
|
|
320
|
-
retryDelayMs: 1_000,
|
|
321
|
-
compensate:
|
|
322
|
-
releaseStock,
|
|
216
|
+
status: "paid",
|
|
323
217
|
}
|
|
324
218
|
);
|
|
325
219
|
```
|
|
326
220
|
|
|
327
|
-
|
|
221
|
+
Presence metadata can be attached during `join()` and read with `realtime.members(channel)`.
|
|
222
|
+
|
|
223
|
+
For private channels, configure `authenticate`, `getUserId` and `authorizeChannel` on `createRealtime()`.
|
|
224
|
+
|
|
225
|
+
### WebSocket integration
|
|
226
|
+
|
|
227
|
+
BCP does not install a WebSocket library. Adapt your selected provider to `RealtimeSocket` and pass it to:
|
|
328
228
|
|
|
329
229
|
```ts
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
230
|
+
await realtime.attachSocket(
|
|
231
|
+
socketAdapter,
|
|
232
|
+
{
|
|
233
|
+
request,
|
|
234
|
+
}
|
|
235
|
+
);
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Server-Sent Events
|
|
239
|
+
|
|
240
|
+
SSE is available without another dependency:
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
export function GET(
|
|
244
|
+
request: Request
|
|
245
|
+
) {
|
|
246
|
+
return realtime.sse(
|
|
247
|
+
"jobs:42",
|
|
334
248
|
{
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
workflowStore,
|
|
249
|
+
signal:
|
|
250
|
+
request.signal,
|
|
338
251
|
}
|
|
339
252
|
);
|
|
253
|
+
}
|
|
340
254
|
```
|
|
341
255
|
|
|
342
|
-
The
|
|
256
|
+
The memory broker/presence store are local-only. Multi-instance production deployments should provide shared `RealtimeBroker` and `RealtimePresenceStore` implementations.
|
|
343
257
|
|
|
344
|
-
|
|
258
|
+
`bcp/realtime` is server-only and cannot be imported into page/client bundles.
|
|
345
259
|
|
|
346
|
-
|
|
260
|
+
## Storage providers
|
|
347
261
|
|
|
348
|
-
|
|
262
|
+
Supported presets are Local Server, Amazon S3 and Cloudflare R2. Storage credentials are server-only and must not use `BCP_PUBLIC_*` variables.
|
|
349
263
|
|
|
350
|
-
|
|
264
|
+
## Application packaging
|
|
351
265
|
|
|
352
266
|
```bash
|
|
353
267
|
npm run package
|
|
@@ -355,7 +269,7 @@ npm run package
|
|
|
355
269
|
|
|
356
270
|
The deployment package excludes application `devDependencies` and project `.env` values. Supply real secrets through the deployment environment.
|
|
357
271
|
|
|
358
|
-
## Project generators
|
|
272
|
+
## Project generators
|
|
359
273
|
|
|
360
274
|
```bash
|
|
361
275
|
npm run generate -- page dashboard/users
|
|
@@ -364,15 +278,6 @@ npm run generate -- middleware
|
|
|
364
278
|
npm run generate -- migration create_users
|
|
365
279
|
```
|
|
366
280
|
|
|
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
281
|
## Options
|
|
377
282
|
|
|
378
283
|
```text
|
|
@@ -387,8 +292,8 @@ bcp generate migration create_users
|
|
|
387
292
|
-h, --help Show help
|
|
388
293
|
```
|
|
389
294
|
|
|
390
|
-
|
|
295
|
+
For prerelease/local package verification:
|
|
391
296
|
|
|
392
297
|
```bash
|
|
393
|
-
npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.
|
|
298
|
+
npx create-bcp-app my-app --bcp file:../chidchanun-bcp-0.2.13.tgz
|
|
394
299
|
```
|
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,132 +82,21 @@ const worker =
|
|
|
124
82
|
});
|
|
125
83
|
```
|
|
126
84
|
|
|
127
|
-
Retry-exhausted jobs are available through the adapter DLQ contract:
|
|
128
|
-
|
|
129
|
-
```ts
|
|
130
|
-
const deadLetters =
|
|
131
|
-
await jobs.deadLetters();
|
|
132
|
-
|
|
133
|
-
await jobs.requeueDeadLetter(
|
|
134
|
-
deadLetters[0].id,
|
|
135
|
-
{
|
|
136
|
-
resetAttempts: true,
|
|
137
|
-
}
|
|
138
|
-
);
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
Operational helpers:
|
|
142
|
-
|
|
143
|
-
```ts
|
|
144
|
-
await jobs.recoverStale();
|
|
145
|
-
const stats = await jobs.stats();
|
|
146
|
-
await jobs.cleanup({
|
|
147
|
-
before:
|
|
148
|
-
Date.now() -
|
|
149
|
-
7 * 24 * 60 * 60 * 1000,
|
|
150
|
-
});
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### Redis-compatible adapters
|
|
154
|
-
|
|
155
|
-
BCP does not install a Redis library. Supply an application-owned command client:
|
|
156
|
-
|
|
157
|
-
```ts
|
|
158
|
-
interface RedisCommandClient {
|
|
159
|
-
sendCommand(
|
|
160
|
-
command: string[]
|
|
161
|
-
): Promise<unknown>;
|
|
162
|
-
}
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
Create a durable queue:
|
|
166
|
-
|
|
167
|
-
```ts
|
|
168
|
-
import {
|
|
169
|
-
createJobQueue,
|
|
170
|
-
createRedisJobQueueAdapter,
|
|
171
|
-
} from "bcp/jobs";
|
|
172
|
-
|
|
173
|
-
const adapter =
|
|
174
|
-
createRedisJobQueueAdapter({
|
|
175
|
-
client: redisCommandClient,
|
|
176
|
-
namespace: "my-app:{jobs}",
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
export const jobs =
|
|
180
|
-
createJobQueue({
|
|
181
|
-
adapter,
|
|
182
|
-
});
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
Create a shared schedule store:
|
|
186
|
-
|
|
187
|
-
```ts
|
|
188
|
-
import {
|
|
189
|
-
createJobScheduler,
|
|
190
|
-
createRedisJobScheduleStore,
|
|
191
|
-
} from "bcp/jobs";
|
|
192
|
-
|
|
193
|
-
const store =
|
|
194
|
-
createRedisJobScheduleStore({
|
|
195
|
-
client: redisCommandClient,
|
|
196
|
-
namespace: "my-app:{jobs}",
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
export const scheduler =
|
|
200
|
-
createJobScheduler({
|
|
201
|
-
queue: jobs,
|
|
202
|
-
store,
|
|
203
|
-
ownerId: "scheduler-a",
|
|
204
|
-
});
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
A typical deployment may use:
|
|
208
|
-
|
|
209
|
-
```dotenv
|
|
210
|
-
REDIS_URL=redis://localhost:6379
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
BCP does not read this variable automatically. The application owns Redis connection creation, credentials, TLS/Cluster configuration and shutdown.
|
|
214
|
-
|
|
215
|
-
The processing model is at-least-once, so side-effecting job handlers should be idempotent when duplicate execution is unsafe.
|
|
216
|
-
|
|
217
|
-
`bcp/jobs` is server-only and cannot be imported into page/client bundles.
|
|
218
|
-
|
|
219
85
|
## Workflow orchestration — BCP 0.2.11+
|
|
220
86
|
|
|
221
|
-
Define persistent server-side workflows through `bcp/workflow`:
|
|
222
|
-
|
|
223
87
|
```ts
|
|
224
88
|
import {
|
|
225
89
|
createWorkflow,
|
|
226
90
|
} from "bcp/workflow";
|
|
227
91
|
|
|
228
92
|
export const onboarding =
|
|
229
|
-
createWorkflow
|
|
230
|
-
userId: number;
|
|
231
|
-
}>(
|
|
93
|
+
createWorkflow(
|
|
232
94
|
"user.onboarding",
|
|
233
95
|
workflow => {
|
|
234
96
|
workflow.step(
|
|
235
97
|
"profile",
|
|
236
98
|
createProfile
|
|
237
99
|
);
|
|
238
|
-
|
|
239
|
-
workflow.parallel(
|
|
240
|
-
"initialize",
|
|
241
|
-
parallel => {
|
|
242
|
-
parallel.step(
|
|
243
|
-
"preferences",
|
|
244
|
-
createPreferences
|
|
245
|
-
);
|
|
246
|
-
parallel.step(
|
|
247
|
-
"workspace",
|
|
248
|
-
createWorkspace
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
);
|
|
252
|
-
|
|
253
100
|
workflow.delay(
|
|
254
101
|
"cooldown",
|
|
255
102
|
1_000
|
|
@@ -258,41 +105,87 @@ export const onboarding =
|
|
|
258
105
|
);
|
|
259
106
|
```
|
|
260
107
|
|
|
261
|
-
|
|
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.
|
|
262
113
|
|
|
263
114
|
```ts
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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:
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
import {
|
|
140
|
+
createRealtime,
|
|
141
|
+
} from "bcp/realtime";
|
|
142
|
+
|
|
143
|
+
export const realtime =
|
|
144
|
+
createRealtime();
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Channels/rooms:
|
|
148
|
+
|
|
149
|
+
```ts
|
|
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",
|
|
267
160
|
{
|
|
268
|
-
|
|
269
|
-
retryDelayMs: 1_000,
|
|
270
|
-
compensate:
|
|
271
|
-
releaseStock,
|
|
161
|
+
status: "paid",
|
|
272
162
|
}
|
|
273
163
|
);
|
|
274
164
|
```
|
|
275
165
|
|
|
276
|
-
|
|
166
|
+
Presence metadata can be supplied during `join()` and queried with `realtime.members(channel)`.
|
|
167
|
+
|
|
168
|
+
BCP does not install a WebSocket server dependency. Adapt the selected provider to `RealtimeSocket` and call `realtime.attachSocket(socketAdapter, { request })`.
|
|
169
|
+
|
|
170
|
+
SSE is built in:
|
|
277
171
|
|
|
278
172
|
```ts
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
173
|
+
export function GET(
|
|
174
|
+
request: Request
|
|
175
|
+
) {
|
|
176
|
+
return realtime.sse(
|
|
177
|
+
"jobs:42",
|
|
283
178
|
{
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
workflowStore,
|
|
179
|
+
signal:
|
|
180
|
+
request.signal,
|
|
287
181
|
}
|
|
288
182
|
);
|
|
183
|
+
}
|
|
289
184
|
```
|
|
290
185
|
|
|
291
|
-
|
|
186
|
+
For multi-instance deployment, replace the memory broker/presence store with shared `RealtimeBroker` and `RealtimePresenceStore` implementations.
|
|
292
187
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
`bcp/workflow` is server-only and cannot be imported into page/client bundles.
|
|
188
|
+
`bcp/realtime` is server-only and cannot be imported into page/client bundles.
|
|
296
189
|
|
|
297
190
|
## Generate framework files
|
|
298
191
|
|
|
@@ -303,22 +196,9 @@ npm run generate -- middleware
|
|
|
303
196
|
npm run generate -- migration create_users
|
|
304
197
|
```
|
|
305
198
|
|
|
306
|
-
Equivalent direct commands:
|
|
307
|
-
|
|
308
|
-
```bash
|
|
309
|
-
bcp generate page dashboard/users
|
|
310
|
-
bcp generate api users
|
|
311
|
-
bcp generate middleware
|
|
312
|
-
bcp generate migration create_users
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
Existing page/API/middleware targets are not replaced unless `--force` is supplied explicitly.
|
|
316
|
-
|
|
317
199
|
## Direct CLI usage
|
|
318
200
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
For PowerShell direct usage:
|
|
201
|
+
For PowerShell:
|
|
322
202
|
|
|
323
203
|
```powershell
|
|
324
204
|
npm exec -- bcp-framework --version
|
|
@@ -330,8 +210,6 @@ npm exec -- bcp-framework build
|
|
|
330
210
|
npm exec -- bcp-framework package
|
|
331
211
|
```
|
|
332
212
|
|
|
333
|
-
Microsoft SQL Server can install another Windows executable named `bcp.exe`, so the `bcp-framework` alias avoids that command-name collision.
|
|
334
|
-
|
|
335
213
|
## Production build
|
|
336
214
|
|
|
337
215
|
```bash
|
|
@@ -339,12 +217,10 @@ npm run build
|
|
|
339
217
|
npm start
|
|
340
218
|
```
|
|
341
219
|
|
|
342
|
-
## Deployment package
|
|
220
|
+
## Deployment package
|
|
343
221
|
|
|
344
222
|
```bash
|
|
345
223
|
npm run package
|
|
346
224
|
```
|
|
347
225
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
BCP intentionally excludes project `.env` files and application `devDependencies` from the deployment package. Provide secrets through your deployment environment.
|
|
226
|
+
BCP excludes project `.env` files and application `devDependencies` from the deployment package. Supply secrets through the deployment environment.
|