@blinkdotnew/sdk 0.18.7 → 0.19.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/dist/index.mjs CHANGED
@@ -5,6 +5,124 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
5
5
  throw Error('Dynamic require of "' + x + '" is not supported');
6
6
  });
7
7
 
8
+ // ../core/src/storage-adapter.ts
9
+ var WebStorageAdapter = class {
10
+ getItem(key) {
11
+ try {
12
+ if (typeof localStorage === "undefined") return null;
13
+ return localStorage.getItem(key);
14
+ } catch (error) {
15
+ console.warn("Failed to get item from localStorage:", error);
16
+ return null;
17
+ }
18
+ }
19
+ setItem(key, value) {
20
+ try {
21
+ if (typeof localStorage === "undefined") return;
22
+ localStorage.setItem(key, value);
23
+ } catch (error) {
24
+ console.warn("Failed to set item in localStorage:", error);
25
+ }
26
+ }
27
+ removeItem(key) {
28
+ try {
29
+ if (typeof localStorage === "undefined") return;
30
+ localStorage.removeItem(key);
31
+ } catch (error) {
32
+ console.warn("Failed to remove item from localStorage:", error);
33
+ }
34
+ }
35
+ clear() {
36
+ try {
37
+ if (typeof localStorage === "undefined") return;
38
+ localStorage.clear();
39
+ } catch (error) {
40
+ console.warn("Failed to clear localStorage:", error);
41
+ }
42
+ }
43
+ };
44
+ var AsyncStorageAdapter = class {
45
+ constructor(asyncStorage) {
46
+ this.asyncStorage = asyncStorage;
47
+ if (!asyncStorage) {
48
+ throw new Error("AsyncStorage instance is required");
49
+ }
50
+ }
51
+ async getItem(key) {
52
+ try {
53
+ return await this.asyncStorage.getItem(key);
54
+ } catch (error) {
55
+ console.warn("Failed to get item from AsyncStorage:", error);
56
+ return null;
57
+ }
58
+ }
59
+ async setItem(key, value) {
60
+ try {
61
+ await this.asyncStorage.setItem(key, value);
62
+ } catch (error) {
63
+ console.warn("Failed to set item in AsyncStorage:", error);
64
+ }
65
+ }
66
+ async removeItem(key) {
67
+ try {
68
+ await this.asyncStorage.removeItem(key);
69
+ } catch (error) {
70
+ console.warn("Failed to remove item from AsyncStorage:", error);
71
+ }
72
+ }
73
+ async clear() {
74
+ try {
75
+ await this.asyncStorage.clear();
76
+ } catch (error) {
77
+ console.warn("Failed to clear AsyncStorage:", error);
78
+ }
79
+ }
80
+ };
81
+ var NoOpStorageAdapter = class {
82
+ getItem(_key) {
83
+ return null;
84
+ }
85
+ setItem(_key, _value) {
86
+ }
87
+ removeItem(_key) {
88
+ }
89
+ clear() {
90
+ }
91
+ };
92
+ function getDefaultStorageAdapter() {
93
+ if (typeof window !== "undefined" && typeof localStorage !== "undefined") {
94
+ try {
95
+ localStorage.setItem("__test__", "test");
96
+ localStorage.removeItem("__test__");
97
+ return new WebStorageAdapter();
98
+ } catch {
99
+ }
100
+ }
101
+ return new NoOpStorageAdapter();
102
+ }
103
+
104
+ // ../core/src/platform.ts
105
+ function detectPlatform() {
106
+ if (typeof process !== "undefined" && process.versions?.node) {
107
+ if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
108
+ return "react-native";
109
+ }
110
+ return "node";
111
+ }
112
+ if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
113
+ return "react-native";
114
+ }
115
+ if (typeof window !== "undefined" && typeof document !== "undefined") {
116
+ return "web";
117
+ }
118
+ return "node";
119
+ }
120
+ var platform = detectPlatform();
121
+ var isWeb = platform === "web";
122
+ var isReactNative = platform === "react-native";
123
+ var isNode = platform === "node";
124
+ var isBrowser = isWeb || isReactNative;
125
+
8
126
  // ../core/src/types.ts
9
127
  var BlinkError = class extends Error {
10
128
  constructor(message, code, status, details) {
@@ -912,6 +1030,7 @@ var BlinkAuth = class {
912
1030
  isIframe = false;
913
1031
  initializationPromise = null;
914
1032
  isInitialized = false;
1033
+ storage;
915
1034
  constructor(config) {
916
1035
  this.config = config;
917
1036
  if (!config.projectId) {
@@ -938,7 +1057,8 @@ var BlinkAuth = class {
938
1057
  isAuthenticated: false,
939
1058
  isLoading: false
940
1059
  };
941
- if (typeof window !== "undefined") {
1060
+ this.storage = config.auth?.storage || config.storage || getDefaultStorageAdapter();
1061
+ if (isWeb) {
942
1062
  this.isIframe = window.self !== window.top;
943
1063
  this.setupParentWindowListener();
944
1064
  this.setupCrossTabSync();
@@ -975,7 +1095,7 @@ var BlinkAuth = class {
975
1095
  * Setup listener for tokens from parent window
976
1096
  */
977
1097
  setupParentWindowListener() {
978
- if (!this.isIframe) return;
1098
+ if (!isWeb || !this.isIframe) return;
979
1099
  window.addEventListener("message", (event) => {
980
1100
  if (event.origin !== "https://blink.new" && event.origin !== "http://localhost:3000" && event.origin !== "http://localhost:3001") {
981
1101
  return;
@@ -1030,7 +1150,7 @@ var BlinkAuth = class {
1030
1150
  console.log("\u2705 Auth initialization complete (from URL)");
1031
1151
  return;
1032
1152
  }
1033
- const storedTokens = this.getStoredTokens();
1153
+ const storedTokens = await this.getStoredTokens();
1034
1154
  if (storedTokens) {
1035
1155
  console.log("\u{1F4BE} Found stored tokens, validating...", {
1036
1156
  hasAccessToken: !!storedTokens.access_token,
@@ -2083,15 +2203,18 @@ var BlinkAuth = class {
2083
2203
  expiresIn: tokensWithTimestamp.expires_in,
2084
2204
  issuedAt: tokensWithTimestamp.issued_at
2085
2205
  });
2086
- if (persist && typeof window !== "undefined") {
2206
+ if (persist) {
2087
2207
  try {
2088
- localStorage.setItem(this.getStorageKey("tokens"), JSON.stringify(tokensWithTimestamp));
2089
- console.log("\u{1F4BE} Tokens persisted to localStorage");
2090
- } catch (error) {
2091
- console.log("\u{1F4A5} Error persisting tokens to localStorage:", error);
2092
- if (error instanceof DOMException && error.name === "SecurityError") {
2093
- console.log("\u{1F6AB} localStorage access blocked - running in cross-origin iframe");
2208
+ const result = this.storage.setItem(
2209
+ this.getStorageKey("tokens"),
2210
+ JSON.stringify(tokensWithTimestamp)
2211
+ );
2212
+ if (result instanceof Promise) {
2213
+ await result;
2094
2214
  }
2215
+ console.log("\u{1F4BE} Tokens persisted to storage");
2216
+ } catch (error) {
2217
+ console.log("\u{1F4A5} Error persisting tokens:", error);
2095
2218
  }
2096
2219
  }
2097
2220
  let user = null;
@@ -2134,12 +2257,15 @@ var BlinkAuth = class {
2134
2257
  });
2135
2258
  }
2136
2259
  clearTokens() {
2137
- if (typeof window !== "undefined") {
2138
- try {
2139
- localStorage.removeItem(this.getStorageKey("tokens"));
2140
- } catch (error) {
2141
- console.log("\u{1F4A5} Error clearing tokens from localStorage:", error);
2260
+ try {
2261
+ const result = this.storage.removeItem(this.getStorageKey("tokens"));
2262
+ if (result instanceof Promise) {
2263
+ result.catch((error) => {
2264
+ console.log("\u{1F4A5} Error clearing tokens from storage:", error);
2265
+ });
2142
2266
  }
2267
+ } catch (error) {
2268
+ console.log("\u{1F4A5} Error clearing tokens:", error);
2143
2269
  }
2144
2270
  this.updateAuthState({
2145
2271
  user: null,
@@ -2148,18 +2274,17 @@ var BlinkAuth = class {
2148
2274
  isLoading: false
2149
2275
  });
2150
2276
  }
2151
- getStoredTokens() {
2152
- if (typeof window === "undefined") return null;
2153
- if (this.isIframe && this.parentWindowTokens) {
2277
+ async getStoredTokens() {
2278
+ if (isWeb && this.isIframe && this.parentWindowTokens) {
2154
2279
  return this.parentWindowTokens;
2155
2280
  }
2156
2281
  try {
2157
- const stored = localStorage.getItem(this.getStorageKey("tokens"));
2158
- console.log("\u{1F50D} Checking localStorage for tokens:", {
2282
+ const result = this.storage.getItem(this.getStorageKey("tokens"));
2283
+ const stored = result instanceof Promise ? await result : result;
2284
+ console.log("\u{1F50D} Checking storage for tokens:", {
2159
2285
  hasStoredData: !!stored,
2160
2286
  storedLength: stored?.length || 0,
2161
- origin: window.location.origin,
2162
- isIframe: window.self !== window.top
2287
+ isIframe: isWeb && this.isIframe
2163
2288
  });
2164
2289
  if (stored) {
2165
2290
  const tokens = JSON.parse(stored);
@@ -2173,10 +2298,7 @@ var BlinkAuth = class {
2173
2298
  }
2174
2299
  return null;
2175
2300
  } catch (error) {
2176
- console.log("\u{1F4A5} Error accessing localStorage:", error);
2177
- if (error instanceof DOMException && error.name === "SecurityError") {
2178
- console.log("\u{1F6AB} localStorage access blocked - likely due to cross-origin iframe restrictions");
2179
- }
2301
+ console.log("\u{1F4A5} Error reading tokens from storage:", error);
2180
2302
  return null;
2181
2303
  }
2182
2304
  }
@@ -2322,7 +2444,7 @@ var BlinkAuth = class {
2322
2444
  * Setup cross-tab authentication synchronization
2323
2445
  */
2324
2446
  setupCrossTabSync() {
2325
- if (typeof window === "undefined") return;
2447
+ if (!isWeb) return;
2326
2448
  window.addEventListener("storage", (e) => {
2327
2449
  if (e.key === this.getStorageKey("tokens")) {
2328
2450
  const newTokens = e.newValue ? JSON.parse(e.newValue) : null;
@@ -3368,38 +3490,58 @@ var BlinkAIImpl = class {
3368
3490
  }
3369
3491
  }
3370
3492
  /**
3371
- * Generates images from text descriptions using Gemini 2.5 Flash Image.
3493
+ * Generates images from text descriptions using AI image models.
3372
3494
  *
3373
3495
  * @param options - Object containing:
3374
3496
  * - `prompt`: Text description of the desired image (required, up to 100k characters)
3497
+ * - `model`: AI model to use (optional). Available models:
3498
+ * **Fal.ai Models (Recommended):**
3499
+ * - `"fal-ai/nano-banana"` (default) - Gemini 2.5 Flash Image (Fast)
3500
+ * - `"fal-ai/nano-banana-pro"` - Gemini 3 Pro Image (High quality)
3501
+ * - `"fal-ai/gemini-25-flash-image"` - Alias for nano-banana
3502
+ * - `"fal-ai/gemini-3-pro-image-preview"` - Alias for nano-banana-pro
3503
+ * **Legacy Gemini Models:**
3504
+ * - `"gemini-2.5-flash-image-preview"` - Direct Gemini API
3505
+ * - `"gemini-3-pro-image-preview"` - Direct Gemini API
3375
3506
  * - `n`: Number of images to generate (default: 1)
3507
+ * - `size`: Image dimensions (e.g., "1024x1024", "512x512")
3376
3508
  * - Plus optional signal parameter
3377
3509
  *
3378
3510
  * @example
3379
3511
  * ```ts
3380
- * // Basic image generation
3512
+ * // Basic image generation (uses default fast model)
3381
3513
  * const { data } = await blink.ai.generateImage({
3382
3514
  * prompt: "A serene landscape with mountains and a lake at sunset"
3383
3515
  * });
3384
3516
  * console.log("Image URL:", data[0].url);
3385
3517
  *
3386
- * // Multiple images
3518
+ * // High quality generation with Pro model
3519
+ * const { data } = await blink.ai.generateImage({
3520
+ * prompt: "A detailed infographic about AI with charts and diagrams",
3521
+ * model: "fal-ai/nano-banana-pro",
3522
+ * n: 2
3523
+ * });
3524
+ *
3525
+ * // Fast generation with specific size
3387
3526
  * const { data } = await blink.ai.generateImage({
3388
3527
  * prompt: "A futuristic city skyline with flying cars",
3528
+ * model: "fal-ai/nano-banana",
3529
+ * size: "1024x1024",
3389
3530
  * n: 3
3390
3531
  * });
3391
3532
  * data.forEach((img, i) => console.log(`Image ${i+1}:`, img.url));
3392
3533
  *
3393
- * // Detailed prompt for better results
3534
+ * // Using legacy Gemini model
3394
3535
  * const { data } = await blink.ai.generateImage({
3395
- * prompt: "A cute robot mascot for a tech company, digital art style, vibrant colors, modern design, friendly expression"
3536
+ * prompt: "A cute robot mascot for a tech company",
3537
+ * model: "gemini-2.5-flash-image-preview"
3396
3538
  * });
3397
3539
  * ```
3398
3540
  *
3399
3541
  * @returns Promise<ImageGenerationResponse> - Object containing:
3400
3542
  * - `data`: Array of generated images with URLs
3401
3543
  * - `created`: Timestamp of generation
3402
- * - `model`: Always "gemini-2.5-flash-image-preview"
3544
+ * - `model`: The model used for generation
3403
3545
  */
3404
3546
  async generateImage(options) {
3405
3547
  try {
@@ -3409,7 +3551,9 @@ var BlinkAIImpl = class {
3409
3551
  const response = await this.httpClient.aiImage(
3410
3552
  options.prompt,
3411
3553
  {
3554
+ model: options.model,
3412
3555
  n: options.n,
3556
+ size: options.size,
3413
3557
  signal: options.signal
3414
3558
  }
3415
3559
  );
@@ -3446,16 +3590,38 @@ var BlinkAIImpl = class {
3446
3590
  }
3447
3591
  }
3448
3592
  /**
3449
- * Modifies existing images using Gemini 2.5 Flash Image with text prompts for image-to-image editing.
3593
+ * Modifies existing images using AI image editing models with text prompts for image-to-image editing.
3450
3594
  *
3451
3595
  * @param options - Object containing:
3452
3596
  * - `images`: Array of public image URLs to modify (required, up to 50 images)
3453
3597
  * - `prompt`: Text description of desired modifications (required, up to 100k characters)
3598
+ * - `model`: AI model to use (optional). Available editing models:
3599
+ * **Fal.ai Editing Models (Recommended):**
3600
+ * - `"fal-ai/nano-banana/edit"` (default) - Flash editing (Fast)
3601
+ * - `"fal-ai/nano-banana-pro/edit"` - Pro editing (High quality)
3602
+ * - `"fal-ai/gemini-25-flash-image/edit"` - Alias for nano-banana/edit
3603
+ * - `"fal-ai/gemini-3-pro-image-preview/edit"` - Alias for nano-banana-pro/edit
3604
+ * **Legacy Gemini Models:**
3605
+ * - `"gemini-2.5-flash-image-preview"` - Direct Gemini API
3606
+ * - `"gemini-3-pro-image-preview"` - Direct Gemini API
3454
3607
  * - `n`: Number of output images to generate (default: 1)
3455
3608
  * - Plus optional signal parameter
3456
3609
  *
3457
3610
  * @example
3458
3611
  * ```ts
3612
+ * // Fast editing with default model
3613
+ * const { data } = await blink.ai.modifyImage({
3614
+ * images: ["https://storage.example.com/photo.jpg"],
3615
+ * prompt: "make it green"
3616
+ * });
3617
+ *
3618
+ * // High quality editing with Pro model
3619
+ * const { data } = await blink.ai.modifyImage({
3620
+ * images: ["https://storage.example.com/landscape.jpg"],
3621
+ * prompt: "add a tree in the background",
3622
+ * model: "fal-ai/nano-banana-pro/edit"
3623
+ * });
3624
+ *
3459
3625
  * // Professional headshots from casual photos
3460
3626
  * const { data } = await blink.ai.modifyImage({
3461
3627
  * images: [
@@ -3463,6 +3629,7 @@ var BlinkAIImpl = class {
3463
3629
  * "https://storage.example.com/user-photo-2.jpg"
3464
3630
  * ],
3465
3631
  * prompt: "Transform into professional business headshots with studio lighting",
3632
+ * model: "fal-ai/nano-banana/edit",
3466
3633
  * n: 4
3467
3634
  * });
3468
3635
  * data.forEach((img, i) => console.log(`Headshot ${i+1}:`, img.url));
@@ -3470,7 +3637,8 @@ var BlinkAIImpl = class {
3470
3637
  * // Artistic style transformation
3471
3638
  * const { data } = await blink.ai.modifyImage({
3472
3639
  * images: ["https://storage.example.com/portrait.jpg"],
3473
- * prompt: "Transform into oil painting style with dramatic lighting"
3640
+ * prompt: "Transform into oil painting style with dramatic lighting",
3641
+ * model: "fal-ai/nano-banana-pro/edit"
3474
3642
  * });
3475
3643
  *
3476
3644
  * // Background replacement
@@ -3508,7 +3676,7 @@ var BlinkAIImpl = class {
3508
3676
  * @returns Promise<ImageGenerationResponse> - Object containing:
3509
3677
  * - `data`: Array of modified images with URLs
3510
3678
  * - `created`: Timestamp of generation
3511
- * - `model`: Always "gemini-2.5-flash-image-preview"
3679
+ * - `model`: The model used for editing
3512
3680
  */
3513
3681
  async modifyImage(options) {
3514
3682
  try {
@@ -3531,6 +3699,7 @@ var BlinkAIImpl = class {
3531
3699
  options.prompt,
3532
3700
  // Non-null assertion since we validated above
3533
3701
  {
3702
+ model: options.model,
3534
3703
  images: options.images,
3535
3704
  n: options.n,
3536
3705
  signal: options.signal
@@ -4487,7 +4656,8 @@ var BlinkAnalyticsImpl = class {
4487
4656
  constructor(httpClient, projectId) {
4488
4657
  this.httpClient = httpClient;
4489
4658
  this.projectId = projectId;
4490
- if (typeof window === "undefined") {
4659
+ if (!isWeb) {
4660
+ this.enabled = false;
4491
4661
  return;
4492
4662
  }
4493
4663
  if (navigator.doNotTrack === "1") {
@@ -4511,7 +4681,7 @@ var BlinkAnalyticsImpl = class {
4511
4681
  * Log a custom analytics event
4512
4682
  */
4513
4683
  log(eventName, data = {}) {
4514
- if (!this.enabled || typeof window === "undefined") {
4684
+ if (!this.enabled || !isWeb) {
4515
4685
  return;
4516
4686
  }
4517
4687
  const event = this.buildEvent(eventName, data);
@@ -4699,6 +4869,7 @@ var BlinkAnalyticsImpl = class {
4699
4869
  }
4700
4870
  }
4701
4871
  setupRouteChangeListener() {
4872
+ if (!isWeb) return;
4702
4873
  if (!window.__blinkAnalyticsSetup) {
4703
4874
  const originalPushState = history.pushState;
4704
4875
  const originalReplaceState = history.replaceState;
@@ -4732,6 +4903,7 @@ var BlinkAnalyticsImpl = class {
4732
4903
  window.__blinkAnalyticsInstances?.add(this);
4733
4904
  }
4734
4905
  setupUnloadListener() {
4906
+ if (!isWeb) return;
4735
4907
  window.addEventListener("pagehide", () => {
4736
4908
  this.flush();
4737
4909
  });
@@ -4740,6 +4912,7 @@ var BlinkAnalyticsImpl = class {
4740
4912
  });
4741
4913
  }
4742
4914
  captureUTMParams() {
4915
+ if (!isWeb) return;
4743
4916
  const urlParams = new URLSearchParams(window.location.search);
4744
4917
  this.utmParams = {
4745
4918
  utm_source: urlParams.get("utm_source"),
@@ -4851,6 +5024,6 @@ function createClient(config) {
4851
5024
  return new BlinkClientImpl(config);
4852
5025
  }
4853
5026
 
4854
- export { BlinkAIImpl, BlinkAnalyticsImpl, BlinkDataImpl, BlinkDatabase, BlinkRealtimeChannel, BlinkRealtimeImpl, BlinkStorageImpl, BlinkTable, createClient };
5027
+ export { AsyncStorageAdapter, BlinkAIImpl, BlinkAnalyticsImpl, BlinkDataImpl, BlinkDatabase, BlinkRealtimeChannel, BlinkRealtimeImpl, BlinkStorageImpl, BlinkTable, NoOpStorageAdapter, WebStorageAdapter, createClient, getDefaultStorageAdapter, isBrowser, isNode, isReactNative, isWeb, platform };
4855
5028
  //# sourceMappingURL=index.mjs.map
4856
5029
  //# sourceMappingURL=index.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blinkdotnew/sdk",
3
- "version": "0.18.7",
3
+ "version": "0.19.0",
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",