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.
- package/README.md +1 -1
- package/lib/agent/extensions/handoff.d.ts.map +1 -1
- package/lib/agent/extensions/handoff.js +2 -0
- package/lib/agent/extensions/handoff.js.map +1 -1
- package/lib/agent/startup-maintenance.d.ts +1 -0
- package/lib/agent/startup-maintenance.d.ts.map +1 -1
- package/lib/agent/startup-maintenance.js +7 -1
- package/lib/agent/startup-maintenance.js.map +1 -1
- package/lib/agent/system-prompt.js +1 -1
- package/lib/commands/apps/git/clone.js +1 -1
- package/lib/commands/apps/git/clone.js.map +1 -1
- package/lib/commands/apps/init.d.ts +3 -1
- package/lib/commands/apps/init.d.ts.map +1 -1
- package/lib/commands/apps/init.js +105 -58
- package/lib/commands/apps/init.js.map +1 -1
- package/lib/commands/apps/register.js +2 -2
- package/lib/commands/apps/register.js.map +1 -1
- package/lib/dev/local-outbound.d.ts.map +1 -1
- package/lib/dev/local-outbound.js +17 -3
- package/lib/dev/local-outbound.js.map +1 -1
- package/lib/dev/miniflare.js +1 -1
- package/lib/dev/miniflare.js.map +1 -1
- package/lib/dev/preflight.js +1 -1
- package/lib/dev/preflight.js.map +1 -1
- package/lib/dev/shared.js +1 -1
- package/lib/dev/shared.js.map +1 -1
- package/lib/docs/apps/ai.md +270 -0
- package/lib/docs/apps/app-listing.md +86 -0
- package/lib/docs/apps/architecture.md +188 -0
- package/lib/docs/apps/configuration.md +171 -0
- package/lib/docs/apps/context-menu.md +69 -0
- package/lib/docs/apps/deploying.md +181 -0
- package/lib/docs/apps/development.md +122 -0
- package/lib/docs/apps/event-handlers.md +248 -0
- package/lib/docs/apps/first-app.md +76 -0
- package/lib/docs/apps/overview.md +106 -0
- package/lib/docs/apps/self-hosted.md +63 -0
- package/lib/docs/apps/shared-app-source.md +85 -0
- package/lib/docs/cli/app-management.md +16 -4
- package/lib/docs/index.md +12 -1
- package/lib/docs/sdk/bkper-js.md +5 -0
- package/lib/upgrade/index.d.ts +1 -1
- package/lib/upgrade/index.d.ts.map +1 -1
- package/lib/upgrade/index.js +1 -1
- package/lib/upgrade/index.js.map +1 -1
- package/lib/upgrade/installation.d.ts +4 -0
- package/lib/upgrade/installation.d.ts.map +1 -1
- package/lib/upgrade/installation.js +23 -0
- package/lib/upgrade/installation.js.map +1 -1
- package/package.json +3 -3
- package/lib/docs/apps/app-building.md +0 -1429
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# App Architecture
|
|
2
|
+
|
|
3
|
+
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`.
|
|
4
|
+
|
|
5
|
+
Treat `/api/*` as the reusable surface for app behavior. The bundled web client is one consumer; scripts, external clients, and agents can call the same routes with bearer authentication.
|
|
6
|
+
|
|
7
|
+
## Structure
|
|
8
|
+
|
|
9
|
+
```txt
|
|
10
|
+
my-app/
|
|
11
|
+
├── client/
|
|
12
|
+
│ ├── index.html
|
|
13
|
+
│ ├── package.json
|
|
14
|
+
│ ├── vite.config.ts
|
|
15
|
+
│ └── src/
|
|
16
|
+
│ ├── api/
|
|
17
|
+
│ ├── app/
|
|
18
|
+
│ ├── auth/
|
|
19
|
+
│ ├── components/
|
|
20
|
+
│ └── services/
|
|
21
|
+
├── server/
|
|
22
|
+
│ ├── package.json
|
|
23
|
+
│ └── src/
|
|
24
|
+
│ ├── api/
|
|
25
|
+
│ ├── events/
|
|
26
|
+
│ ├── services/
|
|
27
|
+
│ └── index.ts
|
|
28
|
+
├── scripts/
|
|
29
|
+
├── bkper.yaml
|
|
30
|
+
├── env.d.ts
|
|
31
|
+
├── package.json
|
|
32
|
+
├── package-lock.json
|
|
33
|
+
└── tsconfig.json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The root npm workspace orchestrates development, tests, builds, and deployment. The template keeps browser dependencies in `client/` and Worker dependencies in `server/`. Add a shared package only when both sides actually need one.
|
|
37
|
+
|
|
38
|
+
## Client
|
|
39
|
+
|
|
40
|
+
The client uses:
|
|
41
|
+
|
|
42
|
+
- [Lit](https://lit.dev/) for components and rendering.
|
|
43
|
+
- [Web Awesome](https://webawesome.com/) for UI components.
|
|
44
|
+
- [`@bkper/web-design`](https://www.npmjs.com/package/@bkper/web-design) for Bkper design tokens.
|
|
45
|
+
- [Vite](https://vitejs.dev/) for development and production builds, configured in `client/vite.config.ts`.
|
|
46
|
+
|
|
47
|
+
Client code has two data paths:
|
|
48
|
+
|
|
49
|
+
- **Direct Bkper calls** use `bkper-js` for browser-specific behavior.
|
|
50
|
+
- **App API calls** use the generated typed client in `client/src/api/` with `auth.authenticatedFetch()`.
|
|
51
|
+
|
|
52
|
+
### Client authentication
|
|
53
|
+
|
|
54
|
+
The client authenticates users with [`@bkper/web-auth`](https://www.npmjs.com/package/@bkper/web-auth). OAuth is preconfigured on the platform, so there are no client IDs, redirect URIs, or consent screens to configure.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { Bkper } from 'bkper-js';
|
|
58
|
+
import { BkperAuth } from '@bkper/web-auth';
|
|
59
|
+
|
|
60
|
+
const isLocalDev = ['localhost', '127.0.0.1'].includes(window.location.hostname);
|
|
61
|
+
const auth = new BkperAuth({
|
|
62
|
+
baseUrl: isLocalDev ? window.location.origin : undefined,
|
|
63
|
+
onLoginSuccess: () => initializeApp(),
|
|
64
|
+
onLoginRequired: () => showLoginButton(),
|
|
65
|
+
});
|
|
66
|
+
await auth.init();
|
|
67
|
+
|
|
68
|
+
const bkper = new Bkper({
|
|
69
|
+
oauthTokenProvider: async () => auth.getAccessToken(),
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`@bkper/web-auth` handles login, redirects, and token refresh. The template keeps this behavior behind `client/src/auth/auth-session.ts`.
|
|
74
|
+
|
|
75
|
+
See the [@bkper/web-auth API Reference](https://bkper.com/docs/api/bkper-web-auth.md) for the full SDK documentation.
|
|
76
|
+
|
|
77
|
+
## Server Worker
|
|
78
|
+
|
|
79
|
+
The server runs on [Cloudflare Workers](https://developers.cloudflare.com/workers/) and uses [Hono](https://hono.dev/) with typed OpenAPI routes. It handles:
|
|
80
|
+
|
|
81
|
+
- app API routes under `/api/*`;
|
|
82
|
+
- Bkper event ingress under `/events`;
|
|
83
|
+
- platform services such as KV and secrets through `c.env`;
|
|
84
|
+
- static client assets through the `ASSETS` binding.
|
|
85
|
+
|
|
86
|
+
The Worker entry point composes those concerns while routes delegate business behavior to services:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { OpenAPIHono } from '@hono/zod-openapi';
|
|
90
|
+
import { registerApiRoutes } from './api/routes.js';
|
|
91
|
+
import { registerEventRoutes } from './events/routes.js';
|
|
92
|
+
import { appContextMiddleware, type AppEnv } from './app-context.js';
|
|
93
|
+
|
|
94
|
+
const app = new OpenAPIHono();
|
|
95
|
+
|
|
96
|
+
app.use('/api/*', appContextMiddleware());
|
|
97
|
+
app.use('/events', appContextMiddleware());
|
|
98
|
+
registerApiRoutes(app);
|
|
99
|
+
registerEventRoutes(app);
|
|
100
|
+
|
|
101
|
+
app.get('*', c => c.env.ASSETS.fetch(c.req.raw));
|
|
102
|
+
|
|
103
|
+
export default app;
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## App API contract
|
|
107
|
+
|
|
108
|
+
The default template publishes versioned routes under `/api/v1/*` and exposes their OpenAPI contract at `/openapi.json`.
|
|
109
|
+
|
|
110
|
+
| Concern | Location |
|
|
111
|
+
| ---------------------------- | ------------------------------------- |
|
|
112
|
+
| OpenAPI metadata | `server/src/api/openapi.ts` |
|
|
113
|
+
| Request and response schemas | `server/src/api/schemas.ts` |
|
|
114
|
+
| Thin route handlers | `server/src/api/routes.ts` |
|
|
115
|
+
| Business behavior | `server/src/services/` |
|
|
116
|
+
| Generated client types | `client/src/api/generated/types.d.ts` |
|
|
117
|
+
| Typed client wrapper | `client/src/api/app-api.ts` |
|
|
118
|
+
| Contract snapshot | `server/test/openapi.snapshot.json` |
|
|
119
|
+
|
|
120
|
+
When changing the API:
|
|
121
|
+
|
|
122
|
+
1. Update schemas, services, routes, and focused unit tests.
|
|
123
|
+
2. Run `npm run api` to regenerate client types.
|
|
124
|
+
3. Review the OpenAPI snapshot when the public contract changes.
|
|
125
|
+
4. Run `npm run check` before release.
|
|
126
|
+
|
|
127
|
+
Keep existing `/api/v1/*` contracts backward compatible. Additive fields and routes can remain in `v1`; breaking changes belong in a new namespace such as `/api/v2/*`.
|
|
128
|
+
|
|
129
|
+
### URLs
|
|
130
|
+
|
|
131
|
+
```txt
|
|
132
|
+
Production API: https://{appId}.bkper.app/api/*
|
|
133
|
+
Preview API: https://{appId}-preview.bkper.app/api/*
|
|
134
|
+
Local API: http://localhost:8787/api/*
|
|
135
|
+
|
|
136
|
+
Production spec: https://{appId}.bkper.app/openapi.json
|
|
137
|
+
Preview spec: https://{appId}-preview.bkper.app/openapi.json
|
|
138
|
+
Local spec: http://localhost:8787/openapi.json
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Example script call:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
TOKEN="$(bkper auth token)"
|
|
145
|
+
|
|
146
|
+
curl \
|
|
147
|
+
-H "Authorization: Bearer ${TOKEN}" \
|
|
148
|
+
"https://my-app.bkper.app/api/v1/books"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Replace `my-app` with the app id from `bkper.yaml`.
|
|
152
|
+
|
|
153
|
+
### Server API authentication
|
|
154
|
+
|
|
155
|
+
Deployed `/api/*` routes require a Bkper OAuth bearer token. The template client uses `authenticatedFetch()` so token attachment and refresh stay inside `@bkper/web-auth`:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
const response = await auth.authenticatedFetch('/api/v1/books');
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Dispatch validates the incoming bearer token and strips the `Authorization` header before the Worker runs. Server code should not read or forward the token.
|
|
162
|
+
|
|
163
|
+
When a route calls Bkper, create the SDK without a token provider:
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
import { Bkper } from 'bkper-js';
|
|
167
|
+
|
|
168
|
+
const bkper = new Bkper();
|
|
169
|
+
const books = await bkper.getBooks();
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Platform outbound authentication injects the validated user's OAuth token on Bkper API requests.
|
|
173
|
+
|
|
174
|
+
## Event handlers
|
|
175
|
+
|
|
176
|
+
Platform event deliveries reach `/events` on the same Worker. Event adapters live in `server/src/events/`, while reusable business behavior belongs in `server/src/services/`.
|
|
177
|
+
|
|
178
|
+
Event code uses server-side `new Bkper()` and must not read `bkper-oauth-token`, `bkper-agent-id`, or `Authorization` headers. Dispatch and platform outbound authentication handle the event token and app agent identity.
|
|
179
|
+
|
|
180
|
+
See [Event Handlers](https://bkper.com/docs/build/apps/event-handlers.md) for routing, responses, loop prevention, and event types. Self-hosted handlers process event authentication directly because the platform outbound layer is not involved.
|
|
181
|
+
|
|
182
|
+
## App shapes
|
|
183
|
+
|
|
184
|
+
The platform supports different shapes:
|
|
185
|
+
|
|
186
|
+
- **Full app** — Client UI, `/api/*` backend behavior, and `/events` automation in one Worker. This is the default template.
|
|
187
|
+
- **Event-only app** — Keep `server/` and omit `deployment.client`.
|
|
188
|
+
- **UI-only app** — Keep a minimal Worker for static assets when behavior is truly browser-only. Add `/api/*` when scripts, integrations, or agents should reuse that behavior.
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# App Configuration
|
|
2
|
+
|
|
3
|
+
The `bkper.yaml` file is the single configuration file for your Bkper app. It defines the app's identity, access control, menu integration, event handling, and deployment settings.
|
|
4
|
+
|
|
5
|
+
It lives in the root of your project. Use `bkper app sync` to push metadata changes to Bkper, and use `bkper app deploy` to upload built code to the platform.
|
|
6
|
+
|
|
7
|
+
## Minimal example
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
id: my-app
|
|
11
|
+
name: My App
|
|
12
|
+
description: A Bkper app that does something useful
|
|
13
|
+
developers: myuser
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Starter example
|
|
17
|
+
|
|
18
|
+
From the [app template](https://github.com/bkper/bkper-app-template):
|
|
19
|
+
|
|
20
|
+
```yaml
|
|
21
|
+
id: my-app
|
|
22
|
+
name: My App
|
|
23
|
+
description: A Bkper app that does something useful
|
|
24
|
+
|
|
25
|
+
logoUrl: https://my-app.bkper.app/images/logo-light.svg
|
|
26
|
+
logoUrlDark: https://my-app.bkper.app/images/logo-dark.svg
|
|
27
|
+
|
|
28
|
+
website: https://my-app.bkper.app
|
|
29
|
+
ownerName: Bkper
|
|
30
|
+
ownerLogoUrl: https://avatars.githubusercontent.com/u/11943086?v=4
|
|
31
|
+
ownerWebsite: https://bkper.com
|
|
32
|
+
|
|
33
|
+
developers: someuser *@yoursite.com
|
|
34
|
+
users: someuser *@yoursite.com
|
|
35
|
+
|
|
36
|
+
menuUrl: https://my-app.bkper.app?bookId=${book.id}
|
|
37
|
+
menuUrlDev: https://my-app-preview.bkper.app?bookId=${book.id}
|
|
38
|
+
menuOpenMode: SIDEBAR
|
|
39
|
+
|
|
40
|
+
webhookUrl: https://my-app.bkper.app/events
|
|
41
|
+
webhookUrlDev: https://my-app-preview.bkper.app/events
|
|
42
|
+
apiVersion: v5
|
|
43
|
+
events:
|
|
44
|
+
- TRANSACTION_CHECKED
|
|
45
|
+
|
|
46
|
+
deployment:
|
|
47
|
+
server: server/src/index.ts
|
|
48
|
+
client: client
|
|
49
|
+
services:
|
|
50
|
+
- KV
|
|
51
|
+
secrets: []
|
|
52
|
+
compatibility_date: '2026-01-28'
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### App identity
|
|
56
|
+
|
|
57
|
+
| Field | Description |
|
|
58
|
+
| ------------- | --------------------------------------------------------------------------------------------------------- |
|
|
59
|
+
| `id` | Permanent app identifier. Lowercase letters, numbers, and hyphens only. Cannot be changed after creation. |
|
|
60
|
+
| `name` | Display name shown in the Bkper UI. |
|
|
61
|
+
| `description` | Brief description of what the app does. |
|
|
62
|
+
|
|
63
|
+
### Branding
|
|
64
|
+
|
|
65
|
+
| Field | Description |
|
|
66
|
+
| ------------- | ------------------------------------------ |
|
|
67
|
+
| `logoUrl` | App logo for light mode (SVG recommended). |
|
|
68
|
+
| `logoUrlDark` | App logo for dark mode. |
|
|
69
|
+
| `website` | App website or documentation URL. |
|
|
70
|
+
|
|
71
|
+
### Ownership
|
|
72
|
+
|
|
73
|
+
| Field | Description |
|
|
74
|
+
| -------------- | ------------------------------------------------------------ |
|
|
75
|
+
| `ownerName` | Developer or company name. |
|
|
76
|
+
| `ownerLogoUrl` | Owner's logo/avatar URL. |
|
|
77
|
+
| `ownerWebsite` | Owner's website. |
|
|
78
|
+
| `repoUrl` | Source code repository URL. |
|
|
79
|
+
| `repoPrivate` | Whether the repository is private. |
|
|
80
|
+
| `deprecated` | Hides from app listings; existing installs continue working. |
|
|
81
|
+
|
|
82
|
+
### Access control
|
|
83
|
+
|
|
84
|
+
| Field | Description |
|
|
85
|
+
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
86
|
+
| `developers` | Who can update the app and deploy new versions. Accepts comma- or space-separated Bkper usernames and domain wildcards such as `*@yoursite.com`. |
|
|
87
|
+
| `users` | Who can install and use the app. Uses the same format as `developers`; leave empty for public apps. |
|
|
88
|
+
|
|
89
|
+
### Menu integration
|
|
90
|
+
|
|
91
|
+
| Field | Description |
|
|
92
|
+
| -------------- | --------------------------------------------------------------------------- |
|
|
93
|
+
| `menuUrl` | Production menu URL. Supports [variable substitution](#menu-url-variables). |
|
|
94
|
+
| `menuUrlDev` | Development menu URL, typically a preview or local app URL. |
|
|
95
|
+
| `menuText` | Custom menu text (defaults to app name). |
|
|
96
|
+
| `menuOpenMode` | How the app menu opens: `SIDEBAR` (default), `EXPANDED`, or `NEW_TAB`. |
|
|
97
|
+
|
|
98
|
+
See [Context Menu](https://bkper.com/docs/build/apps/context-menu.md) for details on building menu integrations.
|
|
99
|
+
|
|
100
|
+
### Menu URL variables
|
|
101
|
+
|
|
102
|
+
The following variables can be used in `menuUrl` and `menuUrlDev`:
|
|
103
|
+
|
|
104
|
+
| Variable | Description |
|
|
105
|
+
| --------------------------- | ---------------------------------------- |
|
|
106
|
+
| `${book.id}` | Current book ID |
|
|
107
|
+
| `${book.properties.xxx}` | Book property value |
|
|
108
|
+
| `${account.id}` | Selected account ID |
|
|
109
|
+
| `${account.name}` | Selected account name |
|
|
110
|
+
| `${account.properties.xxx}` | Account property value |
|
|
111
|
+
| `${group.id}` | Selected group ID |
|
|
112
|
+
| `${group.name}` | Selected group name |
|
|
113
|
+
| `${group.properties.xxx}` | Group property value |
|
|
114
|
+
| `${transactions.ids}` | Comma-separated selected transaction IDs |
|
|
115
|
+
| `${transactions.query}` | Current search query |
|
|
116
|
+
|
|
117
|
+
### Event handling
|
|
118
|
+
|
|
119
|
+
| Field | Description |
|
|
120
|
+
| --------------- | ----------------------------------------------------------------------------------- |
|
|
121
|
+
| `webhookUrl` | Production webhook URL for receiving events. |
|
|
122
|
+
| `webhookUrlDev` | Development webhook URL (auto-updated by `bkper app dev`). |
|
|
123
|
+
| `apiVersion` | API version for event payloads (currently `v5`). |
|
|
124
|
+
| `events` | List of [event types](https://bkper.com/docs/build/apps/event-handlers.md#event-types) to subscribe to. |
|
|
125
|
+
|
|
126
|
+
See [Event Handlers](https://bkper.com/docs/build/apps/event-handlers.md) for details on handling events.
|
|
127
|
+
|
|
128
|
+
### File patterns
|
|
129
|
+
|
|
130
|
+
| Field | Description |
|
|
131
|
+
| -------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
132
|
+
| `filePatterns` | List of glob patterns (e.g., `*.ofx`, `*.csv`). When a matching file is uploaded, a `FILE_CREATED` event is triggered. |
|
|
133
|
+
|
|
134
|
+
### Properties schema
|
|
135
|
+
|
|
136
|
+
The `propertiesSchema` field defines autocomplete suggestions for custom properties in the Bkper UI, helping users discover the correct property keys and values for your app.
|
|
137
|
+
|
|
138
|
+
Suggested keys must follow the same custom property rules as user-entered keys, including the 30-character maximum after normalization.
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
propertiesSchema:
|
|
142
|
+
book:
|
|
143
|
+
keys:
|
|
144
|
+
- my_app_enabled
|
|
145
|
+
values:
|
|
146
|
+
- 'true'
|
|
147
|
+
- 'false'
|
|
148
|
+
group:
|
|
149
|
+
keys:
|
|
150
|
+
- my_app_category
|
|
151
|
+
account:
|
|
152
|
+
keys:
|
|
153
|
+
- my_app_sync_id
|
|
154
|
+
transaction:
|
|
155
|
+
keys:
|
|
156
|
+
- my_app_reference
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Deployment
|
|
160
|
+
|
|
161
|
+
For apps deployed to the [Bkper Platform](https://bkper.com/docs/build/apps/overview.md):
|
|
162
|
+
|
|
163
|
+
| Field | Description |
|
|
164
|
+
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
165
|
+
| `deployment.server` | TypeScript entry point for the single server Worker. It serves `/api/*`, `/events`, and static assets. |
|
|
166
|
+
| `deployment.client` | Optional Vite/static client root. Built assets are deployed with the same Worker. |
|
|
167
|
+
| `deployment.services` | Platform services to provision. Currently: `KV` (key-value storage). |
|
|
168
|
+
| `deployment.secrets` | Secret names used by the app. Managed via `bkper app secrets`. |
|
|
169
|
+
| `deployment.compatibility_date` | [Cloudflare Workers compatibility date](https://developers.cloudflare.com/workers/configuration/compatibility-dates/). |
|
|
170
|
+
|
|
171
|
+
See [Building & Deploying](https://bkper.com/docs/build/apps/deploying.md) for the full deployment workflow.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Context Menu
|
|
2
|
+
|
|
3
|
+
Apps can add context menu items on the Transactions page **More** menu in your Books. This lets you open dynamically built URLs with reference to the current Book's context — the active query, selected account, date range, and more.
|
|
4
|
+
|
|
5
|
+
## How it works
|
|
6
|
+
|
|
7
|
+
Once you install an App with a menu configuration, a new menu item appears in your Book:
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
When clicked, a popup opens carrying the particular context of that book at that moment:
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
## Configuration
|
|
16
|
+
|
|
17
|
+
Configure the menu URL in your [`bkper.yaml`](https://bkper.com/docs/build/apps/configuration.md):
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
menuUrl: https://my-app.bkper.app?bookId=${book.id}&query=${transactions.query}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
When the user clicks the menu item, the URL expressions `${xxxx}` are replaced with contextual information from the Book:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
https://my-app.bkper.app?bookId=abc123&query=account:Sales
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Where `abc123` is the current Book id and `account:Sales` is the current query being executed.
|
|
30
|
+
|
|
31
|
+
### Development URL
|
|
32
|
+
|
|
33
|
+
Use `menuUrlDev` to keep developer testing separate from production. The app template points it to the preview deployment:
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
menuUrl: https://my-app.bkper.app?bookId=${book.id}&query=${transactions.query}
|
|
37
|
+
menuUrlDev: https://my-app-preview.bkper.app?bookId=${book.id}&query=${transactions.query}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
During local development, you can instead point it to the local Worker URL at `http://localhost:8787`. The development URL is used when an app developer clicks the menu item.
|
|
41
|
+
|
|
42
|
+
### Menu open mode
|
|
43
|
+
|
|
44
|
+
Control how the menu opens with `menuOpenMode`:
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
menuOpenMode: SIDEBAR
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
| Mode | Behavior |
|
|
51
|
+
| ---------- | --------------------------------------------------------------------- |
|
|
52
|
+
| `SIDEBAR` | Opens in a narrow side panel (default). |
|
|
53
|
+
| `EXPANDED` | Opens in a wider panel with more room for complex UIs. |
|
|
54
|
+
| `NEW_TAB` | Opens the menu URL in a new browser tab instead of an embedded panel. |
|
|
55
|
+
|
|
56
|
+
### Available expressions
|
|
57
|
+
|
|
58
|
+
The menu URL supports these dynamic expressions:
|
|
59
|
+
|
|
60
|
+
| Expression | Description |
|
|
61
|
+
| ----------------------- | ------------------------- |
|
|
62
|
+
| `${book.id}` | The current Book ID |
|
|
63
|
+
| `${transactions.query}` | The current query string |
|
|
64
|
+
| `${account.id}` | The selected account ID |
|
|
65
|
+
| `${account.name}` | The selected account name |
|
|
66
|
+
| `${group.id}` | The selected group ID |
|
|
67
|
+
| `${group.name}` | The selected group name |
|
|
68
|
+
|
|
69
|
+
For the full list of accepted expressions, see the [Menu URL variables](https://bkper.com/docs/build/apps/configuration.md#menu-url-variables) reference.
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Building & Deploying
|
|
2
|
+
|
|
3
|
+
## The deployment workflow
|
|
4
|
+
|
|
5
|
+
Run the template's deterministic checks before releasing:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm run check
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
1. **Build** — Compile your code
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm run build
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
This runs two build steps:
|
|
18
|
+
- Client (Vite) to static assets in `dist/client/`
|
|
19
|
+
- Server Worker bundle (esbuild) to `dist/server/`
|
|
20
|
+
|
|
21
|
+
Build output includes size reporting so you can monitor bundle sizes.
|
|
22
|
+
|
|
23
|
+
2. **Sync** — Update app metadata and managed source
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bkper app sync
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Syncs your `bkper.yaml` configuration to Bkper — name, description, menu URLs, webhook URLs, access control, and branding. For an app using Bkper-managed source, it also safely pushes the current clean, committed branch. Sync does not build or deploy the app.
|
|
30
|
+
|
|
31
|
+
3. **Deploy** — Upload the local build to the platform
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
bkper app deploy
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For a managed-source app, deploy safely pushes and verifies the current commit. It then uploads your existing pre-built code from `dist/` to the Bkper Platform. The command does not run a build. Your app is live at `https://{appId}.bkper.app`.
|
|
38
|
+
|
|
39
|
+
The app template combines all three after source changes are committed:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm run deploy
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Use `npm run deploy:preview` for the preview environment.
|
|
46
|
+
|
|
47
|
+
> **Caution: Source is not deployment**
|
|
48
|
+
> An ordinary `git push` stores source only and never deploys. `bkper app sync` also does not deploy. Run `bkper app deploy` explicitly when the local build is ready to release.
|
|
49
|
+
See [Shared App Source](https://bkper.com/docs/build/apps/shared-app-source.md) for managed-source setup, cloning, access, and external Git workflows.
|
|
50
|
+
|
|
51
|
+
### Production
|
|
52
|
+
|
|
53
|
+
The default deployment target. Your app runs at `https://{appId}.bkper.app`.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
bkper app deploy
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Production serves:
|
|
60
|
+
|
|
61
|
+
```txt
|
|
62
|
+
Client: https://{appId}.bkper.app
|
|
63
|
+
API routes: https://{appId}.bkper.app/api/*
|
|
64
|
+
OpenAPI spec: https://{appId}.bkper.app/openapi.json
|
|
65
|
+
Events: https://{appId}.bkper.app/events
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Preview
|
|
69
|
+
|
|
70
|
+
Deploy to a separate preview environment for testing before production:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
bkper app deploy --preview
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Preview URLs use a dash suffix: `https://{appId}-preview.bkper.app`. For example, an app with `id: my-app` deploys to `https://my-app-preview.bkper.app`.
|
|
77
|
+
|
|
78
|
+
Preview serves:
|
|
79
|
+
|
|
80
|
+
```txt
|
|
81
|
+
Client: https://{appId}-preview.bkper.app
|
|
82
|
+
API routes: https://{appId}-preview.bkper.app/api/*
|
|
83
|
+
OpenAPI spec: https://{appId}-preview.bkper.app/openapi.json
|
|
84
|
+
Events: https://{appId}-preview.bkper.app/events
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Preview has independent secrets and KV storage from production.
|
|
88
|
+
|
|
89
|
+
There is one app deployment per environment. `/events` is handled by the same Worker as the client assets and `/api/*` routes.
|
|
90
|
+
|
|
91
|
+
## Secrets management
|
|
92
|
+
|
|
93
|
+
Secrets are environment variables stored securely on the platform. Declare them in `bkper.yaml`:
|
|
94
|
+
|
|
95
|
+
```yaml
|
|
96
|
+
deployment:
|
|
97
|
+
secrets:
|
|
98
|
+
- EXTERNAL_SERVICE_TOKEN
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Setting secrets
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Set for production
|
|
105
|
+
bkper app secrets put EXTERNAL_SERVICE_TOKEN
|
|
106
|
+
|
|
107
|
+
# Set for preview
|
|
108
|
+
bkper app secrets put EXTERNAL_SERVICE_TOKEN --preview
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
You'll be prompted to enter the value.
|
|
112
|
+
|
|
113
|
+
### Listing and deleting
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# List all secrets
|
|
117
|
+
bkper app secrets list
|
|
118
|
+
|
|
119
|
+
# Delete a secret
|
|
120
|
+
bkper app secrets delete EXTERNAL_SERVICE_TOKEN
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Accessing in code
|
|
124
|
+
|
|
125
|
+
Secrets are available as `c.env.SECRET_NAME` in your Hono handlers:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
app.get('/api/data', async c => {
|
|
129
|
+
const token = c.env.EXTERNAL_SERVICE_TOKEN;
|
|
130
|
+
// use token
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
During local development, use the `.dev.vars` file instead. See [Development Experience](https://bkper.com/docs/build/apps/development.md#local-secrets).
|
|
135
|
+
|
|
136
|
+
### KV storage
|
|
137
|
+
|
|
138
|
+
Declare KV in `bkper.yaml`:
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
deployment:
|
|
142
|
+
services:
|
|
143
|
+
- KV
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The platform provisions a KV namespace for your app. Access it via `c.env.KV`:
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
await c.env.KV.put('key', 'value', { expirationTtl: 3600 });
|
|
150
|
+
const value = await c.env.KV.get('key');
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
KV storage is separate between production and preview environments.
|
|
154
|
+
|
|
155
|
+
## Deployment status
|
|
156
|
+
|
|
157
|
+
Check the current state of your deployment:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
bkper app status
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Installing on books
|
|
164
|
+
|
|
165
|
+
After deploying, install the app on specific books to activate it:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
# Install on a book
|
|
169
|
+
bkper app install <appId> -b <bookId>
|
|
170
|
+
|
|
171
|
+
# Uninstall from a book
|
|
172
|
+
bkper app uninstall <appId> -b <bookId>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
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.
|
|
176
|
+
|
|
177
|
+
## Next steps
|
|
178
|
+
|
|
179
|
+
- [Shared App Source](https://bkper.com/docs/build/apps/shared-app-source.md) — Share private source without coupling Git pushes to deployment
|
|
180
|
+
- [Development Experience](https://bkper.com/docs/build/apps/development.md) — Run the app and event delivery locally
|
|
181
|
+
- [App Listing](https://bkper.com/docs/build/apps/app-listing.md) — Prepare the app for installation
|