@blinkdotnew/sdk 0.7.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -0
- package/dist/index.d.mts +86 -1
- package/dist/index.d.ts +86 -1
- package/dist/index.js +287 -0
- package/dist/index.mjs +287 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -81,6 +81,22 @@ await blink.realtime.publish('chat-room', 'message', { text: 'Hello world!' })
|
|
|
81
81
|
const users = await blink.realtime.presence('chat-room')
|
|
82
82
|
console.log('Online users:', users.length)
|
|
83
83
|
|
|
84
|
+
// Analytics operations (automatic pageview tracking + custom events)
|
|
85
|
+
// Pageviews are tracked automatically on initialization and route changes
|
|
86
|
+
blink.analytics.log('button_clicked', {
|
|
87
|
+
button_id: 'signup',
|
|
88
|
+
page: '/pricing'
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
// Check if analytics is enabled
|
|
92
|
+
if (blink.analytics.isEnabled()) {
|
|
93
|
+
console.log('Analytics is active')
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Disable/enable analytics
|
|
97
|
+
blink.analytics.disable()
|
|
98
|
+
blink.analytics.enable()
|
|
99
|
+
|
|
84
100
|
// Storage operations (instant - returns public URL directly)
|
|
85
101
|
const { publicUrl } = await blink.storage.upload(
|
|
86
102
|
file,
|
|
@@ -109,6 +125,7 @@ This SDK powers every Blink-generated app with:
|
|
|
109
125
|
- **📁 Storage**: File upload, download, and management
|
|
110
126
|
- **📧 Notifications**: Email sending with attachments, custom branding, and delivery tracking
|
|
111
127
|
- **⚡ Realtime**: WebSocket-based pub/sub messaging, presence tracking, and live updates
|
|
128
|
+
- **📊 Analytics**: Automatic pageview tracking, custom event logging, session management, and privacy-first design
|
|
112
129
|
- **🌐 Universal**: Works on client-side and server-side
|
|
113
130
|
- **📱 Framework Agnostic**: React, Vue, Svelte, vanilla JS, Node.js, Deno
|
|
114
131
|
- **🔄 Real-time**: Built-in auth state management and token refresh
|
|
@@ -550,6 +567,34 @@ try {
|
|
|
550
567
|
}
|
|
551
568
|
```
|
|
552
569
|
|
|
570
|
+
### Analytics Operations
|
|
571
|
+
|
|
572
|
+
```typescript
|
|
573
|
+
// 🔥 Analytics (NEW!) - Automatic pageview tracking + custom events
|
|
574
|
+
// Pageviews are tracked automatically on initialization and route changes
|
|
575
|
+
|
|
576
|
+
// Log custom events - context data is added automatically
|
|
577
|
+
blink.analytics.log('button_clicked', {
|
|
578
|
+
button_id: 'signup',
|
|
579
|
+
campaign: 'summer_sale'
|
|
580
|
+
})
|
|
581
|
+
|
|
582
|
+
// All events automatically include:
|
|
583
|
+
// - timestamp, project_id, user_id, user_email, session_id
|
|
584
|
+
// - pathname (current page), referrer, screen_width
|
|
585
|
+
// - device/browser/OS info (parsed server-side)
|
|
586
|
+
// - channel detection (Organic Search, Social, Direct, etc.)
|
|
587
|
+
// - UTM parameters (source, medium, campaign, content, term)
|
|
588
|
+
// - entry_page, exit_page tracking
|
|
589
|
+
|
|
590
|
+
// Control analytics
|
|
591
|
+
blink.analytics.disable()
|
|
592
|
+
blink.analytics.enable()
|
|
593
|
+
const isEnabled = blink.analytics.isEnabled()
|
|
594
|
+
|
|
595
|
+
// Features: Privacy-first, offline support, event batching, session management
|
|
596
|
+
```
|
|
597
|
+
|
|
553
598
|
### Realtime Operations
|
|
554
599
|
|
|
555
600
|
```typescript
|
package/dist/index.d.mts
CHANGED
|
@@ -248,6 +248,90 @@ declare class BlinkDataImpl implements BlinkData {
|
|
|
248
248
|
}): Promise<SearchResponse>;
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Blink Analytics Module
|
|
253
|
+
* Provides automatic pageview tracking and custom event logging
|
|
254
|
+
*/
|
|
255
|
+
|
|
256
|
+
interface AnalyticsEvent {
|
|
257
|
+
type: string;
|
|
258
|
+
timestamp?: string;
|
|
259
|
+
user_id?: string | null;
|
|
260
|
+
user_email?: string | null;
|
|
261
|
+
session_id?: string | null;
|
|
262
|
+
pathname?: string | null;
|
|
263
|
+
referrer?: string | null;
|
|
264
|
+
screen_width?: number | null;
|
|
265
|
+
channel?: string | null;
|
|
266
|
+
utm_source?: string | null;
|
|
267
|
+
utm_medium?: string | null;
|
|
268
|
+
utm_campaign?: string | null;
|
|
269
|
+
utm_content?: string | null;
|
|
270
|
+
utm_term?: string | null;
|
|
271
|
+
entry_page?: string | null;
|
|
272
|
+
exit_page?: string | null;
|
|
273
|
+
[key: string]: any;
|
|
274
|
+
}
|
|
275
|
+
interface BlinkAnalytics {
|
|
276
|
+
log(eventName: string, data?: Record<string, any>): void;
|
|
277
|
+
disable(): void;
|
|
278
|
+
enable(): void;
|
|
279
|
+
isEnabled(): boolean;
|
|
280
|
+
setUserId(userId: string | null): void;
|
|
281
|
+
setUserEmail(email: string | null): void;
|
|
282
|
+
}
|
|
283
|
+
declare class BlinkAnalyticsImpl implements BlinkAnalytics {
|
|
284
|
+
private httpClient;
|
|
285
|
+
private projectId;
|
|
286
|
+
private queue;
|
|
287
|
+
private timer;
|
|
288
|
+
private enabled;
|
|
289
|
+
private userId;
|
|
290
|
+
private userEmail;
|
|
291
|
+
private hasTrackedPageview;
|
|
292
|
+
private entryPage;
|
|
293
|
+
private utmParams;
|
|
294
|
+
constructor(httpClient: HttpClient, projectId: string);
|
|
295
|
+
/**
|
|
296
|
+
* Log a custom analytics event
|
|
297
|
+
*/
|
|
298
|
+
log(eventName: string, data?: Record<string, any>): void;
|
|
299
|
+
/**
|
|
300
|
+
* Disable analytics tracking
|
|
301
|
+
*/
|
|
302
|
+
disable(): void;
|
|
303
|
+
/**
|
|
304
|
+
* Enable analytics tracking
|
|
305
|
+
*/
|
|
306
|
+
enable(): void;
|
|
307
|
+
/**
|
|
308
|
+
* Check if analytics is enabled
|
|
309
|
+
*/
|
|
310
|
+
isEnabled(): boolean;
|
|
311
|
+
/**
|
|
312
|
+
* Set the user ID for analytics events
|
|
313
|
+
*/
|
|
314
|
+
setUserId(userId: string | null): void;
|
|
315
|
+
/**
|
|
316
|
+
* Set the user email for analytics events
|
|
317
|
+
*/
|
|
318
|
+
setUserEmail(email: string | null): void;
|
|
319
|
+
private buildEvent;
|
|
320
|
+
private sanitizeData;
|
|
321
|
+
private enqueue;
|
|
322
|
+
private flush;
|
|
323
|
+
private clearTimer;
|
|
324
|
+
private getOrCreateSessionId;
|
|
325
|
+
private createNewSession;
|
|
326
|
+
private loadQueue;
|
|
327
|
+
private persistQueue;
|
|
328
|
+
private trackPageview;
|
|
329
|
+
private setupRouteChangeListener;
|
|
330
|
+
private setupUnloadListener;
|
|
331
|
+
private captureUTMParams;
|
|
332
|
+
private detectChannel;
|
|
333
|
+
}
|
|
334
|
+
|
|
251
335
|
/**
|
|
252
336
|
* Blink Client - Main SDK entry point
|
|
253
337
|
* Factory function and client class for the Blink SDK
|
|
@@ -261,6 +345,7 @@ interface BlinkClient {
|
|
|
261
345
|
data: BlinkData;
|
|
262
346
|
realtime: BlinkRealtime;
|
|
263
347
|
notifications: BlinkNotifications;
|
|
348
|
+
analytics: BlinkAnalytics;
|
|
264
349
|
}
|
|
265
350
|
/**
|
|
266
351
|
* Create a new Blink client instance
|
|
@@ -720,4 +805,4 @@ declare class BlinkRealtimeImpl implements BlinkRealtime {
|
|
|
720
805
|
onPresence(channelName: string, callback: (users: PresenceUser[]) => void): () => void;
|
|
721
806
|
}
|
|
722
807
|
|
|
723
|
-
export { type AuthStateChangeCallback, BlinkAIImpl, type BlinkClient, type BlinkData, BlinkDataImpl, BlinkDatabase, BlinkRealtimeChannel, BlinkRealtimeImpl, BlinkStorageImpl, BlinkTable, createClient };
|
|
808
|
+
export { type AnalyticsEvent, type AuthStateChangeCallback, BlinkAIImpl, type BlinkAnalytics, BlinkAnalyticsImpl, type BlinkClient, type BlinkData, BlinkDataImpl, BlinkDatabase, BlinkRealtimeChannel, BlinkRealtimeImpl, BlinkStorageImpl, BlinkTable, createClient };
|
package/dist/index.d.ts
CHANGED
|
@@ -248,6 +248,90 @@ declare class BlinkDataImpl implements BlinkData {
|
|
|
248
248
|
}): Promise<SearchResponse>;
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Blink Analytics Module
|
|
253
|
+
* Provides automatic pageview tracking and custom event logging
|
|
254
|
+
*/
|
|
255
|
+
|
|
256
|
+
interface AnalyticsEvent {
|
|
257
|
+
type: string;
|
|
258
|
+
timestamp?: string;
|
|
259
|
+
user_id?: string | null;
|
|
260
|
+
user_email?: string | null;
|
|
261
|
+
session_id?: string | null;
|
|
262
|
+
pathname?: string | null;
|
|
263
|
+
referrer?: string | null;
|
|
264
|
+
screen_width?: number | null;
|
|
265
|
+
channel?: string | null;
|
|
266
|
+
utm_source?: string | null;
|
|
267
|
+
utm_medium?: string | null;
|
|
268
|
+
utm_campaign?: string | null;
|
|
269
|
+
utm_content?: string | null;
|
|
270
|
+
utm_term?: string | null;
|
|
271
|
+
entry_page?: string | null;
|
|
272
|
+
exit_page?: string | null;
|
|
273
|
+
[key: string]: any;
|
|
274
|
+
}
|
|
275
|
+
interface BlinkAnalytics {
|
|
276
|
+
log(eventName: string, data?: Record<string, any>): void;
|
|
277
|
+
disable(): void;
|
|
278
|
+
enable(): void;
|
|
279
|
+
isEnabled(): boolean;
|
|
280
|
+
setUserId(userId: string | null): void;
|
|
281
|
+
setUserEmail(email: string | null): void;
|
|
282
|
+
}
|
|
283
|
+
declare class BlinkAnalyticsImpl implements BlinkAnalytics {
|
|
284
|
+
private httpClient;
|
|
285
|
+
private projectId;
|
|
286
|
+
private queue;
|
|
287
|
+
private timer;
|
|
288
|
+
private enabled;
|
|
289
|
+
private userId;
|
|
290
|
+
private userEmail;
|
|
291
|
+
private hasTrackedPageview;
|
|
292
|
+
private entryPage;
|
|
293
|
+
private utmParams;
|
|
294
|
+
constructor(httpClient: HttpClient, projectId: string);
|
|
295
|
+
/**
|
|
296
|
+
* Log a custom analytics event
|
|
297
|
+
*/
|
|
298
|
+
log(eventName: string, data?: Record<string, any>): void;
|
|
299
|
+
/**
|
|
300
|
+
* Disable analytics tracking
|
|
301
|
+
*/
|
|
302
|
+
disable(): void;
|
|
303
|
+
/**
|
|
304
|
+
* Enable analytics tracking
|
|
305
|
+
*/
|
|
306
|
+
enable(): void;
|
|
307
|
+
/**
|
|
308
|
+
* Check if analytics is enabled
|
|
309
|
+
*/
|
|
310
|
+
isEnabled(): boolean;
|
|
311
|
+
/**
|
|
312
|
+
* Set the user ID for analytics events
|
|
313
|
+
*/
|
|
314
|
+
setUserId(userId: string | null): void;
|
|
315
|
+
/**
|
|
316
|
+
* Set the user email for analytics events
|
|
317
|
+
*/
|
|
318
|
+
setUserEmail(email: string | null): void;
|
|
319
|
+
private buildEvent;
|
|
320
|
+
private sanitizeData;
|
|
321
|
+
private enqueue;
|
|
322
|
+
private flush;
|
|
323
|
+
private clearTimer;
|
|
324
|
+
private getOrCreateSessionId;
|
|
325
|
+
private createNewSession;
|
|
326
|
+
private loadQueue;
|
|
327
|
+
private persistQueue;
|
|
328
|
+
private trackPageview;
|
|
329
|
+
private setupRouteChangeListener;
|
|
330
|
+
private setupUnloadListener;
|
|
331
|
+
private captureUTMParams;
|
|
332
|
+
private detectChannel;
|
|
333
|
+
}
|
|
334
|
+
|
|
251
335
|
/**
|
|
252
336
|
* Blink Client - Main SDK entry point
|
|
253
337
|
* Factory function and client class for the Blink SDK
|
|
@@ -261,6 +345,7 @@ interface BlinkClient {
|
|
|
261
345
|
data: BlinkData;
|
|
262
346
|
realtime: BlinkRealtime;
|
|
263
347
|
notifications: BlinkNotifications;
|
|
348
|
+
analytics: BlinkAnalytics;
|
|
264
349
|
}
|
|
265
350
|
/**
|
|
266
351
|
* Create a new Blink client instance
|
|
@@ -720,4 +805,4 @@ declare class BlinkRealtimeImpl implements BlinkRealtime {
|
|
|
720
805
|
onPresence(channelName: string, callback: (users: PresenceUser[]) => void): () => void;
|
|
721
806
|
}
|
|
722
807
|
|
|
723
|
-
export { type AuthStateChangeCallback, BlinkAIImpl, type BlinkClient, type BlinkData, BlinkDataImpl, BlinkDatabase, BlinkRealtimeChannel, BlinkRealtimeImpl, BlinkStorageImpl, BlinkTable, createClient };
|
|
808
|
+
export { type AnalyticsEvent, type AuthStateChangeCallback, BlinkAIImpl, type BlinkAnalytics, BlinkAnalyticsImpl, type BlinkClient, type BlinkData, BlinkDataImpl, BlinkDatabase, BlinkRealtimeChannel, BlinkRealtimeImpl, BlinkStorageImpl, BlinkTable, createClient };
|
package/dist/index.js
CHANGED
|
@@ -2880,6 +2880,281 @@ var BlinkNotificationsImpl = class {
|
|
|
2880
2880
|
}
|
|
2881
2881
|
};
|
|
2882
2882
|
|
|
2883
|
+
// src/analytics.ts
|
|
2884
|
+
var SESSION_DURATION = 30 * 60 * 1e3;
|
|
2885
|
+
var MAX_BATCH_SIZE = 10;
|
|
2886
|
+
var BATCH_TIMEOUT = 3e3;
|
|
2887
|
+
var MAX_STRING_LENGTH = 256;
|
|
2888
|
+
var STORAGE_KEY_QUEUE = "blinkAnalyticsQueue";
|
|
2889
|
+
var STORAGE_KEY_SESSION = "blinkAnalyticsSession";
|
|
2890
|
+
var BlinkAnalyticsImpl = class {
|
|
2891
|
+
httpClient;
|
|
2892
|
+
projectId;
|
|
2893
|
+
queue = [];
|
|
2894
|
+
timer = null;
|
|
2895
|
+
enabled = true;
|
|
2896
|
+
userId = null;
|
|
2897
|
+
userEmail = null;
|
|
2898
|
+
hasTrackedPageview = false;
|
|
2899
|
+
entryPage = null;
|
|
2900
|
+
utmParams = {};
|
|
2901
|
+
constructor(httpClient, projectId) {
|
|
2902
|
+
this.httpClient = httpClient;
|
|
2903
|
+
this.projectId = projectId;
|
|
2904
|
+
if (typeof window === "undefined") {
|
|
2905
|
+
return;
|
|
2906
|
+
}
|
|
2907
|
+
if (navigator.doNotTrack === "1") {
|
|
2908
|
+
this.enabled = false;
|
|
2909
|
+
return;
|
|
2910
|
+
}
|
|
2911
|
+
this.entryPage = window.location.pathname;
|
|
2912
|
+
this.captureUTMParams();
|
|
2913
|
+
this.loadQueue();
|
|
2914
|
+
this.trackPageview();
|
|
2915
|
+
this.setupRouteChangeListener();
|
|
2916
|
+
this.setupUnloadListener();
|
|
2917
|
+
}
|
|
2918
|
+
/**
|
|
2919
|
+
* Log a custom analytics event
|
|
2920
|
+
*/
|
|
2921
|
+
log(eventName, data = {}) {
|
|
2922
|
+
if (!this.enabled || typeof window === "undefined") {
|
|
2923
|
+
return;
|
|
2924
|
+
}
|
|
2925
|
+
const event = this.buildEvent(eventName, data);
|
|
2926
|
+
this.enqueue(event);
|
|
2927
|
+
}
|
|
2928
|
+
/**
|
|
2929
|
+
* Disable analytics tracking
|
|
2930
|
+
*/
|
|
2931
|
+
disable() {
|
|
2932
|
+
this.enabled = false;
|
|
2933
|
+
this.clearTimer();
|
|
2934
|
+
}
|
|
2935
|
+
/**
|
|
2936
|
+
* Enable analytics tracking
|
|
2937
|
+
*/
|
|
2938
|
+
enable() {
|
|
2939
|
+
this.enabled = true;
|
|
2940
|
+
}
|
|
2941
|
+
/**
|
|
2942
|
+
* Check if analytics is enabled
|
|
2943
|
+
*/
|
|
2944
|
+
isEnabled() {
|
|
2945
|
+
return this.enabled;
|
|
2946
|
+
}
|
|
2947
|
+
/**
|
|
2948
|
+
* Set the user ID for analytics events
|
|
2949
|
+
*/
|
|
2950
|
+
setUserId(userId) {
|
|
2951
|
+
this.userId = userId;
|
|
2952
|
+
}
|
|
2953
|
+
/**
|
|
2954
|
+
* Set the user email for analytics events
|
|
2955
|
+
*/
|
|
2956
|
+
setUserEmail(email) {
|
|
2957
|
+
this.userEmail = email;
|
|
2958
|
+
}
|
|
2959
|
+
// Private methods
|
|
2960
|
+
buildEvent(type, data = {}) {
|
|
2961
|
+
const sessionId = this.getOrCreateSessionId();
|
|
2962
|
+
const channel = this.detectChannel();
|
|
2963
|
+
return {
|
|
2964
|
+
type,
|
|
2965
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2966
|
+
project_id: this.projectId,
|
|
2967
|
+
user_id: this.userId,
|
|
2968
|
+
user_email: this.userEmail,
|
|
2969
|
+
session_id: sessionId,
|
|
2970
|
+
pathname: window.location.pathname,
|
|
2971
|
+
referrer: document.referrer || null,
|
|
2972
|
+
screen_width: window.innerWidth,
|
|
2973
|
+
channel,
|
|
2974
|
+
utm_source: this.utmParams.utm_source || null,
|
|
2975
|
+
utm_medium: this.utmParams.utm_medium || null,
|
|
2976
|
+
utm_campaign: this.utmParams.utm_campaign || null,
|
|
2977
|
+
utm_content: this.utmParams.utm_content || null,
|
|
2978
|
+
utm_term: this.utmParams.utm_term || null,
|
|
2979
|
+
entry_page: this.entryPage,
|
|
2980
|
+
exit_page: window.location.pathname,
|
|
2981
|
+
// Current page is potential exit
|
|
2982
|
+
...this.sanitizeData(data)
|
|
2983
|
+
};
|
|
2984
|
+
}
|
|
2985
|
+
sanitizeData(data) {
|
|
2986
|
+
if (typeof data === "string") {
|
|
2987
|
+
return data.length > MAX_STRING_LENGTH ? data.slice(0, MAX_STRING_LENGTH - 3) + "..." : data;
|
|
2988
|
+
}
|
|
2989
|
+
if (typeof data === "object" && data !== null) {
|
|
2990
|
+
const result = {};
|
|
2991
|
+
for (const key in data) {
|
|
2992
|
+
result[key] = this.sanitizeData(data[key]);
|
|
2993
|
+
}
|
|
2994
|
+
return result;
|
|
2995
|
+
}
|
|
2996
|
+
return data;
|
|
2997
|
+
}
|
|
2998
|
+
enqueue(event) {
|
|
2999
|
+
this.queue.push(event);
|
|
3000
|
+
this.persistQueue();
|
|
3001
|
+
if (this.queue.length >= MAX_BATCH_SIZE) {
|
|
3002
|
+
this.flush();
|
|
3003
|
+
} else if (!this.timer) {
|
|
3004
|
+
this.timer = setTimeout(() => this.flush(), BATCH_TIMEOUT);
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
async flush() {
|
|
3008
|
+
this.clearTimer();
|
|
3009
|
+
if (this.queue.length === 0) {
|
|
3010
|
+
return;
|
|
3011
|
+
}
|
|
3012
|
+
const events = this.queue.slice(0, MAX_BATCH_SIZE);
|
|
3013
|
+
this.queue = this.queue.slice(MAX_BATCH_SIZE);
|
|
3014
|
+
this.persistQueue();
|
|
3015
|
+
try {
|
|
3016
|
+
await this.httpClient.post(`/api/analytics/${this.projectId}/log`, { events });
|
|
3017
|
+
} catch (error) {
|
|
3018
|
+
this.queue = [...events, ...this.queue];
|
|
3019
|
+
this.persistQueue();
|
|
3020
|
+
console.error("Failed to send analytics events:", error);
|
|
3021
|
+
}
|
|
3022
|
+
if (this.queue.length > 0) {
|
|
3023
|
+
this.timer = setTimeout(() => this.flush(), BATCH_TIMEOUT);
|
|
3024
|
+
}
|
|
3025
|
+
}
|
|
3026
|
+
clearTimer() {
|
|
3027
|
+
if (this.timer) {
|
|
3028
|
+
clearTimeout(this.timer);
|
|
3029
|
+
this.timer = null;
|
|
3030
|
+
}
|
|
3031
|
+
}
|
|
3032
|
+
getOrCreateSessionId() {
|
|
3033
|
+
try {
|
|
3034
|
+
const stored = localStorage.getItem(STORAGE_KEY_SESSION);
|
|
3035
|
+
if (stored) {
|
|
3036
|
+
const session = JSON.parse(stored);
|
|
3037
|
+
const now = Date.now();
|
|
3038
|
+
if (now - session.lastActivityAt > SESSION_DURATION) {
|
|
3039
|
+
return this.createNewSession();
|
|
3040
|
+
}
|
|
3041
|
+
session.lastActivityAt = now;
|
|
3042
|
+
localStorage.setItem(STORAGE_KEY_SESSION, JSON.stringify(session));
|
|
3043
|
+
return session.id;
|
|
3044
|
+
}
|
|
3045
|
+
return this.createNewSession();
|
|
3046
|
+
} catch {
|
|
3047
|
+
return null;
|
|
3048
|
+
}
|
|
3049
|
+
}
|
|
3050
|
+
createNewSession() {
|
|
3051
|
+
const now = Date.now();
|
|
3052
|
+
const randomId = Math.random().toString(36).substring(2, 10);
|
|
3053
|
+
const session = {
|
|
3054
|
+
id: `sess_${now}_${randomId}`,
|
|
3055
|
+
startedAt: now,
|
|
3056
|
+
lastActivityAt: now
|
|
3057
|
+
};
|
|
3058
|
+
try {
|
|
3059
|
+
localStorage.setItem(STORAGE_KEY_SESSION, JSON.stringify(session));
|
|
3060
|
+
} catch {
|
|
3061
|
+
}
|
|
3062
|
+
return session.id;
|
|
3063
|
+
}
|
|
3064
|
+
loadQueue() {
|
|
3065
|
+
try {
|
|
3066
|
+
const stored = localStorage.getItem(STORAGE_KEY_QUEUE);
|
|
3067
|
+
if (stored) {
|
|
3068
|
+
this.queue = JSON.parse(stored);
|
|
3069
|
+
if (this.queue.length > 0) {
|
|
3070
|
+
this.timer = setTimeout(() => this.flush(), BATCH_TIMEOUT);
|
|
3071
|
+
}
|
|
3072
|
+
}
|
|
3073
|
+
} catch {
|
|
3074
|
+
this.queue = [];
|
|
3075
|
+
}
|
|
3076
|
+
}
|
|
3077
|
+
persistQueue() {
|
|
3078
|
+
try {
|
|
3079
|
+
if (this.queue.length === 0) {
|
|
3080
|
+
localStorage.removeItem(STORAGE_KEY_QUEUE);
|
|
3081
|
+
} else {
|
|
3082
|
+
localStorage.setItem(STORAGE_KEY_QUEUE, JSON.stringify(this.queue));
|
|
3083
|
+
}
|
|
3084
|
+
} catch {
|
|
3085
|
+
}
|
|
3086
|
+
}
|
|
3087
|
+
trackPageview() {
|
|
3088
|
+
if (!this.hasTrackedPageview) {
|
|
3089
|
+
this.log("pageview");
|
|
3090
|
+
this.hasTrackedPageview = true;
|
|
3091
|
+
}
|
|
3092
|
+
}
|
|
3093
|
+
setupRouteChangeListener() {
|
|
3094
|
+
const originalPushState = history.pushState;
|
|
3095
|
+
const originalReplaceState = history.replaceState;
|
|
3096
|
+
history.pushState = (...args) => {
|
|
3097
|
+
originalPushState.apply(history, args);
|
|
3098
|
+
this.log("pageview");
|
|
3099
|
+
};
|
|
3100
|
+
history.replaceState = (...args) => {
|
|
3101
|
+
originalReplaceState.apply(history, args);
|
|
3102
|
+
this.log("pageview");
|
|
3103
|
+
};
|
|
3104
|
+
window.addEventListener("popstate", () => {
|
|
3105
|
+
this.log("pageview");
|
|
3106
|
+
});
|
|
3107
|
+
}
|
|
3108
|
+
setupUnloadListener() {
|
|
3109
|
+
window.addEventListener("pagehide", () => {
|
|
3110
|
+
this.flush();
|
|
3111
|
+
});
|
|
3112
|
+
window.addEventListener("unload", () => {
|
|
3113
|
+
this.flush();
|
|
3114
|
+
});
|
|
3115
|
+
}
|
|
3116
|
+
captureUTMParams() {
|
|
3117
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
3118
|
+
this.utmParams = {
|
|
3119
|
+
utm_source: urlParams.get("utm_source"),
|
|
3120
|
+
utm_medium: urlParams.get("utm_medium"),
|
|
3121
|
+
utm_campaign: urlParams.get("utm_campaign"),
|
|
3122
|
+
utm_content: urlParams.get("utm_content"),
|
|
3123
|
+
utm_term: urlParams.get("utm_term")
|
|
3124
|
+
};
|
|
3125
|
+
}
|
|
3126
|
+
detectChannel() {
|
|
3127
|
+
const referrer = document.referrer;
|
|
3128
|
+
const utmMedium = this.utmParams.utm_medium;
|
|
3129
|
+
this.utmParams.utm_source;
|
|
3130
|
+
if (utmMedium) {
|
|
3131
|
+
if (utmMedium === "cpc" || utmMedium === "ppc") return "Paid Search";
|
|
3132
|
+
if (utmMedium === "email") return "Email";
|
|
3133
|
+
if (utmMedium === "social") return "Social";
|
|
3134
|
+
if (utmMedium === "referral") return "Referral";
|
|
3135
|
+
if (utmMedium === "display") return "Display";
|
|
3136
|
+
if (utmMedium === "affiliate") return "Affiliate";
|
|
3137
|
+
}
|
|
3138
|
+
if (!referrer) return "Direct";
|
|
3139
|
+
try {
|
|
3140
|
+
const referrerUrl = new URL(referrer);
|
|
3141
|
+
const referrerDomain = referrerUrl.hostname.toLowerCase();
|
|
3142
|
+
if (/google\.|bing\.|yahoo\.|duckduckgo\.|baidu\.|yandex\./.test(referrerDomain)) {
|
|
3143
|
+
return "Organic Search";
|
|
3144
|
+
}
|
|
3145
|
+
if (/facebook\.|twitter\.|linkedin\.|instagram\.|youtube\.|tiktok\.|reddit\./.test(referrerDomain)) {
|
|
3146
|
+
return "Social";
|
|
3147
|
+
}
|
|
3148
|
+
if (/mail\.|outlook\.|gmail\./.test(referrerDomain)) {
|
|
3149
|
+
return "Email";
|
|
3150
|
+
}
|
|
3151
|
+
return "Referral";
|
|
3152
|
+
} catch {
|
|
3153
|
+
return "Direct";
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
};
|
|
3157
|
+
|
|
2883
3158
|
// src/client.ts
|
|
2884
3159
|
var BlinkClientImpl = class {
|
|
2885
3160
|
auth;
|
|
@@ -2889,6 +3164,7 @@ var BlinkClientImpl = class {
|
|
|
2889
3164
|
data;
|
|
2890
3165
|
realtime;
|
|
2891
3166
|
notifications;
|
|
3167
|
+
analytics;
|
|
2892
3168
|
httpClient;
|
|
2893
3169
|
constructor(config) {
|
|
2894
3170
|
this.auth = new BlinkAuth(config);
|
|
@@ -2903,6 +3179,16 @@ var BlinkClientImpl = class {
|
|
|
2903
3179
|
this.data = new BlinkDataImpl(this.httpClient, config.projectId);
|
|
2904
3180
|
this.realtime = new BlinkRealtimeImpl(this.httpClient, config.projectId);
|
|
2905
3181
|
this.notifications = new BlinkNotificationsImpl(this.httpClient);
|
|
3182
|
+
this.analytics = new BlinkAnalyticsImpl(this.httpClient, config.projectId);
|
|
3183
|
+
this.auth.onAuthStateChanged((state) => {
|
|
3184
|
+
if (state.isAuthenticated && state.user) {
|
|
3185
|
+
this.analytics.setUserId(state.user.id);
|
|
3186
|
+
this.analytics.setUserEmail(state.user.email);
|
|
3187
|
+
} else {
|
|
3188
|
+
this.analytics.setUserId(null);
|
|
3189
|
+
this.analytics.setUserEmail(null);
|
|
3190
|
+
}
|
|
3191
|
+
});
|
|
2906
3192
|
}
|
|
2907
3193
|
};
|
|
2908
3194
|
function createClient(config) {
|
|
@@ -2917,6 +3203,7 @@ function createClient(config) {
|
|
|
2917
3203
|
}
|
|
2918
3204
|
|
|
2919
3205
|
exports.BlinkAIImpl = BlinkAIImpl;
|
|
3206
|
+
exports.BlinkAnalyticsImpl = BlinkAnalyticsImpl;
|
|
2920
3207
|
exports.BlinkDataImpl = BlinkDataImpl;
|
|
2921
3208
|
exports.BlinkDatabase = BlinkDatabase;
|
|
2922
3209
|
exports.BlinkRealtimeChannel = BlinkRealtimeChannel;
|
package/dist/index.mjs
CHANGED
|
@@ -2878,6 +2878,281 @@ var BlinkNotificationsImpl = class {
|
|
|
2878
2878
|
}
|
|
2879
2879
|
};
|
|
2880
2880
|
|
|
2881
|
+
// src/analytics.ts
|
|
2882
|
+
var SESSION_DURATION = 30 * 60 * 1e3;
|
|
2883
|
+
var MAX_BATCH_SIZE = 10;
|
|
2884
|
+
var BATCH_TIMEOUT = 3e3;
|
|
2885
|
+
var MAX_STRING_LENGTH = 256;
|
|
2886
|
+
var STORAGE_KEY_QUEUE = "blinkAnalyticsQueue";
|
|
2887
|
+
var STORAGE_KEY_SESSION = "blinkAnalyticsSession";
|
|
2888
|
+
var BlinkAnalyticsImpl = class {
|
|
2889
|
+
httpClient;
|
|
2890
|
+
projectId;
|
|
2891
|
+
queue = [];
|
|
2892
|
+
timer = null;
|
|
2893
|
+
enabled = true;
|
|
2894
|
+
userId = null;
|
|
2895
|
+
userEmail = null;
|
|
2896
|
+
hasTrackedPageview = false;
|
|
2897
|
+
entryPage = null;
|
|
2898
|
+
utmParams = {};
|
|
2899
|
+
constructor(httpClient, projectId) {
|
|
2900
|
+
this.httpClient = httpClient;
|
|
2901
|
+
this.projectId = projectId;
|
|
2902
|
+
if (typeof window === "undefined") {
|
|
2903
|
+
return;
|
|
2904
|
+
}
|
|
2905
|
+
if (navigator.doNotTrack === "1") {
|
|
2906
|
+
this.enabled = false;
|
|
2907
|
+
return;
|
|
2908
|
+
}
|
|
2909
|
+
this.entryPage = window.location.pathname;
|
|
2910
|
+
this.captureUTMParams();
|
|
2911
|
+
this.loadQueue();
|
|
2912
|
+
this.trackPageview();
|
|
2913
|
+
this.setupRouteChangeListener();
|
|
2914
|
+
this.setupUnloadListener();
|
|
2915
|
+
}
|
|
2916
|
+
/**
|
|
2917
|
+
* Log a custom analytics event
|
|
2918
|
+
*/
|
|
2919
|
+
log(eventName, data = {}) {
|
|
2920
|
+
if (!this.enabled || typeof window === "undefined") {
|
|
2921
|
+
return;
|
|
2922
|
+
}
|
|
2923
|
+
const event = this.buildEvent(eventName, data);
|
|
2924
|
+
this.enqueue(event);
|
|
2925
|
+
}
|
|
2926
|
+
/**
|
|
2927
|
+
* Disable analytics tracking
|
|
2928
|
+
*/
|
|
2929
|
+
disable() {
|
|
2930
|
+
this.enabled = false;
|
|
2931
|
+
this.clearTimer();
|
|
2932
|
+
}
|
|
2933
|
+
/**
|
|
2934
|
+
* Enable analytics tracking
|
|
2935
|
+
*/
|
|
2936
|
+
enable() {
|
|
2937
|
+
this.enabled = true;
|
|
2938
|
+
}
|
|
2939
|
+
/**
|
|
2940
|
+
* Check if analytics is enabled
|
|
2941
|
+
*/
|
|
2942
|
+
isEnabled() {
|
|
2943
|
+
return this.enabled;
|
|
2944
|
+
}
|
|
2945
|
+
/**
|
|
2946
|
+
* Set the user ID for analytics events
|
|
2947
|
+
*/
|
|
2948
|
+
setUserId(userId) {
|
|
2949
|
+
this.userId = userId;
|
|
2950
|
+
}
|
|
2951
|
+
/**
|
|
2952
|
+
* Set the user email for analytics events
|
|
2953
|
+
*/
|
|
2954
|
+
setUserEmail(email) {
|
|
2955
|
+
this.userEmail = email;
|
|
2956
|
+
}
|
|
2957
|
+
// Private methods
|
|
2958
|
+
buildEvent(type, data = {}) {
|
|
2959
|
+
const sessionId = this.getOrCreateSessionId();
|
|
2960
|
+
const channel = this.detectChannel();
|
|
2961
|
+
return {
|
|
2962
|
+
type,
|
|
2963
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2964
|
+
project_id: this.projectId,
|
|
2965
|
+
user_id: this.userId,
|
|
2966
|
+
user_email: this.userEmail,
|
|
2967
|
+
session_id: sessionId,
|
|
2968
|
+
pathname: window.location.pathname,
|
|
2969
|
+
referrer: document.referrer || null,
|
|
2970
|
+
screen_width: window.innerWidth,
|
|
2971
|
+
channel,
|
|
2972
|
+
utm_source: this.utmParams.utm_source || null,
|
|
2973
|
+
utm_medium: this.utmParams.utm_medium || null,
|
|
2974
|
+
utm_campaign: this.utmParams.utm_campaign || null,
|
|
2975
|
+
utm_content: this.utmParams.utm_content || null,
|
|
2976
|
+
utm_term: this.utmParams.utm_term || null,
|
|
2977
|
+
entry_page: this.entryPage,
|
|
2978
|
+
exit_page: window.location.pathname,
|
|
2979
|
+
// Current page is potential exit
|
|
2980
|
+
...this.sanitizeData(data)
|
|
2981
|
+
};
|
|
2982
|
+
}
|
|
2983
|
+
sanitizeData(data) {
|
|
2984
|
+
if (typeof data === "string") {
|
|
2985
|
+
return data.length > MAX_STRING_LENGTH ? data.slice(0, MAX_STRING_LENGTH - 3) + "..." : data;
|
|
2986
|
+
}
|
|
2987
|
+
if (typeof data === "object" && data !== null) {
|
|
2988
|
+
const result = {};
|
|
2989
|
+
for (const key in data) {
|
|
2990
|
+
result[key] = this.sanitizeData(data[key]);
|
|
2991
|
+
}
|
|
2992
|
+
return result;
|
|
2993
|
+
}
|
|
2994
|
+
return data;
|
|
2995
|
+
}
|
|
2996
|
+
enqueue(event) {
|
|
2997
|
+
this.queue.push(event);
|
|
2998
|
+
this.persistQueue();
|
|
2999
|
+
if (this.queue.length >= MAX_BATCH_SIZE) {
|
|
3000
|
+
this.flush();
|
|
3001
|
+
} else if (!this.timer) {
|
|
3002
|
+
this.timer = setTimeout(() => this.flush(), BATCH_TIMEOUT);
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
3005
|
+
async flush() {
|
|
3006
|
+
this.clearTimer();
|
|
3007
|
+
if (this.queue.length === 0) {
|
|
3008
|
+
return;
|
|
3009
|
+
}
|
|
3010
|
+
const events = this.queue.slice(0, MAX_BATCH_SIZE);
|
|
3011
|
+
this.queue = this.queue.slice(MAX_BATCH_SIZE);
|
|
3012
|
+
this.persistQueue();
|
|
3013
|
+
try {
|
|
3014
|
+
await this.httpClient.post(`/api/analytics/${this.projectId}/log`, { events });
|
|
3015
|
+
} catch (error) {
|
|
3016
|
+
this.queue = [...events, ...this.queue];
|
|
3017
|
+
this.persistQueue();
|
|
3018
|
+
console.error("Failed to send analytics events:", error);
|
|
3019
|
+
}
|
|
3020
|
+
if (this.queue.length > 0) {
|
|
3021
|
+
this.timer = setTimeout(() => this.flush(), BATCH_TIMEOUT);
|
|
3022
|
+
}
|
|
3023
|
+
}
|
|
3024
|
+
clearTimer() {
|
|
3025
|
+
if (this.timer) {
|
|
3026
|
+
clearTimeout(this.timer);
|
|
3027
|
+
this.timer = null;
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
getOrCreateSessionId() {
|
|
3031
|
+
try {
|
|
3032
|
+
const stored = localStorage.getItem(STORAGE_KEY_SESSION);
|
|
3033
|
+
if (stored) {
|
|
3034
|
+
const session = JSON.parse(stored);
|
|
3035
|
+
const now = Date.now();
|
|
3036
|
+
if (now - session.lastActivityAt > SESSION_DURATION) {
|
|
3037
|
+
return this.createNewSession();
|
|
3038
|
+
}
|
|
3039
|
+
session.lastActivityAt = now;
|
|
3040
|
+
localStorage.setItem(STORAGE_KEY_SESSION, JSON.stringify(session));
|
|
3041
|
+
return session.id;
|
|
3042
|
+
}
|
|
3043
|
+
return this.createNewSession();
|
|
3044
|
+
} catch {
|
|
3045
|
+
return null;
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
createNewSession() {
|
|
3049
|
+
const now = Date.now();
|
|
3050
|
+
const randomId = Math.random().toString(36).substring(2, 10);
|
|
3051
|
+
const session = {
|
|
3052
|
+
id: `sess_${now}_${randomId}`,
|
|
3053
|
+
startedAt: now,
|
|
3054
|
+
lastActivityAt: now
|
|
3055
|
+
};
|
|
3056
|
+
try {
|
|
3057
|
+
localStorage.setItem(STORAGE_KEY_SESSION, JSON.stringify(session));
|
|
3058
|
+
} catch {
|
|
3059
|
+
}
|
|
3060
|
+
return session.id;
|
|
3061
|
+
}
|
|
3062
|
+
loadQueue() {
|
|
3063
|
+
try {
|
|
3064
|
+
const stored = localStorage.getItem(STORAGE_KEY_QUEUE);
|
|
3065
|
+
if (stored) {
|
|
3066
|
+
this.queue = JSON.parse(stored);
|
|
3067
|
+
if (this.queue.length > 0) {
|
|
3068
|
+
this.timer = setTimeout(() => this.flush(), BATCH_TIMEOUT);
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
} catch {
|
|
3072
|
+
this.queue = [];
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
persistQueue() {
|
|
3076
|
+
try {
|
|
3077
|
+
if (this.queue.length === 0) {
|
|
3078
|
+
localStorage.removeItem(STORAGE_KEY_QUEUE);
|
|
3079
|
+
} else {
|
|
3080
|
+
localStorage.setItem(STORAGE_KEY_QUEUE, JSON.stringify(this.queue));
|
|
3081
|
+
}
|
|
3082
|
+
} catch {
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
trackPageview() {
|
|
3086
|
+
if (!this.hasTrackedPageview) {
|
|
3087
|
+
this.log("pageview");
|
|
3088
|
+
this.hasTrackedPageview = true;
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
3091
|
+
setupRouteChangeListener() {
|
|
3092
|
+
const originalPushState = history.pushState;
|
|
3093
|
+
const originalReplaceState = history.replaceState;
|
|
3094
|
+
history.pushState = (...args) => {
|
|
3095
|
+
originalPushState.apply(history, args);
|
|
3096
|
+
this.log("pageview");
|
|
3097
|
+
};
|
|
3098
|
+
history.replaceState = (...args) => {
|
|
3099
|
+
originalReplaceState.apply(history, args);
|
|
3100
|
+
this.log("pageview");
|
|
3101
|
+
};
|
|
3102
|
+
window.addEventListener("popstate", () => {
|
|
3103
|
+
this.log("pageview");
|
|
3104
|
+
});
|
|
3105
|
+
}
|
|
3106
|
+
setupUnloadListener() {
|
|
3107
|
+
window.addEventListener("pagehide", () => {
|
|
3108
|
+
this.flush();
|
|
3109
|
+
});
|
|
3110
|
+
window.addEventListener("unload", () => {
|
|
3111
|
+
this.flush();
|
|
3112
|
+
});
|
|
3113
|
+
}
|
|
3114
|
+
captureUTMParams() {
|
|
3115
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
3116
|
+
this.utmParams = {
|
|
3117
|
+
utm_source: urlParams.get("utm_source"),
|
|
3118
|
+
utm_medium: urlParams.get("utm_medium"),
|
|
3119
|
+
utm_campaign: urlParams.get("utm_campaign"),
|
|
3120
|
+
utm_content: urlParams.get("utm_content"),
|
|
3121
|
+
utm_term: urlParams.get("utm_term")
|
|
3122
|
+
};
|
|
3123
|
+
}
|
|
3124
|
+
detectChannel() {
|
|
3125
|
+
const referrer = document.referrer;
|
|
3126
|
+
const utmMedium = this.utmParams.utm_medium;
|
|
3127
|
+
this.utmParams.utm_source;
|
|
3128
|
+
if (utmMedium) {
|
|
3129
|
+
if (utmMedium === "cpc" || utmMedium === "ppc") return "Paid Search";
|
|
3130
|
+
if (utmMedium === "email") return "Email";
|
|
3131
|
+
if (utmMedium === "social") return "Social";
|
|
3132
|
+
if (utmMedium === "referral") return "Referral";
|
|
3133
|
+
if (utmMedium === "display") return "Display";
|
|
3134
|
+
if (utmMedium === "affiliate") return "Affiliate";
|
|
3135
|
+
}
|
|
3136
|
+
if (!referrer) return "Direct";
|
|
3137
|
+
try {
|
|
3138
|
+
const referrerUrl = new URL(referrer);
|
|
3139
|
+
const referrerDomain = referrerUrl.hostname.toLowerCase();
|
|
3140
|
+
if (/google\.|bing\.|yahoo\.|duckduckgo\.|baidu\.|yandex\./.test(referrerDomain)) {
|
|
3141
|
+
return "Organic Search";
|
|
3142
|
+
}
|
|
3143
|
+
if (/facebook\.|twitter\.|linkedin\.|instagram\.|youtube\.|tiktok\.|reddit\./.test(referrerDomain)) {
|
|
3144
|
+
return "Social";
|
|
3145
|
+
}
|
|
3146
|
+
if (/mail\.|outlook\.|gmail\./.test(referrerDomain)) {
|
|
3147
|
+
return "Email";
|
|
3148
|
+
}
|
|
3149
|
+
return "Referral";
|
|
3150
|
+
} catch {
|
|
3151
|
+
return "Direct";
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
};
|
|
3155
|
+
|
|
2881
3156
|
// src/client.ts
|
|
2882
3157
|
var BlinkClientImpl = class {
|
|
2883
3158
|
auth;
|
|
@@ -2887,6 +3162,7 @@ var BlinkClientImpl = class {
|
|
|
2887
3162
|
data;
|
|
2888
3163
|
realtime;
|
|
2889
3164
|
notifications;
|
|
3165
|
+
analytics;
|
|
2890
3166
|
httpClient;
|
|
2891
3167
|
constructor(config) {
|
|
2892
3168
|
this.auth = new BlinkAuth(config);
|
|
@@ -2901,6 +3177,16 @@ var BlinkClientImpl = class {
|
|
|
2901
3177
|
this.data = new BlinkDataImpl(this.httpClient, config.projectId);
|
|
2902
3178
|
this.realtime = new BlinkRealtimeImpl(this.httpClient, config.projectId);
|
|
2903
3179
|
this.notifications = new BlinkNotificationsImpl(this.httpClient);
|
|
3180
|
+
this.analytics = new BlinkAnalyticsImpl(this.httpClient, config.projectId);
|
|
3181
|
+
this.auth.onAuthStateChanged((state) => {
|
|
3182
|
+
if (state.isAuthenticated && state.user) {
|
|
3183
|
+
this.analytics.setUserId(state.user.id);
|
|
3184
|
+
this.analytics.setUserEmail(state.user.email);
|
|
3185
|
+
} else {
|
|
3186
|
+
this.analytics.setUserId(null);
|
|
3187
|
+
this.analytics.setUserEmail(null);
|
|
3188
|
+
}
|
|
3189
|
+
});
|
|
2904
3190
|
}
|
|
2905
3191
|
};
|
|
2906
3192
|
function createClient(config) {
|
|
@@ -2914,6 +3200,6 @@ function createClient(config) {
|
|
|
2914
3200
|
return new BlinkClientImpl(clientConfig);
|
|
2915
3201
|
}
|
|
2916
3202
|
|
|
2917
|
-
export { BlinkAIImpl, BlinkDataImpl, BlinkDatabase, BlinkRealtimeChannel, BlinkRealtimeImpl, BlinkStorageImpl, BlinkTable, createClient };
|
|
3203
|
+
export { BlinkAIImpl, BlinkAnalyticsImpl, BlinkDataImpl, BlinkDatabase, BlinkRealtimeChannel, BlinkRealtimeImpl, BlinkStorageImpl, BlinkTable, createClient };
|
|
2918
3204
|
//# sourceMappingURL=index.mjs.map
|
|
2919
3205
|
//# sourceMappingURL=index.mjs.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blinkdotnew/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Blink TypeScript SDK for client-side applications - Zero-boilerplate CRUD + auth + AI + notifications for modern SaaS/AI apps",
|
|
3
|
+
"version": "0.9.0",
|
|
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",
|
|
7
7
|
"sdk",
|