@blinkdotnew/sdk 2.0.3 → 2.1.1
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.d.mts +92 -4
- package/dist/index.d.ts +92 -4
- package/dist/index.js +135 -41
- package/dist/index.mjs +134 -42
- package/package.json +3 -2
package/dist/index.d.mts
CHANGED
|
@@ -61,6 +61,39 @@ interface BlinkClientConfig {
|
|
|
61
61
|
projectId: string;
|
|
62
62
|
authRequired?: boolean;
|
|
63
63
|
auth?: BlinkAuthConfig;
|
|
64
|
+
/**
|
|
65
|
+
* Publishable key (client-safe).
|
|
66
|
+
*
|
|
67
|
+
* Used for **public endpoints** when no user JWT is present (e.g. analytics ingest, storage upload,
|
|
68
|
+
* optional public DB reads). Never use for privileged operations.
|
|
69
|
+
*/
|
|
70
|
+
publishableKey?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Secret key (server-only, privileged). Permanent, never expires.
|
|
73
|
+
*
|
|
74
|
+
* Used in **server runtimes** (Edge Functions, Workers) for privileged operations that require
|
|
75
|
+
* service-role access (e.g. raw SQL, bypassing row-level security).
|
|
76
|
+
*
|
|
77
|
+
* Format: `blnk_sk_{projectId-last-8}_{random}` (similar to Stripe's `sk_live_...`)
|
|
78
|
+
*
|
|
79
|
+
* **Security**: Never expose this key in client-side code. It is injected by the platform
|
|
80
|
+
* into edge function environments as `BLINK_SECRET_KEY`.
|
|
81
|
+
*
|
|
82
|
+
* When present, this key takes precedence over user JWTs for all requests.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* // Edge function (Deno)
|
|
86
|
+
* const blink = createClient({
|
|
87
|
+
* projectId: Deno.env.get('BLINK_PROJECT_ID')!,
|
|
88
|
+
* secretKey: Deno.env.get('BLINK_SECRET_KEY'),
|
|
89
|
+
* })
|
|
90
|
+
*/
|
|
91
|
+
secretKey?: string;
|
|
92
|
+
/**
|
|
93
|
+
* @deprecated Use `secretKey` instead. Service tokens are JWT-based and expire after 365 days.
|
|
94
|
+
* Secret keys are permanent and never expire.
|
|
95
|
+
*/
|
|
96
|
+
serviceToken?: string;
|
|
64
97
|
/**
|
|
65
98
|
* Storage adapter for cross-platform token persistence
|
|
66
99
|
*
|
|
@@ -281,6 +314,9 @@ declare class BlinkError extends Error {
|
|
|
281
314
|
constructor(message: string, code?: string | undefined, status?: number | undefined, details?: any);
|
|
282
315
|
}
|
|
283
316
|
interface StorageUploadOptions {
|
|
317
|
+
/**
|
|
318
|
+
* @deprecated Blink storage uploads are add-only by default. This option is ignored.
|
|
319
|
+
*/
|
|
284
320
|
upsert?: boolean;
|
|
285
321
|
onProgress?: (percent: number) => void;
|
|
286
322
|
}
|
|
@@ -737,7 +773,7 @@ interface BlinkNotifications {
|
|
|
737
773
|
*/
|
|
738
774
|
|
|
739
775
|
interface RequestOptions {
|
|
740
|
-
method?: 'GET' | 'POST' | 'PATCH' | 'DELETE';
|
|
776
|
+
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
741
777
|
headers?: Record<string, string>;
|
|
742
778
|
body?: any;
|
|
743
779
|
searchParams?: Record<string, string>;
|
|
@@ -752,9 +788,14 @@ declare class HttpClient {
|
|
|
752
788
|
private readonly authUrl;
|
|
753
789
|
private readonly coreUrl;
|
|
754
790
|
readonly projectId: string;
|
|
791
|
+
private readonly publishableKey?;
|
|
792
|
+
private readonly secretKey?;
|
|
755
793
|
private getToken;
|
|
756
794
|
private getValidToken?;
|
|
757
795
|
constructor(config: BlinkClientConfig, getToken: () => string | null, getValidToken?: () => Promise<string | null>);
|
|
796
|
+
private shouldAttachPublishableKey;
|
|
797
|
+
private shouldSkipSecretKey;
|
|
798
|
+
private getAuthorizationHeader;
|
|
758
799
|
/**
|
|
759
800
|
* Make an authenticated request to the Blink API
|
|
760
801
|
*/
|
|
@@ -949,9 +990,9 @@ declare class HttpClient {
|
|
|
949
990
|
|
|
950
991
|
/**
|
|
951
992
|
* Platform detection for cross-platform compatibility
|
|
952
|
-
* Detects whether code is running on web, React Native,
|
|
993
|
+
* Detects whether code is running on web, React Native, Node.js, or Deno
|
|
953
994
|
*/
|
|
954
|
-
type Platform = 'web' | 'react-native' | 'node';
|
|
995
|
+
type Platform = 'web' | 'react-native' | 'node' | 'deno';
|
|
955
996
|
/**
|
|
956
997
|
* Current platform
|
|
957
998
|
*/
|
|
@@ -962,7 +1003,9 @@ declare const platform: Platform;
|
|
|
962
1003
|
declare const isWeb: boolean;
|
|
963
1004
|
declare const isReactNative: boolean;
|
|
964
1005
|
declare const isNode: boolean;
|
|
1006
|
+
declare const isDeno: boolean;
|
|
965
1007
|
declare const isBrowser: boolean;
|
|
1008
|
+
declare const isServer: boolean;
|
|
966
1009
|
|
|
967
1010
|
/**
|
|
968
1011
|
* Blink Auth Module - Client-side authentication management
|
|
@@ -1633,6 +1676,50 @@ declare class BlinkAnalyticsImpl implements BlinkAnalytics {
|
|
|
1633
1676
|
private detectChannel;
|
|
1634
1677
|
}
|
|
1635
1678
|
|
|
1679
|
+
/**
|
|
1680
|
+
* Blink Functions - Edge function invocation helper
|
|
1681
|
+
* Provides a simple interface for calling Blink Edge Functions with automatic JWT attachment
|
|
1682
|
+
*/
|
|
1683
|
+
|
|
1684
|
+
interface FunctionsInvokeOptions {
|
|
1685
|
+
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
1686
|
+
body?: any;
|
|
1687
|
+
headers?: Record<string, string>;
|
|
1688
|
+
searchParams?: Record<string, string>;
|
|
1689
|
+
}
|
|
1690
|
+
interface FunctionsInvokeResponse<T = any> {
|
|
1691
|
+
data: T;
|
|
1692
|
+
status: number;
|
|
1693
|
+
headers: Headers;
|
|
1694
|
+
}
|
|
1695
|
+
interface BlinkFunctions {
|
|
1696
|
+
/**
|
|
1697
|
+
* Invoke a Blink Edge Function.
|
|
1698
|
+
*
|
|
1699
|
+
* Automatically attaches the user's JWT for authenticated requests.
|
|
1700
|
+
* The function URL is constructed as: https://{projectSuffix}--{functionSlug}.functions.blink.new
|
|
1701
|
+
*
|
|
1702
|
+
* @param functionSlug - The slug of the edge function to invoke
|
|
1703
|
+
* @param options - Request options (method, body, headers, etc.)
|
|
1704
|
+
* @returns The function response
|
|
1705
|
+
*
|
|
1706
|
+
* @example
|
|
1707
|
+
* // Simple POST request
|
|
1708
|
+
* const { data } = await blink.functions.invoke('my-function', {
|
|
1709
|
+
* method: 'POST',
|
|
1710
|
+
* body: { message: 'Hello' }
|
|
1711
|
+
* })
|
|
1712
|
+
*
|
|
1713
|
+
* @example
|
|
1714
|
+
* // GET request with query params
|
|
1715
|
+
* const { data } = await blink.functions.invoke('my-function', {
|
|
1716
|
+
* method: 'GET',
|
|
1717
|
+
* searchParams: { limit: '10' }
|
|
1718
|
+
* })
|
|
1719
|
+
*/
|
|
1720
|
+
invoke<T = any>(functionSlug: string, options?: FunctionsInvokeOptions): Promise<FunctionsInvokeResponse<T>>;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1636
1723
|
/**
|
|
1637
1724
|
* Blink Client - Main SDK entry point
|
|
1638
1725
|
* Factory function and client class for the Blink SDK
|
|
@@ -1647,6 +1734,7 @@ interface BlinkClient {
|
|
|
1647
1734
|
realtime: BlinkRealtime;
|
|
1648
1735
|
notifications: BlinkNotifications;
|
|
1649
1736
|
analytics: BlinkAnalytics;
|
|
1737
|
+
functions: BlinkFunctions;
|
|
1650
1738
|
}
|
|
1651
1739
|
/**
|
|
1652
1740
|
* Create a new Blink client instance
|
|
@@ -2296,4 +2384,4 @@ declare class BlinkRealtimeImpl implements BlinkRealtime {
|
|
|
2296
2384
|
onPresence(channelName: string, callback: (users: PresenceUser[]) => void): () => void;
|
|
2297
2385
|
}
|
|
2298
2386
|
|
|
2299
|
-
export { type AnalyticsEvent, AsyncStorageAdapter, type AuthState, type AuthStateChangeCallback, type AuthTokens, type BlinkAI, BlinkAIImpl, type BlinkAnalytics, BlinkAnalyticsImpl, type BlinkClient, type BlinkClientConfig, type BlinkData, BlinkDataImpl, BlinkDatabase, type BlinkRealtime, BlinkRealtimeChannel, BlinkRealtimeError, BlinkRealtimeImpl, type BlinkStorage, BlinkStorageImpl, BlinkTable, type BlinkUser, type CreateOptions, type DataExtraction, type FileObject, type FilterCondition, type ImageGenerationRequest, type ImageGenerationResponse, type Message, NoOpStorageAdapter, type ObjectGenerationRequest, type ObjectGenerationResponse, type PresenceUser, type QueryOptions, type RealtimeChannel, type RealtimeGetMessagesOptions, type RealtimeMessage, type RealtimePublishOptions, type RealtimeSubscribeOptions, type SearchRequest, type SearchResponse, type SpeechGenerationRequest, type SpeechGenerationResponse, type StorageAdapter, type StorageUploadOptions, type StorageUploadResponse, type TableOperations, type TextGenerationRequest, type TextGenerationResponse, type TokenUsage, type TranscriptionRequest, type TranscriptionResponse, type UpdateOptions, type UpsertOptions, type WebBrowserModule, WebStorageAdapter, createClient, getDefaultStorageAdapter, isBrowser, isNode, isReactNative, isWeb, platform };
|
|
2387
|
+
export { type AnalyticsEvent, AsyncStorageAdapter, type AuthState, type AuthStateChangeCallback, type AuthTokens, type BlinkAI, BlinkAIImpl, type BlinkAnalytics, BlinkAnalyticsImpl, type BlinkClient, type BlinkClientConfig, type BlinkData, BlinkDataImpl, BlinkDatabase, type BlinkRealtime, BlinkRealtimeChannel, BlinkRealtimeError, BlinkRealtimeImpl, type BlinkStorage, BlinkStorageImpl, BlinkTable, type BlinkUser, type CreateOptions, type DataExtraction, type FileObject, type FilterCondition, type ImageGenerationRequest, type ImageGenerationResponse, type Message, NoOpStorageAdapter, type ObjectGenerationRequest, type ObjectGenerationResponse, type PresenceUser, type QueryOptions, type RealtimeChannel, type RealtimeGetMessagesOptions, type RealtimeMessage, type RealtimePublishOptions, type RealtimeSubscribeOptions, type SearchRequest, type SearchResponse, type SpeechGenerationRequest, type SpeechGenerationResponse, type StorageAdapter, type StorageUploadOptions, type StorageUploadResponse, type TableOperations, type TextGenerationRequest, type TextGenerationResponse, type TokenUsage, type TranscriptionRequest, type TranscriptionResponse, type UpdateOptions, type UpsertOptions, type WebBrowserModule, WebStorageAdapter, createClient, getDefaultStorageAdapter, isBrowser, isDeno, isNode, isReactNative, isServer, isWeb, platform };
|
package/dist/index.d.ts
CHANGED
|
@@ -61,6 +61,39 @@ interface BlinkClientConfig {
|
|
|
61
61
|
projectId: string;
|
|
62
62
|
authRequired?: boolean;
|
|
63
63
|
auth?: BlinkAuthConfig;
|
|
64
|
+
/**
|
|
65
|
+
* Publishable key (client-safe).
|
|
66
|
+
*
|
|
67
|
+
* Used for **public endpoints** when no user JWT is present (e.g. analytics ingest, storage upload,
|
|
68
|
+
* optional public DB reads). Never use for privileged operations.
|
|
69
|
+
*/
|
|
70
|
+
publishableKey?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Secret key (server-only, privileged). Permanent, never expires.
|
|
73
|
+
*
|
|
74
|
+
* Used in **server runtimes** (Edge Functions, Workers) for privileged operations that require
|
|
75
|
+
* service-role access (e.g. raw SQL, bypassing row-level security).
|
|
76
|
+
*
|
|
77
|
+
* Format: `blnk_sk_{projectId-last-8}_{random}` (similar to Stripe's `sk_live_...`)
|
|
78
|
+
*
|
|
79
|
+
* **Security**: Never expose this key in client-side code. It is injected by the platform
|
|
80
|
+
* into edge function environments as `BLINK_SECRET_KEY`.
|
|
81
|
+
*
|
|
82
|
+
* When present, this key takes precedence over user JWTs for all requests.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* // Edge function (Deno)
|
|
86
|
+
* const blink = createClient({
|
|
87
|
+
* projectId: Deno.env.get('BLINK_PROJECT_ID')!,
|
|
88
|
+
* secretKey: Deno.env.get('BLINK_SECRET_KEY'),
|
|
89
|
+
* })
|
|
90
|
+
*/
|
|
91
|
+
secretKey?: string;
|
|
92
|
+
/**
|
|
93
|
+
* @deprecated Use `secretKey` instead. Service tokens are JWT-based and expire after 365 days.
|
|
94
|
+
* Secret keys are permanent and never expire.
|
|
95
|
+
*/
|
|
96
|
+
serviceToken?: string;
|
|
64
97
|
/**
|
|
65
98
|
* Storage adapter for cross-platform token persistence
|
|
66
99
|
*
|
|
@@ -281,6 +314,9 @@ declare class BlinkError extends Error {
|
|
|
281
314
|
constructor(message: string, code?: string | undefined, status?: number | undefined, details?: any);
|
|
282
315
|
}
|
|
283
316
|
interface StorageUploadOptions {
|
|
317
|
+
/**
|
|
318
|
+
* @deprecated Blink storage uploads are add-only by default. This option is ignored.
|
|
319
|
+
*/
|
|
284
320
|
upsert?: boolean;
|
|
285
321
|
onProgress?: (percent: number) => void;
|
|
286
322
|
}
|
|
@@ -737,7 +773,7 @@ interface BlinkNotifications {
|
|
|
737
773
|
*/
|
|
738
774
|
|
|
739
775
|
interface RequestOptions {
|
|
740
|
-
method?: 'GET' | 'POST' | 'PATCH' | 'DELETE';
|
|
776
|
+
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
741
777
|
headers?: Record<string, string>;
|
|
742
778
|
body?: any;
|
|
743
779
|
searchParams?: Record<string, string>;
|
|
@@ -752,9 +788,14 @@ declare class HttpClient {
|
|
|
752
788
|
private readonly authUrl;
|
|
753
789
|
private readonly coreUrl;
|
|
754
790
|
readonly projectId: string;
|
|
791
|
+
private readonly publishableKey?;
|
|
792
|
+
private readonly secretKey?;
|
|
755
793
|
private getToken;
|
|
756
794
|
private getValidToken?;
|
|
757
795
|
constructor(config: BlinkClientConfig, getToken: () => string | null, getValidToken?: () => Promise<string | null>);
|
|
796
|
+
private shouldAttachPublishableKey;
|
|
797
|
+
private shouldSkipSecretKey;
|
|
798
|
+
private getAuthorizationHeader;
|
|
758
799
|
/**
|
|
759
800
|
* Make an authenticated request to the Blink API
|
|
760
801
|
*/
|
|
@@ -949,9 +990,9 @@ declare class HttpClient {
|
|
|
949
990
|
|
|
950
991
|
/**
|
|
951
992
|
* Platform detection for cross-platform compatibility
|
|
952
|
-
* Detects whether code is running on web, React Native,
|
|
993
|
+
* Detects whether code is running on web, React Native, Node.js, or Deno
|
|
953
994
|
*/
|
|
954
|
-
type Platform = 'web' | 'react-native' | 'node';
|
|
995
|
+
type Platform = 'web' | 'react-native' | 'node' | 'deno';
|
|
955
996
|
/**
|
|
956
997
|
* Current platform
|
|
957
998
|
*/
|
|
@@ -962,7 +1003,9 @@ declare const platform: Platform;
|
|
|
962
1003
|
declare const isWeb: boolean;
|
|
963
1004
|
declare const isReactNative: boolean;
|
|
964
1005
|
declare const isNode: boolean;
|
|
1006
|
+
declare const isDeno: boolean;
|
|
965
1007
|
declare const isBrowser: boolean;
|
|
1008
|
+
declare const isServer: boolean;
|
|
966
1009
|
|
|
967
1010
|
/**
|
|
968
1011
|
* Blink Auth Module - Client-side authentication management
|
|
@@ -1633,6 +1676,50 @@ declare class BlinkAnalyticsImpl implements BlinkAnalytics {
|
|
|
1633
1676
|
private detectChannel;
|
|
1634
1677
|
}
|
|
1635
1678
|
|
|
1679
|
+
/**
|
|
1680
|
+
* Blink Functions - Edge function invocation helper
|
|
1681
|
+
* Provides a simple interface for calling Blink Edge Functions with automatic JWT attachment
|
|
1682
|
+
*/
|
|
1683
|
+
|
|
1684
|
+
interface FunctionsInvokeOptions {
|
|
1685
|
+
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
1686
|
+
body?: any;
|
|
1687
|
+
headers?: Record<string, string>;
|
|
1688
|
+
searchParams?: Record<string, string>;
|
|
1689
|
+
}
|
|
1690
|
+
interface FunctionsInvokeResponse<T = any> {
|
|
1691
|
+
data: T;
|
|
1692
|
+
status: number;
|
|
1693
|
+
headers: Headers;
|
|
1694
|
+
}
|
|
1695
|
+
interface BlinkFunctions {
|
|
1696
|
+
/**
|
|
1697
|
+
* Invoke a Blink Edge Function.
|
|
1698
|
+
*
|
|
1699
|
+
* Automatically attaches the user's JWT for authenticated requests.
|
|
1700
|
+
* The function URL is constructed as: https://{projectSuffix}--{functionSlug}.functions.blink.new
|
|
1701
|
+
*
|
|
1702
|
+
* @param functionSlug - The slug of the edge function to invoke
|
|
1703
|
+
* @param options - Request options (method, body, headers, etc.)
|
|
1704
|
+
* @returns The function response
|
|
1705
|
+
*
|
|
1706
|
+
* @example
|
|
1707
|
+
* // Simple POST request
|
|
1708
|
+
* const { data } = await blink.functions.invoke('my-function', {
|
|
1709
|
+
* method: 'POST',
|
|
1710
|
+
* body: { message: 'Hello' }
|
|
1711
|
+
* })
|
|
1712
|
+
*
|
|
1713
|
+
* @example
|
|
1714
|
+
* // GET request with query params
|
|
1715
|
+
* const { data } = await blink.functions.invoke('my-function', {
|
|
1716
|
+
* method: 'GET',
|
|
1717
|
+
* searchParams: { limit: '10' }
|
|
1718
|
+
* })
|
|
1719
|
+
*/
|
|
1720
|
+
invoke<T = any>(functionSlug: string, options?: FunctionsInvokeOptions): Promise<FunctionsInvokeResponse<T>>;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1636
1723
|
/**
|
|
1637
1724
|
* Blink Client - Main SDK entry point
|
|
1638
1725
|
* Factory function and client class for the Blink SDK
|
|
@@ -1647,6 +1734,7 @@ interface BlinkClient {
|
|
|
1647
1734
|
realtime: BlinkRealtime;
|
|
1648
1735
|
notifications: BlinkNotifications;
|
|
1649
1736
|
analytics: BlinkAnalytics;
|
|
1737
|
+
functions: BlinkFunctions;
|
|
1650
1738
|
}
|
|
1651
1739
|
/**
|
|
1652
1740
|
* Create a new Blink client instance
|
|
@@ -2296,4 +2384,4 @@ declare class BlinkRealtimeImpl implements BlinkRealtime {
|
|
|
2296
2384
|
onPresence(channelName: string, callback: (users: PresenceUser[]) => void): () => void;
|
|
2297
2385
|
}
|
|
2298
2386
|
|
|
2299
|
-
export { type AnalyticsEvent, AsyncStorageAdapter, type AuthState, type AuthStateChangeCallback, type AuthTokens, type BlinkAI, BlinkAIImpl, type BlinkAnalytics, BlinkAnalyticsImpl, type BlinkClient, type BlinkClientConfig, type BlinkData, BlinkDataImpl, BlinkDatabase, type BlinkRealtime, BlinkRealtimeChannel, BlinkRealtimeError, BlinkRealtimeImpl, type BlinkStorage, BlinkStorageImpl, BlinkTable, type BlinkUser, type CreateOptions, type DataExtraction, type FileObject, type FilterCondition, type ImageGenerationRequest, type ImageGenerationResponse, type Message, NoOpStorageAdapter, type ObjectGenerationRequest, type ObjectGenerationResponse, type PresenceUser, type QueryOptions, type RealtimeChannel, type RealtimeGetMessagesOptions, type RealtimeMessage, type RealtimePublishOptions, type RealtimeSubscribeOptions, type SearchRequest, type SearchResponse, type SpeechGenerationRequest, type SpeechGenerationResponse, type StorageAdapter, type StorageUploadOptions, type StorageUploadResponse, type TableOperations, type TextGenerationRequest, type TextGenerationResponse, type TokenUsage, type TranscriptionRequest, type TranscriptionResponse, type UpdateOptions, type UpsertOptions, type WebBrowserModule, WebStorageAdapter, createClient, getDefaultStorageAdapter, isBrowser, isNode, isReactNative, isWeb, platform };
|
|
2387
|
+
export { type AnalyticsEvent, AsyncStorageAdapter, type AuthState, type AuthStateChangeCallback, type AuthTokens, type BlinkAI, BlinkAIImpl, type BlinkAnalytics, BlinkAnalyticsImpl, type BlinkClient, type BlinkClientConfig, type BlinkData, BlinkDataImpl, BlinkDatabase, type BlinkRealtime, BlinkRealtimeChannel, BlinkRealtimeError, BlinkRealtimeImpl, type BlinkStorage, BlinkStorageImpl, BlinkTable, type BlinkUser, type CreateOptions, type DataExtraction, type FileObject, type FilterCondition, type ImageGenerationRequest, type ImageGenerationResponse, type Message, NoOpStorageAdapter, type ObjectGenerationRequest, type ObjectGenerationResponse, type PresenceUser, type QueryOptions, type RealtimeChannel, type RealtimeGetMessagesOptions, type RealtimeMessage, type RealtimePublishOptions, type RealtimeSubscribeOptions, type SearchRequest, type SearchResponse, type SpeechGenerationRequest, type SpeechGenerationResponse, type StorageAdapter, type StorageUploadOptions, type StorageUploadResponse, type TableOperations, type TextGenerationRequest, type TextGenerationResponse, type TokenUsage, type TranscriptionRequest, type TranscriptionResponse, type UpdateOptions, type UpsertOptions, type WebBrowserModule, WebStorageAdapter, createClient, getDefaultStorageAdapter, isBrowser, isDeno, isNode, isReactNative, isServer, isWeb, platform };
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,33 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
7
7
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
8
|
});
|
|
9
9
|
|
|
10
|
+
// ../core/src/platform.ts
|
|
11
|
+
function detectPlatform() {
|
|
12
|
+
if (typeof Deno !== "undefined") {
|
|
13
|
+
return "deno";
|
|
14
|
+
}
|
|
15
|
+
if (typeof process !== "undefined" && process.versions?.node) {
|
|
16
|
+
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
17
|
+
return "react-native";
|
|
18
|
+
}
|
|
19
|
+
return "node";
|
|
20
|
+
}
|
|
21
|
+
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
22
|
+
return "react-native";
|
|
23
|
+
}
|
|
24
|
+
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
25
|
+
return "web";
|
|
26
|
+
}
|
|
27
|
+
return "node";
|
|
28
|
+
}
|
|
29
|
+
var platform = detectPlatform();
|
|
30
|
+
var isWeb = platform === "web";
|
|
31
|
+
var isReactNative = platform === "react-native";
|
|
32
|
+
var isNode = platform === "node";
|
|
33
|
+
var isDeno = platform === "deno";
|
|
34
|
+
var isBrowser = isWeb || isReactNative;
|
|
35
|
+
var isServer = isNode || isDeno;
|
|
36
|
+
|
|
10
37
|
// ../core/src/storage-adapter.ts
|
|
11
38
|
var WebStorageAdapter = class {
|
|
12
39
|
getItem(key) {
|
|
@@ -92,6 +119,9 @@ var NoOpStorageAdapter = class {
|
|
|
92
119
|
}
|
|
93
120
|
};
|
|
94
121
|
function getDefaultStorageAdapter() {
|
|
122
|
+
if (isDeno) {
|
|
123
|
+
return new NoOpStorageAdapter();
|
|
124
|
+
}
|
|
95
125
|
if (typeof window !== "undefined" && typeof localStorage !== "undefined") {
|
|
96
126
|
try {
|
|
97
127
|
localStorage.setItem("__test__", "test");
|
|
@@ -103,28 +133,6 @@ function getDefaultStorageAdapter() {
|
|
|
103
133
|
return new NoOpStorageAdapter();
|
|
104
134
|
}
|
|
105
135
|
|
|
106
|
-
// ../core/src/platform.ts
|
|
107
|
-
function detectPlatform() {
|
|
108
|
-
if (typeof process !== "undefined" && process.versions?.node) {
|
|
109
|
-
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
110
|
-
return "react-native";
|
|
111
|
-
}
|
|
112
|
-
return "node";
|
|
113
|
-
}
|
|
114
|
-
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
115
|
-
return "react-native";
|
|
116
|
-
}
|
|
117
|
-
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
118
|
-
return "web";
|
|
119
|
-
}
|
|
120
|
-
return "node";
|
|
121
|
-
}
|
|
122
|
-
var platform = detectPlatform();
|
|
123
|
-
var isWeb = platform === "web";
|
|
124
|
-
var isReactNative = platform === "react-native";
|
|
125
|
-
var isNode = platform === "node";
|
|
126
|
-
var isBrowser = isWeb || isReactNative;
|
|
127
|
-
|
|
128
136
|
// ../core/src/types.ts
|
|
129
137
|
var BlinkError = class extends Error {
|
|
130
138
|
constructor(message, code, status, details) {
|
|
@@ -391,32 +399,65 @@ var HttpClient = class {
|
|
|
391
399
|
authUrl = "https://blink.new";
|
|
392
400
|
coreUrl = "https://core.blink.new";
|
|
393
401
|
projectId;
|
|
402
|
+
publishableKey;
|
|
403
|
+
secretKey;
|
|
404
|
+
// Permanent, non-expiring key (like Stripe's sk_live_...)
|
|
394
405
|
getToken;
|
|
395
406
|
getValidToken;
|
|
396
407
|
constructor(config, getToken, getValidToken) {
|
|
397
408
|
this.projectId = config.projectId;
|
|
409
|
+
this.publishableKey = config.publishableKey;
|
|
410
|
+
this.secretKey = config.secretKey || config.serviceToken;
|
|
398
411
|
this.getToken = getToken;
|
|
399
412
|
this.getValidToken = getValidToken;
|
|
400
413
|
}
|
|
414
|
+
shouldAttachPublishableKey(path, method) {
|
|
415
|
+
if (method !== "GET" && method !== "POST") return false;
|
|
416
|
+
if (path.includes("/api/analytics/")) return true;
|
|
417
|
+
if (path.includes("/api/storage/")) return true;
|
|
418
|
+
if (path.includes("/api/db/") && path.includes("/rest/v1/")) return method === "GET";
|
|
419
|
+
return false;
|
|
420
|
+
}
|
|
421
|
+
shouldSkipSecretKey(url) {
|
|
422
|
+
try {
|
|
423
|
+
const parsed = new URL(url);
|
|
424
|
+
return parsed.hostname.endsWith(".functions.blink.new");
|
|
425
|
+
} catch {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
getAuthorizationHeader(url, token) {
|
|
430
|
+
if (this.secretKey && !this.shouldSkipSecretKey(url)) {
|
|
431
|
+
return `Bearer ${this.secretKey}`;
|
|
432
|
+
}
|
|
433
|
+
if (token) {
|
|
434
|
+
return `Bearer ${token}`;
|
|
435
|
+
}
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
401
438
|
/**
|
|
402
439
|
* Make an authenticated request to the Blink API
|
|
403
440
|
*/
|
|
404
441
|
async request(path, options = {}) {
|
|
405
442
|
const url = this.buildUrl(path, options.searchParams);
|
|
406
443
|
const token = this.getValidToken ? await this.getValidToken() : this.getToken();
|
|
444
|
+
const method = options.method || "GET";
|
|
407
445
|
const headers = {
|
|
408
446
|
"Content-Type": "application/json",
|
|
409
447
|
...options.headers
|
|
410
448
|
};
|
|
411
|
-
|
|
412
|
-
|
|
449
|
+
const auth = this.getAuthorizationHeader(url, token);
|
|
450
|
+
if (auth) {
|
|
451
|
+
headers.Authorization = auth;
|
|
452
|
+
} else if (this.publishableKey && !headers["x-blink-publishable-key"] && this.shouldAttachPublishableKey(path, method)) {
|
|
453
|
+
headers["x-blink-publishable-key"] = this.publishableKey;
|
|
413
454
|
}
|
|
414
455
|
const requestInit = {
|
|
415
|
-
method
|
|
456
|
+
method,
|
|
416
457
|
headers,
|
|
417
458
|
signal: options.signal
|
|
418
459
|
};
|
|
419
|
-
if (options.body &&
|
|
460
|
+
if (options.body && method !== "GET") {
|
|
420
461
|
requestInit.body = typeof options.body === "string" ? options.body : JSON.stringify(options.body);
|
|
421
462
|
}
|
|
422
463
|
try {
|
|
@@ -570,12 +611,12 @@ var HttpClient = class {
|
|
|
570
611
|
throw new BlinkValidationError("Unsupported file type");
|
|
571
612
|
}
|
|
572
613
|
formData.append("path", filePath);
|
|
573
|
-
if (options.upsert !== void 0) {
|
|
574
|
-
formData.append("options", JSON.stringify({ upsert: options.upsert }));
|
|
575
|
-
}
|
|
576
614
|
const headers = {};
|
|
577
|
-
|
|
578
|
-
|
|
615
|
+
const auth = this.getAuthorizationHeader(url, token);
|
|
616
|
+
if (auth) {
|
|
617
|
+
headers.Authorization = auth;
|
|
618
|
+
} else if (this.publishableKey && path.includes("/api/storage/") && !headers["x-blink-publishable-key"]) {
|
|
619
|
+
headers["x-blink-publishable-key"] = this.publishableKey;
|
|
579
620
|
}
|
|
580
621
|
try {
|
|
581
622
|
if (typeof XMLHttpRequest !== "undefined" && options.onProgress) {
|
|
@@ -684,9 +725,8 @@ var HttpClient = class {
|
|
|
684
725
|
const headers = {
|
|
685
726
|
"Content-Type": "application/json"
|
|
686
727
|
};
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
}
|
|
728
|
+
const auth = this.getAuthorizationHeader(url, token);
|
|
729
|
+
if (auth) headers.Authorization = auth;
|
|
690
730
|
const body = {
|
|
691
731
|
prompt,
|
|
692
732
|
stream: true,
|
|
@@ -739,9 +779,8 @@ var HttpClient = class {
|
|
|
739
779
|
const headers = {
|
|
740
780
|
"Content-Type": "application/json"
|
|
741
781
|
};
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
}
|
|
782
|
+
const auth = this.getAuthorizationHeader(url, token);
|
|
783
|
+
if (auth) headers.Authorization = auth;
|
|
745
784
|
const body = {
|
|
746
785
|
prompt,
|
|
747
786
|
stream: true,
|
|
@@ -2966,6 +3005,11 @@ var BlinkAuth = class {
|
|
|
2966
3005
|
};
|
|
2967
3006
|
|
|
2968
3007
|
// src/database.ts
|
|
3008
|
+
function assertServerOnly(methodName) {
|
|
3009
|
+
if (typeof window !== "undefined") {
|
|
3010
|
+
throw new Error(`${methodName} is server-only. Use Blink CRUD methods (blink.db.<table>.*) instead.`);
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
2969
3013
|
function camelToSnake3(str) {
|
|
2970
3014
|
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
2971
3015
|
}
|
|
@@ -3184,6 +3228,7 @@ var BlinkTable = class {
|
|
|
3184
3228
|
* Raw SQL query on this table (for advanced use cases)
|
|
3185
3229
|
*/
|
|
3186
3230
|
async sql(query, params) {
|
|
3231
|
+
assertServerOnly("blink.db.<table>.sql");
|
|
3187
3232
|
const response = await this.httpClient.dbSql(query, params);
|
|
3188
3233
|
return response.data;
|
|
3189
3234
|
}
|
|
@@ -3232,6 +3277,7 @@ var BlinkDatabase = class {
|
|
|
3232
3277
|
* Execute raw SQL query
|
|
3233
3278
|
*/
|
|
3234
3279
|
async sql(query, params) {
|
|
3280
|
+
assertServerOnly("blink.db.sql");
|
|
3235
3281
|
const response = await this.httpClient.dbSql(query, params);
|
|
3236
3282
|
return response.data;
|
|
3237
3283
|
}
|
|
@@ -3239,6 +3285,7 @@ var BlinkDatabase = class {
|
|
|
3239
3285
|
* Execute batch SQL operations
|
|
3240
3286
|
*/
|
|
3241
3287
|
async batch(statements, mode = "write") {
|
|
3288
|
+
assertServerOnly("blink.db.batch");
|
|
3242
3289
|
const response = await this.httpClient.dbBatch(statements, mode);
|
|
3243
3290
|
return response.data;
|
|
3244
3291
|
}
|
|
@@ -3301,7 +3348,6 @@ var BlinkStorageImpl = class {
|
|
|
3301
3348
|
correctedPath,
|
|
3302
3349
|
// Use corrected path with proper extension
|
|
3303
3350
|
{
|
|
3304
|
-
upsert: options.upsert,
|
|
3305
3351
|
onProgress: options.onProgress,
|
|
3306
3352
|
contentType: detectedContentType
|
|
3307
3353
|
// Pass detected content type
|
|
@@ -3321,7 +3367,7 @@ var BlinkStorageImpl = class {
|
|
|
3321
3367
|
if (error instanceof Error && "status" in error) {
|
|
3322
3368
|
const status = error.status;
|
|
3323
3369
|
if (status === 409) {
|
|
3324
|
-
throw new BlinkStorageError("File already exists.
|
|
3370
|
+
throw new BlinkStorageError("File already exists.", 409);
|
|
3325
3371
|
}
|
|
3326
3372
|
if (status === 400) {
|
|
3327
3373
|
throw new BlinkStorageError("Invalid request parameters", 400);
|
|
@@ -3366,7 +3412,6 @@ var BlinkStorageImpl = class {
|
|
|
3366
3412
|
detectedContentType
|
|
3367
3413
|
};
|
|
3368
3414
|
} catch (error) {
|
|
3369
|
-
console.warn("File type detection failed, using original path:", error);
|
|
3370
3415
|
return {
|
|
3371
3416
|
correctedPath: originalPath,
|
|
3372
3417
|
detectedContentType: "application/octet-stream"
|
|
@@ -5292,7 +5337,6 @@ var BlinkAnalyticsImpl = class {
|
|
|
5292
5337
|
} catch (error) {
|
|
5293
5338
|
this.queue = [...events, ...this.queue];
|
|
5294
5339
|
this.persistQueue();
|
|
5295
|
-
console.error("Failed to send analytics events:", error);
|
|
5296
5340
|
}
|
|
5297
5341
|
if (this.queue.length > 0) {
|
|
5298
5342
|
this.timer = setTimeout(() => this.flush(), BATCH_TIMEOUT);
|
|
@@ -5483,6 +5527,45 @@ var BlinkAnalyticsImpl = class {
|
|
|
5483
5527
|
}
|
|
5484
5528
|
};
|
|
5485
5529
|
|
|
5530
|
+
// src/functions.ts
|
|
5531
|
+
var BlinkFunctionsImpl = class {
|
|
5532
|
+
httpClient;
|
|
5533
|
+
projectId;
|
|
5534
|
+
constructor(httpClient, projectId, _getToken) {
|
|
5535
|
+
this.httpClient = httpClient;
|
|
5536
|
+
this.projectId = projectId;
|
|
5537
|
+
}
|
|
5538
|
+
/**
|
|
5539
|
+
* Get the project suffix from the full project ID.
|
|
5540
|
+
* Project IDs are formatted as: prj_xxxxx
|
|
5541
|
+
* The suffix is the last 8 characters used in function URLs.
|
|
5542
|
+
*/
|
|
5543
|
+
getProjectSuffix() {
|
|
5544
|
+
return this.projectId.slice(-8);
|
|
5545
|
+
}
|
|
5546
|
+
/**
|
|
5547
|
+
* Build the full function URL
|
|
5548
|
+
*/
|
|
5549
|
+
buildFunctionUrl(functionSlug, searchParams) {
|
|
5550
|
+
const suffix = this.getProjectSuffix();
|
|
5551
|
+
const baseUrl = `https://${suffix}--${functionSlug}.functions.blink.new`;
|
|
5552
|
+
if (!searchParams || Object.keys(searchParams).length === 0) {
|
|
5553
|
+
return baseUrl;
|
|
5554
|
+
}
|
|
5555
|
+
const url = new URL(baseUrl);
|
|
5556
|
+
Object.entries(searchParams).forEach(([key, value]) => {
|
|
5557
|
+
url.searchParams.set(key, value);
|
|
5558
|
+
});
|
|
5559
|
+
return url.toString();
|
|
5560
|
+
}
|
|
5561
|
+
async invoke(functionSlug, options = {}) {
|
|
5562
|
+
const { method = "POST", body, headers = {}, searchParams } = options;
|
|
5563
|
+
const url = this.buildFunctionUrl(functionSlug, searchParams);
|
|
5564
|
+
const res = await this.httpClient.request(url, { method, body, headers });
|
|
5565
|
+
return { data: res.data, status: res.status, headers: res.headers };
|
|
5566
|
+
}
|
|
5567
|
+
};
|
|
5568
|
+
|
|
5486
5569
|
// src/client.ts
|
|
5487
5570
|
var BlinkClientImpl = class {
|
|
5488
5571
|
auth;
|
|
@@ -5493,8 +5576,12 @@ var BlinkClientImpl = class {
|
|
|
5493
5576
|
realtime;
|
|
5494
5577
|
notifications;
|
|
5495
5578
|
analytics;
|
|
5579
|
+
functions;
|
|
5496
5580
|
httpClient;
|
|
5497
5581
|
constructor(config) {
|
|
5582
|
+
if ((config.secretKey || config.serviceToken) && isBrowser) {
|
|
5583
|
+
throw new Error("secretKey/serviceToken is server-only. Do not provide it in browser/React Native clients.");
|
|
5584
|
+
}
|
|
5498
5585
|
this.auth = new BlinkAuth(config);
|
|
5499
5586
|
this.httpClient = new HttpClient(
|
|
5500
5587
|
config,
|
|
@@ -5508,6 +5595,11 @@ var BlinkClientImpl = class {
|
|
|
5508
5595
|
this.realtime = new BlinkRealtimeImpl(this.httpClient, config.projectId);
|
|
5509
5596
|
this.notifications = new BlinkNotificationsImpl(this.httpClient);
|
|
5510
5597
|
this.analytics = new BlinkAnalyticsImpl(this.httpClient, config.projectId);
|
|
5598
|
+
this.functions = new BlinkFunctionsImpl(
|
|
5599
|
+
this.httpClient,
|
|
5600
|
+
config.projectId,
|
|
5601
|
+
() => this.auth.getValidToken()
|
|
5602
|
+
);
|
|
5511
5603
|
this.auth.onAuthStateChanged((state) => {
|
|
5512
5604
|
if (state.isAuthenticated && state.user) {
|
|
5513
5605
|
this.analytics.setUserId(state.user.id);
|
|
@@ -5540,8 +5632,10 @@ exports.WebStorageAdapter = WebStorageAdapter;
|
|
|
5540
5632
|
exports.createClient = createClient;
|
|
5541
5633
|
exports.getDefaultStorageAdapter = getDefaultStorageAdapter;
|
|
5542
5634
|
exports.isBrowser = isBrowser;
|
|
5635
|
+
exports.isDeno = isDeno;
|
|
5543
5636
|
exports.isNode = isNode;
|
|
5544
5637
|
exports.isReactNative = isReactNative;
|
|
5638
|
+
exports.isServer = isServer;
|
|
5545
5639
|
exports.isWeb = isWeb;
|
|
5546
5640
|
exports.platform = platform;
|
|
5547
5641
|
//# sourceMappingURL=index.js.map
|
package/dist/index.mjs
CHANGED
|
@@ -5,6 +5,33 @@ 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/platform.ts
|
|
9
|
+
function detectPlatform() {
|
|
10
|
+
if (typeof Deno !== "undefined") {
|
|
11
|
+
return "deno";
|
|
12
|
+
}
|
|
13
|
+
if (typeof process !== "undefined" && process.versions?.node) {
|
|
14
|
+
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
15
|
+
return "react-native";
|
|
16
|
+
}
|
|
17
|
+
return "node";
|
|
18
|
+
}
|
|
19
|
+
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
20
|
+
return "react-native";
|
|
21
|
+
}
|
|
22
|
+
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
23
|
+
return "web";
|
|
24
|
+
}
|
|
25
|
+
return "node";
|
|
26
|
+
}
|
|
27
|
+
var platform = detectPlatform();
|
|
28
|
+
var isWeb = platform === "web";
|
|
29
|
+
var isReactNative = platform === "react-native";
|
|
30
|
+
var isNode = platform === "node";
|
|
31
|
+
var isDeno = platform === "deno";
|
|
32
|
+
var isBrowser = isWeb || isReactNative;
|
|
33
|
+
var isServer = isNode || isDeno;
|
|
34
|
+
|
|
8
35
|
// ../core/src/storage-adapter.ts
|
|
9
36
|
var WebStorageAdapter = class {
|
|
10
37
|
getItem(key) {
|
|
@@ -90,6 +117,9 @@ var NoOpStorageAdapter = class {
|
|
|
90
117
|
}
|
|
91
118
|
};
|
|
92
119
|
function getDefaultStorageAdapter() {
|
|
120
|
+
if (isDeno) {
|
|
121
|
+
return new NoOpStorageAdapter();
|
|
122
|
+
}
|
|
93
123
|
if (typeof window !== "undefined" && typeof localStorage !== "undefined") {
|
|
94
124
|
try {
|
|
95
125
|
localStorage.setItem("__test__", "test");
|
|
@@ -101,28 +131,6 @@ function getDefaultStorageAdapter() {
|
|
|
101
131
|
return new NoOpStorageAdapter();
|
|
102
132
|
}
|
|
103
133
|
|
|
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
|
-
|
|
126
134
|
// ../core/src/types.ts
|
|
127
135
|
var BlinkError = class extends Error {
|
|
128
136
|
constructor(message, code, status, details) {
|
|
@@ -389,32 +397,65 @@ var HttpClient = class {
|
|
|
389
397
|
authUrl = "https://blink.new";
|
|
390
398
|
coreUrl = "https://core.blink.new";
|
|
391
399
|
projectId;
|
|
400
|
+
publishableKey;
|
|
401
|
+
secretKey;
|
|
402
|
+
// Permanent, non-expiring key (like Stripe's sk_live_...)
|
|
392
403
|
getToken;
|
|
393
404
|
getValidToken;
|
|
394
405
|
constructor(config, getToken, getValidToken) {
|
|
395
406
|
this.projectId = config.projectId;
|
|
407
|
+
this.publishableKey = config.publishableKey;
|
|
408
|
+
this.secretKey = config.secretKey || config.serviceToken;
|
|
396
409
|
this.getToken = getToken;
|
|
397
410
|
this.getValidToken = getValidToken;
|
|
398
411
|
}
|
|
412
|
+
shouldAttachPublishableKey(path, method) {
|
|
413
|
+
if (method !== "GET" && method !== "POST") return false;
|
|
414
|
+
if (path.includes("/api/analytics/")) return true;
|
|
415
|
+
if (path.includes("/api/storage/")) return true;
|
|
416
|
+
if (path.includes("/api/db/") && path.includes("/rest/v1/")) return method === "GET";
|
|
417
|
+
return false;
|
|
418
|
+
}
|
|
419
|
+
shouldSkipSecretKey(url) {
|
|
420
|
+
try {
|
|
421
|
+
const parsed = new URL(url);
|
|
422
|
+
return parsed.hostname.endsWith(".functions.blink.new");
|
|
423
|
+
} catch {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
getAuthorizationHeader(url, token) {
|
|
428
|
+
if (this.secretKey && !this.shouldSkipSecretKey(url)) {
|
|
429
|
+
return `Bearer ${this.secretKey}`;
|
|
430
|
+
}
|
|
431
|
+
if (token) {
|
|
432
|
+
return `Bearer ${token}`;
|
|
433
|
+
}
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
399
436
|
/**
|
|
400
437
|
* Make an authenticated request to the Blink API
|
|
401
438
|
*/
|
|
402
439
|
async request(path, options = {}) {
|
|
403
440
|
const url = this.buildUrl(path, options.searchParams);
|
|
404
441
|
const token = this.getValidToken ? await this.getValidToken() : this.getToken();
|
|
442
|
+
const method = options.method || "GET";
|
|
405
443
|
const headers = {
|
|
406
444
|
"Content-Type": "application/json",
|
|
407
445
|
...options.headers
|
|
408
446
|
};
|
|
409
|
-
|
|
410
|
-
|
|
447
|
+
const auth = this.getAuthorizationHeader(url, token);
|
|
448
|
+
if (auth) {
|
|
449
|
+
headers.Authorization = auth;
|
|
450
|
+
} else if (this.publishableKey && !headers["x-blink-publishable-key"] && this.shouldAttachPublishableKey(path, method)) {
|
|
451
|
+
headers["x-blink-publishable-key"] = this.publishableKey;
|
|
411
452
|
}
|
|
412
453
|
const requestInit = {
|
|
413
|
-
method
|
|
454
|
+
method,
|
|
414
455
|
headers,
|
|
415
456
|
signal: options.signal
|
|
416
457
|
};
|
|
417
|
-
if (options.body &&
|
|
458
|
+
if (options.body && method !== "GET") {
|
|
418
459
|
requestInit.body = typeof options.body === "string" ? options.body : JSON.stringify(options.body);
|
|
419
460
|
}
|
|
420
461
|
try {
|
|
@@ -568,12 +609,12 @@ var HttpClient = class {
|
|
|
568
609
|
throw new BlinkValidationError("Unsupported file type");
|
|
569
610
|
}
|
|
570
611
|
formData.append("path", filePath);
|
|
571
|
-
if (options.upsert !== void 0) {
|
|
572
|
-
formData.append("options", JSON.stringify({ upsert: options.upsert }));
|
|
573
|
-
}
|
|
574
612
|
const headers = {};
|
|
575
|
-
|
|
576
|
-
|
|
613
|
+
const auth = this.getAuthorizationHeader(url, token);
|
|
614
|
+
if (auth) {
|
|
615
|
+
headers.Authorization = auth;
|
|
616
|
+
} else if (this.publishableKey && path.includes("/api/storage/") && !headers["x-blink-publishable-key"]) {
|
|
617
|
+
headers["x-blink-publishable-key"] = this.publishableKey;
|
|
577
618
|
}
|
|
578
619
|
try {
|
|
579
620
|
if (typeof XMLHttpRequest !== "undefined" && options.onProgress) {
|
|
@@ -682,9 +723,8 @@ var HttpClient = class {
|
|
|
682
723
|
const headers = {
|
|
683
724
|
"Content-Type": "application/json"
|
|
684
725
|
};
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
}
|
|
726
|
+
const auth = this.getAuthorizationHeader(url, token);
|
|
727
|
+
if (auth) headers.Authorization = auth;
|
|
688
728
|
const body = {
|
|
689
729
|
prompt,
|
|
690
730
|
stream: true,
|
|
@@ -737,9 +777,8 @@ var HttpClient = class {
|
|
|
737
777
|
const headers = {
|
|
738
778
|
"Content-Type": "application/json"
|
|
739
779
|
};
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
}
|
|
780
|
+
const auth = this.getAuthorizationHeader(url, token);
|
|
781
|
+
if (auth) headers.Authorization = auth;
|
|
743
782
|
const body = {
|
|
744
783
|
prompt,
|
|
745
784
|
stream: true,
|
|
@@ -2964,6 +3003,11 @@ var BlinkAuth = class {
|
|
|
2964
3003
|
};
|
|
2965
3004
|
|
|
2966
3005
|
// src/database.ts
|
|
3006
|
+
function assertServerOnly(methodName) {
|
|
3007
|
+
if (typeof window !== "undefined") {
|
|
3008
|
+
throw new Error(`${methodName} is server-only. Use Blink CRUD methods (blink.db.<table>.*) instead.`);
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
2967
3011
|
function camelToSnake3(str) {
|
|
2968
3012
|
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
2969
3013
|
}
|
|
@@ -3182,6 +3226,7 @@ var BlinkTable = class {
|
|
|
3182
3226
|
* Raw SQL query on this table (for advanced use cases)
|
|
3183
3227
|
*/
|
|
3184
3228
|
async sql(query, params) {
|
|
3229
|
+
assertServerOnly("blink.db.<table>.sql");
|
|
3185
3230
|
const response = await this.httpClient.dbSql(query, params);
|
|
3186
3231
|
return response.data;
|
|
3187
3232
|
}
|
|
@@ -3230,6 +3275,7 @@ var BlinkDatabase = class {
|
|
|
3230
3275
|
* Execute raw SQL query
|
|
3231
3276
|
*/
|
|
3232
3277
|
async sql(query, params) {
|
|
3278
|
+
assertServerOnly("blink.db.sql");
|
|
3233
3279
|
const response = await this.httpClient.dbSql(query, params);
|
|
3234
3280
|
return response.data;
|
|
3235
3281
|
}
|
|
@@ -3237,6 +3283,7 @@ var BlinkDatabase = class {
|
|
|
3237
3283
|
* Execute batch SQL operations
|
|
3238
3284
|
*/
|
|
3239
3285
|
async batch(statements, mode = "write") {
|
|
3286
|
+
assertServerOnly("blink.db.batch");
|
|
3240
3287
|
const response = await this.httpClient.dbBatch(statements, mode);
|
|
3241
3288
|
return response.data;
|
|
3242
3289
|
}
|
|
@@ -3299,7 +3346,6 @@ var BlinkStorageImpl = class {
|
|
|
3299
3346
|
correctedPath,
|
|
3300
3347
|
// Use corrected path with proper extension
|
|
3301
3348
|
{
|
|
3302
|
-
upsert: options.upsert,
|
|
3303
3349
|
onProgress: options.onProgress,
|
|
3304
3350
|
contentType: detectedContentType
|
|
3305
3351
|
// Pass detected content type
|
|
@@ -3319,7 +3365,7 @@ var BlinkStorageImpl = class {
|
|
|
3319
3365
|
if (error instanceof Error && "status" in error) {
|
|
3320
3366
|
const status = error.status;
|
|
3321
3367
|
if (status === 409) {
|
|
3322
|
-
throw new BlinkStorageError("File already exists.
|
|
3368
|
+
throw new BlinkStorageError("File already exists.", 409);
|
|
3323
3369
|
}
|
|
3324
3370
|
if (status === 400) {
|
|
3325
3371
|
throw new BlinkStorageError("Invalid request parameters", 400);
|
|
@@ -3364,7 +3410,6 @@ var BlinkStorageImpl = class {
|
|
|
3364
3410
|
detectedContentType
|
|
3365
3411
|
};
|
|
3366
3412
|
} catch (error) {
|
|
3367
|
-
console.warn("File type detection failed, using original path:", error);
|
|
3368
3413
|
return {
|
|
3369
3414
|
correctedPath: originalPath,
|
|
3370
3415
|
detectedContentType: "application/octet-stream"
|
|
@@ -5290,7 +5335,6 @@ var BlinkAnalyticsImpl = class {
|
|
|
5290
5335
|
} catch (error) {
|
|
5291
5336
|
this.queue = [...events, ...this.queue];
|
|
5292
5337
|
this.persistQueue();
|
|
5293
|
-
console.error("Failed to send analytics events:", error);
|
|
5294
5338
|
}
|
|
5295
5339
|
if (this.queue.length > 0) {
|
|
5296
5340
|
this.timer = setTimeout(() => this.flush(), BATCH_TIMEOUT);
|
|
@@ -5481,6 +5525,45 @@ var BlinkAnalyticsImpl = class {
|
|
|
5481
5525
|
}
|
|
5482
5526
|
};
|
|
5483
5527
|
|
|
5528
|
+
// src/functions.ts
|
|
5529
|
+
var BlinkFunctionsImpl = class {
|
|
5530
|
+
httpClient;
|
|
5531
|
+
projectId;
|
|
5532
|
+
constructor(httpClient, projectId, _getToken) {
|
|
5533
|
+
this.httpClient = httpClient;
|
|
5534
|
+
this.projectId = projectId;
|
|
5535
|
+
}
|
|
5536
|
+
/**
|
|
5537
|
+
* Get the project suffix from the full project ID.
|
|
5538
|
+
* Project IDs are formatted as: prj_xxxxx
|
|
5539
|
+
* The suffix is the last 8 characters used in function URLs.
|
|
5540
|
+
*/
|
|
5541
|
+
getProjectSuffix() {
|
|
5542
|
+
return this.projectId.slice(-8);
|
|
5543
|
+
}
|
|
5544
|
+
/**
|
|
5545
|
+
* Build the full function URL
|
|
5546
|
+
*/
|
|
5547
|
+
buildFunctionUrl(functionSlug, searchParams) {
|
|
5548
|
+
const suffix = this.getProjectSuffix();
|
|
5549
|
+
const baseUrl = `https://${suffix}--${functionSlug}.functions.blink.new`;
|
|
5550
|
+
if (!searchParams || Object.keys(searchParams).length === 0) {
|
|
5551
|
+
return baseUrl;
|
|
5552
|
+
}
|
|
5553
|
+
const url = new URL(baseUrl);
|
|
5554
|
+
Object.entries(searchParams).forEach(([key, value]) => {
|
|
5555
|
+
url.searchParams.set(key, value);
|
|
5556
|
+
});
|
|
5557
|
+
return url.toString();
|
|
5558
|
+
}
|
|
5559
|
+
async invoke(functionSlug, options = {}) {
|
|
5560
|
+
const { method = "POST", body, headers = {}, searchParams } = options;
|
|
5561
|
+
const url = this.buildFunctionUrl(functionSlug, searchParams);
|
|
5562
|
+
const res = await this.httpClient.request(url, { method, body, headers });
|
|
5563
|
+
return { data: res.data, status: res.status, headers: res.headers };
|
|
5564
|
+
}
|
|
5565
|
+
};
|
|
5566
|
+
|
|
5484
5567
|
// src/client.ts
|
|
5485
5568
|
var BlinkClientImpl = class {
|
|
5486
5569
|
auth;
|
|
@@ -5491,8 +5574,12 @@ var BlinkClientImpl = class {
|
|
|
5491
5574
|
realtime;
|
|
5492
5575
|
notifications;
|
|
5493
5576
|
analytics;
|
|
5577
|
+
functions;
|
|
5494
5578
|
httpClient;
|
|
5495
5579
|
constructor(config) {
|
|
5580
|
+
if ((config.secretKey || config.serviceToken) && isBrowser) {
|
|
5581
|
+
throw new Error("secretKey/serviceToken is server-only. Do not provide it in browser/React Native clients.");
|
|
5582
|
+
}
|
|
5496
5583
|
this.auth = new BlinkAuth(config);
|
|
5497
5584
|
this.httpClient = new HttpClient(
|
|
5498
5585
|
config,
|
|
@@ -5506,6 +5593,11 @@ var BlinkClientImpl = class {
|
|
|
5506
5593
|
this.realtime = new BlinkRealtimeImpl(this.httpClient, config.projectId);
|
|
5507
5594
|
this.notifications = new BlinkNotificationsImpl(this.httpClient);
|
|
5508
5595
|
this.analytics = new BlinkAnalyticsImpl(this.httpClient, config.projectId);
|
|
5596
|
+
this.functions = new BlinkFunctionsImpl(
|
|
5597
|
+
this.httpClient,
|
|
5598
|
+
config.projectId,
|
|
5599
|
+
() => this.auth.getValidToken()
|
|
5600
|
+
);
|
|
5509
5601
|
this.auth.onAuthStateChanged((state) => {
|
|
5510
5602
|
if (state.isAuthenticated && state.user) {
|
|
5511
5603
|
this.analytics.setUserId(state.user.id);
|
|
@@ -5524,6 +5616,6 @@ function createClient(config) {
|
|
|
5524
5616
|
return new BlinkClientImpl(config);
|
|
5525
5617
|
}
|
|
5526
5618
|
|
|
5527
|
-
export { AsyncStorageAdapter, BlinkAIImpl, BlinkAnalyticsImpl, BlinkDataImpl, BlinkDatabase, BlinkRealtimeChannel, BlinkRealtimeImpl, BlinkStorageImpl, BlinkTable, NoOpStorageAdapter, WebStorageAdapter, createClient, getDefaultStorageAdapter, isBrowser, isNode, isReactNative, isWeb, platform };
|
|
5619
|
+
export { AsyncStorageAdapter, BlinkAIImpl, BlinkAnalyticsImpl, BlinkDataImpl, BlinkDatabase, BlinkRealtimeChannel, BlinkRealtimeImpl, BlinkStorageImpl, BlinkTable, NoOpStorageAdapter, WebStorageAdapter, createClient, getDefaultStorageAdapter, isBrowser, isDeno, isNode, isReactNative, isServer, isWeb, platform };
|
|
5528
5620
|
//# sourceMappingURL=index.mjs.map
|
|
5529
5621
|
//# sourceMappingURL=index.mjs.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blinkdotnew/sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
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",
|
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
"build": "tsup",
|
|
47
47
|
"dev": "tsup --watch",
|
|
48
48
|
"type-check": "tsc --noEmit",
|
|
49
|
-
"clean": "rm -rf dist"
|
|
49
|
+
"clean": "rm -rf dist",
|
|
50
|
+
"prepublishOnly": "npm run build"
|
|
50
51
|
},
|
|
51
52
|
"dependencies": {},
|
|
52
53
|
"devDependencies": {
|