@blinkdotnew/sdk 0.4.0 → 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 +159 -2
- package/dist/index.d.mts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +27 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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,
|
|
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
|
|
@@ -194,7 +202,8 @@ const { text, sources } = await blink.ai.generateText({
|
|
|
194
202
|
const { text } = await blink.ai.generateText({
|
|
195
203
|
prompt: 'Research and analyze tech trends',
|
|
196
204
|
search: true,
|
|
197
|
-
maxSteps:
|
|
205
|
+
maxSteps: 10, // Override default (25 when tools used)
|
|
206
|
+
experimental_continueSteps: true // Override default (true when tools used)
|
|
198
207
|
})
|
|
199
208
|
|
|
200
209
|
// Text generation with image content
|
|
@@ -320,6 +329,77 @@ const fullPageUrl = await blink.data.screenshot('https://example.com', {
|
|
|
320
329
|
height: 1080
|
|
321
330
|
});
|
|
322
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
|
+
|
|
323
403
|
// Error handling for data extraction
|
|
324
404
|
try {
|
|
325
405
|
const result = await blink.data.extractFromUrl('https://example.com/huge-file.pdf');
|
|
@@ -417,6 +497,47 @@ const todos = await blink.db.todos.list<Todo>({
|
|
|
417
497
|
// todos is fully typed as ListResponse<Todo>
|
|
418
498
|
```
|
|
419
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
|
+
|
|
420
541
|
## 🌍 Framework Examples
|
|
421
542
|
|
|
422
543
|
### React
|
|
@@ -441,6 +562,42 @@ function App() {
|
|
|
441
562
|
|
|
442
563
|
return <div>Welcome, {user.email}!</div>
|
|
443
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
|
+
}
|
|
444
601
|
```
|
|
445
602
|
|
|
446
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
|