# @blinkdotnew/sdk v2.7.1 > Blink TypeScript SDK for client-side applications - Zero-boilerplate CRUD + auth + AI + analytics + notifications for modern SaaS/AI apps > Install: `npm install @blinkdotnew/sdk` > Docs: https://blink.new/docs/sdk --- # Blink TypeScript SDK `@blinkdotnew/sdk` gives you auth, database, AI, storage, and realtime in a single import. ## Install ```bash npm install @blinkdotnew/sdk ``` ## Quick example ```typescript import { createClient } from '@blinkdotnew/sdk' const blink = createClient({ projectId: 'your-project-id', authRequired: true, }) const user = await blink.auth.me() const todos = await blink.db.todos.list({ where: { user_id: user.id }, orderBy: { created_at: 'desc' }, }) ``` ## Guides | Guide | What it covers | |-------|---------------| | [Quickstart](/docs/sdk/quickstart) | Install, first query, file upload, AI in 5 minutes | | [Authentication](/docs/sdk/authentication) | OAuth, magic links, headless mode, React Native | | [Database](/docs/sdk/database) | CRUD, filtering, ordering, pagination | | [AI](/docs/sdk/ai) | Text, streaming, objects, images, speech, agents | | [Storage](/docs/sdk/storage) | Upload, list, download, delete | | [Realtime](/docs/sdk/realtime) | Channels, pub/sub, presence | ## API Reference Full TypeDoc reference (auto-generated from source) → [blink-new.github.io/blink-sdk](https://blink-new.github.io/blink-sdk/) ## Packages | Package | Description | |---------|-------------| | `@blinkdotnew/sdk` | Main SDK — browser, Node.js, Deno | | `@blinkdotnew/cli` | CLI — deploy, db, storage, AI from terminal | --- # Quickstart ## Install ```bash npm install @blinkdotnew/sdk ``` ## Create a client ```typescript import { createClient } from '@blinkdotnew/sdk' const blink = createClient({ projectId: 'your-project-id', authRequired: true, }) ``` `projectId` is found in your Blink project settings. Set `authRequired: true` to redirect unauthenticated users to sign in automatically. ## Get the current user ```typescript const user = await blink.auth.me() console.log(user.id, user.email) ``` ## Read and write data ```typescript // Create a record const todo = await blink.db.todos.create({ title: 'Ship it', completed: false, user_id: user.id, }) // List with filter + sort const todos = await blink.db.todos.list({ where: { user_id: user.id, completed: false }, orderBy: { created_at: 'desc' }, limit: 20, }) // Update await blink.db.todos.update(todo.id, { completed: true }) // Delete await blink.db.todos.delete(todo.id) ``` ## Upload a file ```typescript const { publicUrl } = await blink.storage.upload( file, `avatars/${user.id}.png`, { upsert: true } ) ``` ## Generate AI text ```typescript const { text } = await blink.ai.generateText({ prompt: 'Summarize this todo list', context: JSON.stringify(todos), }) ``` ## Next steps - [Authentication](/docs/sdk/authentication) — OAuth, magic links, headless mode - [Database](/docs/sdk/database) — CRUD, filtering, ordering, pagination - [AI](/docs/sdk/ai) — generateText, streamText, generateObject, generateImage - [Storage](/docs/sdk/storage) — upload, list, download, delete - [Realtime](/docs/sdk/realtime) — pub/sub channels, presence - [API Reference](https://blink-new.github.io/blink-sdk/) — full TypeDoc API reference --- # Authentication The SDK supports two auth modes: **managed** (default) and **headless**. ## Managed mode Blink handles the sign-in UI. Users are redirected to `blink.new/auth` and back to your app. ```typescript const blink = createClient({ projectId: 'your-project-id', authRequired: true, // redirect to sign-in if not authenticated }) // Trigger sign-in manually blink.auth.login() // Sign out blink.auth.logout() ``` ## Headless mode You build the UI. Blink provides the auth endpoints. ```typescript const blink = createClient({ projectId: 'your-project-id', auth: { mode: 'headless' }, }) // Email + password const user = await blink.auth.signInWithEmail('user@example.com', 'password') // Sign up const user = await blink.auth.signUp({ email: 'user@example.com', password: 'password' }) // OAuth providers const user = await blink.auth.signInWithGoogle() const user = await blink.auth.signInWithGitHub() const user = await blink.auth.signInWithApple() // Magic link await blink.auth.sendMagicLink('user@example.com') ``` ## Get current user ```typescript // Async — waits for auth to initialize const user = await blink.auth.me() // Sync — returns null if not yet initialized const user = blink.auth.currentUser() // Check auth state if (blink.auth.isAuthenticated()) { ... } ``` ## Listen for auth changes ```typescript const unsubscribe = blink.auth.onAuthStateChanged((state) => { console.log(state.isAuthenticated, state.user) }) // Call unsubscribe() to stop listening ``` ## Password management ```typescript // Send reset email await blink.auth.sendPasswordResetEmail('user@example.com') // Confirm reset await blink.auth.confirmPasswordReset(token, newPassword) // Change password (requires current auth) await blink.auth.changePassword(oldPassword, newPassword) ``` ## Email verification ```typescript await blink.auth.sendEmailVerification() await blink.auth.verifyEmail(token) ``` ## Update profile ```typescript const updated = await blink.auth.updateMe({ displayName: 'Alice', photoURL: 'https://...', }) ``` ## Server-side token verification Use in Deno Edge Functions or any server context: ```typescript const result = await blink.auth.verifyToken(req.headers.get('Authorization')) if (!result.valid) { return new Response('Unauthorized', { status: 401 }) } console.log(result.userId, result.email) ``` ## React Native Pass `expo-web-browser` to enable OAuth on mobile: ```typescript import * as WebBrowser from 'expo-web-browser' const blink = createClient({ projectId: 'your-project-id', auth: { mode: 'headless', webBrowser: WebBrowser, }, }) // Works on iOS, Android, and Web const user = await blink.auth.signInWithGoogle() ``` --- # Database `blink.db` gives you a PostgREST-compatible table interface. Table names are auto-mapped from camelCase to snake_case. ## Basic CRUD ```typescript // Create const post = await blink.db.posts.create({ title: 'Hello world', content: '...', user_id: user.id, }) // Read by ID const post = await blink.db.posts.get(postId) // List all const posts = await blink.db.posts.list() // Update await blink.db.posts.update(postId, { title: 'Updated' }) // Delete by ID await blink.db.posts.delete(postId) ``` IDs are auto-generated as secure random hex strings if not provided. ## Filtering ```typescript const posts = await blink.db.posts.list({ where: { user_id: userId, published: true, }, }) ``` ## Ordering and pagination ```typescript const posts = await blink.db.posts.list({ orderBy: { created_at: 'desc' }, limit: 20, offset: 0, }) ``` ## Count ```typescript const count = await blink.db.posts.count({ where: { published: true } }) ``` ## Upsert ```typescript // Insert or update on ID conflict const post = await blink.db.posts.upsert({ id: 'existing-or-new-id', title: 'My post', user_id: user.id, }) ``` ## Batch operations ```typescript // Batch create const posts = await blink.db.posts.createMany([ { title: 'Post 1', user_id: user.id }, { title: 'Post 2', user_id: user.id }, ]) // Delete multiple records matching a filter await blink.db.posts.deleteMany({ where: { user_id: userId, published: false }, }) // Update multiple records await blink.db.posts.updateMany( { where: { user_id: userId } }, { published: true } ) ``` ## TypeScript types The table is typed at the `BlinkTable` class level. Pass your type when accessing via the proxy: ```typescript type Post = { id: string title: string content: string user_id: string published: boolean created_at: string } // blink.db.posts returns BlinkTable when you type your schema const posts = await blink.db.posts.list() // posts is Post[] ``` ## Notes - Table names in camelCase (`blink.db.blogPosts`) map to snake_case (`blog_posts`) in the database. - All queries require an authenticated user unless your project disables row-level security. - IDs are strings — the SDK generates secure random IDs when not provided. --- # AI `blink.ai` wraps Blink's AI API with Vercel AI SDK-compatible streaming. ## Generate text ```typescript const { text } = await blink.ai.generateText({ prompt: 'Write a product description for a blue sneaker.', }) ``` With a system prompt and conversation history: ```typescript const { text } = await blink.ai.generateText({ messages: [ { role: 'user', content: 'What is the capital of France?' }, ], system: 'You are a helpful geography assistant.', }) ``` ## Stream text `streamText` uses a callback that fires on each chunk: ```typescript await blink.ai.streamText( { prompt: 'Write a short story.' }, (chunk) => { process.stdout.write(chunk) } ) ``` ## Generate structured objects ```typescript const { object } = await blink.ai.generateObject({ prompt: 'Extract the key info from this email', context: emailContent, schema: { type: 'object', properties: { sender: { type: 'string' }, subject: { type: 'string' }, urgency: { type: 'string', enum: ['low', 'medium', 'high'] }, }, required: ['sender', 'subject', 'urgency'], }, }) console.log(object.urgency) // 'high' ``` ## Stream objects (partial updates) `streamObject` uses a callback that fires as the object is progressively built: ```typescript await blink.ai.streamObject( { prompt: 'Generate a product catalog', schema: { ... } }, (partial) => { renderUI(partial) } ) ``` ## Generate images ```typescript const { data } = await blink.ai.generateImage({ prompt: 'A minimalist logo for a coffee shop', model: 'flux-pro', size: '1024x1024', }) const imageUrl = data[0].url ``` ## Edit/modify an image Image editing uses `modifyImage`, which takes one or more existing image URLs: ```typescript const { data } = await blink.ai.modifyImage({ images: [existingImageUrl], prompt: 'Make the background white', }) const editedUrl = data[0].url ``` ## Text to speech ```typescript const { url } = await blink.ai.generateSpeech({ text: 'Hello, welcome to Blink.', voice: 'alloy', }) ``` ## Transcription ```typescript const { text } = await blink.ai.transcribeAudio({ audio: 'https://example.com/recording.mp3', // URL, base64, or ArrayBuffer }) ``` ## AI Agent For multi-step autonomous tasks: ```typescript import { Agent } from '@blinkdotnew/sdk' const agent = new Agent({ model: 'anthropic/claude-3-7-sonnet', system: 'You are a helpful assistant.', tools: [webSearch, fetchUrl], }) const { text } = await agent.generate({ prompt: 'Research the latest AI news and summarize the top 3 stories.', }) ``` For streaming, `agent.stream()` returns a raw SSE `Response` you can read manually, or use the `@blinkdotnew/react` hooks which handle this automatically: ```typescript // Raw streaming (advanced) const response = await agent.stream({ prompt: 'Help me plan my week.' }) const reader = response.body!.getReader() const decoder = new TextDecoder() while (true) { const { done, value } = await reader.read() if (done) break updateUI(decoder.decode(value)) } ``` --- # Storage `blink.storage` provides file storage with automatic file type detection and public URLs. ## Upload a file ```typescript const { publicUrl } = await blink.storage.upload( file, // File | Blob | Buffer 'avatars/user123' // Path (extension auto-detected from file type) ) ``` The SDK detects the file's MIME type and corrects the extension automatically. A PNG file uploaded to `avatars/user123.jpg` will be stored as `avatars/user123.png`. ## Upload with options ```typescript const { publicUrl } = await blink.storage.upload(file, 'images/hero.png', { upsert: true, // Overwrite if exists onProgress: (progress) => { console.log(progress.percent + '% uploaded') }, }) ``` ## Download a file `download` returns a signed URL you can open or link to — not a blob: ```typescript const { downloadUrl, filename } = await blink.storage.download('avatars/user123.png') // Open in new tab window.open(downloadUrl, '_blank') // Or use as an anchor href Download ``` ## Remove a file ```typescript // Remove one file await blink.storage.remove('avatars/user123.png') // Remove multiple files at once await blink.storage.remove('file1.pdf', 'file2.pdf', 'file3.pdf') ``` ## Notes - Maximum file size: 50 MB - Supported types: images, videos, audio, documents, and more - The upload path acts as a file key; the SDK auto-corrects extensions to match actual MIME type - `download` returns a pre-signed URL valid for a limited time, not raw binary data --- # Realtime `blink.realtime` provides WebSocket-based pub/sub channels. A single connection is shared across all channels. ## Subscribe to a channel ```typescript const channel = blink.realtime.channel('chat:room-1') await channel.subscribe({ userId: user.id }) channel.onMessage((message) => { console.log(message.type, message.data, message.userId) }) ``` ## Publish a message ```typescript await channel.publish('message', { text: 'Hello!', timestamp: Date.now(), }) ``` ## Presence Track who is online in a channel: ```typescript channel.onPresence((users) => { console.log('Online:', users.map(u => u.userId)) }) ``` Each user is represented with `userId`, `metadata`, and `joinedAt`. ## Unsubscribe ```typescript await channel.unsubscribe() ``` ## Get message history ```typescript const messages = await channel.getMessages({ limit: 50 }) ``` ## Full example — live chat ```typescript const channel = blink.realtime.channel(`chat:${roomId}`) await channel.subscribe({ userId: user.id, metadata: { name: user.displayName } }) channel.onMessage((msg) => addMessageToUI(msg)) channel.onPresence((users) => setOnlineCount(users.length)) async function send(text: string) { await channel.publish('message', { text, userId: user.id }) } function leave() { channel.unsubscribe() } ``` ## Notes - One WebSocket connection per client, multiplexed across all channels - Channels are created on demand when you subscribe - Presence updates fire when users join or leave ---