bkper 4.13.6 → 4.14.0
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/lib/commands/apps/build.d.ts +1 -2
- package/lib/commands/apps/build.d.ts.map +1 -1
- package/lib/commands/apps/build.js +13 -39
- package/lib/commands/apps/build.js.map +1 -1
- package/lib/commands/apps/config.d.ts +5 -14
- package/lib/commands/apps/config.d.ts.map +1 -1
- package/lib/commands/apps/config.js +13 -45
- package/lib/commands/apps/config.js.map +1 -1
- package/lib/commands/apps/deploy.d.ts +14 -4
- package/lib/commands/apps/deploy.d.ts.map +1 -1
- package/lib/commands/apps/deploy.js +42 -58
- package/lib/commands/apps/deploy.js.map +1 -1
- package/lib/commands/apps/dev.d.ts +1 -7
- package/lib/commands/apps/dev.d.ts.map +1 -1
- package/lib/commands/apps/dev.js +44 -111
- package/lib/commands/apps/dev.js.map +1 -1
- package/lib/commands/apps/init.d.ts +1 -1
- package/lib/commands/apps/init.d.ts.map +1 -1
- package/lib/commands/apps/init.js +6 -12
- package/lib/commands/apps/init.js.map +1 -1
- package/lib/commands/apps/register.d.ts.map +1 -1
- package/lib/commands/apps/register.js +3 -11
- package/lib/commands/apps/register.js.map +1 -1
- package/lib/commands/apps/types.d.ts +3 -27
- package/lib/commands/apps/types.d.ts.map +1 -1
- package/lib/dev/local-assets.d.ts +15 -0
- package/lib/dev/local-assets.d.ts.map +1 -0
- package/lib/dev/local-assets.js +43 -0
- package/lib/dev/local-assets.js.map +1 -0
- package/lib/dev/local-outbound.d.ts +8 -0
- package/lib/dev/local-outbound.d.ts.map +1 -0
- package/lib/dev/local-outbound.js +88 -0
- package/lib/dev/local-outbound.js.map +1 -0
- package/lib/dev/logger.d.ts +3 -7
- package/lib/dev/logger.d.ts.map +1 -1
- package/lib/dev/logger.js +3 -6
- package/lib/dev/logger.js.map +1 -1
- package/lib/dev/miniflare.d.ts +4 -0
- package/lib/dev/miniflare.d.ts.map +1 -1
- package/lib/dev/miniflare.js +85 -21
- package/lib/dev/miniflare.js.map +1 -1
- package/lib/docs/app-building.md +151 -141
- package/lib/docs/app-management.md +43 -28
- package/lib/docs/bkper-js.md +2 -0
- package/lib/docs/index.md +1 -1
- package/lib/platform/client.d.ts +2 -2
- package/lib/platform/client.js +2 -2
- package/package.json +2 -2
package/lib/docs/app-building.md
CHANGED
|
@@ -86,32 +86,38 @@ source: /docs/build/apps/architecture.md
|
|
|
86
86
|
|
|
87
87
|
# App Architecture
|
|
88
88
|
|
|
89
|
-
Bkper platform apps
|
|
89
|
+
Bkper platform apps use one Worker bundle per app and environment. The same Worker serves the browser client, app-defined `/api/*` routes, and Bkper event ingress at `/events`.
|
|
90
90
|
|
|
91
91
|
## Structure
|
|
92
92
|
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
├──
|
|
96
|
-
├──
|
|
97
|
-
│
|
|
98
|
-
|
|
99
|
-
└──
|
|
93
|
+
```txt
|
|
94
|
+
my-app/
|
|
95
|
+
├── client/
|
|
96
|
+
│ ├── index.html
|
|
97
|
+
│ └── src/ — Frontend UI (Vite + Lit)
|
|
98
|
+
├── server/
|
|
99
|
+
│ └── src/
|
|
100
|
+
│ ├── index.ts
|
|
101
|
+
│ └── handlers/
|
|
102
|
+
├── bkper.yaml
|
|
103
|
+
├── package.json
|
|
104
|
+
├── tsconfig.json
|
|
105
|
+
└── vite.config.ts
|
|
100
106
|
```
|
|
101
107
|
|
|
102
|
-
The
|
|
108
|
+
The default template is intentionally not a monorepo. Add a shared package only when the app actually needs one.
|
|
103
109
|
|
|
104
|
-
##
|
|
110
|
+
## Client
|
|
105
111
|
|
|
106
|
-
The client
|
|
112
|
+
The client folder builds a browser UI with [Lit](https://lit.dev/) and [@bkper/web-design](https://www.npmjs.com/package/@bkper/web-design) for consistent Bkper styling.
|
|
107
113
|
|
|
108
114
|
- Built with [Vite](https://vitejs.dev/) — configured in the project's `vite.config.ts` for fast builds and HMR during development
|
|
109
|
-
-
|
|
115
|
+
- Built assets are deployed with the same Worker
|
|
110
116
|
- Communicates with Bkper via `bkper-js`
|
|
111
117
|
|
|
112
118
|
This is where your app's UI lives — book pickers, account lists, reports, forms.
|
|
113
119
|
|
|
114
|
-
###
|
|
120
|
+
### Client authentication
|
|
115
121
|
|
|
116
122
|
The client authenticates users via the [`@bkper/web-auth`](https://www.npmjs.com/package/@bkper/web-auth) SDK. OAuth is pre-configured on the platform — no client IDs, redirect URIs, or consent screens to set up.
|
|
117
123
|
|
|
@@ -131,53 +137,105 @@ const bkper = new Bkper({
|
|
|
131
137
|
});
|
|
132
138
|
```
|
|
133
139
|
|
|
134
|
-
This is the canonical pattern. Do not implement custom OAuth flows, redirect handling, or token refresh — the SDK and platform handle everything. See the [@bkper/web-auth API Reference](https://bkper.com/docs/api/bkper-web-auth.md) for the full SDK documentation.
|
|
140
|
+
This is the canonical browser pattern. Do not implement custom OAuth flows, redirect handling, or token refresh — the SDK and platform handle everything. See the [@bkper/web-auth API Reference](https://bkper.com/docs/api/bkper-web-auth.md) for the full SDK documentation.
|
|
135
141
|
|
|
136
|
-
##
|
|
142
|
+
## Server Worker
|
|
137
143
|
|
|
138
|
-
The server
|
|
144
|
+
The server folder runs on [Cloudflare Workers](https://developers.cloudflare.com/workers/) using [Hono](https://hono.dev/) as the web framework. It handles:
|
|
139
145
|
|
|
140
146
|
- Serving the client's static assets
|
|
141
|
-
- Custom API routes for your app's backend logic
|
|
147
|
+
- Custom API routes for your app's backend logic under `/api/*`
|
|
148
|
+
- Bkper event ingress under `/events`
|
|
142
149
|
- Type-safe access to platform services (KV, secrets) via `c.env`
|
|
143
150
|
|
|
144
151
|
```ts
|
|
145
152
|
import { Hono } from 'hono';
|
|
146
|
-
import
|
|
153
|
+
import { Bkper, Book } from 'bkper-js';
|
|
154
|
+
import type { Env } from '../../env.js';
|
|
147
155
|
|
|
148
156
|
const app = new Hono<{ Bindings: Env }>();
|
|
149
157
|
|
|
150
|
-
app.get('/api/
|
|
151
|
-
const
|
|
152
|
-
|
|
158
|
+
app.get('/api/books', async c => {
|
|
159
|
+
const bkper = new Bkper();
|
|
160
|
+
const books = await bkper.getBooks();
|
|
161
|
+
return c.json({ books });
|
|
153
162
|
});
|
|
154
163
|
|
|
164
|
+
app.post('/events', async c => {
|
|
165
|
+
const event: bkper.Event = await c.req.json();
|
|
166
|
+
const bkper = new Bkper();
|
|
167
|
+
const book = new Book(event.book, bkper.getConfig());
|
|
168
|
+
// route by event.type
|
|
169
|
+
return c.json({ result: false });
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
app.get('*', c => c.env.ASSETS.fetch(c.req.raw));
|
|
173
|
+
|
|
155
174
|
export default app;
|
|
156
175
|
```
|
|
157
176
|
|
|
158
|
-
|
|
177
|
+
### Server API authentication
|
|
159
178
|
|
|
160
|
-
|
|
179
|
+
For deployed apps, server API routes under `/api/*` require a standard bearer token on the incoming request:
|
|
161
180
|
|
|
162
181
|
```ts
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
182
|
+
const token = auth.getAccessToken();
|
|
183
|
+
if (!token) throw new Error('Not authenticated');
|
|
184
|
+
|
|
185
|
+
const response = await fetch('/api/data', {
|
|
186
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Dispatch validates the bearer token before your Worker runs. It then strips the `Authorization` header and passes only an internal outbound context, so app code should not read user tokens from request headers.
|
|
191
|
+
|
|
192
|
+
When the server route calls Bkper, use `bkper-js` without a token provider:
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
import { Bkper } from 'bkper-js';
|
|
196
|
+
|
|
197
|
+
app.get('/api/books', async c => {
|
|
198
|
+
const bkper = new Bkper();
|
|
199
|
+
const books = await bkper.getBooks();
|
|
200
|
+
return c.json({
|
|
201
|
+
books: books.map(book => ({
|
|
202
|
+
id: book.getId(),
|
|
203
|
+
name: book.getName(),
|
|
204
|
+
})),
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Platform outbound auth injects the validated user's OAuth token on exact Bkper API requests. Browser sessions only allow access to app web pages; they do not authorize `/api/*` server routes or create outbound auth context.
|
|
210
|
+
|
|
211
|
+
### Event handler authentication
|
|
212
|
+
|
|
213
|
+
On the Bkper Platform, `/events` is an internal Bkper delivery channel on the same Worker. App code must not read `bkper-oauth-token`, `bkper-agent-id`, or `Authorization` headers.
|
|
214
|
+
|
|
215
|
+
Use the same server-side Bkper API pattern as `/api/*` routes:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
const bkper = new Bkper();
|
|
219
|
+
const book = new Book(event.book, bkper.getConfig());
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Dispatch consumes the Core-sent event access token and strips platform headers before invoking your Worker. Platform outbound auth injects the token and app agent identity when your event handler calls the Bkper API.
|
|
223
|
+
|
|
224
|
+
For [self-hosted](https://bkper.com/docs/build/apps/self-hosted.md) event handlers, you receive and process event auth headers directly because the platform outbound layer is not involved.
|
|
225
|
+
|
|
226
|
+
## Event routing pattern
|
|
167
227
|
|
|
168
|
-
|
|
228
|
+
A typical server routes events by type and delegates to small handlers:
|
|
169
229
|
|
|
170
|
-
|
|
230
|
+
```ts
|
|
231
|
+
app.post('/events', async c => {
|
|
171
232
|
const event: bkper.Event = await c.req.json();
|
|
172
233
|
|
|
173
234
|
if (!event.book) {
|
|
174
235
|
return c.json({ error: 'Missing book in event payload' }, 400);
|
|
175
236
|
}
|
|
176
237
|
|
|
177
|
-
const bkper = new Bkper(
|
|
178
|
-
oauthTokenProvider: async () => c.req.header('bkper-oauth-token'),
|
|
179
|
-
agentIdProvider: async () => c.req.header('bkper-agent-id'),
|
|
180
|
-
});
|
|
238
|
+
const bkper = new Bkper();
|
|
181
239
|
const book = new Book(event.book, bkper.getConfig());
|
|
182
240
|
|
|
183
241
|
switch (event.type) {
|
|
@@ -187,47 +245,19 @@ app.post('/', async c => {
|
|
|
187
245
|
return c.json({ result: false });
|
|
188
246
|
}
|
|
189
247
|
});
|
|
190
|
-
|
|
191
|
-
export default app;
|
|
192
248
|
```
|
|
193
249
|
|
|
194
|
-
Event handlers run at `https://{appId}.bkper.app/events` in production. During development, a Cloudflare tunnel routes events to
|
|
250
|
+
Event handlers run at `https://{appId}.bkper.app/events` in production. During development, a Cloudflare tunnel routes events to the same local Worker.
|
|
195
251
|
|
|
196
252
|
See [Event Handlers](https://bkper.com/docs/build/apps/event-handlers.md) for patterns and details.
|
|
197
253
|
|
|
198
|
-
##
|
|
199
|
-
|
|
200
|
-
Common types, utilities, and constants used across packages:
|
|
201
|
-
|
|
202
|
-
```ts
|
|
203
|
-
// packages/shared/src/types.ts
|
|
204
|
-
export interface EventResult {
|
|
205
|
-
result?: string | string[] | boolean;
|
|
206
|
-
error?: string;
|
|
207
|
-
warning?: string;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// packages/shared/src/constants.ts
|
|
211
|
-
export const APP_NAME = 'my-app';
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
Import in any package:
|
|
215
|
-
|
|
216
|
-
```ts
|
|
217
|
-
import type { EventResult } from '@my-app/shared';
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
> **Note:** The `Env` type (KV bindings, secrets) lives in the root `env.d.ts` file, auto-generated from `bkper.yaml`. Import it as `import type { Env } from '../../../env.js'` — it is not part of the shared package.
|
|
221
|
-
|
|
222
|
-
## When you don't need all three
|
|
254
|
+
## When you don't need every part
|
|
223
255
|
|
|
224
256
|
Not every app needs a UI, API, and event handler:
|
|
225
257
|
|
|
226
|
-
- **Event-only app** —
|
|
227
|
-
- **UI-only app** —
|
|
228
|
-
- **Full app** —
|
|
229
|
-
|
|
230
|
-
The template includes all three by default. Remove what you don't need.
|
|
258
|
+
- **Event-only app** — Keep `server/` and omit `deployment.client`. Automates reactions to book events without a user interface.
|
|
259
|
+
- **UI-only app** — Use `client/` and keep a minimal server Worker for static assets. Remove the `events` list and `webhookUrl` if you do not handle events.
|
|
260
|
+
- **Full app** — Client UI, `/api/*` backend logic, and `/events` automation in one Worker.
|
|
231
261
|
|
|
232
262
|
## Simple App Patterns
|
|
233
263
|
|
|
@@ -235,10 +265,10 @@ These are the minimal, canonical patterns for common app tasks. Use them as star
|
|
|
235
265
|
|
|
236
266
|
### Client-only UI with authentication
|
|
237
267
|
|
|
238
|
-
The smallest useful app
|
|
268
|
+
The smallest useful app can keep all business logic in `client/`. No custom server routes, no event handlers, no custom auth logic.
|
|
239
269
|
|
|
240
270
|
```ts
|
|
241
|
-
//
|
|
271
|
+
// client/src/app.ts
|
|
242
272
|
import { Bkper } from 'bkper-js';
|
|
243
273
|
import { BkperAuth } from '@bkper/web-auth';
|
|
244
274
|
|
|
@@ -260,6 +290,7 @@ async function render() {
|
|
|
260
290
|
```
|
|
261
291
|
|
|
262
292
|
Key points:
|
|
293
|
+
|
|
263
294
|
- `BkperAuth` handles OAuth, token refresh, and session management internally.
|
|
264
295
|
- `auth.getAccessToken()` returns a valid token synchronously after `init()` resolves.
|
|
265
296
|
- Do not add server-side `/auth/*` routes. Do not implement `refresh_token` logic yourself.
|
|
@@ -280,9 +311,10 @@ Use `bkper-js` for all API calls. Do not call the REST API directly when `bkper-
|
|
|
280
311
|
|------|-----|------------|
|
|
281
312
|
| Client authentication | `@bkper/web-auth` (`BkperAuth`, `getAccessToken`) | Custom OAuth flows, manual `fetch('/auth/refresh')`, `google-auth-library` in the browser |
|
|
282
313
|
| API calls from client | `bkper-js` (`Bkper`, `Book`, `Account`, `Transaction`) | Direct `fetch()` to REST endpoints |
|
|
283
|
-
| API calls from
|
|
314
|
+
| API calls from app server `/api/*` route | Incoming `Authorization: Bearer <token>` + server-side `new Bkper()` | Reading OAuth tokens in server code, relying on browser sessions for API auth |
|
|
315
|
+
| API calls from platform event handler | Server-side `new Bkper()` in `/events` | Reading `bkper-oauth-token` or `bkper-agent-id` in platform app code |
|
|
284
316
|
| Local development server | `npm run dev` (template script) | Manual `miniflare` + `cloudflared` invocations |
|
|
285
|
-
| Event handler routing | `switch (event.type)` in `
|
|
317
|
+
| Event handler routing | `switch (event.type)` in `server/src/index.ts` or `server/src/handlers/` | Middleware frameworks, external webhook routers |
|
|
286
318
|
| UI components | `@bkper/web-design` + Lit | Heavy UI frameworks unless the user explicitly requests them |
|
|
287
319
|
|
|
288
320
|
## Common Pitfalls
|
|
@@ -295,19 +327,22 @@ Avoid these patterns even if they seem necessary. The platform or SDK already so
|
|
|
295
327
|
2. **Adding `/api/auth/refresh` or similar routes**
|
|
296
328
|
- Token refresh is internal to `@bkper/web-auth`. Exposing it via Hono routes creates security surface area and duplicates platform functionality.
|
|
297
329
|
|
|
298
|
-
3. **
|
|
299
|
-
-
|
|
330
|
+
3. **Relying on browser sessions for server API auth**
|
|
331
|
+
- Sessions let users open app web pages, but `/api/*` routes require `Authorization: Bearer <token>`. Dispatch validates bearer tokens and platform outbound uses that validated context for Bkper API calls.
|
|
332
|
+
|
|
333
|
+
4. **Modifying `server/` for a simple UI task**
|
|
334
|
+
- If the user only asked for a client-side feature, do not touch server routes. The Vite dev server proxies `/api` to the Miniflare worker automatically; you do not need to add routes unless the user explicitly asks for custom backend logic.
|
|
300
335
|
|
|
301
|
-
|
|
336
|
+
5. **Installing additional auth or HTTP libraries**
|
|
302
337
|
- `bkper-js` and `@bkper/web-auth` are the only packages you need for Bkper API access and authentication. Adding `axios`, `google-auth-library`, or similar is almost always wrong.
|
|
303
338
|
|
|
304
|
-
|
|
305
|
-
- If the user says "show me a list of books in a popup," that is a client-only task. Do not
|
|
339
|
+
6. **Creating event handlers when the user asked for a UI-only feature**
|
|
340
|
+
- If the user says "show me a list of books in a popup," that is a client-only task. Do not add `/events` logic or subscribe to webhooks.
|
|
306
341
|
|
|
307
|
-
|
|
342
|
+
7. **Calling REST endpoints directly when `bkper-js` has the method**
|
|
308
343
|
- If `bkper-js` exposes `book.getTransactions()`, use it. Do not `fetch('https://api.bkper.com/...')` and parse JSON manually.
|
|
309
344
|
|
|
310
|
-
|
|
345
|
+
8. **Reverse-engineering SDK internals**
|
|
311
346
|
- Use the public API surface documented in the API reference. Do not read SDK source to find private methods or internal request patterns.
|
|
312
347
|
|
|
313
348
|
---
|
|
@@ -360,11 +395,8 @@ events:
|
|
|
360
395
|
- TRANSACTION_CHECKED
|
|
361
396
|
|
|
362
397
|
deployment:
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
client: packages/web/client
|
|
366
|
-
events:
|
|
367
|
-
main: packages/events/src/index.ts
|
|
398
|
+
server: server/src/index.ts
|
|
399
|
+
client: client
|
|
368
400
|
services:
|
|
369
401
|
- KV
|
|
370
402
|
compatibility_date: '2026-01-28'
|
|
@@ -478,9 +510,8 @@ For apps deployed to the [Bkper Platform](https://bkper.com/docs/build/apps/over
|
|
|
478
510
|
|
|
479
511
|
| Field | Description |
|
|
480
512
|
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
481
|
-
| `deployment.
|
|
482
|
-
| `deployment.
|
|
483
|
-
| `deployment.events.main` | Entry point for the events handler (processes webhooks). |
|
|
513
|
+
| `deployment.server` | TypeScript entry point for the single server Worker. It serves `/api/*`, `/events`, and static assets. |
|
|
514
|
+
| `deployment.client` | Optional Vite/static client root. Built assets are deployed with the same Worker. |
|
|
484
515
|
| `deployment.services` | Platform services to provision. Currently: `KV` (key-value storage). |
|
|
485
516
|
| `deployment.secrets` | Secret names used by the app. Managed via `bkper app secrets`. |
|
|
486
517
|
| `deployment.compatibility_date` | [Cloudflare Workers compatibility date](https://developers.cloudflare.com/workers/configuration/compatibility-dates/). |
|
|
@@ -574,8 +605,8 @@ source: /docs/build/apps/deploying.md
|
|
|
574
605
|
```
|
|
575
606
|
|
|
576
607
|
This runs two build steps:
|
|
577
|
-
- Client (Vite) to static assets in `dist/
|
|
578
|
-
- Worker
|
|
608
|
+
- Client (Vite) to static assets in `dist/client/`
|
|
609
|
+
- Server Worker bundle (esbuild) to `dist/server/`
|
|
579
610
|
|
|
580
611
|
Build output includes size reporting so you can monitor bundle sizes.
|
|
581
612
|
|
|
@@ -621,15 +652,7 @@ Preview URLs use a dash suffix: `https://{appId}-preview.bkper.app`. For example
|
|
|
621
652
|
|
|
622
653
|
Preview has independent secrets and KV storage from production.
|
|
623
654
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
Deploy only the events handler:
|
|
627
|
-
|
|
628
|
-
```bash
|
|
629
|
-
bkper app deploy --events
|
|
630
|
-
```
|
|
631
|
-
|
|
632
|
-
Useful when you've only changed the events handler and want a faster deployment. Web is deployed by default.
|
|
655
|
+
There is one app deployment per environment. `/events` is handled by the same Worker as the client assets and `/api/*` routes.
|
|
633
656
|
|
|
634
657
|
## Secrets management
|
|
635
658
|
|
|
@@ -715,7 +738,7 @@ bkper app install <appId> -b <bookId>
|
|
|
715
738
|
bkper app uninstall <appId> -b <bookId>
|
|
716
739
|
```
|
|
717
740
|
|
|
718
|
-
Once installed, the app's [event handlers](https://bkper.com/docs/build/apps/event-handlers.md) receive events from that book
|
|
741
|
+
Once installed, the app's [event handlers](https://bkper.com/docs/build/apps/event-handlers.md) receive events from that book at `/events`, and the app's [context menu](https://bkper.com/docs/build/apps/context-menu.md) appears in the book's UI.
|
|
719
742
|
|
|
720
743
|
---
|
|
721
744
|
source: /docs/build/apps/development.md
|
|
@@ -734,35 +757,28 @@ The project template runs both processes via `concurrently`:
|
|
|
734
757
|
|
|
735
758
|
1. **`vite dev`** — Client dev server with HMR. Changes to Lit components reflect instantly in the browser. Configured in `vite.config.ts`.
|
|
736
759
|
2. **`bkper app dev`** — The worker runtime:
|
|
737
|
-
- **Miniflare** — Simulates the Cloudflare
|
|
738
|
-
- **Cloudflare tunnel** — Exposes
|
|
739
|
-
- **File watching** — Server
|
|
760
|
+
- **Miniflare** — Simulates the single Cloudflare Worker locally.
|
|
761
|
+
- **Cloudflare tunnel** — Exposes `/events` via a public URL so Bkper can route webhook events to your machine.
|
|
762
|
+
- **File watching** — Server changes trigger automatic rebuilds via esbuild.
|
|
740
763
|
|
|
741
|
-
You can also run them independently: `npm run dev:client` for just the UI, or `npm run dev:server`
|
|
764
|
+
You can also run them independently: `npm run dev:client` for just the UI, or `npm run dev:server` for the local Worker.
|
|
742
765
|
|
|
743
766
|
## URLs
|
|
744
767
|
|
|
745
|
-
|
|
|
768
|
+
| Endpoint | URL |
|
|
746
769
|
| --- | --- |
|
|
747
770
|
| Client (Vite dev server) | `http://localhost:5173` |
|
|
748
|
-
|
|
|
749
|
-
| Events (via tunnel) | `https://<random>.trycloudflare.com/events` |
|
|
771
|
+
| Server Worker (Miniflare) | `http://localhost:8787` |
|
|
772
|
+
| Events (via tunnel to the same Worker) | `https://<random>.trycloudflare.com/events` |
|
|
750
773
|
|
|
751
774
|
The Vite dev server proxies `/api` requests to `http://localhost:8787` (configured in `vite.config.ts`). The tunnel URL is automatically registered as the `webhookUrlDev` in Bkper, so events from books where you're the developer are routed to your local machine.
|
|
752
775
|
|
|
753
776
|
## Configuration flags
|
|
754
777
|
|
|
755
|
-
|
|
778
|
+
There is one local Worker. Override its port when needed:
|
|
756
779
|
|
|
757
780
|
```bash
|
|
758
|
-
|
|
759
|
-
bkper app dev --web
|
|
760
|
-
|
|
761
|
-
# Start only the events worker
|
|
762
|
-
bkper app dev --events
|
|
763
|
-
|
|
764
|
-
# Override default ports
|
|
765
|
-
bkper app dev --sp 8787 --ep 8791
|
|
781
|
+
bkper app dev --sp 8787
|
|
766
782
|
```
|
|
767
783
|
|
|
768
784
|
## Client configuration
|
|
@@ -785,6 +801,8 @@ bkper auth login # one-time setup
|
|
|
785
801
|
|
|
786
802
|
Then `npm run dev` handles authentication automatically. The client calls `auth.getAccessToken()` and the middleware ensures the token is valid.
|
|
787
803
|
|
|
804
|
+
When your client calls an app server route under `/api/*`, include that token as `Authorization: Bearer <token>` to match production dispatch behavior. Local outbound uses your CLI credentials when the app server or event handler calls Bkper.
|
|
805
|
+
|
|
788
806
|
If you see authentication errors in the browser, verify you're logged in:
|
|
789
807
|
|
|
790
808
|
```bash
|
|
@@ -839,7 +857,7 @@ bkper app build
|
|
|
839
857
|
1. Run `npm run dev`
|
|
840
858
|
2. Edit client code — see changes instantly via Vite HMR
|
|
841
859
|
3. Edit server code — auto-rebuilds and reloads via esbuild watch
|
|
842
|
-
4. Trigger events in Bkper — your local
|
|
860
|
+
4. Trigger events in Bkper — your local Worker receives them at `/events` via the tunnel
|
|
843
861
|
5. Check the activity stream in Bkper to see handler responses
|
|
844
862
|
6. Iterate
|
|
845
863
|
|
|
@@ -864,7 +882,7 @@ Event handlers are the code that reacts to events in your Bkper Books. When a tr
|
|
|
864
882
|
2. Bkper sends an HTTP POST to your webhook URL when those events fire
|
|
865
883
|
3. Your handler processes the event and returns a response
|
|
866
884
|
|
|
867
|
-
On the [Bkper Platform](https://bkper.com/docs/build/apps/overview.md), events are routed to
|
|
885
|
+
On the [Bkper Platform](https://bkper.com/docs/build/apps/overview.md), events are routed to `/events` on your app's single Worker — including local development via tunnels. For [self-hosted](https://bkper.com/docs/build/apps/self-hosted.md) setups, you configure the webhook URL directly.
|
|
868
886
|
|
|
869
887
|
## Agent identity
|
|
870
888
|
|
|
@@ -940,45 +958,36 @@ This pattern is essential for any handler that writes back to the same book.
|
|
|
940
958
|
|
|
941
959
|
## Authentication
|
|
942
960
|
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
- `bkper-oauth-token` — The OAuth access token of the user who installed the app. Use this to call the API back on behalf of the user.
|
|
946
|
-
- `bkper-agent-id` — Your app's agent identifier.
|
|
947
|
-
|
|
948
|
-
Pass these directly to `bkper-js`:
|
|
961
|
+
Platform-hosted event handlers use the same server-side Bkper API pattern as `/api/*` routes:
|
|
949
962
|
|
|
950
963
|
```ts
|
|
951
|
-
const bkper = new Bkper(
|
|
952
|
-
oauthTokenProvider: async () => c.req.header('bkper-oauth-token'),
|
|
953
|
-
agentIdProvider: async () => c.req.header('bkper-agent-id'),
|
|
954
|
-
});
|
|
964
|
+
const bkper = new Bkper();
|
|
955
965
|
const book = new Book(event.book, bkper.getConfig());
|
|
956
966
|
```
|
|
957
967
|
|
|
958
|
-
|
|
968
|
+
Dispatch consumes the event delivery token, strips platform headers before your Worker runs, and platform outbound auth injects the OAuth token and app agent identity on Bkper API calls.
|
|
969
|
+
|
|
970
|
+
Do not read `bkper-oauth-token`, `bkper-agent-id`, or `Authorization` headers in platform app code.
|
|
959
971
|
|
|
960
972
|
> **Note**
|
|
961
|
-
>
|
|
962
|
-
For [self-hosted](https://bkper.com/docs/build/apps/self-hosted.md) setups, the
|
|
973
|
+
> During local development, events are routed through the Cloudflare tunnel started by `bkper app dev`. Local outbound uses your CLI credentials when the handler calls Bkper.
|
|
974
|
+
For [self-hosted](https://bkper.com/docs/build/apps/self-hosted.md) setups, the event auth headers are sent to both `webhookUrl` and `webhookUrlDev` and must be handled directly by your infrastructure.
|
|
963
975
|
|
|
964
976
|
## Event routing pattern
|
|
965
977
|
|
|
966
|
-
On the Bkper Platform,
|
|
978
|
+
On the Bkper Platform, your server Worker uses [Hono](https://hono.dev) to receive webhook calls at `/events`. A typical pattern routes events by type:
|
|
967
979
|
|
|
968
980
|
```ts
|
|
969
981
|
import { Bkper, Book } from 'bkper-js';
|
|
970
982
|
|
|
971
|
-
app.post('/', async c => {
|
|
983
|
+
app.post('/events', async c => {
|
|
972
984
|
const event: bkper.Event = await c.req.json();
|
|
973
985
|
|
|
974
986
|
if (!event.book) {
|
|
975
987
|
return c.json({ error: 'Missing book in event payload' }, 400);
|
|
976
988
|
}
|
|
977
989
|
|
|
978
|
-
const bkper = new Bkper(
|
|
979
|
-
oauthTokenProvider: async () => c.req.header('bkper-oauth-token'),
|
|
980
|
-
agentIdProvider: async () => c.req.header('bkper-agent-id'),
|
|
981
|
-
});
|
|
990
|
+
const bkper = new Bkper();
|
|
982
991
|
const book = new Book(event.book, bkper.getConfig());
|
|
983
992
|
|
|
984
993
|
switch (event.type) {
|
|
@@ -1150,11 +1159,11 @@ This tutorial walks you through building and deploying a Bkper app from scratch.
|
|
|
1150
1159
|
|
|
1151
1160
|
5. **Make a change**
|
|
1152
1161
|
|
|
1153
|
-
Edit the handler in `
|
|
1162
|
+
Edit the handler in `server/src/handlers/transaction-checked.ts` and save. The worker reloads automatically. Check another transaction to see your change.
|
|
1154
1163
|
|
|
1155
1164
|
6. **Customize your listing**
|
|
1156
1165
|
|
|
1157
|
-
Update `bkper.yaml` with your app's description, owner details, and repository URL. Replace the placeholder logos in `
|
|
1166
|
+
Update `bkper.yaml` with your app's description, owner details, and repository URL. Replace the placeholder logos in `client/public/images/`. See [App Listing](https://bkper.com/docs/build/apps/app-listing.md) for publishing details.
|
|
1158
1167
|
|
|
1159
1168
|
7. **Update the README**
|
|
1160
1169
|
|
|
@@ -1180,7 +1189,7 @@ This tutorial walks you through building and deploying a Bkper app from scratch.
|
|
|
1180
1189
|
|
|
1181
1190
|
## Next steps
|
|
1182
1191
|
|
|
1183
|
-
- [App Architecture](https://bkper.com/docs/build/apps/architecture.md) — Understand the
|
|
1192
|
+
- [App Architecture](https://bkper.com/docs/build/apps/architecture.md) — Understand the single Worker client/server structure
|
|
1184
1193
|
- [App Configuration](https://bkper.com/docs/build/apps/configuration.md) — Full `bkper.yaml` reference
|
|
1185
1194
|
- [Event Handlers](https://bkper.com/docs/build/apps/event-handlers.md) — All event types and patterns
|
|
1186
1195
|
- [Building & Deploying](https://bkper.com/docs/build/apps/deploying.md) — Preview environments and secrets
|
|
@@ -1202,8 +1211,9 @@ Preview environments are built in — deploy to a preview URL to test before goi
|
|
|
1202
1211
|
|
|
1203
1212
|
OAuth is pre-configured. No client IDs, no redirect URIs, no consent screens to build.
|
|
1204
1213
|
|
|
1205
|
-
- **Web client** — Use `@bkper/web-auth`: `auth.getAccessToken()`. See [App Architecture →
|
|
1206
|
-
- **
|
|
1214
|
+
- **Web client** — Use `@bkper/web-auth`: `auth.getAccessToken()`. See [App Architecture → Client authentication](https://bkper.com/docs/build/apps/architecture.md#client-authentication).
|
|
1215
|
+
- **Server API routes** — Send `Authorization: Bearer <token>` to `/api/*`; dispatch validates it and platform outbound injects auth for server-side Bkper API calls. See [App Architecture → Server API authentication](https://bkper.com/docs/build/apps/architecture.md#server-api-authentication).
|
|
1216
|
+
- **Event handlers** — Handle `/events` in the same Worker and call Bkper with server-side `new Bkper()`; dispatch/outbound handle auth and agent identity. See [Event Handlers → Authentication](https://bkper.com/docs/build/apps/event-handlers.md#authentication).
|
|
1207
1217
|
- **Local development** — The Vite auth middleware uses your CLI credentials. See [Development Experience → Local development authentication](https://bkper.com/docs/build/apps/development.md#local-development-authentication).
|
|
1208
1218
|
|
|
1209
1219
|
### Services
|
|
@@ -1221,7 +1231,7 @@ The project template composes the full development environment:
|
|
|
1221
1231
|
npm run dev
|
|
1222
1232
|
```
|
|
1223
1233
|
|
|
1224
|
-
This runs two processes concurrently: `vite dev` for the client UI (HMR), and `bkper app dev` for the
|
|
1234
|
+
This runs two processes concurrently: `vite dev` for the client UI (HMR), and `bkper app dev` for the Worker runtime (Miniflare for `/api/*` and `/events`, plus a Cloudflare tunnel so Bkper can route webhook events to your laptop). Your entire development environment, running locally.
|
|
1225
1235
|
|
|
1226
1236
|
### Deployment
|
|
1227
1237
|
|
|
@@ -1260,7 +1270,7 @@ bkper app init my-app
|
|
|
1260
1270
|
npm run dev
|
|
1261
1271
|
```
|
|
1262
1272
|
|
|
1263
|
-
This gives you a working app with a client UI, server API, and
|
|
1273
|
+
This gives you a working app with a client UI, server API routes, and `/events` handling in one Worker — all running locally with full HMR and webhook tunneling.
|
|
1264
1274
|
|
|
1265
1275
|
See [Your First App](https://bkper.com/docs/build/apps/first-app.md) for a complete walkthrough, or continue to [App Architecture](https://bkper.com/docs/build/apps/architecture.md) to understand how platform apps are structured.
|
|
1266
1276
|
|