bunnyquery 1.0.9 → 1.1.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # BunnyQuery Client
2
2
 
3
- An embeddable, zero-dependency AI chat widget that connects to a [BunnyQuery](https://www.skapi.com) project. Drop two script tags into any HTML page and your users get a fully featured chat UI backed by Claude or OpenAI, with file-attachment support, persistent history, and MCP-based authentication.
3
+ An embeddable, zero-dependency AI chat widget that connects to a [BunnyQuery](https://www.bunnyquery.com) project. Drop two `<script>` tags into any HTML page and your users get a fully featured chat UI backed by Claude or OpenAI with login, password recovery, account settings, file attachments, persistent history, and MCP-based authentication.
4
4
 
5
5
  ---
6
6
 
@@ -8,10 +8,13 @@ An embeddable, zero-dependency AI chat widget that connects to a [BunnyQuery](ht
8
8
 
9
9
  - **Plug-and-play embed** — one `<script>` tag, one `BunnyQuery.init()` call.
10
10
  - **Claude & OpenAI support** — the AI platform is selected in your project settings; the embed reads it automatically.
11
- - **MCP OAuth** — authentication uses the [Model Context Protocol](https://modelcontextprotocol.io/) OAuth flow (RFC 7591 + PKCE). No API keys are exposed to the browser.
12
- - **Login form** users who are not signed in see a username/password form; after login the MCP token exchange happens silently.
11
+ - **Built-in account UI**
12
+ - Login form (email/username + password).
13
+ - **Forgot password** flow — request a code, set a new password without leaving the embed.
14
+ - **Account settings** dialog — change email (with verification), change password, see verification status.
15
+ - **MCP OAuth** — authentication uses the [Model Context Protocol](https://modelcontextprotocol.io/) OAuth flow (RFC 7591 + PKCE). API keys never reach the browser. After a host login the embed silently exchanges the Skapi session for an MCP access token.
13
16
  - **Persistent history** — previous messages are loaded from the server on startup and paginated as the user scrolls up.
14
- - **File attachments** — users can attach files; they are uploaded to the Skapi host-file store and linked into the message as temporary CDN URLs.
17
+ - **File attachments** — files are uploaded to the Skapi host-file store and linked into the message as temporary CDN URLs.
15
18
  - **Clear / logout** — modal-confirmed actions that respect in-flight requests.
16
19
  - **Responsive** — collapses to full-screen on narrow viewports.
17
20
  - **Read-only mode** — the attach button is hidden automatically when `freeze_database` is set in the project settings.
@@ -22,19 +25,9 @@ An embeddable, zero-dependency AI chat widget that connects to a [BunnyQuery](ht
22
25
 
23
26
  ### 1. Get your project ID
24
27
 
25
- Sign in at [www.bunnyquery.com](https://www.bunnyquery.com) and open your project. Your **Project ID** is displayed in the project settings page. Copy it — you will need it in the next step.
28
+ Sign in at [www.bunnyquery.com](https://www.bunnyquery.com), open your project, and copy the **Project ID** from the project settings page.
26
29
 
27
- ### 2. Set your project ID
28
-
29
- ```html
30
- <script type="module">
31
- const PROJECT_ID = 'your-project-id-here'; // ← paste your ID here
32
- let skapi = new Skapi(PROJECT_ID, { autoLogin: true });
33
- const bqClient = await BunnyQuery.init(skapi, 'bq-client');
34
- </script>
35
- ```
36
-
37
- ## Embedding in Your Own Page
30
+ ### 2. Embed it
38
31
 
39
32
  ```html
40
33
  <!DOCTYPE html>
@@ -43,9 +36,9 @@ Sign in at [www.bunnyquery.com](https://www.bunnyquery.com) and open your projec
43
36
  <meta charset="UTF-8" />
44
37
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
45
38
  <!-- 1. Skapi SDK -->
46
- <script src="https://cdn.jsdelivr.net/npm/skapi-js@beta/dist/skapi.js"></script>
39
+ <script src="https://cdn.jsdelivr.net/npm/skapi-js@latest/dist/skapi.js"></script>
47
40
  <!-- 2. BunnyQuery widget (CSS is injected automatically) -->
48
- <script src="bunnyquery.js"></script>
41
+ <script src="https://cdn.jsdelivr.net/npm/bunnyquery@latest/bunnyquery.js"></script>
49
42
  </head>
50
43
  <body>
51
44
  <!-- 3. Mount point -->
@@ -59,63 +52,72 @@ Sign in at [www.bunnyquery.com](https://www.bunnyquery.com) and open your projec
59
52
  </html>
60
53
  ```
61
54
 
62
- The widget auto-injects `bunnyquery.css` from the same directory as `bunnyquery.js`. If you host the files on a CDN, override the stylesheet URL **before** calling `init`:
63
-
64
- ```js
65
- BunnyQuery.STYLESHEET_URL = 'https://your-cdn.example.com/bunnyquery.css';
66
- await BunnyQuery.init(skapi, 'bq-client');
67
- ```
55
+ That's it. The widget renders the chat if the user is signed in, otherwise it shows the login form.
68
56
 
69
57
  ---
70
58
 
71
59
  ## API Reference
72
60
 
73
- ### `BunnyQuery.init(skapi, elementId)` → `Promise<BunnyQuery>`
61
+ ### `BunnyQuery.init(skapi, elementId, dev?)` → `Promise<BunnyQuery>`
74
62
 
75
63
  Initialises the widget and returns the instance.
76
64
 
77
- | Parameter | Type | Description |
78
- |-----------|------|-------------|
79
- | `skapi` | `Skapi` | An initialised `Skapi` instance. |
80
- | `elementId` | `string \| HTMLElement` | The id string or DOM element to mount the widget into. |
65
+ | Parameter | Type | Description |
66
+ | ----------- | -------------------------- | -------------------------------------------------------------------------------------------------------- |
67
+ | `skapi` | `Skapi` | An initialised `Skapi` instance. |
68
+ | `elementId` | `string \| HTMLElement` | The id string or DOM element to mount the widget into. |
69
+ | `dev` | `boolean` *(optional)* | When `true`, routes every MCP call to the dev MCP host (`MCP_DEV_BASE_URL`). Omit or pass `false` in production. |
81
70
 
82
- ### Static configuration properties
71
+ ### Static configuration
83
72
 
84
- Set these **before** calling `init()`.
73
+ Set these **before** calling `init()`:
85
74
 
86
- | Property | Default | Description |
87
- |----------|---------|-------------|
88
- | `BunnyQuery.MCP_BASE_URL` | `https://mcp-dev.broadwayinc.computer` | MCP OAuth server base URL. Override to point at a different MCP host. |
89
- | `BunnyQuery.STYLESHEET_URL` | *(auto-resolved)* | Override the CSS file URL when auto-resolution fails (e.g. CDN-hosted scripts). |
75
+ | Property | Default | Description |
76
+ | -------------------------- | --------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
77
+ | `BunnyQuery.MCP_BASE_URL` | `https://mcp.broadwayinc.computer` | Production MCP OAuth server base URL. Override to target a different MCP host. Automatically swapped to the dev host when `init(..., true)` is used. |
78
+ | `BunnyQuery.STYLESHEET_URL`| *(auto-resolved)* | Override the CSS file URL when auto-resolution fails (e.g. CDN-hosted scripts behind a custom domain). |
90
79
 
91
- ---
92
-
93
- ## Project Structure
80
+ The widget auto-injects `bunnyquery.css` from the same directory as `bunnyquery.js`. If you bundle the script yourself or serve it from a path that breaks auto-resolution:
94
81
 
95
- ```
96
- bunnyquery-client/
97
- ├── index.html # Example host page
98
- ├── bunnyquery.js # Widget source (vanilla JS, no build step required)
99
- ├── bunnyquery.css # Widget styles
100
- └── package.json # Dev server only (basic-node-server)
82
+ ```js
83
+ BunnyQuery.STYLESHEET_URL = 'https://your-cdn.example.com/bunnyquery.css';
84
+ await BunnyQuery.init(skapi, 'bq-client');
101
85
  ```
102
86
 
103
87
  ---
104
88
 
105
- ## How It Works
89
+ ## Built-in Account UI
106
90
 
107
- 1. **Skapi** handles user authentication and acts as the serverless backend (database, file storage, request queueing).
108
- 2. **MCP OAuth** — after login, the embed exchanges the Skapi session tokens for an MCP access token via `/oauth/session-exchange` (no browser redirect needed). The token is cached in `localStorage`.
109
- 3. **AI requests** are made through `skapi.clientSecretRequest`, which keeps your Claude / OpenAI API key secure on the Skapi edge it is never sent to the browser.
110
- 4. Chat history is fetched with `skapi.clientSecretRequestHistory` and merged with the live message list. Pending (in-flight) requests are polled every 4 seconds until they resolve.
91
+ ### Login
92
+
93
+ Users who are not signed in see a username/password form. After a successful login the embed silently mints an MCP access token via `oauth.exchangeSession(skapi.session)` and switches to the chat view.
94
+
95
+ ### Forgot password
96
+
97
+ A **Forgot password?** link sits under the login submit button and opens a two-step recovery flow inside the same overlay:
98
+
99
+ 1. The user enters their email and presses **Send code** — calls `skapi.forgotPassword({ email })`.
100
+ 2. The user enters the verification code from their inbox plus a new password (with confirmation), and presses **Reset password** — calls `skapi.resetPassword({ email, code, new_password })`.
101
+
102
+ On success the embed returns to the login form with the email pre-filled and a confirmation notice.
103
+
104
+ ### Account settings
105
+
106
+ Once signed in, the chat header shows a **Settings** button between **Clear** and **Logout**. It opens a modal with two sections:
107
+
108
+ - **Email** — shows the current address with a *verified / unverified* badge.
109
+ - For unverified accounts (or right after a change) the user can press **Send code** (`skapi.verifyEmail()`), enter the received code, and press **Verify** (`skapi.verifyEmail({ code })`).
110
+ - Below that, **Change email** updates the address via `skapi.updateProfile({ email })`, marks it unverified, and re-opens the verify flow.
111
+ - **Password** — current / new / confirm fields with a client-side match check, calls `skapi.changePassword({ current_password, new_password })`.
112
+ - Hidden automatically for OpenID / social-login accounts (Cognito password change is not available).
111
113
 
112
114
  ---
113
115
 
114
116
  ## Customisation
115
117
 
116
- ### Mounting styles
118
+ ### Sizing
117
119
 
118
- The widget mounts inside the element you provide. Control its size via CSS on that element:
120
+ The widget fills the element you mount it into. Control size and chrome with normal CSS:
119
121
 
120
122
  ```css
121
123
  #bq-client {
@@ -129,15 +131,15 @@ The widget mounts inside the element you provide. Control its size via CSS on th
129
131
 
130
132
  All colours are CSS custom properties scoped to `.bq-agent`:
131
133
 
132
- | Variable | Default | Usage |
133
- |----------|---------|-------|
134
- | `--bq-ink` | `#111` | Primary text |
135
- | `--bq-paper` | `#fff` | Background |
136
- | `--bq-muted` | `#666` | Secondary text |
137
- | `--bq-line` | `#c8c8c8` | Borders |
138
- | `--bq-hover-bg` | `#ebebeb` | Hover states |
139
- | `--bq-pink` | `#c2185b` | Links |
140
- | `--bq-danger` | `#c44` | Destructive actions |
134
+ | Variable | Default | Usage |
135
+ | ----------------- | ---------- | -------------------- |
136
+ | `--bq-ink` | `#111` | Primary text |
137
+ | `--bq-paper` | `#fff` | Background |
138
+ | `--bq-muted` | `#666` | Secondary text |
139
+ | `--bq-line` | `#c8c8c8` | Borders |
140
+ | `--bq-hover-bg` | `#ebebeb` | Hover states |
141
+ | `--bq-pink` | `#c2185b` | Links |
142
+ | `--bq-danger` | `#c44` | Destructive actions |
141
143
 
142
144
  Override them on a parent element:
143
145
 
@@ -151,6 +153,33 @@ Override them on a parent element:
151
153
 
152
154
  ---
153
155
 
156
+ ## How It Works
157
+
158
+ 1. **Skapi** handles user authentication and acts as the serverless backend (database, file storage, request queueing).
159
+ 2. **MCP OAuth** — after login the embed exchanges the Skapi session for an MCP access token via `/oauth/session-exchange` (no browser redirect needed). The token is cached in `localStorage` and refreshed automatically on stale-token errors.
160
+ 3. **AI requests** are made through `skapi.clientSecretRequest`, which keeps your Claude / OpenAI API key on the Skapi edge — it is never sent to the browser.
161
+ 4. **History** is fetched with `skapi.clientSecretRequestHistory` and merged with the live message list. Pending (in-flight) requests are polled every 4 seconds until they resolve.
162
+
163
+ ---
164
+
165
+ ## Project Structure
166
+
167
+ ```
168
+ bunnyquery-client/
169
+ ├── index.html # Example host page
170
+ ├── bunnyquery.js # Widget source (vanilla JS, no build step)
171
+ ├── bunnyquery.css # Widget styles (auto-injected)
172
+ └── package.json # Dev server only (basic-node-server)
173
+ ```
174
+
175
+ Run locally:
176
+
177
+ ```sh
178
+ npm run dev # serves the folder on http://localhost:3333
179
+ ```
180
+
181
+ ---
182
+
154
183
  ## Requirements
155
184
 
156
185
  - A [Skapi](https://www.skapi.com) project with an AI agent configured (Claude or OpenAI).