@blinkdotnew/sdk 0.1.0 → 0.2.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 CHANGED
@@ -3,40 +3,49 @@
3
3
  [![npm version](https://badge.fury.io/js/%40blinkdotnew%2Fsdk.svg)](https://badge.fury.io/js/%40blinkdotnew%2Fsdk)
4
4
  [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
5
5
 
6
- **Zero-boilerplate CRUD + auth for modern SaaS/AI apps**
6
+ **The full-stack TypeScript SDK that powers Blink AI-generated apps**
7
7
 
8
- Blink SDK provides a Firebase/Supabase-like experience with built-in authentication, database operations, AI capabilities, and file storage. Works seamlessly on both client-side (React, Vue, etc.) and server-side (Node.js, Deno, Edge functions).
8
+ Blink is an AI App Developer that builds fully functional apps in seconds. This SDK (`@blinkdotnew/sdk`) is the TypeScript foundation that powers every Blink app natively, providing zero-boilerplate authentication, database operations, AI capabilities, and file storage. Works seamlessly on both client-side (React, Vue, etc.) and server-side (Node.js, Deno, Edge functions).
9
9
 
10
10
  ## 🚀 Quick Start
11
11
 
12
+ ### **Step 1: Create a Blink Project**
13
+ Visit [blink.new](https://blink.new) and create a new project. Blink's AI agent will build your app in seconds.
14
+
15
+ ### **Step 2: Install the SDK**
16
+ Use Blink's AI agent to automatically install this SDK in your Vite React TypeScript client, or install manually:
17
+
12
18
  ```bash
13
19
  npm install @blinkdotnew/sdk
14
20
  ```
15
21
 
22
+ ### **Step 3: Use Your Project ID**
23
+ Get your project ID from your Blink dashboard and start building:
24
+
16
25
  ```typescript
17
26
  import { createClient } from '@blinkdotnew/sdk'
18
27
 
19
28
  const blink = createClient({
20
- projectId: 'your-project-id',
29
+ projectId: 'your-blink-project-id', // From blink.new dashboard
21
30
  authRequired: true
22
31
  })
23
32
 
24
- // Authentication
33
+ // Authentication (built-in)
25
34
  const user = await blink.auth.me()
26
35
 
27
- // Database operations
36
+ // Database operations (zero config)
28
37
  const todos = await blink.db.todos.list({
29
38
  where: { user_id: user.id },
30
39
  orderBy: { created_at: 'desc' },
31
40
  limit: 20
32
41
  })
33
42
 
34
- // AI operations
43
+ // AI operations (native)
35
44
  const { text } = await blink.ai.generateText({
36
45
  prompt: "Write a summary of the user's todos"
37
46
  })
38
47
 
39
- // Storage operations
48
+ // Storage operations (instant)
40
49
  const { publicUrl } = await blink.storage.upload(
41
50
  file,
42
51
  `avatars/${user.id}.png`,
@@ -44,17 +53,31 @@ const { publicUrl } = await blink.storage.upload(
44
53
  )
45
54
  ```
46
55
 
47
- ## 📚 Features
56
+ ## 🤖 What is Blink?
57
+
58
+ **Blink is an AI App Developer** that creates fully functional applications in seconds. Simply describe what you want to build, and Blink's AI agent will:
59
+
60
+ - 🏗️ **Generate complete apps** with React + TypeScript + Vite
61
+ - 🔧 **Auto-install this SDK** with zero configuration
62
+ - 🎨 **Create beautiful UIs** with Tailwind CSS
63
+ - 🚀 **Deploy instantly** with authentication, database, AI, and storage built-in
64
+
65
+ ## 📚 SDK Features
66
+
67
+ This SDK powers every Blink-generated app with:
48
68
 
49
69
  - **🔐 Authentication**: JWT-based auth with automatic token management
50
- - **🗄️ Database**: PostgREST-compatible CRUD operations with advanced filtering
70
+ - **🗄️ Database**: PostgREST-compatible CRUD operations with advanced filtering
51
71
  - **🤖 AI**: Text generation, object generation, image creation, speech synthesis, and transcription
52
72
  - **📁 Storage**: File upload, download, and management
53
73
  - **🌐 Universal**: Works on client-side and server-side
54
74
  - **📱 Framework Agnostic**: React, Vue, Svelte, vanilla JS, Node.js, Deno
55
75
  - **🔄 Real-time**: Built-in auth state management and token refresh
76
+ - **⚡ Zero Boilerplate**: Everything works out of the box
77
+
78
+ ## 🛠️ Manual Installation & Setup
56
79
 
57
- ## 🛠️ Installation & Setup
80
+ > **💡 Tip**: If you're using Blink's AI agent, this is all done automatically for you!
58
81
 
59
82
  ### Client-side (React, Vue, etc.)
60
83
 
@@ -62,7 +85,7 @@ const { publicUrl } = await blink.storage.upload(
62
85
  import { createClient } from '@blinkdotnew/sdk'
63
86
 
64
87
  const blink = createClient({
65
- projectId: 'your-project-id',
88
+ projectId: 'your-blink-project-id', // From blink.new dashboard
66
89
  authRequired: true // Automatic auth redirect
67
90
  })
68
91
  ```
@@ -73,7 +96,7 @@ const blink = createClient({
73
96
  import { createClient } from '@blinkdotnew/sdk'
74
97
 
75
98
  const blink = createClient({
76
- projectId: 'your-project-id',
99
+ projectId: 'your-blink-project-id', // From blink.new dashboard
77
100
  authRequired: false // Manual token management
78
101
  })
79
102
 
@@ -146,13 +169,40 @@ const result = await blink.db.sql('SELECT * FROM todos WHERE user_id = ?', [user
146
169
  ### AI Operations
147
170
 
148
171
  ```typescript
149
- // Text generation
172
+ // Text generation (simple prompt)
150
173
  const { text } = await blink.ai.generateText({
151
174
  prompt: 'Write a poem about coding',
152
175
  model: 'gpt-4o-mini',
153
176
  maxTokens: 150
154
177
  })
155
178
 
179
+ // Text generation with image content
180
+ const { text } = await blink.ai.generateText({
181
+ messages: [
182
+ {
183
+ role: "user",
184
+ content: [
185
+ { type: "text", text: "What do you see in this image?" },
186
+ { type: "image", image: "https://example.com/photo.jpg" }
187
+ ]
188
+ }
189
+ ]
190
+ })
191
+
192
+ // Mixed content with multiple images
193
+ const { text } = await blink.ai.generateText({
194
+ messages: [
195
+ {
196
+ role: "user",
197
+ content: [
198
+ { type: "text", text: "Compare these two images:" },
199
+ { type: "image", image: "https://example.com/image1.jpg" },
200
+ { type: "image", image: "https://example.com/image2.jpg" }
201
+ ]
202
+ }
203
+ ]
204
+ })
205
+
156
206
  // Structured object generation
157
207
  const { object } = await blink.ai.generateObject({
158
208
  prompt: 'Generate a user profile',
@@ -233,6 +283,26 @@ try {
233
283
  console.error('Auth error:', error.message)
234
284
  }
235
285
  }
286
+
287
+ // Image validation error handling
288
+ try {
289
+ const { text } = await blink.ai.generateText({
290
+ messages: [
291
+ {
292
+ role: "user",
293
+ content: [
294
+ { type: "text", text: "What's in this image?" },
295
+ { type: "image", image: "http://example.com/image.jpg" } // Invalid: not HTTPS
296
+ ]
297
+ }
298
+ ]
299
+ })
300
+ } catch (error) {
301
+ if (error instanceof BlinkAIError) {
302
+ console.error('AI validation error:', error.message)
303
+ // Example: "Message validation failed: Image URLs must use HTTPS protocol"
304
+ }
305
+ }
236
306
  ```
237
307
 
238
308
  ### Custom Configuration
@@ -329,10 +399,15 @@ Deno.serve(async (req) => {
329
399
 
330
400
  ## 🔗 Links
331
401
 
332
- - **Documentation**: [https://docs.blink.new](https://docs.blink.new)
333
- - **GitHub**: [https://github.com/ShadowWalker2014/blink-sdk](https://github.com/ShadowWalker2014/blink-sdk)
334
- - **Website**: [https://blink.new](https://blink.new)
335
- - **Discord**: [Join our community](https://discord.gg/blink)
402
+ - **🌟 Try Blink AI**: [https://blink.new](https://blink.new) - Build apps in seconds
403
+ - **📚 Documentation**: [https://docs.blink.new](https://docs.blink.new)
404
+ - **💻 GitHub**: [https://github.com/ShadowWalker2014/blink-sdk](https://github.com/ShadowWalker2014/blink-sdk)
405
+
406
+ ### Social Links
407
+ - **🐦 X (Twitter)**: [https://x.com/blinkdotnew](https://x.com/blinkdotnew)
408
+ - **💼 LinkedIn**: [https://www.linkedin.com/company/blinkdotnew](https://www.linkedin.com/company/blinkdotnew)
409
+ - **💬 Discord**: [https://discord.gg/2RjY7wP4a8](https://discord.gg/2RjY7wP4a8)
410
+ - **🔴 Reddit**: [https://www.reddit.com/r/blinkdotnew/](https://www.reddit.com/r/blinkdotnew/)
336
411
 
337
412
  ## 📄 License
338
413
 
@@ -340,4 +415,6 @@ MIT © Blink Team
340
415
 
341
416
  ---
342
417
 
343
- **Made with ❤️ by the Blink team**
418
+ **Made with ❤️ by the Blink team**
419
+
420
+ 🤖 **Ready to build your next app?** Visit [blink.new](https://blink.new) and let our AI create it for you in seconds!
package/dist/index.d.mts CHANGED
@@ -264,6 +264,15 @@ declare class BlinkStorageImpl implements BlinkStorage {
264
264
  declare class BlinkAIImpl implements BlinkAI {
265
265
  private httpClient;
266
266
  constructor(httpClient: HttpClient);
267
+ private readonly SUPPORTED_IMAGE_FORMATS;
268
+ /**
269
+ * Validates if a URL is a valid HTTPS image URL
270
+ */
271
+ private validateImageUrl;
272
+ /**
273
+ * Validates messages for image content
274
+ */
275
+ private validateMessages;
267
276
  /**
268
277
  * Get MIME type for audio format
269
278
  */
@@ -283,7 +292,7 @@ declare class BlinkAIImpl implements BlinkAI {
283
292
  * prompt: "Write a poem about coding"
284
293
  * });
285
294
  *
286
- * // Chat messages
295
+ * // Chat messages (text only)
287
296
  * const { text } = await blink.ai.generateText({
288
297
  * messages: [
289
298
  * { role: "system", content: "You are a helpful assistant" },
@@ -291,6 +300,33 @@ declare class BlinkAIImpl implements BlinkAI {
291
300
  * ]
292
301
  * });
293
302
  *
303
+ * // With image content
304
+ * const { text } = await blink.ai.generateText({
305
+ * messages: [
306
+ * {
307
+ * role: "user",
308
+ * content: [
309
+ * { type: "text", text: "What do you see in this image?" },
310
+ * { type: "image", image: "https://example.com/photo.jpg" }
311
+ * ]
312
+ * }
313
+ * ]
314
+ * });
315
+ *
316
+ * // Mixed content with multiple images
317
+ * const { text } = await blink.ai.generateText({
318
+ * messages: [
319
+ * {
320
+ * role: "user",
321
+ * content: [
322
+ * { type: "text", text: "Compare these two images:" },
323
+ * { type: "image", image: "https://example.com/image1.jpg" },
324
+ * { type: "image", image: "https://example.com/image2.jpg" }
325
+ * ]
326
+ * }
327
+ * ]
328
+ * });
329
+ *
294
330
  * // With options
295
331
  * const { text, usage } = await blink.ai.generateText({
296
332
  * prompt: "Summarize this article",
package/dist/index.d.ts CHANGED
@@ -264,6 +264,15 @@ declare class BlinkStorageImpl implements BlinkStorage {
264
264
  declare class BlinkAIImpl implements BlinkAI {
265
265
  private httpClient;
266
266
  constructor(httpClient: HttpClient);
267
+ private readonly SUPPORTED_IMAGE_FORMATS;
268
+ /**
269
+ * Validates if a URL is a valid HTTPS image URL
270
+ */
271
+ private validateImageUrl;
272
+ /**
273
+ * Validates messages for image content
274
+ */
275
+ private validateMessages;
267
276
  /**
268
277
  * Get MIME type for audio format
269
278
  */
@@ -283,7 +292,7 @@ declare class BlinkAIImpl implements BlinkAI {
283
292
  * prompt: "Write a poem about coding"
284
293
  * });
285
294
  *
286
- * // Chat messages
295
+ * // Chat messages (text only)
287
296
  * const { text } = await blink.ai.generateText({
288
297
  * messages: [
289
298
  * { role: "system", content: "You are a helpful assistant" },
@@ -291,6 +300,33 @@ declare class BlinkAIImpl implements BlinkAI {
291
300
  * ]
292
301
  * });
293
302
  *
303
+ * // With image content
304
+ * const { text } = await blink.ai.generateText({
305
+ * messages: [
306
+ * {
307
+ * role: "user",
308
+ * content: [
309
+ * { type: "text", text: "What do you see in this image?" },
310
+ * { type: "image", image: "https://example.com/photo.jpg" }
311
+ * ]
312
+ * }
313
+ * ]
314
+ * });
315
+ *
316
+ * // Mixed content with multiple images
317
+ * const { text } = await blink.ai.generateText({
318
+ * messages: [
319
+ * {
320
+ * role: "user",
321
+ * content: [
322
+ * { type: "text", text: "Compare these two images:" },
323
+ * { type: "image", image: "https://example.com/image1.jpg" },
324
+ * { type: "image", image: "https://example.com/image2.jpg" }
325
+ * ]
326
+ * }
327
+ * ]
328
+ * });
329
+ *
294
330
  * // With options
295
331
  * const { text, usage } = await blink.ai.generateText({
296
332
  * prompt: "Summarize this article",
package/dist/index.js CHANGED
@@ -1603,6 +1603,55 @@ var BlinkAIImpl = class {
1603
1603
  constructor(httpClient) {
1604
1604
  this.httpClient = httpClient;
1605
1605
  }
1606
+ // Supported image formats for validation
1607
+ SUPPORTED_IMAGE_FORMATS = ["jpg", "jpeg", "png", "gif", "webp"];
1608
+ /**
1609
+ * Validates if a URL is a valid HTTPS image URL
1610
+ */
1611
+ validateImageUrl(url) {
1612
+ try {
1613
+ const parsedUrl = new URL(url);
1614
+ if (parsedUrl.protocol !== "https:") {
1615
+ return { isValid: false, error: "Image URLs must use HTTPS protocol" };
1616
+ }
1617
+ const pathname = parsedUrl.pathname.toLowerCase();
1618
+ const hasValidExtension = this.SUPPORTED_IMAGE_FORMATS.some(
1619
+ (format) => pathname.endsWith(`.${format}`)
1620
+ );
1621
+ if (!hasValidExtension) {
1622
+ return {
1623
+ isValid: false,
1624
+ error: `Image URL must end with a supported format: ${this.SUPPORTED_IMAGE_FORMATS.join(", ")}`
1625
+ };
1626
+ }
1627
+ return { isValid: true };
1628
+ } catch (error) {
1629
+ return { isValid: false, error: "Invalid URL format" };
1630
+ }
1631
+ }
1632
+ /**
1633
+ * Validates messages for image content
1634
+ */
1635
+ validateMessages(messages) {
1636
+ const errors = [];
1637
+ messages.forEach((message, messageIndex) => {
1638
+ if (Array.isArray(message.content)) {
1639
+ message.content.forEach((item, contentIndex) => {
1640
+ if (item.type === "image") {
1641
+ if (!item.image || typeof item.image !== "string") {
1642
+ errors.push(`Message ${messageIndex}, content ${contentIndex}: Image content must have a valid image URL`);
1643
+ } else {
1644
+ const validation = this.validateImageUrl(item.image);
1645
+ if (!validation.isValid) {
1646
+ errors.push(`Message ${messageIndex}, content ${contentIndex}: ${validation.error}`);
1647
+ }
1648
+ }
1649
+ }
1650
+ });
1651
+ }
1652
+ });
1653
+ return { isValid: errors.length === 0, errors };
1654
+ }
1606
1655
  /**
1607
1656
  * Get MIME type for audio format
1608
1657
  */
@@ -1632,7 +1681,7 @@ var BlinkAIImpl = class {
1632
1681
  * prompt: "Write a poem about coding"
1633
1682
  * });
1634
1683
  *
1635
- * // Chat messages
1684
+ * // Chat messages (text only)
1636
1685
  * const { text } = await blink.ai.generateText({
1637
1686
  * messages: [
1638
1687
  * { role: "system", content: "You are a helpful assistant" },
@@ -1640,6 +1689,33 @@ var BlinkAIImpl = class {
1640
1689
  * ]
1641
1690
  * });
1642
1691
  *
1692
+ * // With image content
1693
+ * const { text } = await blink.ai.generateText({
1694
+ * messages: [
1695
+ * {
1696
+ * role: "user",
1697
+ * content: [
1698
+ * { type: "text", text: "What do you see in this image?" },
1699
+ * { type: "image", image: "https://example.com/photo.jpg" }
1700
+ * ]
1701
+ * }
1702
+ * ]
1703
+ * });
1704
+ *
1705
+ * // Mixed content with multiple images
1706
+ * const { text } = await blink.ai.generateText({
1707
+ * messages: [
1708
+ * {
1709
+ * role: "user",
1710
+ * content: [
1711
+ * { type: "text", text: "Compare these two images:" },
1712
+ * { type: "image", image: "https://example.com/image1.jpg" },
1713
+ * { type: "image", image: "https://example.com/image2.jpg" }
1714
+ * ]
1715
+ * }
1716
+ * ]
1717
+ * });
1718
+ *
1643
1719
  * // With options
1644
1720
  * const { text, usage } = await blink.ai.generateText({
1645
1721
  * prompt: "Summarize this article",
@@ -1659,6 +1735,12 @@ var BlinkAIImpl = class {
1659
1735
  if (!options.prompt && !options.messages) {
1660
1736
  throw new BlinkAIError("Either prompt or messages is required");
1661
1737
  }
1738
+ if (options.messages) {
1739
+ const validation = this.validateMessages(options.messages);
1740
+ if (!validation.isValid) {
1741
+ throw new BlinkAIError(`Message validation failed: ${validation.errors.join("; ")}`);
1742
+ }
1743
+ }
1662
1744
  const requestBody = {
1663
1745
  model: options.model,
1664
1746
  stream: false,
@@ -1729,6 +1811,12 @@ var BlinkAIImpl = class {
1729
1811
  if (!options.prompt && !options.messages) {
1730
1812
  throw new BlinkAIError("Either prompt or messages is required");
1731
1813
  }
1814
+ if (options.messages) {
1815
+ const validation = this.validateMessages(options.messages);
1816
+ if (!validation.isValid) {
1817
+ throw new BlinkAIError(`Message validation failed: ${validation.errors.join("; ")}`);
1818
+ }
1819
+ }
1732
1820
  const result = await this.httpClient.streamAiText(
1733
1821
  options.prompt || "",
1734
1822
  {