bkper 4.25.0 → 4.26.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.
Files changed (51) hide show
  1. package/README.md +1 -1
  2. package/lib/agent/extensions/handoff.d.ts.map +1 -1
  3. package/lib/agent/extensions/handoff.js +2 -0
  4. package/lib/agent/extensions/handoff.js.map +1 -1
  5. package/lib/agent/startup-maintenance.d.ts +1 -0
  6. package/lib/agent/startup-maintenance.d.ts.map +1 -1
  7. package/lib/agent/startup-maintenance.js +7 -1
  8. package/lib/agent/startup-maintenance.js.map +1 -1
  9. package/lib/agent/system-prompt.js +1 -1
  10. package/lib/commands/apps/git/clone.js +1 -1
  11. package/lib/commands/apps/git/clone.js.map +1 -1
  12. package/lib/commands/apps/init.d.ts +3 -1
  13. package/lib/commands/apps/init.d.ts.map +1 -1
  14. package/lib/commands/apps/init.js +105 -58
  15. package/lib/commands/apps/init.js.map +1 -1
  16. package/lib/commands/apps/register.js +2 -2
  17. package/lib/commands/apps/register.js.map +1 -1
  18. package/lib/dev/local-outbound.d.ts.map +1 -1
  19. package/lib/dev/local-outbound.js +17 -3
  20. package/lib/dev/local-outbound.js.map +1 -1
  21. package/lib/dev/miniflare.js +1 -1
  22. package/lib/dev/miniflare.js.map +1 -1
  23. package/lib/dev/preflight.js +1 -1
  24. package/lib/dev/preflight.js.map +1 -1
  25. package/lib/dev/shared.js +1 -1
  26. package/lib/dev/shared.js.map +1 -1
  27. package/lib/docs/apps/ai.md +270 -0
  28. package/lib/docs/apps/app-listing.md +86 -0
  29. package/lib/docs/apps/architecture.md +188 -0
  30. package/lib/docs/apps/configuration.md +171 -0
  31. package/lib/docs/apps/context-menu.md +69 -0
  32. package/lib/docs/apps/deploying.md +181 -0
  33. package/lib/docs/apps/development.md +122 -0
  34. package/lib/docs/apps/event-handlers.md +248 -0
  35. package/lib/docs/apps/first-app.md +76 -0
  36. package/lib/docs/apps/overview.md +106 -0
  37. package/lib/docs/apps/self-hosted.md +63 -0
  38. package/lib/docs/apps/shared-app-source.md +85 -0
  39. package/lib/docs/cli/app-management.md +16 -4
  40. package/lib/docs/index.md +12 -1
  41. package/lib/docs/sdk/bkper-js.md +5 -0
  42. package/lib/upgrade/index.d.ts +1 -1
  43. package/lib/upgrade/index.d.ts.map +1 -1
  44. package/lib/upgrade/index.js +1 -1
  45. package/lib/upgrade/index.js.map +1 -1
  46. package/lib/upgrade/installation.d.ts +4 -0
  47. package/lib/upgrade/installation.d.ts.map +1 -1
  48. package/lib/upgrade/installation.js +23 -0
  49. package/lib/upgrade/installation.js.map +1 -1
  50. package/package.json +3 -3
  51. package/lib/docs/apps/app-building.md +0 -1429
@@ -0,0 +1,122 @@
1
+ # Development Experience
2
+
3
+ Local development uses two composable processes — the worker runtime and the client dev server — that run concurrently.
4
+
5
+ ## What runs
6
+
7
+ ```bash
8
+ npm run dev
9
+ ```
10
+
11
+ The project template runs both processes via `concurrently`:
12
+
13
+ 1. **`vite dev`** — Client dev server with HMR. Changes to Lit components reflect instantly in the browser. Configured in `client/vite.config.ts`.
14
+ 2. **`bkper app dev`** — The worker runtime:
15
+ - **Miniflare** — Simulates the single Cloudflare Worker locally.
16
+ - **Cloudflare tunnel** — Exposes `/events` via a public URL so Bkper can route webhook events to your machine.
17
+ - **File watching** — Server changes trigger automatic rebuilds via esbuild.
18
+
19
+ You can also run them independently: `npm run dev:client` for just the UI, or `npm run dev:server` for the local Worker.
20
+
21
+ ## URLs
22
+
23
+ | Endpoint | URL |
24
+ | -------------------------------------- | ------------------------------------------- |
25
+ | Client (Vite dev server) | `http://localhost:5173` |
26
+ | Server Worker (Miniflare) | `http://localhost:8787` |
27
+ | App API routes | `http://localhost:8787/api/*` |
28
+ | App OpenAPI spec | `http://localhost:8787/openapi.json` |
29
+ | Events (via tunnel to the same Worker) | `https://<random>.trycloudflare.com/events` |
30
+
31
+ The Vite dev server proxies `/api` requests to `http://localhost:8787` through `client/vite.config.ts`. The app OpenAPI spec is served by the Worker at `http://localhost:8787/openapi.json`. The tunnel URL is automatically registered as `webhookUrlDev`, so development-mode events are routed to your local machine.
32
+
33
+ ## Configuration flags
34
+
35
+ There is one local Worker. Override its port when needed:
36
+
37
+ ```bash
38
+ bkper app dev --sp 8787
39
+ ```
40
+
41
+ ## Client configuration
42
+
43
+ The client dev server is configured in `client/vite.config.ts`. This standard Vite configuration registers local auth middleware and proxies `/api` requests to the Worker.
44
+
45
+ ### Local development authentication
46
+
47
+ During local development, the Vite dev server runs `createBkperAuthMiddleware()` from `bkper/dev`. It serves the local `/auth/refresh` endpoint used by `@bkper/web-auth`, obtaining OAuth tokens from your CLI credentials.
48
+
49
+ The separate Vite proxy configuration forwards `/api` requests to the Miniflare Worker.
50
+
51
+ Before starting development, run:
52
+
53
+ ```bash
54
+ bkper auth login # one-time setup
55
+ ```
56
+
57
+ Then `npm run dev` handles local authentication. Direct `bkper-js` calls use `auth.getAccessToken()`, while the typed app API client uses `auth.authenticatedFetch()` to attach and refresh bearer authentication.
58
+
59
+ Local outbound uses your CLI credentials when the app server or event handler calls Bkper.
60
+
61
+ If you see authentication errors in the browser, verify you're logged in:
62
+
63
+ ```bash
64
+ bkper auth token # should print a token
65
+ ```
66
+
67
+ This is the canonical pattern for local development. Do not manually pass tokens or implement custom auth flows.
68
+
69
+ ## Local secrets
70
+
71
+ Environment variables for local development live in a `.dev.vars` file at the project root:
72
+
73
+ ```bash
74
+ # .dev.vars (gitignored)
75
+ EXTERNAL_SERVICE_TOKEN=your-token-here
76
+ ```
77
+
78
+ Copy from the provided template:
79
+
80
+ ```bash
81
+ cp .dev.vars.example .dev.vars
82
+ ```
83
+
84
+ These variables are available as `c.env.SECRET_NAME` in your Hono handlers during development.
85
+
86
+ ## KV storage
87
+
88
+ KV data persists locally in the `.mf/kv/` directory during development. This means your data survives restarts — useful for testing caching and state patterns.
89
+
90
+ ```ts
91
+ // Read
92
+ const value = await c.env.KV.get('my-key');
93
+
94
+ // Write with TTL
95
+ await c.env.KV.put('my-key', 'value', { expirationTtl: 3600 });
96
+ ```
97
+
98
+ See the [Cloudflare KV documentation](https://developers.cloudflare.com/kv/) for more usage patterns.
99
+
100
+ ## Type generation
101
+
102
+ The `env.d.ts` file provides TypeScript types for the Worker environment — KV bindings, secrets, and other platform services. It's auto-generated based on your `bkper.yaml` configuration and checked into version control.
103
+
104
+ Rebuild it after changing services or secrets in `bkper.yaml`:
105
+
106
+ ```bash
107
+ bkper app build
108
+ ```
109
+
110
+ ## The development loop
111
+
112
+ 1. Run `npm run dev`.
113
+ 2. Edit client code and use Vite HMR.
114
+ 3. Edit server code and let the Worker reload.
115
+ 4. Trigger events in Bkper and inspect handler responses in the activity stream.
116
+ 5. Run `npm run check` before considering the change complete.
117
+
118
+ ## Debugging
119
+
120
+ - **Server errors** — Check the terminal output from `bkper app dev`. Worker runtime errors appear here.
121
+ - **Event handler errors** — Check the Bkper activity stream. Click on an event handler response to see the result or error, and replay failed events.
122
+ - **Client errors** — Use browser DevTools. The Vite dev server provides source maps.
@@ -0,0 +1,248 @@
1
+ # Event Handlers
2
+
3
+ Event handlers are the code that reacts to events in your Bkper Books. When a transaction is checked, an account is created, or any other event occurs, your handler receives it and can take action — calculate taxes, sync data between books, post to external services, and more.
4
+
5
+ ![Bkper Event Handler](https://bkper.com/images/bots/bkper-tax-bot/bkper-tax-bot.gif)
6
+
7
+ ## How it works
8
+
9
+ 1. You declare which events your app handles in [`bkper.yaml`](https://bkper.com/docs/build/apps/configuration.md)
10
+ 2. Bkper sends an HTTP POST to your webhook URL when those events fire
11
+ 3. Your handler processes the event and returns a response
12
+
13
+ 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.
14
+
15
+ ## Agent identity
16
+
17
+ Event handlers **run on behalf of the user who installed the app**. Their transactions and activities are identified in the UI by the app's logo and name:
18
+
19
+ ![Event handler agents identified in the activity stream](https://bkper.com/docs/_astro/bkper-bot-agents.CtsWIZEd.png)
20
+
21
+ ## Responses
22
+
23
+ Handler responses are recorded in the activity that triggered the event. You can view and replay them by clicking the response at the bottom of the activity:
24
+
25
+ ![Event handler responses in the activity stream](https://bkper.com/docs/_astro/bkper-bot-responses.UQXhqdai.png)
26
+
27
+ ### Response format
28
+
29
+ Your handler must return a response in this format:
30
+
31
+ ```ts
32
+ { result?: string | string[] | boolean; error?: string; warning?: string }
33
+ ```
34
+
35
+ - The `result` is recorded as the handler response in the book activity
36
+ - If you return `{ result: false }`, the response is suppressed and not recorded
37
+ - Errors like `{ error: "This is an error" }` show up as error responses
38
+
39
+ To show the full error stack trace for debugging:
40
+
41
+ ```ts
42
+ try {
43
+ // handler logic
44
+ } catch (err) {
45
+ return { error: err instanceof Error ? err.message : String(err) };
46
+ }
47
+ ```
48
+
49
+ ### HTML in responses
50
+
51
+ If you return an **HTML snippet** (e.g., a link) in the result, it will be rendered in the response popup.
52
+
53
+ ## Development mode
54
+
55
+ Event handlers run in _Development Mode_ when executed by the **developer or owner** of the App.
56
+
57
+ In development mode, both successful results and errors are shown as responses:
58
+
59
+ ![Event handler error in development mode](https://bkper.com/docs/_astro/bkper-bot-error.4eq2AKEM.png)
60
+
61
+ You can click a response to **replay** failed executions — useful for debugging without recreating the triggering event.
62
+
63
+ To find transactions with bot errors in a book, run the query:
64
+
65
+ ```
66
+ error:true
67
+ ```
68
+
69
+ ## Preventing loops
70
+
71
+ When your event handler creates or modifies transactions, those changes fire new events. To prevent infinite loops, check the `event.agent.id` field:
72
+
73
+ ```ts
74
+ function handleEvent(event: bkper.Event) {
75
+ // Skip events triggered by this app
76
+ if (event.agent?.id === 'your-app-id') {
77
+ return { result: false };
78
+ }
79
+
80
+ // Process the event
81
+ // ...
82
+ }
83
+ ```
84
+
85
+ This pattern is essential for any handler that writes back to the same book.
86
+
87
+ ## Authentication
88
+
89
+ Platform-hosted event handlers use the same server-side Bkper API pattern as `/api/*` routes:
90
+
91
+ ```ts
92
+ const bkper = new Bkper();
93
+ const book = new Book(event.book, bkper.getConfig());
94
+ ```
95
+
96
+ 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.
97
+
98
+ Do not read `bkper-oauth-token`, `bkper-agent-id`, or `Authorization` headers in platform app code.
99
+
100
+ > **Note**
101
+ > 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.
102
+ 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.
103
+
104
+ ## Event routing pattern
105
+
106
+ 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:
107
+
108
+ ```ts
109
+ import { Bkper, Book } from 'bkper-js';
110
+
111
+ app.post('/events', async c => {
112
+ const event: bkper.Event = await c.req.json();
113
+
114
+ if (!event.book) {
115
+ return c.json({ error: 'Missing book in event payload' }, 400);
116
+ }
117
+
118
+ const bkper = new Bkper();
119
+ const book = new Book(event.book, bkper.getConfig());
120
+
121
+ switch (event.type) {
122
+ case 'TRANSACTION_CHECKED':
123
+ return c.json(await handleTransactionChecked(book, event));
124
+ default:
125
+ return c.json({ result: false });
126
+ }
127
+ });
128
+ ```
129
+
130
+ ## The Event object
131
+
132
+ The event payload has the following structure:
133
+
134
+ ```ts
135
+ {
136
+ /** The id of the Book associated to the Event */
137
+ bookId?: string;
138
+
139
+ /** The Book object associated with the Event */
140
+ book?: {
141
+ agentId?: string;
142
+ collection?: Collection;
143
+ createdAt?: string;
144
+ datePattern?: string;
145
+ decimalSeparator?: "DOT" | "COMMA";
146
+ fractionDigits?: number;
147
+ id?: string;
148
+ lastUpdateMs?: string;
149
+ lockDate?: string;
150
+ name?: string;
151
+ ownerName?: string;
152
+ pageSize?: number;
153
+ period?: "MONTH" | "QUARTER" | "YEAR";
154
+ periodStartMonth?: "JANUARY" | "FEBRUARY" | "MARCH" | "APRIL"
155
+ | "MAY" | "JUNE" | "JULY" | "AUGUST" | "SEPTEMBER"
156
+ | "OCTOBER" | "NOVEMBER" | "DECEMBER";
157
+ permission?: "OWNER" | "EDITOR" | "POSTER" | "RECORDER"
158
+ | "VIEWER" | "NONE";
159
+ properties?: { [name: string]: string };
160
+ timeZone?: string;
161
+ timeZoneOffset?: number;
162
+ };
163
+
164
+ /** The user in charge of the Event */
165
+ user?: {
166
+ avatarUrl?: string;
167
+ name?: string;
168
+ username?: string;
169
+ };
170
+
171
+ /** The Event agent, such as the App, Bot or Bank institution */
172
+ agent?: {
173
+ id?: string;
174
+ logo?: string;
175
+ name?: string;
176
+ };
177
+
178
+ /** The creation timestamp, in milliseconds */
179
+ createdAt?: string;
180
+
181
+ /** The event data */
182
+ data?: {
183
+ /** The object payload. Depends on the event type. */
184
+ object?: any;
185
+ /** The object previous attributes when updated */
186
+ previousAttributes?: { [name: string]: string };
187
+ };
188
+
189
+ /** The unique id that identifies the Event */
190
+ id?: string;
191
+
192
+ /** The resource associated to the Event */
193
+ resource?: string;
194
+
195
+ /** The type of the Event */
196
+ type?: EventType;
197
+ }
198
+ ```
199
+
200
+ The event payload is the same structure exposed by the [REST API](https://bkper.com/docs/build/scripts/rest-api.md). If you use TypeScript, add the [`@bkper/bkper-api-types`](https://www.npmjs.com/package/@bkper/bkper-api-types) package to your project for full type definitions.
201
+
202
+ For update events, `data.previousAttributes` contains the fields that changed and their previous values — useful for computing diffs or reacting only to specific field changes.
203
+
204
+ ## Event types
205
+
206
+ Declare which events your app handles in `bkper.yaml`:
207
+
208
+ ```yaml
209
+ events:
210
+ - TRANSACTION_CHECKED
211
+ - TRANSACTION_POSTED
212
+ - ACCOUNT_CREATED
213
+ ```
214
+
215
+ The complete current set of event types:
216
+
217
+ | Event | Description |
218
+ | --- | --- |
219
+ | `FILE_CREATED` | A file was attached to the book. |
220
+ | `FILE_UPDATED` | An attached file was updated. |
221
+ | `TRANSACTION_CREATED` | A draft transaction was created. |
222
+ | `TRANSACTION_UPDATED` | A transaction was updated. |
223
+ | `TRANSACTION_DELETED` | A transaction was deleted. |
224
+ | `TRANSACTION_POSTED` | A draft transaction was posted and now affects balances. |
225
+ | `TRANSACTION_CHECKED` | A posted transaction was checked (reviewed and locked). |
226
+ | `TRANSACTION_UNCHECKED` | A checked transaction was unchecked and becomes editable again. |
227
+ | `TRANSACTION_RESTORED` | A deleted transaction was restored. |
228
+ | `ACCOUNT_CREATED` | An account was created. |
229
+ | `ACCOUNT_UPDATED` | An account was updated. |
230
+ | `ACCOUNT_DELETED` | An account was deleted. |
231
+ | `QUERY_CREATED` | A saved query was created. |
232
+ | `QUERY_UPDATED` | A saved query was updated. |
233
+ | `QUERY_DELETED` | A saved query was deleted. |
234
+ | `GROUP_CREATED` | A group was created. |
235
+ | `GROUP_UPDATED` | A group was updated. |
236
+ | `GROUP_DELETED` | A group was deleted. |
237
+ | `COMMENT_CREATED` | A comment was added. |
238
+ | `COMMENT_DELETED` | A comment was deleted. |
239
+ | `COLLABORATOR_ADDED` | A collaborator was added to the book. |
240
+ | `COLLABORATOR_UPDATED` | A collaborator's permissions were updated. |
241
+ | `COLLABORATOR_REMOVED` | A collaborator was removed from the book. |
242
+ | `INTEGRATION_CREATED` | An integration was created in the book. |
243
+ | `INTEGRATION_UPDATED` | An integration was updated. |
244
+ | `INTEGRATION_DELETED` | An integration was deleted. |
245
+ | `BOOK_CREATED` | A book was created. |
246
+ | `BOOK_AUDITED` | A balances audit completed for the book. |
247
+ | `BOOK_UPDATED` | Book settings were updated. |
248
+ | `BOOK_DELETED` | The book was deleted. |
@@ -0,0 +1,76 @@
1
+ # Your First App
2
+
3
+ This tutorial walks you through building and deploying a Bkper app from scratch. For the deep reference on any topic — architecture, configuration, development, events, or deployment — follow the links in each step.
4
+
5
+ ## Prerequisites
6
+
7
+ [Development Setup](https://bkper.com/docs/build/getting-started/setup.md) — the CLI installed and authenticated.
8
+
9
+ ## Walkthrough
10
+
11
+ 1. **Scaffold from the template**
12
+
13
+ ```bash
14
+ bkper app init my-app
15
+ cd my-app
16
+ ```
17
+
18
+ `bkper app init my-app` creates `./my-app` and uses `my-app` as the app id. The CLI sets your package name, URLs, and event-handler loop guards automatically. See [App Configuration](https://bkper.com/docs/build/apps/configuration.md) for the full `bkper.yaml` reference.
19
+
20
+ 2. **Install and start developing**
21
+
22
+ ```bash
23
+ npm install
24
+ npm run dev
25
+ ```
26
+
27
+ This runs the Vite client dev server and the local Worker runtime with automatic event tunneling. See [Development Experience](https://bkper.com/docs/build/apps/development.md) for details.
28
+
29
+ 3. **Open the app**
30
+
31
+ Visit [http://localhost:5173](http://localhost:5173). Select a book to see account balances. No OAuth setup required — the platform handles authentication.
32
+
33
+ 4. **Trigger an event**
34
+
35
+ Go to any Bkper book and check a transaction. The event handler creates a 20% draft using the original from and to Accounts. It does not affect balances unless posted. See [Event Handlers](https://bkper.com/docs/build/apps/event-handlers.md) for the full event model.
36
+
37
+ 5. **Make a change**
38
+
39
+ Edit `server/src/events/handlers/transaction-checked.ts` and save. The Worker reloads automatically. Check another transaction to see your change.
40
+
41
+ 6. **Customize your listing**
42
+
43
+ Update `bkper.yaml` with your app's description and owner details. Replace the placeholder logos in `client/public/images/`. See [App Listing](https://bkper.com/docs/build/apps/app-listing.md) for publishing details.
44
+
45
+ 7. **Update the README**
46
+
47
+ Edit `README.md` for end users — what the app does and how to use it. If your app exposes `/api/*` routes for users or integrators, include the app API base URL, `/openapi.json` URL, and one minimal authenticated example. Keep deeper developer docs in `AGENTS.md`.
48
+
49
+ 8. **Establish shared source**
50
+
51
+ Review the app, create its first commit, and sync it:
52
+
53
+ ```bash
54
+ git add .
55
+ git commit -m "Initial app"
56
+ bkper app sync
57
+ ```
58
+
59
+ For an eligible standalone app without an external remote, sync creates private Bkper-managed source and configures it as `origin`. Authorized teammates and coding agents can then clone the same codebase with `bkper app clone my-app`. See [Shared App Source](https://bkper.com/docs/build/apps/shared-app-source.md) for access rules and other source workflows.
60
+
61
+ 9. **Check and deploy**
62
+
63
+ ```bash
64
+ npm run check
65
+ npm run deploy
66
+ ```
67
+
68
+ Deployment is explicit: syncing or pushing source does not deploy the app. Your app is live at `https://my-app.bkper.app`. See [Building & Deploying](https://bkper.com/docs/build/apps/deploying.md) for preview environments, secrets, and KV.
69
+
70
+ ## Next steps
71
+
72
+ - [Shared App Source](https://bkper.com/docs/build/apps/shared-app-source.md) — Clone and improve one private app codebase together
73
+ - [App Architecture](https://bkper.com/docs/build/apps/architecture.md) — Understand the single Worker client/server structure
74
+ - [App Configuration](https://bkper.com/docs/build/apps/configuration.md) — Full `bkper.yaml` reference
75
+ - [Event Handlers](https://bkper.com/docs/build/apps/event-handlers.md) — All event types and patterns
76
+ - [Building & Deploying](https://bkper.com/docs/build/apps/deploying.md) — Preview environments and secrets
@@ -0,0 +1,106 @@
1
+ # The Bkper Platform
2
+
3
+ The Bkper Platform is a complete managed environment for building, deploying, and hosting apps on Bkper. It removes infrastructure complexity so you can focus on business logic.
4
+
5
+ ### Hosting
6
+
7
+ Apps are deployed to `{appId}.bkper.app` on a global edge network powered by [Cloudflare Workers for Platforms](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/). Your app runs close to your users, with zero infrastructure to manage.
8
+
9
+ Preview environments are built in — deploy to a preview URL to test before going to production.
10
+
11
+ ### App APIs
12
+
13
+ The same Worker can expose app-defined `/api/*` routes. Treat those routes as the reusable contract for your app behavior:
14
+
15
+ - The bundled web client can call them.
16
+ - Scripts, external clients, and agents can call them too.
17
+ - The default template documents them with an app OpenAPI spec at `/openapi.json`.
18
+
19
+ ### AI inference
20
+
21
+ When an app needs model inference, use Bkper AI by default. An authenticated app API route or event establishes the user and app identity, then platform outbound supplies authorization and usage attribution for the Worker's Bkper AI requests. The app does not need provider credentials.
22
+
23
+ See [Add Bkper AI to an App](https://bkper.com/docs/build/apps/ai.md) for live model discovery, strict structured output, validation, and the client-to-Worker authentication flow.
24
+
25
+ ### Authentication
26
+
27
+ OAuth is pre-configured. No client IDs, no redirect URIs, no consent screens to build.
28
+
29
+ - **Web client** — Use `@bkper/web-auth`: `auth.getAccessToken()`. See [App Architecture → Client authentication](https://bkper.com/docs/build/apps/architecture.md#client-authentication).
30
+ - **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).
31
+ - **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).
32
+ - **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).
33
+
34
+ ### Services
35
+
36
+ Declare the services you need in [`bkper.yaml`](https://bkper.com/docs/build/apps/configuration.md) and the platform provisions them:
37
+
38
+ - **KV storage** — Key-value storage for caching and state. Access via `c.env.KV` in your handlers.
39
+ - **Secrets** — Securely stored environment variables. Set via `bkper app secrets put`, access via `c.env.SECRET_NAME`.
40
+
41
+ ### Developer experience
42
+
43
+ The project template composes the full development environment:
44
+
45
+ ```bash
46
+ npm run dev
47
+ ```
48
+
49
+ 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.
50
+
51
+ ### Shared app source
52
+
53
+ Bkper can host one private codebase for your app. Authorized teammates and coding agents can clone it, improve it locally, and continue building from the same shared history.
54
+
55
+ Source synchronization remains separate from deployment. A Git push stores source but never builds or deploys the app.
56
+
57
+ See [Shared App Source](https://bkper.com/docs/build/apps/shared-app-source.md) for the collaboration workflow, access rules, and external Git options.
58
+
59
+ ### Deployment
60
+
61
+ Check and deploy the app template:
62
+
63
+ ```bash
64
+ npm run check
65
+ npm run deploy
66
+ ```
67
+
68
+ Your app is live at `{appId}.bkper.app`. The platform handles routing, SSL, and edge distribution.
69
+
70
+ ## What you'd build yourself without it
71
+
72
+ Without the platform, creating a Bkper app with a UI, event handling, and authentication requires:
73
+
74
+ | Concern | Without the platform | With the platform |
75
+ | ------------------------ | --------------------------------------------------------------------------------------- | ----------------------------------------------- |
76
+ | **Hosting** | Provision servers, configure domains, SSL, CDN | `bkper app deploy` |
77
+ | **Authentication** | Register OAuth client, build consent screen, handle token refresh, manage redirect URIs | `auth.getAccessToken()` |
78
+ | **Event webhooks** | Set up a public endpoint, configure DNS, handle JWT verification | Declare in `bkper.yaml`, platform routes events |
79
+ | **Local dev webhooks** | Install ngrok or similar, manually configure tunnel URL | `bkper app dev` starts tunnel automatically |
80
+ | **Secrets** | Set up a secrets manager, configure access | `bkper app secrets put` |
81
+ | **KV storage** | Deploy Redis/Memcached, manage connections | Declare `KV` in `bkper.yaml` |
82
+ | **Preview environments** | Build a staging pipeline | `bkper app deploy --preview` |
83
+ | **Shared app source** | Operate a separate private Git host | Managed source for app developers and agents |
84
+ | **Type safety** | Manually create type definitions | `env.d.ts` auto-generated |
85
+
86
+ The platform eliminates all of this. You write business logic, the platform handles infrastructure.
87
+
88
+ ## Getting started
89
+
90
+ ```bash
91
+ # Create a new app from the template
92
+ bkper app init my-app
93
+ cd my-app
94
+
95
+ # Install dependencies and start developing
96
+ npm install
97
+ npm run dev
98
+ ```
99
+
100
+ 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.
101
+
102
+ ## Next steps
103
+
104
+ - [Your First App](https://bkper.com/docs/build/apps/first-app.md) — Build and deploy a complete platform app
105
+ - [Shared App Source](https://bkper.com/docs/build/apps/shared-app-source.md) — Collaborate from one private codebase
106
+ - [App Architecture](https://bkper.com/docs/build/apps/architecture.md) — Understand how platform apps are structured
@@ -0,0 +1,63 @@
1
+ # Self-Hosted Alternative
2
+
3
+ The [Bkper Platform](https://bkper.com/docs/build/apps/overview.md) handles hosting, authentication, and deployment for you. However, you can host event handlers on your own infrastructure if you have specific requirements — existing cloud setup, compliance constraints, or legacy apps.
4
+
5
+ > **Tip**
6
+ > Use the Bkper Platform unless you have a specific reason to self-host. It eliminates the need to manage authentication, secrets, hosting, and deployment yourself.
7
+ ## Cloud Functions
8
+
9
+ A Bkper event handler running on [Google Cloud Functions](https://cloud.google.com/functions/) receives authenticated calls from the `bkper-hrd@appspot.gserviceaccount.com` service account. You need to grant this service account the [Cloud Functions Invoker IAM role](https://cloud.google.com/functions/docs/securing/managing-access-iam) (`roles/cloudfunctions.invoker`).
10
+
11
+ Set the production endpoint in [`bkper.yaml`](https://bkper.com/docs/build/apps/configuration.md):
12
+
13
+ ```yaml
14
+ webhookUrl: https://us-central1-my-project.cloudfunctions.net/events
15
+ ```
16
+
17
+ ### Authentication
18
+
19
+ An OAuth Access Token **of the user who installed the app** is sent to the production `webhookUrl` endpoint in the `bkper-oauth-token` HTTP header, along with the agent identifier in `bkper-agent-id`, on each event. Your handler uses this token to call the API back on behalf of the user.
20
+
21
+ Both production (`webhookUrl`) and development (`webhookUrlDev`) endpoints receive OAuth tokens in the `bkper-oauth-token` header.
22
+
23
+ ### Throughput and scaling
24
+
25
+ Event throughput can be high, especially when processing large batches. Set the [max instance limit](https://cloud.google.com/functions/docs/max-instances#setting_max_instances_limits) — usually **1-2 is enough**. When the function returns `429 Too Many Requests`, the event is automatically retried with incremental backoff until it receives an HTTP `200`.
26
+
27
+ ### Response format
28
+
29
+ The function response must follow the standard format:
30
+
31
+ ```ts
32
+ { result?: any, error?: any }
33
+ ```
34
+
35
+ See [Event Handlers](https://bkper.com/docs/build/apps/event-handlers.md#response-format) for details on response handling.
36
+
37
+ ### Considerations
38
+
39
+ - Execution environment is subject to [Cloud Function Quotas](https://cloud.google.com/functions/quotas) — quota counts against the developer account, not the end user
40
+ - Recommended for scenarios where event throughput exceeds **1 event/second/user** and processing can be handled asynchronously
41
+ - Can be combined with context menus built with [Apps Script HTML Service](https://developers.google.com/apps-script/guides/html) or any other UI infrastructure
42
+
43
+ ---
44
+
45
+ ## Generic Webhooks
46
+
47
+ You can host event handlers on any infrastructure — other cloud providers, containers, on-premise servers.
48
+
49
+ Configure the same `webhookUrl` property in [`bkper.yaml`](https://bkper.com/docs/build/apps/configuration.md):
50
+
51
+ ```yaml
52
+ webhookUrl: https://my-server.example.com/bkper/events
53
+ ```
54
+
55
+ ### Authentication
56
+
57
+ Calls to the production webhook URL are signed with a JWT token using the [Service to Function](https://cloud.google.com/functions/docs/securing/authenticating#service-to-function) method. You can verify this token to assert the identity of the Bkper service.
58
+
59
+ > **Note**
60
+ > Cloud Functions handles JWT verification automatically. For other infrastructure, you need to implement verification yourself. We strongly recommend Cloud Functions for this reason.
61
+ ### Retry behavior
62
+
63
+ If your infrastructure returns an HTTP `429` status, the event is automatically retried with incremental backoff until it receives an HTTP `200`. Use this to handle temporary overload gracefully.