@blinkdotnew/sdk 0.4.1 → 0.4.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.
package/README.md CHANGED
@@ -52,6 +52,14 @@ const text = await blink.data.extractFromUrl("https://example.com/document.pdf")
52
52
  const { markdown, metadata, links } = await blink.data.scrape("https://competitor.com")
53
53
  const screenshotUrl = await blink.data.screenshot("https://competitor.com")
54
54
 
55
+ // Secure API proxy (call external APIs with secret substitution)
56
+ const response = await blink.data.fetch({
57
+ url: "https://api.sendgrid.com/v3/mail/send",
58
+ method: "POST",
59
+ headers: { "Authorization": "Bearer {{sendgrid_api_key}}" },
60
+ body: { /* email data */ }
61
+ })
62
+
55
63
  // Storage operations (instant - returns public URL directly)
56
64
  const { publicUrl } = await blink.storage.upload(
57
65
  file,
@@ -76,7 +84,7 @@ This SDK powers every Blink-generated app with:
76
84
  - **🔐 Authentication**: JWT-based auth with automatic token management
77
85
  - **🗄️ Database**: PostgREST-compatible CRUD operations with advanced filtering
78
86
  - **🤖 AI**: Text generation with web search, object generation, image creation, speech synthesis, and transcription
79
- - **📄 Data**: Extract text content from documents, spreadsheets, and more
87
+ - **📄 Data**: Extract text content from documents, secure API proxy with secret substitution, web scraping, and screenshots
80
88
  - **📁 Storage**: File upload, download, and management
81
89
  - **🌐 Universal**: Works on client-side and server-side
82
90
  - **📱 Framework Agnostic**: React, Vue, Svelte, vanilla JS, Node.js, Deno
@@ -321,6 +329,77 @@ const fullPageUrl = await blink.data.screenshot('https://example.com', {
321
329
  height: 1080
322
330
  });
323
331
 
332
+ // 🔥 Secure API Proxy (NEW!) - Make API calls with secret substitution
333
+ // Perfect for calling external APIs from frontend while keeping API keys safe
334
+
335
+ // Basic API call with secret substitution
336
+ const response = await blink.data.fetch({
337
+ url: 'https://api.sendgrid.com/v3/mail/send',
338
+ method: 'POST',
339
+ headers: {
340
+ 'Authorization': 'Bearer {{sendgrid_api_key}}', // Secret replaced server-side
341
+ 'Content-Type': 'application/json'
342
+ },
343
+ body: {
344
+ from: { email: 'me@example.com' },
345
+ personalizations: [{ to: [{ email: 'user@example.com' }] }],
346
+ subject: 'Hello from Blink',
347
+ content: [{ type: 'text/plain', value: 'Sent securely through Blink!' }]
348
+ }
349
+ });
350
+
351
+ console.log('Email sent:', response.status === 200);
352
+ console.log('Response:', response.body);
353
+ console.log('Took:', response.durationMs, 'ms');
354
+
355
+ // GET request with secret in URL and query params
356
+ const weatherData = await blink.data.fetch({
357
+ url: 'https://api.openweathermap.org/data/2.5/weather',
358
+ method: 'GET',
359
+ query: {
360
+ q: 'London',
361
+ appid: '{{openweather_api_key}}', // Secret replaced in query params
362
+ units: 'metric'
363
+ }
364
+ });
365
+
366
+ console.log('Weather:', weatherData.body.main.temp, '°C');
367
+
368
+ // Async/background requests (fire-and-forget)
369
+ const asyncResponse = await blink.data.fetchAsync({
370
+ url: 'https://api.stripe.com/v1/customers',
371
+ method: 'POST',
372
+ headers: {
373
+ 'Authorization': 'Bearer {{stripe_secret_key}}',
374
+ 'Content-Type': 'application/x-www-form-urlencoded'
375
+ },
376
+ body: 'email=customer@example.com&name=John Doe'
377
+ });
378
+
379
+ console.log(asyncResponse.status); // 'triggered'
380
+ console.log(asyncResponse.message); // 'Request triggered in background'
381
+
382
+ // Multiple secrets in different places
383
+ const complexRequest = await blink.data.fetch({
384
+ url: 'https://api.github.com/repos/{{github_username}}/{{repo_name}}/issues',
385
+ method: 'POST',
386
+ headers: {
387
+ 'Authorization': 'token {{github_token}}',
388
+ 'Accept': 'application/vnd.github.v3+json',
389
+ 'User-Agent': '{{app_name}}'
390
+ },
391
+ body: {
392
+ title: 'Bug Report',
393
+ body: 'Found via {{app_name}} monitoring'
394
+ }
395
+ });
396
+
397
+ // Secret substitution works everywhere:
398
+ // - URL path: /api/{{version}}/users
399
+ // - Query params: ?key={{api_key}}&user={{user_id}}
400
+ // - Headers: Authorization: Bearer {{token}}
401
+ // - Body: { "apiKey": "{{secret}}", "data": "{{value}}" }
402
+
324
403
  // Error handling for data extraction
325
404
  try {
326
405
  const result = await blink.data.extractFromUrl('https://example.com/huge-file.pdf');
@@ -418,6 +497,47 @@ const todos = await blink.db.todos.list<Todo>({
418
497
  // todos is fully typed as ListResponse<Todo>
419
498
  ```
420
499
 
500
+ ### Secret Management for API Proxy
501
+
502
+ The `blink.data.fetch()` method allows you to make secure API calls with automatic secret substitution. Here's how to set it up:
503
+
504
+ **Step 1: Store your secrets in your Blink project**
505
+ Visit your project dashboard at [blink.new](https://blink.new) and add your API keys in the "Secrets" section:
506
+ - `sendgrid_api_key` → `SG.abc123...`
507
+ - `openweather_api_key` → `d4f5g6h7...`
508
+ - `stripe_secret_key` → `sk_live_abc123...`
509
+
510
+ **Step 2: Use secrets in your API calls**
511
+ ```typescript
512
+ // Secrets are automatically substituted server-side - never exposed to frontend
513
+ const result = await blink.data.fetch({
514
+ url: 'https://api.example.com/endpoint',
515
+ headers: {
516
+ 'Authorization': 'Bearer {{your_secret_key}}' // Replaced with actual value
517
+ }
518
+ })
519
+ ```
520
+
521
+ **Step 3: Secret substitution works everywhere**
522
+ ```typescript
523
+ await blink.data.fetch({
524
+ url: 'https://api.{{service_domain}}/v{{api_version}}/users/{{user_id}}',
525
+ query: {
526
+ key: '{{api_key}}',
527
+ format: 'json'
528
+ },
529
+ headers: {
530
+ 'X-API-Key': '{{secondary_key}}'
531
+ },
532
+ body: {
533
+ token: '{{auth_token}}',
534
+ data: 'regular string data'
535
+ }
536
+ })
537
+ ```
538
+
539
+ All `{{secret_name}}` placeholders are replaced with encrypted values from your project's secret store. Secrets never leave the server and are never visible to your frontend code.
540
+
421
541
  ## 🌍 Framework Examples
422
542
 
423
543
  ### React
@@ -442,6 +562,42 @@ function App() {
442
562
 
443
563
  return <div>Welcome, {user.email}!</div>
444
564
  }
565
+
566
+ // React example with secure API calls
567
+ function EmailSender() {
568
+ const [status, setStatus] = useState('')
569
+
570
+ const sendEmail = async () => {
571
+ setStatus('Sending...')
572
+ try {
573
+ const response = await blink.data.fetch({
574
+ url: 'https://api.sendgrid.com/v3/mail/send',
575
+ method: 'POST',
576
+ headers: {
577
+ 'Authorization': 'Bearer {{sendgrid_api_key}}', // Secret safe on server
578
+ 'Content-Type': 'application/json'
579
+ },
580
+ body: {
581
+ from: { email: 'app@example.com' },
582
+ personalizations: [{ to: [{ email: user.email }] }],
583
+ subject: 'Welcome to our app!',
584
+ content: [{ type: 'text/plain', value: 'Thanks for signing up!' }]
585
+ }
586
+ })
587
+
588
+ setStatus(response.status === 202 ? 'Email sent!' : 'Failed to send')
589
+ } catch (error) {
590
+ setStatus('Error: ' + error.message)
591
+ }
592
+ }
593
+
594
+ return (
595
+ <div>
596
+ <button onClick={sendEmail}>Send Welcome Email</button>
597
+ <p>{status}</p>
598
+ </div>
599
+ )
600
+ }
445
601
  ```
446
602
 
447
603
  ### Next.js API Routes
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { BlinkClientConfig, BlinkUser, AuthState, HttpClient, TableOperations, CreateOptions, UpsertOptions, QueryOptions, ListResponse, UpdateOptions, FilterCondition, ScrapeResult, BlinkStorage, BlinkAI, StorageUploadOptions, StorageUploadResponse, TextGenerationRequest, TextGenerationResponse, ObjectGenerationRequest, ObjectGenerationResponse, ImageGenerationRequest, ImageGenerationResponse, SpeechGenerationRequest, SpeechGenerationResponse, TranscriptionRequest, TranscriptionResponse } from '@blink/core';
1
+ import { BlinkClientConfig, BlinkUser, AuthState, HttpClient, TableOperations, CreateOptions, UpsertOptions, QueryOptions, ListResponse, UpdateOptions, FilterCondition, ScrapeResult, FetchRequest, FetchResponse, AsyncFetchResponse, BlinkStorage, BlinkAI, StorageUploadOptions, StorageUploadResponse, TextGenerationRequest, TextGenerationResponse, ObjectGenerationRequest, ObjectGenerationResponse, ImageGenerationRequest, ImageGenerationResponse, SpeechGenerationRequest, SpeechGenerationResponse, TranscriptionRequest, TranscriptionResponse } from '@blink/core';
2
2
  export { AuthState, AuthTokens, BlinkAI, BlinkClientConfig, BlinkData, BlinkStorage, BlinkUser, CreateOptions, DataExtraction, FileObject, FilterCondition, ImageGenerationRequest, ImageGenerationResponse, ListResponse, Message, ObjectGenerationRequest, ObjectGenerationResponse, QueryOptions, SpeechGenerationRequest, SpeechGenerationResponse, StorageUploadOptions, StorageUploadResponse, TableOperations, TextGenerationRequest, TextGenerationResponse, TokenUsage, TranscriptionRequest, TranscriptionResponse, UpdateOptions, UpsertOptions } from '@blink/core';
3
3
 
4
4
  /**
@@ -211,6 +211,8 @@ interface BlinkData {
211
211
  width?: number;
212
212
  height?: number;
213
213
  }): Promise<string>;
214
+ fetch(request: FetchRequest): Promise<FetchResponse>;
215
+ fetchAsync(request: Omit<FetchRequest, 'async'>): Promise<AsyncFetchResponse>;
214
216
  }
215
217
  declare class BlinkDataImpl implements BlinkData {
216
218
  private httpClient;
@@ -230,6 +232,8 @@ declare class BlinkDataImpl implements BlinkData {
230
232
  width?: number;
231
233
  height?: number;
232
234
  }): Promise<string>;
235
+ fetch(request: FetchRequest): Promise<FetchResponse>;
236
+ fetchAsync(request: Omit<FetchRequest, 'async'>): Promise<AsyncFetchResponse>;
233
237
  }
234
238
 
235
239
  /**
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { BlinkClientConfig, BlinkUser, AuthState, HttpClient, TableOperations, CreateOptions, UpsertOptions, QueryOptions, ListResponse, UpdateOptions, FilterCondition, ScrapeResult, BlinkStorage, BlinkAI, StorageUploadOptions, StorageUploadResponse, TextGenerationRequest, TextGenerationResponse, ObjectGenerationRequest, ObjectGenerationResponse, ImageGenerationRequest, ImageGenerationResponse, SpeechGenerationRequest, SpeechGenerationResponse, TranscriptionRequest, TranscriptionResponse } from '@blink/core';
1
+ import { BlinkClientConfig, BlinkUser, AuthState, HttpClient, TableOperations, CreateOptions, UpsertOptions, QueryOptions, ListResponse, UpdateOptions, FilterCondition, ScrapeResult, FetchRequest, FetchResponse, AsyncFetchResponse, BlinkStorage, BlinkAI, StorageUploadOptions, StorageUploadResponse, TextGenerationRequest, TextGenerationResponse, ObjectGenerationRequest, ObjectGenerationResponse, ImageGenerationRequest, ImageGenerationResponse, SpeechGenerationRequest, SpeechGenerationResponse, TranscriptionRequest, TranscriptionResponse } from '@blink/core';
2
2
  export { AuthState, AuthTokens, BlinkAI, BlinkClientConfig, BlinkData, BlinkStorage, BlinkUser, CreateOptions, DataExtraction, FileObject, FilterCondition, ImageGenerationRequest, ImageGenerationResponse, ListResponse, Message, ObjectGenerationRequest, ObjectGenerationResponse, QueryOptions, SpeechGenerationRequest, SpeechGenerationResponse, StorageUploadOptions, StorageUploadResponse, TableOperations, TextGenerationRequest, TextGenerationResponse, TokenUsage, TranscriptionRequest, TranscriptionResponse, UpdateOptions, UpsertOptions } from '@blink/core';
3
3
 
4
4
  /**
@@ -211,6 +211,8 @@ interface BlinkData {
211
211
  width?: number;
212
212
  height?: number;
213
213
  }): Promise<string>;
214
+ fetch(request: FetchRequest): Promise<FetchResponse>;
215
+ fetchAsync(request: Omit<FetchRequest, 'async'>): Promise<AsyncFetchResponse>;
214
216
  }
215
217
  declare class BlinkDataImpl implements BlinkData {
216
218
  private httpClient;
@@ -230,6 +232,8 @@ declare class BlinkDataImpl implements BlinkData {
230
232
  width?: number;
231
233
  height?: number;
232
234
  }): Promise<string>;
235
+ fetch(request: FetchRequest): Promise<FetchResponse>;
236
+ fetchAsync(request: Omit<FetchRequest, 'async'>): Promise<AsyncFetchResponse>;
233
237
  }
234
238
 
235
239
  /**
package/dist/index.js CHANGED
@@ -40,6 +40,12 @@ var BlinkAIError = class extends BlinkError {
40
40
  this.name = "BlinkAIError";
41
41
  }
42
42
  };
43
+ var BlinkDataError = class extends BlinkError {
44
+ constructor(message, status, details) {
45
+ super(message, "DATA_ERROR", status, details);
46
+ this.name = "BlinkDataError";
47
+ }
48
+ };
43
49
 
44
50
  // ../core/src/query-builder.ts
45
51
  function buildFilterQuery(condition) {
@@ -564,6 +570,12 @@ var HttpClient = class {
564
570
  body: JSON.stringify(request)
565
571
  });
566
572
  }
573
+ async dataFetch(projectId, request) {
574
+ return this.request(`/api/data/${projectId}/fetch`, {
575
+ method: "POST",
576
+ body: JSON.stringify(request)
577
+ });
578
+ }
567
579
  /**
568
580
  * Private helper methods
569
581
  */
@@ -2392,6 +2404,21 @@ var BlinkDataImpl = class {
2392
2404
  const response = await this.httpClient.dataScreenshot(this.projectId, request);
2393
2405
  return response.data.url;
2394
2406
  }
2407
+ async fetch(request) {
2408
+ const response = await this.httpClient.dataFetch(this.projectId, request);
2409
+ if ("status" in response.data && "headers" in response.data) {
2410
+ return response.data;
2411
+ }
2412
+ throw new BlinkDataError("Unexpected response format from fetch endpoint");
2413
+ }
2414
+ async fetchAsync(request) {
2415
+ const asyncRequest = { ...request, async: true };
2416
+ const response = await this.httpClient.dataFetch(this.projectId, asyncRequest);
2417
+ if ("status" in response.data && response.data.status === "triggered") {
2418
+ return response.data;
2419
+ }
2420
+ throw new BlinkDataError("Unexpected response format from async fetch endpoint");
2421
+ }
2395
2422
  };
2396
2423
 
2397
2424
  // src/client.ts