postbasejs 0.1.0 → 0.1.2

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 (2) hide show
  1. package/README.md +496 -0
  2. package/package.json +12 -2
package/README.md ADDED
@@ -0,0 +1,496 @@
1
+ # postbasejs
2
+
3
+ The official JavaScript/TypeScript client for [Postbase](https://www.getpostbase.com) — a self-hosted, open-source backend as a service.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/postbasejs)](https://www.npmjs.com/package/postbasejs)
6
+ [![license](https://img.shields.io/npm/l/postbasejs)](https://github.com/postbase/postbase/blob/main/LICENSE)
7
+
8
+ > **[getpostbase.com](https://www.getpostbase.com)** · [Documentation](https://www.getpostbase.com/docs) · [GitHub](https://github.com/postbase/postbase)
9
+
10
+ ---
11
+
12
+ ## What is Postbase?
13
+
14
+ Postbase is a self-hosted backend platform built on PostgreSQL. It gives you a database with a REST query API, authentication (password, magic link, OAuth), file storage, and row-level security — all running on your own infrastructure.
15
+
16
+ `postbasejs` is the client SDK for interacting with your Postbase instance from JavaScript or TypeScript apps.
17
+
18
+ ---
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install postbasejs
24
+ # or
25
+ pnpm add postbasejs
26
+ # or
27
+ yarn add postbasejs
28
+ ```
29
+
30
+ ---
31
+
32
+ ## Quick Start
33
+
34
+ ```typescript
35
+ import { createClient } from 'postbasejs'
36
+
37
+ const postbase = createClient(
38
+ 'https://your-postbase-instance.com',
39
+ 'pb_anon_your_api_key'
40
+ )
41
+ ```
42
+
43
+ Your **URL** and **anon key** can be found in the API Keys section of your Postbase dashboard.
44
+
45
+ ---
46
+
47
+ ## Database
48
+
49
+ Query your PostgreSQL tables with a fluent, chainable API.
50
+
51
+ ### Select
52
+
53
+ ```typescript
54
+ // Fetch all posts
55
+ const { data, error } = await postbase.from('posts').select('*')
56
+
57
+ // Select specific columns
58
+ const { data } = await postbase.from('posts').select('id, title, created_at')
59
+
60
+ // With filters
61
+ const { data } = await postbase
62
+ .from('posts')
63
+ .select('*')
64
+ .eq('status', 'published')
65
+ .order('created_at', { ascending: false })
66
+ .limit(10)
67
+
68
+ // Get total count
69
+ const { data, count } = await postbase
70
+ .from('posts')
71
+ .select('*', { count: 'exact' })
72
+ ```
73
+
74
+ ### Filter operators
75
+
76
+ | Method | SQL equivalent |
77
+ |---|---|
78
+ | `.eq(col, val)` | `col = val` |
79
+ | `.neq(col, val)` | `col != val` |
80
+ | `.gt(col, val)` | `col > val` |
81
+ | `.gte(col, val)` | `col >= val` |
82
+ | `.lt(col, val)` | `col < val` |
83
+ | `.lte(col, val)` | `col <= val` |
84
+ | `.like(col, pattern)` | `col LIKE pattern` |
85
+ | `.ilike(col, pattern)` | `col ILIKE pattern` |
86
+ | `.in(col, values)` | `col IN (values)` |
87
+ | `.is(col, null)` | `col IS NULL` |
88
+ | `.contains(col, val)` | `col @> val` |
89
+ | `.overlaps(col, val)` | `col && val` |
90
+ | `.textSearch(col, query)` | full-text search |
91
+ | `.or(filters)` | `col = val OR col = val` |
92
+ | `.not(col, op, val)` | `NOT col op val` |
93
+
94
+ ### Insert
95
+
96
+ ```typescript
97
+ const { data, error } = await postbase
98
+ .from('posts')
99
+ .insert({ title: 'Hello World', status: 'draft' })
100
+ .select()
101
+ .single()
102
+ ```
103
+
104
+ ### Update
105
+
106
+ ```typescript
107
+ const { data, error } = await postbase
108
+ .from('posts')
109
+ .update({ status: 'published' })
110
+ .eq('id', 'post-id')
111
+ .select()
112
+ .single()
113
+ ```
114
+
115
+ ### Upsert
116
+
117
+ ```typescript
118
+ const { data, error } = await postbase
119
+ .from('profiles')
120
+ .upsert({ id: 'user-id', username: 'alice' }, { onConflict: 'id' })
121
+ .select()
122
+ ```
123
+
124
+ ### Delete
125
+
126
+ ```typescript
127
+ const { error } = await postbase
128
+ .from('posts')
129
+ .delete()
130
+ .eq('id', 'post-id')
131
+ ```
132
+
133
+ ### Single row helpers
134
+
135
+ ```typescript
136
+ // Errors if not exactly one row
137
+ const { data, error } = await postbase.from('posts').select('*').eq('id', id).single()
138
+
139
+ // Returns null if not found (no error)
140
+ const { data } = await postbase.from('posts').select('*').eq('id', id).maybeSingle()
141
+ ```
142
+
143
+ ### Pagination
144
+
145
+ ```typescript
146
+ // Limit + offset
147
+ const { data } = await postbase.from('posts').select('*').limit(20).offset(40)
148
+
149
+ // Range (inclusive)
150
+ const { data } = await postbase.from('posts').select('*').range(0, 19)
151
+ ```
152
+
153
+ ---
154
+
155
+ ## Authentication
156
+
157
+ ### Sign up
158
+
159
+ ```typescript
160
+ const { data, error } = await postbase.auth.signUp({
161
+ email: 'user@example.com',
162
+ password: 'supersecret',
163
+ })
164
+ // data.user, data.session
165
+ ```
166
+
167
+ ### Sign in with password
168
+
169
+ ```typescript
170
+ const { data, error } = await postbase.auth.signInWithPassword({
171
+ email: 'user@example.com',
172
+ password: 'supersecret',
173
+ })
174
+ ```
175
+
176
+ ### Magic link (passwordless)
177
+
178
+ ```typescript
179
+ const { error } = await postbase.auth.signInWithOtp({
180
+ email: 'user@example.com',
181
+ options: { redirectTo: 'https://yourapp.com/dashboard' },
182
+ })
183
+ ```
184
+
185
+ ### OAuth (browser redirect)
186
+
187
+ ```typescript
188
+ await postbase.auth.signInWithOAuth({
189
+ provider: 'google', // or 'github', 'discord', etc.
190
+ options: { redirectTo: 'https://yourapp.com/callback' },
191
+ })
192
+ ```
193
+
194
+ ### Get current user
195
+
196
+ ```typescript
197
+ const { data: { user }, error } = await postbase.auth.getUser()
198
+ ```
199
+
200
+ ### Get current session
201
+
202
+ ```typescript
203
+ const { data: { session }, error } = await postbase.auth.getSession()
204
+ // session.accessToken, session.user, session.expiresAt
205
+ ```
206
+
207
+ ### Sign out
208
+
209
+ ```typescript
210
+ await postbase.auth.signOut()
211
+ ```
212
+
213
+ ### Update user
214
+
215
+ ```typescript
216
+ const { data, error } = await postbase.auth.updateUser({
217
+ name: 'Alice',
218
+ metadata: { plan: 'pro' },
219
+ })
220
+ ```
221
+
222
+ ### Listen to auth state changes
223
+
224
+ ```typescript
225
+ const { data: { subscription } } = postbase.auth.onAuthStateChange((event, session) => {
226
+ // event: 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'USER_UPDATED'
227
+ console.log(event, session)
228
+ })
229
+
230
+ // Cleanup
231
+ subscription.unsubscribe()
232
+ ```
233
+
234
+ ### Admin (service role key required)
235
+
236
+ ```typescript
237
+ const adminClient = createClient(url, 'pb_service_your_service_key')
238
+
239
+ // List users
240
+ const { data } = await adminClient.auth.admin.listUsers({ page: 1, perPage: 50 })
241
+
242
+ // Create user
243
+ const { data } = await adminClient.auth.admin.createUser({
244
+ email: 'new@example.com',
245
+ password: 'password',
246
+ email_confirm: true,
247
+ })
248
+
249
+ // Update user
250
+ await adminClient.auth.admin.updateUserById(userId, { email: 'new@example.com' })
251
+
252
+ // Delete user
253
+ await adminClient.auth.admin.deleteUser(userId)
254
+ ```
255
+
256
+ ---
257
+
258
+ ## Storage
259
+
260
+ ### Upload a file
261
+
262
+ ```typescript
263
+ const { data, error } = await postbase
264
+ .storage
265
+ .from('avatars')
266
+ .upload('user-123.png', file, { contentType: 'image/png' })
267
+ // data.path, data.fullPath
268
+ ```
269
+
270
+ ### Get public URL
271
+
272
+ ```typescript
273
+ const { data: { publicUrl } } = postbase
274
+ .storage
275
+ .from('avatars')
276
+ .getPublicUrl('user-123.png')
277
+ ```
278
+
279
+ ### Download a file
280
+
281
+ ```typescript
282
+ const { data: blob, error } = await postbase
283
+ .storage
284
+ .from('avatars')
285
+ .download('user-123.png')
286
+ ```
287
+
288
+ ### Create a signed URL (temporary access)
289
+
290
+ ```typescript
291
+ const { data, error } = await postbase
292
+ .storage
293
+ .from('private-docs')
294
+ .createSignedUrl('report.pdf', 3600) // expires in 1 hour
295
+ // data.signedUrl
296
+ ```
297
+
298
+ ### List files
299
+
300
+ ```typescript
301
+ const { data, error } = await postbase
302
+ .storage
303
+ .from('avatars')
304
+ .list('folder/', { limit: 100, sortBy: { column: 'name', order: 'asc' } })
305
+ ```
306
+
307
+ ### Delete files
308
+
309
+ ```typescript
310
+ const { error } = await postbase
311
+ .storage
312
+ .from('avatars')
313
+ .remove(['user-123.png', 'user-456.png'])
314
+ ```
315
+
316
+ ### Move / Copy
317
+
318
+ ```typescript
319
+ await postbase.storage.from('docs').move('old-name.pdf', 'new-name.pdf')
320
+ await postbase.storage.from('docs').copy('template.pdf', 'copy.pdf')
321
+ ```
322
+
323
+ ### Bucket management
324
+
325
+ ```typescript
326
+ // Create
327
+ await postbase.storage.createBucket('avatars', {
328
+ public: true,
329
+ fileSizeLimit: 5 * 1024 * 1024, // 5 MB
330
+ allowedMimeTypes: ['image/png', 'image/jpeg'],
331
+ })
332
+
333
+ // List
334
+ const { data: buckets } = await postbase.storage.listBuckets()
335
+
336
+ // Update
337
+ await postbase.storage.updateBucket('avatars', { public: false })
338
+
339
+ // Delete
340
+ await postbase.storage.deleteBucket('avatars')
341
+
342
+ // Empty (delete all objects)
343
+ await postbase.storage.emptyBucket('avatars')
344
+ ```
345
+
346
+ ---
347
+
348
+ ## RPC (PostgreSQL functions)
349
+
350
+ Call a stored procedure or function in your project's schema:
351
+
352
+ ```typescript
353
+ const { data, error } = await postbase.rpc('get_nearby_posts', {
354
+ lat: 37.7749,
355
+ lng: -122.4194,
356
+ radius: 10,
357
+ })
358
+ ```
359
+
360
+ ---
361
+
362
+ ## SSR (Server-Side Rendering)
363
+
364
+ For Next.js App Router, SvelteKit, Nuxt, or any SSR framework, import from `postbasejs/ssr`. This forwards the user's session cookie to Postbase so that RLS policies apply server-side.
365
+
366
+ ```bash
367
+ # No extra install needed — it's included in postbasejs
368
+ ```
369
+
370
+ ### Next.js App Router
371
+
372
+ **Server Component:**
373
+
374
+ ```typescript
375
+ import { createServerClient } from 'postbasejs/ssr'
376
+ import { cookies } from 'next/headers'
377
+
378
+ export default async function Page() {
379
+ const cookieStore = await cookies()
380
+
381
+ const postbase = createServerClient(
382
+ process.env.NEXT_PUBLIC_POSTBASE_URL!,
383
+ process.env.NEXT_PUBLIC_POSTBASE_ANON_KEY!,
384
+ {
385
+ cookies: {
386
+ getAll: () => cookieStore.getAll(),
387
+ setAll: () => {}, // read-only in server components
388
+ },
389
+ }
390
+ )
391
+
392
+ const { data: posts } = await postbase.from('posts').select('*')
393
+ return <ul>{posts?.map(p => <li key={p.id}>{p.title}</li>)}</ul>
394
+ }
395
+ ```
396
+
397
+ **Middleware (session refresh):**
398
+
399
+ ```typescript
400
+ // middleware.ts
401
+ import { createServerClient } from 'postbasejs/ssr'
402
+ import { NextResponse } from 'next/server'
403
+ import type { NextRequest } from 'next/server'
404
+
405
+ export async function middleware(req: NextRequest) {
406
+ const res = NextResponse.next()
407
+
408
+ const postbase = createServerClient(
409
+ process.env.NEXT_PUBLIC_POSTBASE_URL!,
410
+ process.env.NEXT_PUBLIC_POSTBASE_ANON_KEY!,
411
+ {
412
+ cookies: {
413
+ getAll: () => req.cookies.getAll(),
414
+ setAll: (cookies) =>
415
+ cookies.forEach(c => res.cookies.set(c.name, c.value, c.options as any)),
416
+ },
417
+ }
418
+ )
419
+
420
+ await postbase.auth.getSession() // refreshes token if needed
421
+ return res
422
+ }
423
+ ```
424
+
425
+ **Client Component:**
426
+
427
+ ```typescript
428
+ 'use client'
429
+ import { createBrowserClient } from 'postbasejs/ssr'
430
+
431
+ const postbase = createBrowserClient(
432
+ process.env.NEXT_PUBLIC_POSTBASE_URL!,
433
+ process.env.NEXT_PUBLIC_POSTBASE_ANON_KEY!
434
+ )
435
+ ```
436
+
437
+ ---
438
+
439
+ ## TypeScript
440
+
441
+ The SDK is fully typed. Pass your row type as a generic for full IntelliSense:
442
+
443
+ ```typescript
444
+ interface Post {
445
+ id: string
446
+ title: string
447
+ status: 'draft' | 'published'
448
+ created_at: string
449
+ }
450
+
451
+ const { data } = await postbase.from<Post>('posts').select('*').eq('status', 'published')
452
+ // data is Post[] | null
453
+ ```
454
+
455
+ ---
456
+
457
+ ## Row Level Security (RLS)
458
+
459
+ When a user is signed in, their session JWT is automatically forwarded with every query. Your RLS policies can reference the user via:
460
+
461
+ ```sql
462
+ current_setting('postbase.user_id', true) -- the authenticated user's ID
463
+ current_setting('postbase.role', true) -- the user's role
464
+ ```
465
+
466
+ Example policy — users can only read their own rows:
467
+
468
+ ```sql
469
+ CREATE POLICY "own rows" ON posts
470
+ FOR SELECT USING (
471
+ user_id = current_setting('postbase.user_id', true)::uuid
472
+ );
473
+ ```
474
+
475
+ ---
476
+
477
+ ## Environment Variables
478
+
479
+ We recommend storing your Postbase credentials in environment variables:
480
+
481
+ ```bash
482
+ NEXT_PUBLIC_POSTBASE_URL=https://your-postbase-instance.com
483
+ NEXT_PUBLIC_POSTBASE_ANON_KEY=pb_anon_...
484
+ ```
485
+
486
+ Use your **service role key** (`pb_service_...`) only in server-side code — it bypasses RLS.
487
+
488
+ ---
489
+
490
+ ## License
491
+
492
+ MIT — see [LICENSE](https://github.com/postbase/postbase/blob/main/LICENSE).
493
+
494
+ ---
495
+
496
+ Built with love by the [Postbase](https://www.getpostbase.com) team.
package/package.json CHANGED
@@ -1,8 +1,18 @@
1
1
  {
2
2
  "name": "postbasejs",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "The official JavaScript client for Postbase — self-hosted backend as a service",
5
- "keywords": ["postbase", "database", "auth", "storage", "backend"],
5
+ "keywords": ["postbase", "database", "auth", "storage", "backend", "self-hosted", "postgresql", "baas"],
6
+ "homepage": "https://www.getpostbase.com",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/harshalone/postbase"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/harshalone/postbase/issues"
13
+ },
14
+ "license": "MIT",
15
+ "author": "Postbase",
6
16
  "main": "./dist/index.js",
7
17
  "module": "./dist/index.mjs",
8
18
  "types": "./dist/index.d.ts",