@picobase_app/client 0.1.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 ADDED
@@ -0,0 +1,233 @@
1
+ # @picobase_app/client
2
+
3
+ TypeScript SDK for PicoBase — add auth, database, realtime, and file storage to your app.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @picobase_app/client
9
+ ```
10
+
11
+ ## Quickstart
12
+
13
+ ```typescript
14
+ import { createClient } from '@picobase_app/client'
15
+
16
+ const pb = createClient('https://myapp.picobase.com', 'pbk_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
17
+ ```
18
+
19
+ Get your URL and API key from the [PicoBase dashboard](https://picobase.com/dashboard).
20
+
21
+ ## Authentication
22
+
23
+ ```typescript
24
+ // Sign up a new user
25
+ const { token, record } = await pb.auth.signUp({
26
+ email: 'user@example.com',
27
+ password: 'securepassword',
28
+ name: 'Jane Doe',
29
+ })
30
+
31
+ // Sign in
32
+ const { token, record } = await pb.auth.signIn({
33
+ email: 'user@example.com',
34
+ password: 'securepassword',
35
+ })
36
+
37
+ // OAuth (Google, GitHub, etc. — configure providers in the dashboard)
38
+ const { token, record } = await pb.auth.signInWithOAuth({
39
+ provider: 'google',
40
+ })
41
+
42
+ // Check current user
43
+ const user = pb.auth.user // RecordModel | null
44
+ const isValid = pb.auth.isValid // boolean
45
+
46
+ // Listen to auth changes
47
+ const unsubscribe = pb.auth.onStateChange((event, record) => {
48
+ // event: 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED'
49
+ console.log(event, record?.email)
50
+ })
51
+
52
+ // Password reset
53
+ await pb.auth.requestPasswordReset('user@example.com')
54
+
55
+ // Sign out
56
+ pb.auth.signOut()
57
+ ```
58
+
59
+ ## Database (Collections)
60
+
61
+ ```typescript
62
+ // List records with pagination, filtering, and sorting
63
+ const result = await pb.collection('posts').getList(1, 20, {
64
+ filter: 'published = true',
65
+ sort: '-created',
66
+ expand: 'author',
67
+ })
68
+ // result.items, result.totalItems, result.totalPages
69
+
70
+ // Get a single record
71
+ const post = await pb.collection('posts').getOne('RECORD_ID')
72
+
73
+ // Find first match
74
+ const admin = await pb.collection('users').getFirstListItem('role = "admin"')
75
+
76
+ // Get all records (auto-paginates — use with caution on large collections)
77
+ const allPosts = await pb.collection('posts').getFullList({
78
+ filter: 'published = true',
79
+ })
80
+
81
+ // Create
82
+ const newPost = await pb.collection('posts').create({
83
+ title: 'Hello World',
84
+ content: 'My first post',
85
+ published: true,
86
+ })
87
+
88
+ // Update
89
+ const updated = await pb.collection('posts').update('RECORD_ID', {
90
+ title: 'Updated Title',
91
+ })
92
+
93
+ // Delete
94
+ await pb.collection('posts').delete('RECORD_ID')
95
+ ```
96
+
97
+ ### TypeScript generics
98
+
99
+ ```typescript
100
+ interface Post {
101
+ id: string
102
+ title: string
103
+ content: string
104
+ published: boolean
105
+ created: string
106
+ updated: string
107
+ }
108
+
109
+ const posts = await pb.collection<Post>('posts').getList(1, 20)
110
+ // posts.items is Post[]
111
+ ```
112
+
113
+ ### File uploads
114
+
115
+ ```typescript
116
+ const formData = new FormData()
117
+ formData.append('title', 'Photo post')
118
+ formData.append('image', fileInput.files[0])
119
+
120
+ const record = await pb.collection('posts').create(formData)
121
+ ```
122
+
123
+ ## Realtime
124
+
125
+ ```typescript
126
+ // Subscribe to all changes on a collection
127
+ const unsubscribe = await pb.collection('posts').subscribe((event) => {
128
+ console.log(event.action, event.record) // 'create' | 'update' | 'delete'
129
+ })
130
+
131
+ // Subscribe to a specific record
132
+ const unsubscribe = await pb.collection('posts').subscribeOne('RECORD_ID', (event) => {
133
+ console.log(event.action, event.record)
134
+ })
135
+
136
+ // Unsubscribe
137
+ await unsubscribe()
138
+
139
+ // Or use the realtime module directly
140
+ const unsub = await pb.realtime.subscribe('posts', (event) => {
141
+ console.log(event)
142
+ })
143
+
144
+ // Disconnect all realtime subscriptions
145
+ await pb.realtime.disconnectAll()
146
+ ```
147
+
148
+ ## File Storage
149
+
150
+ PocketBase stores files as fields on records. Use the storage module to get URLs.
151
+
152
+ ```typescript
153
+ const user = await pb.collection('users').getOne('USER_ID')
154
+
155
+ // Get file URL
156
+ const url = pb.storage.getFileUrl(user, 'avatar.jpg')
157
+
158
+ // Get thumbnail
159
+ const thumb = pb.storage.getFileUrl(user, 'avatar.jpg', { thumb: '100x100' })
160
+
161
+ // Protected files — get a temporary token first
162
+ const token = await pb.storage.getFileToken()
163
+ const protectedUrl = pb.storage.getFileUrl(user, 'document.pdf', { token })
164
+ ```
165
+
166
+ ## Advanced
167
+
168
+ ### Custom auth collection
169
+
170
+ ```typescript
171
+ // If you use a custom auth collection instead of 'users'
172
+ pb.auth.setCollection('members')
173
+ await pb.auth.signIn({ email: 'member@example.com', password: 'pass' })
174
+ ```
175
+
176
+ ### Raw PocketBase access
177
+
178
+ The underlying PocketBase SDK instance is exposed for advanced use cases.
179
+
180
+ ```typescript
181
+ // Access the PocketBase client directly
182
+ const health = await pb.pb.health.check()
183
+
184
+ // Custom API endpoint
185
+ const result = await pb.send('/api/custom-endpoint', { method: 'POST', body: { foo: 'bar' } })
186
+ ```
187
+
188
+ ### Cold-start handling
189
+
190
+ PicoBase instances may be paused when idle. The SDK automatically retries with exponential backoff (2s, 4s, 8s) when it receives a 503 response. You can configure this:
191
+
192
+ ```typescript
193
+ const pb = createClient('https://myapp.picobase.com', 'pbk_...', {
194
+ maxColdStartRetries: 5, // default: 3
195
+ })
196
+ ```
197
+
198
+ ### Error handling
199
+
200
+ ```typescript
201
+ import { PicoBaseError, InstanceUnavailableError, AuthorizationError } from '@picobase_app/client'
202
+
203
+ try {
204
+ await pb.collection('posts').getList()
205
+ } catch (err) {
206
+ if (err instanceof AuthorizationError) {
207
+ // Invalid API key
208
+ } else if (err instanceof InstanceUnavailableError) {
209
+ // Instance not available after retries
210
+ }
211
+ }
212
+ ```
213
+
214
+ ## API Reference
215
+
216
+ ### `createClient(url, apiKey, options?)`
217
+
218
+ | Parameter | Type | Description |
219
+ |---|---|---|
220
+ | `url` | `string` | Your PicoBase instance URL |
221
+ | `apiKey` | `string` | API key from the dashboard (starts with `pbk_`) |
222
+ | `options.maxColdStartRetries` | `number` | Max retries on 503. Default: `3` |
223
+ | `options.lang` | `string` | Accept-Language header. Default: `'en-US'` |
224
+
225
+ ### Modules
226
+
227
+ | Module | Access | Description |
228
+ |---|---|---|
229
+ | `pb.auth` | `PicoBaseAuth` | Sign up, sign in, OAuth, session management |
230
+ | `pb.collection(name)` | `PicoBaseCollection` | CRUD operations on a collection |
231
+ | `pb.realtime` | `PicoBaseRealtime` | Realtime subscriptions |
232
+ | `pb.storage` | `PicoBaseStorage` | File URLs and tokens |
233
+ | `pb.pb` | `PocketBase` | Underlying PocketBase SDK instance |