@blinkdotnew/sdk 0.14.9 → 0.14.11

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 +89 -15
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -35,8 +35,8 @@ const user = await blink.auth.me()
35
35
 
36
36
  // Database operations (zero config)
37
37
  const todos = await blink.db.todos.list({
38
- where: { user_id: user.id },
39
- orderBy: { created_at: 'desc' },
38
+ where: { userId: user.id },
39
+ orderBy: { createdAt: 'desc' },
40
40
  limit: 20
41
41
  })
42
42
 
@@ -187,9 +187,13 @@ await blink.auth.updateMe({ displayName: 'New Name' })
187
187
  blink.auth.setToken(jwt, persist?)
188
188
  const isAuth = blink.auth.isAuthenticated()
189
189
 
190
- // Auth state listener
190
+ // Auth state listener (REQUIRED for React apps!)
191
191
  const unsubscribe = blink.auth.onAuthStateChanged((state) => {
192
192
  console.log('Auth state:', state)
193
+ // state.user - current user or null
194
+ // state.isLoading - true while auth is initializing
195
+ // state.isAuthenticated - true if user is logged in
196
+ // state.tokens - current auth tokens
193
197
  })
194
198
  ```
195
199
 
@@ -201,6 +205,11 @@ The SDK now automatically converts between JavaScript camelCase and SQL snake_ca
201
205
  - **Stored as snake_case**: `user_id`, `created_at`, `is_completed`
202
206
  - **No manual conversion needed!**
203
207
 
208
+ **⚠️ Important: Always Use camelCase in Your Code**
209
+ - ✅ **Correct**: `{ userId: user.id, createdAt: new Date() }`
210
+ - ❌ **Wrong**: `{ user_id: user.id, created_at: new Date() }`
211
+ - **Exception**: Raw SQL queries still use snake_case (as stored in database)
212
+
204
213
  ```typescript
205
214
  // Create (ID auto-generated if not provided)
206
215
  const todo = await blink.db.todos.create({
@@ -226,23 +235,23 @@ const todos = await blink.db.todos.list({
226
235
 
227
236
  // Note: Boolean fields are returned as "0"/"1" strings from SQLite
228
237
  // Check boolean values using Number(value) > 0
229
- const completedTodos = todos.filter(todo => Number(todo.completed) > 0)
230
- const incompleteTodos = todos.filter(todo => Number(todo.completed) === 0)
238
+ const completedTodos = todos.filter(todo => Number(todo.isCompleted) > 0)
239
+ const incompleteTodos = todos.filter(todo => Number(todo.isCompleted) === 0)
231
240
 
232
241
  // Update
233
- await blink.db.todos.update(todo.id, { completed: true })
242
+ await blink.db.todos.update(todo.id, { isCompleted: true })
234
243
 
235
244
  // Delete
236
245
  await blink.db.todos.delete(todo.id)
237
246
 
238
247
  // Bulk operations (IDs auto-generated if not provided)
239
248
  await blink.db.todos.createMany([
240
- { title: 'Task 1', user_id: user.id }, // ID will be auto-generated
241
- { id: 'custom_id', title: 'Task 2', user_id: user.id } // Custom ID provided
249
+ { title: 'Task 1', userId: user.id }, // ID will be auto-generated
250
+ { id: 'custom_id', title: 'Task 2', userId: user.id } // Custom ID provided
242
251
  ])
243
252
  await blink.db.todos.upsertMany([...])
244
253
 
245
- // Raw SQL
254
+ // Raw SQL (note: raw SQL still uses snake_case as stored in database)
246
255
  const result = await blink.db.sql('SELECT * FROM todos WHERE user_id = ?', [user.id])
247
256
  ```
248
257
 
@@ -1205,9 +1214,9 @@ The SDK is written in TypeScript and provides full type safety:
1205
1214
  interface Todo {
1206
1215
  id: string
1207
1216
  title: string
1208
- completed: boolean // Will be returned as "0" or "1" string from SQLite
1209
- user_id: string
1210
- created_at: string
1217
+ isCompleted: boolean // Will be returned as "0" or "1" string from SQLite
1218
+ userId: string // Automatically converted from snake_case user_id
1219
+ createdAt: string // Automatically converted from snake_case created_at
1211
1220
  }
1212
1221
 
1213
1222
  // Note: Boolean fields are returned as "0"/"1" strings from SQLite
@@ -1215,12 +1224,12 @@ interface Todo {
1215
1224
  const todos = await blink.db.todos.list<Todo>()
1216
1225
 
1217
1226
  // Check boolean values properly
1218
- const completedTodos = todos.filter(todo => Number(todo.completed) > 0)
1219
- const incompleteTodos = todos.filter(todo => Number(todo.completed) === 0)
1227
+ const completedTodos = todos.filter(todo => Number(todo.isCompleted) > 0)
1228
+ const incompleteTodos = todos.filter(todo => Number(todo.isCompleted) === 0)
1220
1229
 
1221
1230
  // When filtering by boolean values in queries, use "0"/"1" strings
1222
1231
  const onlyCompleted = await blink.db.todos.list<Todo>({
1223
- where: { completed: "1" } // Use string "1" for true, "0" for false
1232
+ where: { isCompleted: "1" } // Use string "1" for true, "0" for false
1224
1233
  })
1225
1234
  // todos is fully typed as Todo[]
1226
1235
  ```
@@ -1390,6 +1399,44 @@ function MyRealtimeComponent() {
1390
1399
 
1391
1400
  ### React
1392
1401
 
1402
+ **⚠️ Critical: Always Use Auth State Listener, Never One-Time Checks**
1403
+
1404
+ The most common authentication mistake is checking auth status once instead of listening to changes:
1405
+
1406
+ ```typescript
1407
+ // ❌ WRONG - One-time check misses auth completion
1408
+ useEffect(() => {
1409
+ const checkAuth = async () => {
1410
+ try {
1411
+ const userData = await blink.auth.me()
1412
+ setUser(userData)
1413
+ } catch (error) {
1414
+ console.error('Auth check failed:', error)
1415
+ } finally {
1416
+ setLoading(false)
1417
+ }
1418
+ }
1419
+ checkAuth() // Only runs once - misses when auth completes later!
1420
+ }, [])
1421
+
1422
+ // ✅ CORRECT - Listen to auth state changes
1423
+ useEffect(() => {
1424
+ const unsubscribe = blink.auth.onAuthStateChanged((state) => {
1425
+ setUser(state.user)
1426
+ setLoading(state.isLoading)
1427
+ })
1428
+ return unsubscribe
1429
+ }, [])
1430
+ ```
1431
+
1432
+ **Why the one-time check fails:**
1433
+ 1. App loads → `blink.auth.me()` called immediately
1434
+ 2. Auth still initializing → Call fails, user set to `null`
1435
+ 3. Auth completes later → App never knows because it only checked once
1436
+ 4. User stuck on "Please sign in" screen forever
1437
+
1438
+ **Always use `onAuthStateChanged()` for React apps!**
1439
+
1393
1440
  ```typescript
1394
1441
  import { createClient } from '@blinkdotnew/sdk'
1395
1442
  import { useState, useEffect } from 'react'
@@ -1398,19 +1445,46 @@ const blink = createClient({ projectId: 'your-project', authRequired: true })
1398
1445
 
1399
1446
  function App() {
1400
1447
  const [user, setUser] = useState(null)
1448
+ const [loading, setLoading] = useState(true)
1401
1449
 
1402
1450
  useEffect(() => {
1403
1451
  const unsubscribe = blink.auth.onAuthStateChanged((state) => {
1404
1452
  setUser(state.user)
1453
+ setLoading(state.isLoading)
1405
1454
  })
1406
1455
  return unsubscribe
1407
1456
  }, [])
1408
1457
 
1458
+ if (loading) return <div>Loading...</div>
1409
1459
  if (!user) return <div>Please log in</div>
1410
1460
 
1411
1461
  return <div>Welcome, {user.email}!</div>
1412
1462
  }
1413
1463
 
1464
+ // ❌ WRONG - One-time auth check (misses auth state changes)
1465
+ function BadApp() {
1466
+ const [user, setUser] = useState(null)
1467
+ const [loading, setLoading] = useState(true)
1468
+
1469
+ useEffect(() => {
1470
+ const checkAuth = async () => {
1471
+ try {
1472
+ const userData = await blink.auth.me()
1473
+ setUser(userData)
1474
+ } catch (error) {
1475
+ console.error('Auth check failed:', error)
1476
+ } finally {
1477
+ setLoading(false)
1478
+ }
1479
+ }
1480
+
1481
+ checkAuth() // ❌ Only runs once - misses when auth completes later!
1482
+ }, [])
1483
+
1484
+ // This pattern causes users to get stuck on "Please sign in"
1485
+ // even after authentication completes
1486
+ }
1487
+
1414
1488
  // React example with search functionality
1415
1489
  function SearchResults() {
1416
1490
  const [query, setQuery] = useState('')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blinkdotnew/sdk",
3
- "version": "0.14.9",
3
+ "version": "0.14.11",
4
4
  "description": "Blink TypeScript SDK for client-side applications - Zero-boilerplate CRUD + auth + AI + analytics + notifications for modern SaaS/AI apps",
5
5
  "keywords": [
6
6
  "blink",