@butterbase/sdk 2.3.4 → 2.4.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/README.md +339 -339
- package/package.json +51 -51
package/README.md
CHANGED
|
@@ -1,339 +1,339 @@
|
|
|
1
|
-
# @butterbase/sdk
|
|
2
|
-
|
|
3
|
-
Universal TypeScript SDK for Butterbase - works in browser, Node.js, and Deno environments.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install @butterbase/sdk
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Quick Start
|
|
12
|
-
|
|
13
|
-
```typescript
|
|
14
|
-
import { createClient } from '@butterbase/sdk';
|
|
15
|
-
|
|
16
|
-
// Initialize client.
|
|
17
|
-
// apiUrl is the same regardless of which region your app lives in —
|
|
18
|
-
// requests are routed to the right region automatically.
|
|
19
|
-
const butterbase = createClient({
|
|
20
|
-
appId: 'app_abc123',
|
|
21
|
-
apiUrl: 'https://api.butterbase.ai',
|
|
22
|
-
anonKey: 'your-anon-key' // Optional, for public access
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// Query data
|
|
26
|
-
const { data, error } = await butterbase
|
|
27
|
-
.from('posts')
|
|
28
|
-
.select('*')
|
|
29
|
-
.eq('status', 'published')
|
|
30
|
-
.order('created_at', { ascending: false })
|
|
31
|
-
.limit(10);
|
|
32
|
-
|
|
33
|
-
// Insert data
|
|
34
|
-
const { data, error } = await butterbase
|
|
35
|
-
.from('posts')
|
|
36
|
-
.insert({ title: 'Hello World', content: 'My first post' });
|
|
37
|
-
|
|
38
|
-
// Update data
|
|
39
|
-
const { data, error } = await butterbase
|
|
40
|
-
.from('posts')
|
|
41
|
-
.update({ status: 'archived' })
|
|
42
|
-
.eq('id', '123');
|
|
43
|
-
|
|
44
|
-
// Delete data
|
|
45
|
-
const { data, error } = await butterbase
|
|
46
|
-
.from('posts')
|
|
47
|
-
.delete()
|
|
48
|
-
.eq('id', '123');
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Migration from 0.x to 1.0
|
|
52
|
-
|
|
53
|
-
**Breaking Change:** The `authUrl` parameter has been removed. All auth endpoints now run on the same URL as the API.
|
|
54
|
-
|
|
55
|
-
**Before (0.x):**
|
|
56
|
-
```typescript
|
|
57
|
-
const butterbase = createClient({
|
|
58
|
-
appId: 'app_abc123',
|
|
59
|
-
apiUrl: 'https://api.butterbase.ai',
|
|
60
|
-
authUrl: 'https://auth.butterbase.com', // ❌ No longer needed
|
|
61
|
-
});
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
**After (1.0):**
|
|
65
|
-
```typescript
|
|
66
|
-
const butterbase = createClient({
|
|
67
|
-
appId: 'app_abc123',
|
|
68
|
-
apiUrl: 'https://api.butterbase.ai', // ✅ All endpoints use this URL
|
|
69
|
-
});
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Authentication
|
|
73
|
-
|
|
74
|
-
Sessions are automatically persisted to `localStorage` and restored on page refresh. Access tokens are automatically refreshed before they expire.
|
|
75
|
-
|
|
76
|
-
```typescript
|
|
77
|
-
// Sign up
|
|
78
|
-
const { data, error } = await butterbase.auth.signUp({
|
|
79
|
-
email: 'user@example.com',
|
|
80
|
-
password: 'secure123'
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// Sign in (session is automatically persisted)
|
|
84
|
-
const { data, error } = await butterbase.auth.signIn({
|
|
85
|
-
email: 'user@example.com',
|
|
86
|
-
password: 'secure123'
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
// Get current user (works after page refresh)
|
|
90
|
-
const { data: user } = await butterbase.auth.getUser();
|
|
91
|
-
|
|
92
|
-
// Sign out (clears persisted session)
|
|
93
|
-
await butterbase.auth.signOut();
|
|
94
|
-
|
|
95
|
-
// Refresh session manually (uses stored refresh token if none provided)
|
|
96
|
-
const { data } = await butterbase.auth.refreshSession();
|
|
97
|
-
|
|
98
|
-
// OAuth
|
|
99
|
-
const { url } = butterbase.auth.signInWithOAuth({
|
|
100
|
-
provider: 'google',
|
|
101
|
-
redirectTo: 'http://localhost:3000/callback'
|
|
102
|
-
});
|
|
103
|
-
window.location.href = url;
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Auth State Changes
|
|
107
|
-
|
|
108
|
-
Subscribe to authentication events to react to sign-ins, sign-outs, and token refreshes:
|
|
109
|
-
|
|
110
|
-
```typescript
|
|
111
|
-
const { unsubscribe } = butterbase.onAuthStateChange((event, session) => {
|
|
112
|
-
// event: 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'SESSION_RESTORED'
|
|
113
|
-
console.log(event, session?.user);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
// Stop listening
|
|
117
|
-
unsubscribe();
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### React Usage
|
|
121
|
-
|
|
122
|
-
```typescript
|
|
123
|
-
import { useEffect, useState } from 'react';
|
|
124
|
-
import { butterbase } from './lib';
|
|
125
|
-
|
|
126
|
-
function App() {
|
|
127
|
-
const [user, setUser] = useState(null);
|
|
128
|
-
|
|
129
|
-
useEffect(() => {
|
|
130
|
-
// Session is auto-restored — check current state
|
|
131
|
-
const session = butterbase.sessionManager.getSession();
|
|
132
|
-
if (session) setUser(session.user);
|
|
133
|
-
|
|
134
|
-
// React to future auth changes
|
|
135
|
-
const { unsubscribe } = butterbase.onAuthStateChange((event, session) => {
|
|
136
|
-
setUser(session?.user ?? null);
|
|
137
|
-
});
|
|
138
|
-
return unsubscribe;
|
|
139
|
-
}, []);
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### Custom Storage
|
|
144
|
-
|
|
145
|
-
By default, the SDK uses `localStorage` with an in-memory fallback for SSR/Node.js environments. You can provide a custom storage adapter:
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
import { createClient, MemorySessionStorage } from '@butterbase/sdk';
|
|
149
|
-
|
|
150
|
-
// Memory-only (no persistence)
|
|
151
|
-
const butterbase = createClient({
|
|
152
|
-
appId: 'app_abc123',
|
|
153
|
-
apiUrl: 'https://api.butterbase.ai',
|
|
154
|
-
persistSession: false,
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
// Custom storage adapter (e.g., for React Native)
|
|
158
|
-
const butterbase = createClient({
|
|
159
|
-
appId: 'app_abc123',
|
|
160
|
-
apiUrl: 'https://api.butterbase.ai',
|
|
161
|
-
sessionStorage: myCustomStorage, // implements { getItem, setItem, removeItem }
|
|
162
|
-
});
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
## Storage
|
|
166
|
-
|
|
167
|
-
```typescript
|
|
168
|
-
// Upload file
|
|
169
|
-
const { data, error } = await butterbase.storage.upload(file);
|
|
170
|
-
|
|
171
|
-
// Get download URL
|
|
172
|
-
const { data } = await butterbase.storage.getDownloadUrl(objectId);
|
|
173
|
-
|
|
174
|
-
// List files
|
|
175
|
-
const { data: objects } = await butterbase.storage.list();
|
|
176
|
-
|
|
177
|
-
// Delete file
|
|
178
|
-
await butterbase.storage.delete(objectId);
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
## Functions
|
|
182
|
-
|
|
183
|
-
```typescript
|
|
184
|
-
// Invoke serverless function
|
|
185
|
-
const { data, error } = await butterbase.functions.invoke('my-function', {
|
|
186
|
-
body: { key: 'value' },
|
|
187
|
-
method: 'POST'
|
|
188
|
-
});
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
## Query Builder
|
|
192
|
-
|
|
193
|
-
### Operators
|
|
194
|
-
|
|
195
|
-
- `eq(column, value)` - Equal to
|
|
196
|
-
- `neq(column, value)` - Not equal to
|
|
197
|
-
- `gt(column, value)` - Greater than
|
|
198
|
-
- `gte(column, value)` - Greater than or equal to
|
|
199
|
-
- `lt(column, value)` - Less than
|
|
200
|
-
- `lte(column, value)` - Less than or equal to
|
|
201
|
-
- `like(column, pattern)` - Pattern matching (case-sensitive)
|
|
202
|
-
- `ilike(column, pattern)` - Pattern matching (case-insensitive)
|
|
203
|
-
- `in(column, values)` - Value in array
|
|
204
|
-
- `is(column, value)` - Is null/true/false
|
|
205
|
-
|
|
206
|
-
### Modifiers
|
|
207
|
-
|
|
208
|
-
- `select(columns)` - Select specific columns
|
|
209
|
-
- `order(column, options)` - Order results
|
|
210
|
-
- `limit(count)` - Limit results
|
|
211
|
-
- `offset(count)` - Skip results
|
|
212
|
-
|
|
213
|
-
## Usage in Deno
|
|
214
|
-
|
|
215
|
-
```typescript
|
|
216
|
-
import { createClient } from 'npm:@butterbase/sdk';
|
|
217
|
-
|
|
218
|
-
const butterbase = createClient({
|
|
219
|
-
appId: Deno.env.get('BUTTERBASE_APP_ID')!,
|
|
220
|
-
apiUrl: Deno.env.get('BUTTERBASE_API_URL')!,
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
// Use in serverless functions
|
|
224
|
-
export async function handler(req: Request, ctx: any) {
|
|
225
|
-
const { data } = await butterbase.from('posts').select('*');
|
|
226
|
-
return Response.json({ data });
|
|
227
|
-
}
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
## TypeScript Support
|
|
231
|
-
|
|
232
|
-
The SDK is fully typed with TypeScript. All methods return `ButterbaseResponse<T>` with proper type inference:
|
|
233
|
-
|
|
234
|
-
```typescript
|
|
235
|
-
interface Post {
|
|
236
|
-
id: string;
|
|
237
|
-
title: string;
|
|
238
|
-
content: string;
|
|
239
|
-
status: 'draft' | 'published';
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const { data, error } = await butterbase
|
|
243
|
-
.from<Post>('posts')
|
|
244
|
-
.select('*')
|
|
245
|
-
.eq('status', 'published');
|
|
246
|
-
|
|
247
|
-
// data is typed as Post[] | null
|
|
248
|
-
// error is typed as Error | null
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
## Integrations
|
|
252
|
-
|
|
253
|
-
Connect third-party services to your app and execute actions on behalf of your users.
|
|
254
|
-
|
|
255
|
-
### Admin configuration (API key)
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
// Enable a toolkit
|
|
259
|
-
await bb.integrations.configure('gmail', { displayName: 'Gmail' });
|
|
260
|
-
|
|
261
|
-
// List enabled integrations
|
|
262
|
-
const { data } = await bb.integrations.getConfig();
|
|
263
|
-
|
|
264
|
-
// Disable a toolkit
|
|
265
|
-
await bb.integrations.disable('gmail');
|
|
266
|
-
|
|
267
|
-
// Search available toolkits
|
|
268
|
-
const { data } = await bb.integrations.listAvailable({ search: 'salesforce' });
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
### End-user OAuth flow (user JWT)
|
|
272
|
-
|
|
273
|
-
```typescript
|
|
274
|
-
// Generate connect URL — redirect the user to authUrl
|
|
275
|
-
const { data } = await bb.integrations.connect('gmail', {
|
|
276
|
-
redirectUrl: 'https://yourapp.com/settings',
|
|
277
|
-
});
|
|
278
|
-
window.location.href = data.authUrl;
|
|
279
|
-
|
|
280
|
-
// List user's connected accounts
|
|
281
|
-
const { data } = await bb.integrations.listConnections();
|
|
282
|
-
|
|
283
|
-
// Disconnect an account
|
|
284
|
-
await bb.integrations.disconnect(connectionId);
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
### Executing tools
|
|
288
|
-
|
|
289
|
-
```typescript
|
|
290
|
-
// List tools for a toolkit
|
|
291
|
-
const { data } = await bb.integrations.getTools('gmail');
|
|
292
|
-
// data[0] = { name: 'GMAIL_SEND_EMAIL', description: '...', parameters: { ... } }
|
|
293
|
-
|
|
294
|
-
// Execute a tool (user JWT auth)
|
|
295
|
-
const { data } = await bb.integrations.execute('GMAIL_SEND_EMAIL', {
|
|
296
|
-
to: 'user@example.com',
|
|
297
|
-
subject: 'Hello',
|
|
298
|
-
body: 'Sent via Butterbase integrations.',
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
// Execute on behalf of a user (API key + userId, e.g. in a cron)
|
|
302
|
-
const { data } = await bb.integrations
|
|
303
|
-
.asUser('user-uuid')
|
|
304
|
-
.execute('GOOGLECALENDAR_EVENTS_LIST', { timeMin: new Date().toISOString() });
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
## Error handling
|
|
308
|
-
|
|
309
|
-
All client methods return `{ data, error }`. When the backend returned a
|
|
310
|
-
recognizable agent-friendly error, `error` is a typed `ButterbaseError`
|
|
311
|
-
subclass (`AuthError`, `ValidationError`, `NotFoundError`, `QuotaError`,
|
|
312
|
-
`NetworkError`) carrying `code`, `status`, `remediation`, and `details`.
|
|
313
|
-
|
|
314
|
-
```typescript
|
|
315
|
-
import {
|
|
316
|
-
ButterbaseClient, ErrorCodes,
|
|
317
|
-
AuthError, NotFoundError, QuotaError,
|
|
318
|
-
} from '@butterbase/sdk';
|
|
319
|
-
|
|
320
|
-
const r = await client.from('posts').select('*').execute();
|
|
321
|
-
|
|
322
|
-
if (r.error instanceof NotFoundError) {
|
|
323
|
-
console.error('Missing table:', r.error.remediation);
|
|
324
|
-
}
|
|
325
|
-
if (r.error?.code === ErrorCodes.AUTH_INVALID_API_KEY) {
|
|
326
|
-
// rotate the key
|
|
327
|
-
}
|
|
328
|
-
if (r.error instanceof QuotaError) {
|
|
329
|
-
console.error(`Quota hit (${r.error.code}): ${r.error.remediation}`);
|
|
330
|
-
}
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
The full set of codes lives in `ErrorCodes` (re-exported from
|
|
334
|
-
`@butterbase/shared`). Use `parseApiError(status, body)` if you're wrapping
|
|
335
|
-
fetch yourself and want to dispatch to the same typed classes.
|
|
336
|
-
|
|
337
|
-
## License
|
|
338
|
-
|
|
339
|
-
MIT
|
|
1
|
+
# @butterbase/sdk
|
|
2
|
+
|
|
3
|
+
Universal TypeScript SDK for Butterbase - works in browser, Node.js, and Deno environments.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @butterbase/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { createClient } from '@butterbase/sdk';
|
|
15
|
+
|
|
16
|
+
// Initialize client.
|
|
17
|
+
// apiUrl is the same regardless of which region your app lives in —
|
|
18
|
+
// requests are routed to the right region automatically.
|
|
19
|
+
const butterbase = createClient({
|
|
20
|
+
appId: 'app_abc123',
|
|
21
|
+
apiUrl: 'https://api.butterbase.ai',
|
|
22
|
+
anonKey: 'your-anon-key' // Optional, for public access
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Query data
|
|
26
|
+
const { data, error } = await butterbase
|
|
27
|
+
.from('posts')
|
|
28
|
+
.select('*')
|
|
29
|
+
.eq('status', 'published')
|
|
30
|
+
.order('created_at', { ascending: false })
|
|
31
|
+
.limit(10);
|
|
32
|
+
|
|
33
|
+
// Insert data
|
|
34
|
+
const { data, error } = await butterbase
|
|
35
|
+
.from('posts')
|
|
36
|
+
.insert({ title: 'Hello World', content: 'My first post' });
|
|
37
|
+
|
|
38
|
+
// Update data
|
|
39
|
+
const { data, error } = await butterbase
|
|
40
|
+
.from('posts')
|
|
41
|
+
.update({ status: 'archived' })
|
|
42
|
+
.eq('id', '123');
|
|
43
|
+
|
|
44
|
+
// Delete data
|
|
45
|
+
const { data, error } = await butterbase
|
|
46
|
+
.from('posts')
|
|
47
|
+
.delete()
|
|
48
|
+
.eq('id', '123');
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Migration from 0.x to 1.0
|
|
52
|
+
|
|
53
|
+
**Breaking Change:** The `authUrl` parameter has been removed. All auth endpoints now run on the same URL as the API.
|
|
54
|
+
|
|
55
|
+
**Before (0.x):**
|
|
56
|
+
```typescript
|
|
57
|
+
const butterbase = createClient({
|
|
58
|
+
appId: 'app_abc123',
|
|
59
|
+
apiUrl: 'https://api.butterbase.ai',
|
|
60
|
+
authUrl: 'https://auth.butterbase.com', // ❌ No longer needed
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**After (1.0):**
|
|
65
|
+
```typescript
|
|
66
|
+
const butterbase = createClient({
|
|
67
|
+
appId: 'app_abc123',
|
|
68
|
+
apiUrl: 'https://api.butterbase.ai', // ✅ All endpoints use this URL
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Authentication
|
|
73
|
+
|
|
74
|
+
Sessions are automatically persisted to `localStorage` and restored on page refresh. Access tokens are automatically refreshed before they expire.
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// Sign up
|
|
78
|
+
const { data, error } = await butterbase.auth.signUp({
|
|
79
|
+
email: 'user@example.com',
|
|
80
|
+
password: 'secure123'
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Sign in (session is automatically persisted)
|
|
84
|
+
const { data, error } = await butterbase.auth.signIn({
|
|
85
|
+
email: 'user@example.com',
|
|
86
|
+
password: 'secure123'
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Get current user (works after page refresh)
|
|
90
|
+
const { data: user } = await butterbase.auth.getUser();
|
|
91
|
+
|
|
92
|
+
// Sign out (clears persisted session)
|
|
93
|
+
await butterbase.auth.signOut();
|
|
94
|
+
|
|
95
|
+
// Refresh session manually (uses stored refresh token if none provided)
|
|
96
|
+
const { data } = await butterbase.auth.refreshSession();
|
|
97
|
+
|
|
98
|
+
// OAuth
|
|
99
|
+
const { url } = butterbase.auth.signInWithOAuth({
|
|
100
|
+
provider: 'google',
|
|
101
|
+
redirectTo: 'http://localhost:3000/callback'
|
|
102
|
+
});
|
|
103
|
+
window.location.href = url;
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Auth State Changes
|
|
107
|
+
|
|
108
|
+
Subscribe to authentication events to react to sign-ins, sign-outs, and token refreshes:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
const { unsubscribe } = butterbase.onAuthStateChange((event, session) => {
|
|
112
|
+
// event: 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'SESSION_RESTORED'
|
|
113
|
+
console.log(event, session?.user);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Stop listening
|
|
117
|
+
unsubscribe();
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### React Usage
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
import { useEffect, useState } from 'react';
|
|
124
|
+
import { butterbase } from './lib';
|
|
125
|
+
|
|
126
|
+
function App() {
|
|
127
|
+
const [user, setUser] = useState(null);
|
|
128
|
+
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
// Session is auto-restored — check current state
|
|
131
|
+
const session = butterbase.sessionManager.getSession();
|
|
132
|
+
if (session) setUser(session.user);
|
|
133
|
+
|
|
134
|
+
// React to future auth changes
|
|
135
|
+
const { unsubscribe } = butterbase.onAuthStateChange((event, session) => {
|
|
136
|
+
setUser(session?.user ?? null);
|
|
137
|
+
});
|
|
138
|
+
return unsubscribe;
|
|
139
|
+
}, []);
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Custom Storage
|
|
144
|
+
|
|
145
|
+
By default, the SDK uses `localStorage` with an in-memory fallback for SSR/Node.js environments. You can provide a custom storage adapter:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
import { createClient, MemorySessionStorage } from '@butterbase/sdk';
|
|
149
|
+
|
|
150
|
+
// Memory-only (no persistence)
|
|
151
|
+
const butterbase = createClient({
|
|
152
|
+
appId: 'app_abc123',
|
|
153
|
+
apiUrl: 'https://api.butterbase.ai',
|
|
154
|
+
persistSession: false,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Custom storage adapter (e.g., for React Native)
|
|
158
|
+
const butterbase = createClient({
|
|
159
|
+
appId: 'app_abc123',
|
|
160
|
+
apiUrl: 'https://api.butterbase.ai',
|
|
161
|
+
sessionStorage: myCustomStorage, // implements { getItem, setItem, removeItem }
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Storage
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
// Upload file
|
|
169
|
+
const { data, error } = await butterbase.storage.upload(file);
|
|
170
|
+
|
|
171
|
+
// Get download URL
|
|
172
|
+
const { data } = await butterbase.storage.getDownloadUrl(objectId);
|
|
173
|
+
|
|
174
|
+
// List files
|
|
175
|
+
const { data: objects } = await butterbase.storage.list();
|
|
176
|
+
|
|
177
|
+
// Delete file
|
|
178
|
+
await butterbase.storage.delete(objectId);
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Functions
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// Invoke serverless function
|
|
185
|
+
const { data, error } = await butterbase.functions.invoke('my-function', {
|
|
186
|
+
body: { key: 'value' },
|
|
187
|
+
method: 'POST'
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Query Builder
|
|
192
|
+
|
|
193
|
+
### Operators
|
|
194
|
+
|
|
195
|
+
- `eq(column, value)` - Equal to
|
|
196
|
+
- `neq(column, value)` - Not equal to
|
|
197
|
+
- `gt(column, value)` - Greater than
|
|
198
|
+
- `gte(column, value)` - Greater than or equal to
|
|
199
|
+
- `lt(column, value)` - Less than
|
|
200
|
+
- `lte(column, value)` - Less than or equal to
|
|
201
|
+
- `like(column, pattern)` - Pattern matching (case-sensitive)
|
|
202
|
+
- `ilike(column, pattern)` - Pattern matching (case-insensitive)
|
|
203
|
+
- `in(column, values)` - Value in array
|
|
204
|
+
- `is(column, value)` - Is null/true/false
|
|
205
|
+
|
|
206
|
+
### Modifiers
|
|
207
|
+
|
|
208
|
+
- `select(columns)` - Select specific columns
|
|
209
|
+
- `order(column, options)` - Order results
|
|
210
|
+
- `limit(count)` - Limit results
|
|
211
|
+
- `offset(count)` - Skip results
|
|
212
|
+
|
|
213
|
+
## Usage in Deno
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
import { createClient } from 'npm:@butterbase/sdk';
|
|
217
|
+
|
|
218
|
+
const butterbase = createClient({
|
|
219
|
+
appId: Deno.env.get('BUTTERBASE_APP_ID')!,
|
|
220
|
+
apiUrl: Deno.env.get('BUTTERBASE_API_URL')!,
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// Use in serverless functions
|
|
224
|
+
export async function handler(req: Request, ctx: any) {
|
|
225
|
+
const { data } = await butterbase.from('posts').select('*');
|
|
226
|
+
return Response.json({ data });
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## TypeScript Support
|
|
231
|
+
|
|
232
|
+
The SDK is fully typed with TypeScript. All methods return `ButterbaseResponse<T>` with proper type inference:
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
interface Post {
|
|
236
|
+
id: string;
|
|
237
|
+
title: string;
|
|
238
|
+
content: string;
|
|
239
|
+
status: 'draft' | 'published';
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const { data, error } = await butterbase
|
|
243
|
+
.from<Post>('posts')
|
|
244
|
+
.select('*')
|
|
245
|
+
.eq('status', 'published');
|
|
246
|
+
|
|
247
|
+
// data is typed as Post[] | null
|
|
248
|
+
// error is typed as Error | null
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Integrations
|
|
252
|
+
|
|
253
|
+
Connect third-party services to your app and execute actions on behalf of your users.
|
|
254
|
+
|
|
255
|
+
### Admin configuration (API key)
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
// Enable a toolkit
|
|
259
|
+
await bb.integrations.configure('gmail', { displayName: 'Gmail' });
|
|
260
|
+
|
|
261
|
+
// List enabled integrations
|
|
262
|
+
const { data } = await bb.integrations.getConfig();
|
|
263
|
+
|
|
264
|
+
// Disable a toolkit
|
|
265
|
+
await bb.integrations.disable('gmail');
|
|
266
|
+
|
|
267
|
+
// Search available toolkits
|
|
268
|
+
const { data } = await bb.integrations.listAvailable({ search: 'salesforce' });
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### End-user OAuth flow (user JWT)
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
// Generate connect URL — redirect the user to authUrl
|
|
275
|
+
const { data } = await bb.integrations.connect('gmail', {
|
|
276
|
+
redirectUrl: 'https://yourapp.com/settings',
|
|
277
|
+
});
|
|
278
|
+
window.location.href = data.authUrl;
|
|
279
|
+
|
|
280
|
+
// List user's connected accounts
|
|
281
|
+
const { data } = await bb.integrations.listConnections();
|
|
282
|
+
|
|
283
|
+
// Disconnect an account
|
|
284
|
+
await bb.integrations.disconnect(connectionId);
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Executing tools
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
// List tools for a toolkit
|
|
291
|
+
const { data } = await bb.integrations.getTools('gmail');
|
|
292
|
+
// data[0] = { name: 'GMAIL_SEND_EMAIL', description: '...', parameters: { ... } }
|
|
293
|
+
|
|
294
|
+
// Execute a tool (user JWT auth)
|
|
295
|
+
const { data } = await bb.integrations.execute('GMAIL_SEND_EMAIL', {
|
|
296
|
+
to: 'user@example.com',
|
|
297
|
+
subject: 'Hello',
|
|
298
|
+
body: 'Sent via Butterbase integrations.',
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
// Execute on behalf of a user (API key + userId, e.g. in a cron)
|
|
302
|
+
const { data } = await bb.integrations
|
|
303
|
+
.asUser('user-uuid')
|
|
304
|
+
.execute('GOOGLECALENDAR_EVENTS_LIST', { timeMin: new Date().toISOString() });
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## Error handling
|
|
308
|
+
|
|
309
|
+
All client methods return `{ data, error }`. When the backend returned a
|
|
310
|
+
recognizable agent-friendly error, `error` is a typed `ButterbaseError`
|
|
311
|
+
subclass (`AuthError`, `ValidationError`, `NotFoundError`, `QuotaError`,
|
|
312
|
+
`NetworkError`) carrying `code`, `status`, `remediation`, and `details`.
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
import {
|
|
316
|
+
ButterbaseClient, ErrorCodes,
|
|
317
|
+
AuthError, NotFoundError, QuotaError,
|
|
318
|
+
} from '@butterbase/sdk';
|
|
319
|
+
|
|
320
|
+
const r = await client.from('posts').select('*').execute();
|
|
321
|
+
|
|
322
|
+
if (r.error instanceof NotFoundError) {
|
|
323
|
+
console.error('Missing table:', r.error.remediation);
|
|
324
|
+
}
|
|
325
|
+
if (r.error?.code === ErrorCodes.AUTH_INVALID_API_KEY) {
|
|
326
|
+
// rotate the key
|
|
327
|
+
}
|
|
328
|
+
if (r.error instanceof QuotaError) {
|
|
329
|
+
console.error(`Quota hit (${r.error.code}): ${r.error.remediation}`);
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
The full set of codes lives in `ErrorCodes` (re-exported from
|
|
334
|
+
`@butterbase/shared`). Use `parseApiError(status, body)` if you're wrapping
|
|
335
|
+
fetch yourself and want to dispatch to the same typed classes.
|
|
336
|
+
|
|
337
|
+
## License
|
|
338
|
+
|
|
339
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,51 +1,51 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@butterbase/sdk",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Universal TypeScript SDK for Butterbase",
|
|
5
|
-
"license": "Apache-2.0",
|
|
6
|
-
"homepage": "https://butterbase.ai",
|
|
7
|
-
"repository": {
|
|
8
|
-
"type": "git",
|
|
9
|
-
"url": "https://github.com/NetGPT-Inc/butterbase-oss",
|
|
10
|
-
"directory": "packages/sdk"
|
|
11
|
-
},
|
|
12
|
-
"publishConfig": {
|
|
13
|
-
"access": "public"
|
|
14
|
-
},
|
|
15
|
-
"type": "module",
|
|
16
|
-
"main": "./dist/index.js",
|
|
17
|
-
"types": "./dist/index.d.ts",
|
|
18
|
-
"exports": {
|
|
19
|
-
".": {
|
|
20
|
-
"types": "./dist/index.d.ts",
|
|
21
|
-
"import": "./dist/index.js"
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
"files": [
|
|
25
|
-
"dist"
|
|
26
|
-
],
|
|
27
|
-
"scripts": {
|
|
28
|
-
"build": "tsc -b",
|
|
29
|
-
"dev": "tsc -b --watch",
|
|
30
|
-
"test": "vitest run"
|
|
31
|
-
},
|
|
32
|
-
"keywords": [
|
|
33
|
-
"butterbase",
|
|
34
|
-
"backend",
|
|
35
|
-
"baas",
|
|
36
|
-
"database",
|
|
37
|
-
"auth",
|
|
38
|
-
"storage"
|
|
39
|
-
],
|
|
40
|
-
"dependencies": {
|
|
41
|
-
"@butterbase/shared": "^0.
|
|
42
|
-
},
|
|
43
|
-
"devDependencies": {
|
|
44
|
-
"typescript": "^5.7.0",
|
|
45
|
-
"@types/node": "^22.0.0",
|
|
46
|
-
"vitest": "^3.1.1"
|
|
47
|
-
},
|
|
48
|
-
"peerDependencies": {
|
|
49
|
-
"typescript": ">=5.0.0"
|
|
50
|
-
}
|
|
51
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@butterbase/sdk",
|
|
3
|
+
"version": "2.4.0",
|
|
4
|
+
"description": "Universal TypeScript SDK for Butterbase",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"homepage": "https://butterbase.ai",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/NetGPT-Inc/butterbase-oss",
|
|
10
|
+
"directory": "packages/sdk"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc -b",
|
|
29
|
+
"dev": "tsc -b --watch",
|
|
30
|
+
"test": "vitest run"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"butterbase",
|
|
34
|
+
"backend",
|
|
35
|
+
"baas",
|
|
36
|
+
"database",
|
|
37
|
+
"auth",
|
|
38
|
+
"storage"
|
|
39
|
+
],
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@butterbase/shared": "^0.3.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"typescript": "^5.7.0",
|
|
45
|
+
"@types/node": "^22.0.0",
|
|
46
|
+
"vitest": "^3.1.1"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"typescript": ">=5.0.0"
|
|
50
|
+
}
|
|
51
|
+
}
|