krisspy-sdk 0.3.1 → 0.4.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 +110 -5
- package/dist/index.d.ts +110 -5
- package/dist/index.js +209 -1
- package/dist/index.mjs +208 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -6,8 +6,12 @@ interface KrisspyClientOptions {
|
|
|
6
6
|
url?: string;
|
|
7
7
|
/** Backend ID for this client */
|
|
8
8
|
backendId: string;
|
|
9
|
-
/**
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Public API key for the backend (required)
|
|
11
|
+
* This key can be safely exposed in frontend code.
|
|
12
|
+
* Get it from your backend settings in the Krisspy dashboard.
|
|
13
|
+
*/
|
|
14
|
+
anonKey: string;
|
|
11
15
|
/** Custom headers to include in all requests */
|
|
12
16
|
headers?: Record<string, string>;
|
|
13
17
|
/** Enable debug logging */
|
|
@@ -695,6 +699,89 @@ declare class KrisspyRealtime {
|
|
|
695
699
|
private log;
|
|
696
700
|
}
|
|
697
701
|
|
|
702
|
+
/**
|
|
703
|
+
* Krisspy Analytics - Lightweight event tracking module
|
|
704
|
+
*
|
|
705
|
+
* Tracks page views, sessions, custom events. Sends batched events
|
|
706
|
+
* to the analytics ingest endpoint. Works with SPAs (intercepts pushState).
|
|
707
|
+
*
|
|
708
|
+
* @example
|
|
709
|
+
* const krisspy = createClient({ backendId: '...', anonKey: '...' })
|
|
710
|
+
* krisspy.analytics.init({ autoTrackPageViews: true })
|
|
711
|
+
* krisspy.analytics.track('button_click', { label: 'signup' })
|
|
712
|
+
*/
|
|
713
|
+
|
|
714
|
+
interface AnalyticsInitOptions {
|
|
715
|
+
/** Auto-track page views on init + navigation (default: true) */
|
|
716
|
+
autoTrackPageViews?: boolean;
|
|
717
|
+
/** Auto-track SPA navigation via pushState/popstate (default: true) */
|
|
718
|
+
autoTrackNavigation?: boolean;
|
|
719
|
+
/** Flush interval in ms (default: 5000) */
|
|
720
|
+
flushInterval?: number;
|
|
721
|
+
/** Enable debug logging (default: false) */
|
|
722
|
+
debug?: boolean;
|
|
723
|
+
}
|
|
724
|
+
interface AnalyticsEvent {
|
|
725
|
+
eventName: string;
|
|
726
|
+
sessionId: string;
|
|
727
|
+
userId?: string;
|
|
728
|
+
properties?: Record<string, any>;
|
|
729
|
+
timestamp: string;
|
|
730
|
+
}
|
|
731
|
+
declare class KrisspyAnalytics {
|
|
732
|
+
private http;
|
|
733
|
+
private backendId;
|
|
734
|
+
private queue;
|
|
735
|
+
private sessionId;
|
|
736
|
+
private userId;
|
|
737
|
+
private userTraits;
|
|
738
|
+
private initialized;
|
|
739
|
+
private flushTimer;
|
|
740
|
+
private options;
|
|
741
|
+
private originalPushState;
|
|
742
|
+
private popstateHandler;
|
|
743
|
+
private unloadHandler;
|
|
744
|
+
constructor(http: HttpClient, backendId: string);
|
|
745
|
+
/**
|
|
746
|
+
* Initialize analytics tracking
|
|
747
|
+
*
|
|
748
|
+
* @example
|
|
749
|
+
* krisspy.analytics.init()
|
|
750
|
+
* krisspy.analytics.init({ autoTrackPageViews: true, flushInterval: 3000 })
|
|
751
|
+
*/
|
|
752
|
+
init(options?: AnalyticsInitOptions): void;
|
|
753
|
+
/**
|
|
754
|
+
* Track a custom event
|
|
755
|
+
*
|
|
756
|
+
* @example
|
|
757
|
+
* krisspy.analytics.track('button_click', { label: 'signup', variant: 'blue' })
|
|
758
|
+
* krisspy.analytics.track('purchase', { amount: 29.99, plan: 'pro' })
|
|
759
|
+
*/
|
|
760
|
+
track(eventName: string, properties?: Record<string, any>): void;
|
|
761
|
+
/**
|
|
762
|
+
* Identify a user (attach userId + traits to all future events)
|
|
763
|
+
*
|
|
764
|
+
* @example
|
|
765
|
+
* krisspy.analytics.identify('user_123', { name: 'John', plan: 'pro' })
|
|
766
|
+
*/
|
|
767
|
+
identify(userId: string, traits?: Record<string, any>): void;
|
|
768
|
+
/**
|
|
769
|
+
* Flush event queue to the server (async)
|
|
770
|
+
*/
|
|
771
|
+
flush(): Promise<void>;
|
|
772
|
+
/**
|
|
773
|
+
* Synchronous flush using sendBeacon (for page unload)
|
|
774
|
+
*/
|
|
775
|
+
private flushSync;
|
|
776
|
+
/**
|
|
777
|
+
* Stop tracking and cleanup all listeners/timers
|
|
778
|
+
*/
|
|
779
|
+
destroy(): void;
|
|
780
|
+
private getOrCreateSessionId;
|
|
781
|
+
private getIngestUrl;
|
|
782
|
+
private setupNavigationTracking;
|
|
783
|
+
}
|
|
784
|
+
|
|
698
785
|
/**
|
|
699
786
|
* Query Builder - Supabase-style fluent API for database queries
|
|
700
787
|
*/
|
|
@@ -846,6 +933,7 @@ declare class KrisspyClient {
|
|
|
846
933
|
private _auth;
|
|
847
934
|
private _storage;
|
|
848
935
|
private _realtime;
|
|
936
|
+
private _analytics;
|
|
849
937
|
private useRLS;
|
|
850
938
|
private debug;
|
|
851
939
|
constructor(options: KrisspyClientOptions);
|
|
@@ -894,6 +982,23 @@ declare class KrisspyClient {
|
|
|
894
982
|
* const { error } = await krisspy.storage.from('uploads').remove(['old.jpg'])
|
|
895
983
|
*/
|
|
896
984
|
get storage(): KrisspyStorage;
|
|
985
|
+
/**
|
|
986
|
+
* Analytics module for event tracking
|
|
987
|
+
*
|
|
988
|
+
* @example
|
|
989
|
+
* // Initialize tracking
|
|
990
|
+
* krisspy.analytics.init()
|
|
991
|
+
*
|
|
992
|
+
* // Track custom events
|
|
993
|
+
* krisspy.analytics.track('button_click', { label: 'signup' })
|
|
994
|
+
*
|
|
995
|
+
* // Identify a user
|
|
996
|
+
* krisspy.analytics.identify('user_123', { plan: 'pro' })
|
|
997
|
+
*
|
|
998
|
+
* // Cleanup
|
|
999
|
+
* krisspy.analytics.destroy()
|
|
1000
|
+
*/
|
|
1001
|
+
get analytics(): KrisspyAnalytics;
|
|
897
1002
|
/**
|
|
898
1003
|
* Create a realtime channel for subscribing to database changes
|
|
899
1004
|
*
|
|
@@ -1029,7 +1134,7 @@ declare class KrisspyClient {
|
|
|
1029
1134
|
*
|
|
1030
1135
|
* const krisspy = createClient({
|
|
1031
1136
|
* backendId: 'your-backend-id',
|
|
1032
|
-
*
|
|
1137
|
+
* anonKey: 'your-anon-key', // from backend settings
|
|
1033
1138
|
* })
|
|
1034
1139
|
*
|
|
1035
1140
|
* // Auth
|
|
@@ -1071,10 +1176,10 @@ declare class KrisspyClient {
|
|
|
1071
1176
|
* @example
|
|
1072
1177
|
* const krisspy = createClient({
|
|
1073
1178
|
* backendId: 'abc123',
|
|
1074
|
-
*
|
|
1179
|
+
* anonKey: 'your-anon-key',
|
|
1075
1180
|
* url: 'https://api.krisspy.ai', // optional
|
|
1076
1181
|
* })
|
|
1077
1182
|
*/
|
|
1078
1183
|
declare function createClient(options: KrisspyClientOptions): KrisspyClient;
|
|
1079
1184
|
|
|
1080
|
-
export { type AuthChangeEvent, type AuthResponse, type ChannelState, type FileObject, type FileUploadOptions, type Filter, type FilterOperator, type FunctionInvokeOptions, type FunctionResponse, HttpClient, KrisspyAuth, KrisspyClient, type KrisspyClientOptions, type KrisspyError, KrisspyRealtime, KrisspyStorage, type MutationResponse, type OAuthProvider, type OrderBy, type PostgresChangesConfig, QueryBuilder, type QueryOptions, type QueryResponse, RealtimeChannel, type RealtimeEvent, type RealtimePayload, type Session, type SignInCredentials, type SignUpCredentials, type SingleResponse, StorageBucket, type UploadAndLinkOptions, type UploadAndLinkResponse, type User, createClient };
|
|
1185
|
+
export { type AnalyticsEvent, type AnalyticsInitOptions, type AuthChangeEvent, type AuthResponse, type ChannelState, type FileObject, type FileUploadOptions, type Filter, type FilterOperator, type FunctionInvokeOptions, type FunctionResponse, HttpClient, KrisspyAnalytics, KrisspyAuth, KrisspyClient, type KrisspyClientOptions, type KrisspyError, KrisspyRealtime, KrisspyStorage, type MutationResponse, type OAuthProvider, type OrderBy, type PostgresChangesConfig, QueryBuilder, type QueryOptions, type QueryResponse, RealtimeChannel, type RealtimeEvent, type RealtimePayload, type Session, type SignInCredentials, type SignUpCredentials, type SingleResponse, StorageBucket, type UploadAndLinkOptions, type UploadAndLinkResponse, type User, createClient };
|
package/dist/index.d.ts
CHANGED
|
@@ -6,8 +6,12 @@ interface KrisspyClientOptions {
|
|
|
6
6
|
url?: string;
|
|
7
7
|
/** Backend ID for this client */
|
|
8
8
|
backendId: string;
|
|
9
|
-
/**
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Public API key for the backend (required)
|
|
11
|
+
* This key can be safely exposed in frontend code.
|
|
12
|
+
* Get it from your backend settings in the Krisspy dashboard.
|
|
13
|
+
*/
|
|
14
|
+
anonKey: string;
|
|
11
15
|
/** Custom headers to include in all requests */
|
|
12
16
|
headers?: Record<string, string>;
|
|
13
17
|
/** Enable debug logging */
|
|
@@ -695,6 +699,89 @@ declare class KrisspyRealtime {
|
|
|
695
699
|
private log;
|
|
696
700
|
}
|
|
697
701
|
|
|
702
|
+
/**
|
|
703
|
+
* Krisspy Analytics - Lightweight event tracking module
|
|
704
|
+
*
|
|
705
|
+
* Tracks page views, sessions, custom events. Sends batched events
|
|
706
|
+
* to the analytics ingest endpoint. Works with SPAs (intercepts pushState).
|
|
707
|
+
*
|
|
708
|
+
* @example
|
|
709
|
+
* const krisspy = createClient({ backendId: '...', anonKey: '...' })
|
|
710
|
+
* krisspy.analytics.init({ autoTrackPageViews: true })
|
|
711
|
+
* krisspy.analytics.track('button_click', { label: 'signup' })
|
|
712
|
+
*/
|
|
713
|
+
|
|
714
|
+
interface AnalyticsInitOptions {
|
|
715
|
+
/** Auto-track page views on init + navigation (default: true) */
|
|
716
|
+
autoTrackPageViews?: boolean;
|
|
717
|
+
/** Auto-track SPA navigation via pushState/popstate (default: true) */
|
|
718
|
+
autoTrackNavigation?: boolean;
|
|
719
|
+
/** Flush interval in ms (default: 5000) */
|
|
720
|
+
flushInterval?: number;
|
|
721
|
+
/** Enable debug logging (default: false) */
|
|
722
|
+
debug?: boolean;
|
|
723
|
+
}
|
|
724
|
+
interface AnalyticsEvent {
|
|
725
|
+
eventName: string;
|
|
726
|
+
sessionId: string;
|
|
727
|
+
userId?: string;
|
|
728
|
+
properties?: Record<string, any>;
|
|
729
|
+
timestamp: string;
|
|
730
|
+
}
|
|
731
|
+
declare class KrisspyAnalytics {
|
|
732
|
+
private http;
|
|
733
|
+
private backendId;
|
|
734
|
+
private queue;
|
|
735
|
+
private sessionId;
|
|
736
|
+
private userId;
|
|
737
|
+
private userTraits;
|
|
738
|
+
private initialized;
|
|
739
|
+
private flushTimer;
|
|
740
|
+
private options;
|
|
741
|
+
private originalPushState;
|
|
742
|
+
private popstateHandler;
|
|
743
|
+
private unloadHandler;
|
|
744
|
+
constructor(http: HttpClient, backendId: string);
|
|
745
|
+
/**
|
|
746
|
+
* Initialize analytics tracking
|
|
747
|
+
*
|
|
748
|
+
* @example
|
|
749
|
+
* krisspy.analytics.init()
|
|
750
|
+
* krisspy.analytics.init({ autoTrackPageViews: true, flushInterval: 3000 })
|
|
751
|
+
*/
|
|
752
|
+
init(options?: AnalyticsInitOptions): void;
|
|
753
|
+
/**
|
|
754
|
+
* Track a custom event
|
|
755
|
+
*
|
|
756
|
+
* @example
|
|
757
|
+
* krisspy.analytics.track('button_click', { label: 'signup', variant: 'blue' })
|
|
758
|
+
* krisspy.analytics.track('purchase', { amount: 29.99, plan: 'pro' })
|
|
759
|
+
*/
|
|
760
|
+
track(eventName: string, properties?: Record<string, any>): void;
|
|
761
|
+
/**
|
|
762
|
+
* Identify a user (attach userId + traits to all future events)
|
|
763
|
+
*
|
|
764
|
+
* @example
|
|
765
|
+
* krisspy.analytics.identify('user_123', { name: 'John', plan: 'pro' })
|
|
766
|
+
*/
|
|
767
|
+
identify(userId: string, traits?: Record<string, any>): void;
|
|
768
|
+
/**
|
|
769
|
+
* Flush event queue to the server (async)
|
|
770
|
+
*/
|
|
771
|
+
flush(): Promise<void>;
|
|
772
|
+
/**
|
|
773
|
+
* Synchronous flush using sendBeacon (for page unload)
|
|
774
|
+
*/
|
|
775
|
+
private flushSync;
|
|
776
|
+
/**
|
|
777
|
+
* Stop tracking and cleanup all listeners/timers
|
|
778
|
+
*/
|
|
779
|
+
destroy(): void;
|
|
780
|
+
private getOrCreateSessionId;
|
|
781
|
+
private getIngestUrl;
|
|
782
|
+
private setupNavigationTracking;
|
|
783
|
+
}
|
|
784
|
+
|
|
698
785
|
/**
|
|
699
786
|
* Query Builder - Supabase-style fluent API for database queries
|
|
700
787
|
*/
|
|
@@ -846,6 +933,7 @@ declare class KrisspyClient {
|
|
|
846
933
|
private _auth;
|
|
847
934
|
private _storage;
|
|
848
935
|
private _realtime;
|
|
936
|
+
private _analytics;
|
|
849
937
|
private useRLS;
|
|
850
938
|
private debug;
|
|
851
939
|
constructor(options: KrisspyClientOptions);
|
|
@@ -894,6 +982,23 @@ declare class KrisspyClient {
|
|
|
894
982
|
* const { error } = await krisspy.storage.from('uploads').remove(['old.jpg'])
|
|
895
983
|
*/
|
|
896
984
|
get storage(): KrisspyStorage;
|
|
985
|
+
/**
|
|
986
|
+
* Analytics module for event tracking
|
|
987
|
+
*
|
|
988
|
+
* @example
|
|
989
|
+
* // Initialize tracking
|
|
990
|
+
* krisspy.analytics.init()
|
|
991
|
+
*
|
|
992
|
+
* // Track custom events
|
|
993
|
+
* krisspy.analytics.track('button_click', { label: 'signup' })
|
|
994
|
+
*
|
|
995
|
+
* // Identify a user
|
|
996
|
+
* krisspy.analytics.identify('user_123', { plan: 'pro' })
|
|
997
|
+
*
|
|
998
|
+
* // Cleanup
|
|
999
|
+
* krisspy.analytics.destroy()
|
|
1000
|
+
*/
|
|
1001
|
+
get analytics(): KrisspyAnalytics;
|
|
897
1002
|
/**
|
|
898
1003
|
* Create a realtime channel for subscribing to database changes
|
|
899
1004
|
*
|
|
@@ -1029,7 +1134,7 @@ declare class KrisspyClient {
|
|
|
1029
1134
|
*
|
|
1030
1135
|
* const krisspy = createClient({
|
|
1031
1136
|
* backendId: 'your-backend-id',
|
|
1032
|
-
*
|
|
1137
|
+
* anonKey: 'your-anon-key', // from backend settings
|
|
1033
1138
|
* })
|
|
1034
1139
|
*
|
|
1035
1140
|
* // Auth
|
|
@@ -1071,10 +1176,10 @@ declare class KrisspyClient {
|
|
|
1071
1176
|
* @example
|
|
1072
1177
|
* const krisspy = createClient({
|
|
1073
1178
|
* backendId: 'abc123',
|
|
1074
|
-
*
|
|
1179
|
+
* anonKey: 'your-anon-key',
|
|
1075
1180
|
* url: 'https://api.krisspy.ai', // optional
|
|
1076
1181
|
* })
|
|
1077
1182
|
*/
|
|
1078
1183
|
declare function createClient(options: KrisspyClientOptions): KrisspyClient;
|
|
1079
1184
|
|
|
1080
|
-
export { type AuthChangeEvent, type AuthResponse, type ChannelState, type FileObject, type FileUploadOptions, type Filter, type FilterOperator, type FunctionInvokeOptions, type FunctionResponse, HttpClient, KrisspyAuth, KrisspyClient, type KrisspyClientOptions, type KrisspyError, KrisspyRealtime, KrisspyStorage, type MutationResponse, type OAuthProvider, type OrderBy, type PostgresChangesConfig, QueryBuilder, type QueryOptions, type QueryResponse, RealtimeChannel, type RealtimeEvent, type RealtimePayload, type Session, type SignInCredentials, type SignUpCredentials, type SingleResponse, StorageBucket, type UploadAndLinkOptions, type UploadAndLinkResponse, type User, createClient };
|
|
1185
|
+
export { type AnalyticsEvent, type AnalyticsInitOptions, type AuthChangeEvent, type AuthResponse, type ChannelState, type FileObject, type FileUploadOptions, type Filter, type FilterOperator, type FunctionInvokeOptions, type FunctionResponse, HttpClient, KrisspyAnalytics, KrisspyAuth, KrisspyClient, type KrisspyClientOptions, type KrisspyError, KrisspyRealtime, KrisspyStorage, type MutationResponse, type OAuthProvider, type OrderBy, type PostgresChangesConfig, QueryBuilder, type QueryOptions, type QueryResponse, RealtimeChannel, type RealtimeEvent, type RealtimePayload, type Session, type SignInCredentials, type SignUpCredentials, type SingleResponse, StorageBucket, type UploadAndLinkOptions, type UploadAndLinkResponse, type User, createClient };
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
HttpClient: () => HttpClient,
|
|
24
|
+
KrisspyAnalytics: () => KrisspyAnalytics,
|
|
24
25
|
KrisspyAuth: () => KrisspyAuth,
|
|
25
26
|
KrisspyClient: () => KrisspyClient,
|
|
26
27
|
KrisspyRealtime: () => KrisspyRealtime,
|
|
@@ -1144,6 +1145,192 @@ var KrisspyRealtime = class {
|
|
|
1144
1145
|
}
|
|
1145
1146
|
};
|
|
1146
1147
|
|
|
1148
|
+
// src/analytics.ts
|
|
1149
|
+
var KrisspyAnalytics = class {
|
|
1150
|
+
constructor(http, backendId) {
|
|
1151
|
+
this.queue = [];
|
|
1152
|
+
this.sessionId = null;
|
|
1153
|
+
this.userId = null;
|
|
1154
|
+
this.userTraits = {};
|
|
1155
|
+
this.initialized = false;
|
|
1156
|
+
this.flushTimer = null;
|
|
1157
|
+
this.options = {};
|
|
1158
|
+
this.originalPushState = null;
|
|
1159
|
+
this.popstateHandler = null;
|
|
1160
|
+
this.unloadHandler = null;
|
|
1161
|
+
this.http = http;
|
|
1162
|
+
this.backendId = backendId;
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* Initialize analytics tracking
|
|
1166
|
+
*
|
|
1167
|
+
* @example
|
|
1168
|
+
* krisspy.analytics.init()
|
|
1169
|
+
* krisspy.analytics.init({ autoTrackPageViews: true, flushInterval: 3000 })
|
|
1170
|
+
*/
|
|
1171
|
+
init(options) {
|
|
1172
|
+
if (this.initialized) return;
|
|
1173
|
+
if (typeof window === "undefined") return;
|
|
1174
|
+
this.options = {
|
|
1175
|
+
autoTrackPageViews: true,
|
|
1176
|
+
autoTrackNavigation: true,
|
|
1177
|
+
flushInterval: 5e3,
|
|
1178
|
+
debug: false,
|
|
1179
|
+
...options
|
|
1180
|
+
};
|
|
1181
|
+
this.sessionId = this.getOrCreateSessionId();
|
|
1182
|
+
this.initialized = true;
|
|
1183
|
+
if (this.options.autoTrackPageViews) {
|
|
1184
|
+
this.track("session_start", {});
|
|
1185
|
+
this.track("page_view", { url: location.href, referrer: document.referrer });
|
|
1186
|
+
}
|
|
1187
|
+
if (this.options.autoTrackNavigation) {
|
|
1188
|
+
this.setupNavigationTracking();
|
|
1189
|
+
}
|
|
1190
|
+
this.unloadHandler = () => {
|
|
1191
|
+
this.track("session_end", {});
|
|
1192
|
+
this.flushSync();
|
|
1193
|
+
};
|
|
1194
|
+
window.addEventListener("beforeunload", this.unloadHandler);
|
|
1195
|
+
this.flushTimer = setInterval(() => this.flush(), this.options.flushInterval);
|
|
1196
|
+
if (this.options.debug) {
|
|
1197
|
+
console.log("[Krisspy Analytics] Initialized", { backendId: this.backendId, sessionId: this.sessionId });
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1201
|
+
* Track a custom event
|
|
1202
|
+
*
|
|
1203
|
+
* @example
|
|
1204
|
+
* krisspy.analytics.track('button_click', { label: 'signup', variant: 'blue' })
|
|
1205
|
+
* krisspy.analytics.track('purchase', { amount: 29.99, plan: 'pro' })
|
|
1206
|
+
*/
|
|
1207
|
+
track(eventName, properties) {
|
|
1208
|
+
if (!this.initialized || typeof window === "undefined") return;
|
|
1209
|
+
const event = {
|
|
1210
|
+
eventName,
|
|
1211
|
+
sessionId: this.sessionId,
|
|
1212
|
+
userId: this.userId || void 0,
|
|
1213
|
+
properties: {
|
|
1214
|
+
...properties,
|
|
1215
|
+
...this.userId ? { _user_traits: this.userTraits } : {}
|
|
1216
|
+
},
|
|
1217
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1218
|
+
};
|
|
1219
|
+
this.queue.push(event);
|
|
1220
|
+
if (this.options.debug) {
|
|
1221
|
+
console.log("[Krisspy Analytics] Tracked:", eventName, properties);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
/**
|
|
1225
|
+
* Identify a user (attach userId + traits to all future events)
|
|
1226
|
+
*
|
|
1227
|
+
* @example
|
|
1228
|
+
* krisspy.analytics.identify('user_123', { name: 'John', plan: 'pro' })
|
|
1229
|
+
*/
|
|
1230
|
+
identify(userId, traits) {
|
|
1231
|
+
this.userId = userId;
|
|
1232
|
+
this.userTraits = traits || {};
|
|
1233
|
+
if (this.initialized) {
|
|
1234
|
+
this.track("identify", { userId, ...traits });
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
/**
|
|
1238
|
+
* Flush event queue to the server (async)
|
|
1239
|
+
*/
|
|
1240
|
+
async flush() {
|
|
1241
|
+
if (!this.queue.length) return;
|
|
1242
|
+
const events = this.queue.splice(0, 50);
|
|
1243
|
+
const payload = { appId: this.backendId, events };
|
|
1244
|
+
try {
|
|
1245
|
+
await this.http.post("/api/v1/analytics/events", payload);
|
|
1246
|
+
if (this.options.debug) {
|
|
1247
|
+
console.log(`[Krisspy Analytics] Flushed ${events.length} events`);
|
|
1248
|
+
}
|
|
1249
|
+
} catch {
|
|
1250
|
+
this.queue.unshift(...events);
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
/**
|
|
1254
|
+
* Synchronous flush using sendBeacon (for page unload)
|
|
1255
|
+
*/
|
|
1256
|
+
flushSync() {
|
|
1257
|
+
if (!this.queue.length) return;
|
|
1258
|
+
const events = this.queue.splice(0, 50);
|
|
1259
|
+
const payload = JSON.stringify({ appId: this.backendId, events });
|
|
1260
|
+
try {
|
|
1261
|
+
if (typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
1262
|
+
const blob = new Blob([payload], { type: "application/json" });
|
|
1263
|
+
navigator.sendBeacon(this.getIngestUrl(), blob);
|
|
1264
|
+
} else {
|
|
1265
|
+
fetch(this.getIngestUrl(), {
|
|
1266
|
+
method: "POST",
|
|
1267
|
+
headers: { "Content-Type": "application/json" },
|
|
1268
|
+
body: payload,
|
|
1269
|
+
keepalive: true
|
|
1270
|
+
}).catch(() => {
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
} catch {
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
/**
|
|
1277
|
+
* Stop tracking and cleanup all listeners/timers
|
|
1278
|
+
*/
|
|
1279
|
+
destroy() {
|
|
1280
|
+
if (!this.initialized) return;
|
|
1281
|
+
this.flushSync();
|
|
1282
|
+
if (this.flushTimer) {
|
|
1283
|
+
clearInterval(this.flushTimer);
|
|
1284
|
+
this.flushTimer = null;
|
|
1285
|
+
}
|
|
1286
|
+
if (this.originalPushState) {
|
|
1287
|
+
history.pushState = this.originalPushState;
|
|
1288
|
+
this.originalPushState = null;
|
|
1289
|
+
}
|
|
1290
|
+
if (this.popstateHandler) {
|
|
1291
|
+
window.removeEventListener("popstate", this.popstateHandler);
|
|
1292
|
+
this.popstateHandler = null;
|
|
1293
|
+
}
|
|
1294
|
+
if (this.unloadHandler) {
|
|
1295
|
+
window.removeEventListener("beforeunload", this.unloadHandler);
|
|
1296
|
+
this.unloadHandler = null;
|
|
1297
|
+
}
|
|
1298
|
+
this.initialized = false;
|
|
1299
|
+
this.queue = [];
|
|
1300
|
+
if (this.options.debug) {
|
|
1301
|
+
console.log("[Krisspy Analytics] Destroyed");
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
// ── Private helpers ──────────────────────────────────────────────────────
|
|
1305
|
+
getOrCreateSessionId() {
|
|
1306
|
+
const key = "_ka_sid";
|
|
1307
|
+
try {
|
|
1308
|
+
const existing = localStorage.getItem(key);
|
|
1309
|
+
if (existing) return existing;
|
|
1310
|
+
const id = Math.random().toString(36).substring(2, 15) + Date.now().toString(36);
|
|
1311
|
+
localStorage.setItem(key, id);
|
|
1312
|
+
return id;
|
|
1313
|
+
} catch {
|
|
1314
|
+
return Math.random().toString(36).substring(2, 15) + Date.now().toString(36);
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
getIngestUrl() {
|
|
1318
|
+
return `${this.http.baseUrl}/api/v1/analytics/events`;
|
|
1319
|
+
}
|
|
1320
|
+
setupNavigationTracking() {
|
|
1321
|
+
this.originalPushState = history.pushState;
|
|
1322
|
+
const self = this;
|
|
1323
|
+
history.pushState = function(...args) {
|
|
1324
|
+
self.originalPushState.apply(history, args);
|
|
1325
|
+
self.track("page_view", { url: location.href });
|
|
1326
|
+
};
|
|
1327
|
+
this.popstateHandler = () => {
|
|
1328
|
+
this.track("page_view", { url: location.href });
|
|
1329
|
+
};
|
|
1330
|
+
window.addEventListener("popstate", this.popstateHandler);
|
|
1331
|
+
}
|
|
1332
|
+
};
|
|
1333
|
+
|
|
1147
1334
|
// src/query-builder.ts
|
|
1148
1335
|
var QueryBuilder = class {
|
|
1149
1336
|
constructor(http, backendId, tableName, useRLS = true) {
|
|
@@ -1431,13 +1618,14 @@ var KrisspyClient = class {
|
|
|
1431
1618
|
baseUrl: this.baseUrl,
|
|
1432
1619
|
headers: {
|
|
1433
1620
|
...options.headers,
|
|
1434
|
-
|
|
1621
|
+
"apikey": options.anonKey
|
|
1435
1622
|
},
|
|
1436
1623
|
debug: options.debug
|
|
1437
1624
|
});
|
|
1438
1625
|
this._auth = new KrisspyAuth(this.http, this.backendId);
|
|
1439
1626
|
this._storage = new KrisspyStorage(this.http, this.backendId);
|
|
1440
1627
|
this._realtime = new KrisspyRealtime(this.baseUrl, this.backendId, this.debug);
|
|
1628
|
+
this._analytics = new KrisspyAnalytics(this.http, this.backendId);
|
|
1441
1629
|
this._auth.onAuthStateChange((event) => {
|
|
1442
1630
|
if (event === "SIGNED_IN") {
|
|
1443
1631
|
const session = this._auth.session();
|
|
@@ -1498,6 +1686,25 @@ var KrisspyClient = class {
|
|
|
1498
1686
|
get storage() {
|
|
1499
1687
|
return this._storage;
|
|
1500
1688
|
}
|
|
1689
|
+
/**
|
|
1690
|
+
* Analytics module for event tracking
|
|
1691
|
+
*
|
|
1692
|
+
* @example
|
|
1693
|
+
* // Initialize tracking
|
|
1694
|
+
* krisspy.analytics.init()
|
|
1695
|
+
*
|
|
1696
|
+
* // Track custom events
|
|
1697
|
+
* krisspy.analytics.track('button_click', { label: 'signup' })
|
|
1698
|
+
*
|
|
1699
|
+
* // Identify a user
|
|
1700
|
+
* krisspy.analytics.identify('user_123', { plan: 'pro' })
|
|
1701
|
+
*
|
|
1702
|
+
* // Cleanup
|
|
1703
|
+
* krisspy.analytics.destroy()
|
|
1704
|
+
*/
|
|
1705
|
+
get analytics() {
|
|
1706
|
+
return this._analytics;
|
|
1707
|
+
}
|
|
1501
1708
|
/**
|
|
1502
1709
|
* Create a realtime channel for subscribing to database changes
|
|
1503
1710
|
*
|
|
@@ -1666,6 +1873,7 @@ function createClient(options) {
|
|
|
1666
1873
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1667
1874
|
0 && (module.exports = {
|
|
1668
1875
|
HttpClient,
|
|
1876
|
+
KrisspyAnalytics,
|
|
1669
1877
|
KrisspyAuth,
|
|
1670
1878
|
KrisspyClient,
|
|
1671
1879
|
KrisspyRealtime,
|
package/dist/index.mjs
CHANGED
|
@@ -1110,6 +1110,192 @@ var KrisspyRealtime = class {
|
|
|
1110
1110
|
}
|
|
1111
1111
|
};
|
|
1112
1112
|
|
|
1113
|
+
// src/analytics.ts
|
|
1114
|
+
var KrisspyAnalytics = class {
|
|
1115
|
+
constructor(http, backendId) {
|
|
1116
|
+
this.queue = [];
|
|
1117
|
+
this.sessionId = null;
|
|
1118
|
+
this.userId = null;
|
|
1119
|
+
this.userTraits = {};
|
|
1120
|
+
this.initialized = false;
|
|
1121
|
+
this.flushTimer = null;
|
|
1122
|
+
this.options = {};
|
|
1123
|
+
this.originalPushState = null;
|
|
1124
|
+
this.popstateHandler = null;
|
|
1125
|
+
this.unloadHandler = null;
|
|
1126
|
+
this.http = http;
|
|
1127
|
+
this.backendId = backendId;
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
1130
|
+
* Initialize analytics tracking
|
|
1131
|
+
*
|
|
1132
|
+
* @example
|
|
1133
|
+
* krisspy.analytics.init()
|
|
1134
|
+
* krisspy.analytics.init({ autoTrackPageViews: true, flushInterval: 3000 })
|
|
1135
|
+
*/
|
|
1136
|
+
init(options) {
|
|
1137
|
+
if (this.initialized) return;
|
|
1138
|
+
if (typeof window === "undefined") return;
|
|
1139
|
+
this.options = {
|
|
1140
|
+
autoTrackPageViews: true,
|
|
1141
|
+
autoTrackNavigation: true,
|
|
1142
|
+
flushInterval: 5e3,
|
|
1143
|
+
debug: false,
|
|
1144
|
+
...options
|
|
1145
|
+
};
|
|
1146
|
+
this.sessionId = this.getOrCreateSessionId();
|
|
1147
|
+
this.initialized = true;
|
|
1148
|
+
if (this.options.autoTrackPageViews) {
|
|
1149
|
+
this.track("session_start", {});
|
|
1150
|
+
this.track("page_view", { url: location.href, referrer: document.referrer });
|
|
1151
|
+
}
|
|
1152
|
+
if (this.options.autoTrackNavigation) {
|
|
1153
|
+
this.setupNavigationTracking();
|
|
1154
|
+
}
|
|
1155
|
+
this.unloadHandler = () => {
|
|
1156
|
+
this.track("session_end", {});
|
|
1157
|
+
this.flushSync();
|
|
1158
|
+
};
|
|
1159
|
+
window.addEventListener("beforeunload", this.unloadHandler);
|
|
1160
|
+
this.flushTimer = setInterval(() => this.flush(), this.options.flushInterval);
|
|
1161
|
+
if (this.options.debug) {
|
|
1162
|
+
console.log("[Krisspy Analytics] Initialized", { backendId: this.backendId, sessionId: this.sessionId });
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
/**
|
|
1166
|
+
* Track a custom event
|
|
1167
|
+
*
|
|
1168
|
+
* @example
|
|
1169
|
+
* krisspy.analytics.track('button_click', { label: 'signup', variant: 'blue' })
|
|
1170
|
+
* krisspy.analytics.track('purchase', { amount: 29.99, plan: 'pro' })
|
|
1171
|
+
*/
|
|
1172
|
+
track(eventName, properties) {
|
|
1173
|
+
if (!this.initialized || typeof window === "undefined") return;
|
|
1174
|
+
const event = {
|
|
1175
|
+
eventName,
|
|
1176
|
+
sessionId: this.sessionId,
|
|
1177
|
+
userId: this.userId || void 0,
|
|
1178
|
+
properties: {
|
|
1179
|
+
...properties,
|
|
1180
|
+
...this.userId ? { _user_traits: this.userTraits } : {}
|
|
1181
|
+
},
|
|
1182
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1183
|
+
};
|
|
1184
|
+
this.queue.push(event);
|
|
1185
|
+
if (this.options.debug) {
|
|
1186
|
+
console.log("[Krisspy Analytics] Tracked:", eventName, properties);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
/**
|
|
1190
|
+
* Identify a user (attach userId + traits to all future events)
|
|
1191
|
+
*
|
|
1192
|
+
* @example
|
|
1193
|
+
* krisspy.analytics.identify('user_123', { name: 'John', plan: 'pro' })
|
|
1194
|
+
*/
|
|
1195
|
+
identify(userId, traits) {
|
|
1196
|
+
this.userId = userId;
|
|
1197
|
+
this.userTraits = traits || {};
|
|
1198
|
+
if (this.initialized) {
|
|
1199
|
+
this.track("identify", { userId, ...traits });
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* Flush event queue to the server (async)
|
|
1204
|
+
*/
|
|
1205
|
+
async flush() {
|
|
1206
|
+
if (!this.queue.length) return;
|
|
1207
|
+
const events = this.queue.splice(0, 50);
|
|
1208
|
+
const payload = { appId: this.backendId, events };
|
|
1209
|
+
try {
|
|
1210
|
+
await this.http.post("/api/v1/analytics/events", payload);
|
|
1211
|
+
if (this.options.debug) {
|
|
1212
|
+
console.log(`[Krisspy Analytics] Flushed ${events.length} events`);
|
|
1213
|
+
}
|
|
1214
|
+
} catch {
|
|
1215
|
+
this.queue.unshift(...events);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Synchronous flush using sendBeacon (for page unload)
|
|
1220
|
+
*/
|
|
1221
|
+
flushSync() {
|
|
1222
|
+
if (!this.queue.length) return;
|
|
1223
|
+
const events = this.queue.splice(0, 50);
|
|
1224
|
+
const payload = JSON.stringify({ appId: this.backendId, events });
|
|
1225
|
+
try {
|
|
1226
|
+
if (typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
1227
|
+
const blob = new Blob([payload], { type: "application/json" });
|
|
1228
|
+
navigator.sendBeacon(this.getIngestUrl(), blob);
|
|
1229
|
+
} else {
|
|
1230
|
+
fetch(this.getIngestUrl(), {
|
|
1231
|
+
method: "POST",
|
|
1232
|
+
headers: { "Content-Type": "application/json" },
|
|
1233
|
+
body: payload,
|
|
1234
|
+
keepalive: true
|
|
1235
|
+
}).catch(() => {
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
} catch {
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Stop tracking and cleanup all listeners/timers
|
|
1243
|
+
*/
|
|
1244
|
+
destroy() {
|
|
1245
|
+
if (!this.initialized) return;
|
|
1246
|
+
this.flushSync();
|
|
1247
|
+
if (this.flushTimer) {
|
|
1248
|
+
clearInterval(this.flushTimer);
|
|
1249
|
+
this.flushTimer = null;
|
|
1250
|
+
}
|
|
1251
|
+
if (this.originalPushState) {
|
|
1252
|
+
history.pushState = this.originalPushState;
|
|
1253
|
+
this.originalPushState = null;
|
|
1254
|
+
}
|
|
1255
|
+
if (this.popstateHandler) {
|
|
1256
|
+
window.removeEventListener("popstate", this.popstateHandler);
|
|
1257
|
+
this.popstateHandler = null;
|
|
1258
|
+
}
|
|
1259
|
+
if (this.unloadHandler) {
|
|
1260
|
+
window.removeEventListener("beforeunload", this.unloadHandler);
|
|
1261
|
+
this.unloadHandler = null;
|
|
1262
|
+
}
|
|
1263
|
+
this.initialized = false;
|
|
1264
|
+
this.queue = [];
|
|
1265
|
+
if (this.options.debug) {
|
|
1266
|
+
console.log("[Krisspy Analytics] Destroyed");
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
// ── Private helpers ──────────────────────────────────────────────────────
|
|
1270
|
+
getOrCreateSessionId() {
|
|
1271
|
+
const key = "_ka_sid";
|
|
1272
|
+
try {
|
|
1273
|
+
const existing = localStorage.getItem(key);
|
|
1274
|
+
if (existing) return existing;
|
|
1275
|
+
const id = Math.random().toString(36).substring(2, 15) + Date.now().toString(36);
|
|
1276
|
+
localStorage.setItem(key, id);
|
|
1277
|
+
return id;
|
|
1278
|
+
} catch {
|
|
1279
|
+
return Math.random().toString(36).substring(2, 15) + Date.now().toString(36);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
getIngestUrl() {
|
|
1283
|
+
return `${this.http.baseUrl}/api/v1/analytics/events`;
|
|
1284
|
+
}
|
|
1285
|
+
setupNavigationTracking() {
|
|
1286
|
+
this.originalPushState = history.pushState;
|
|
1287
|
+
const self = this;
|
|
1288
|
+
history.pushState = function(...args) {
|
|
1289
|
+
self.originalPushState.apply(history, args);
|
|
1290
|
+
self.track("page_view", { url: location.href });
|
|
1291
|
+
};
|
|
1292
|
+
this.popstateHandler = () => {
|
|
1293
|
+
this.track("page_view", { url: location.href });
|
|
1294
|
+
};
|
|
1295
|
+
window.addEventListener("popstate", this.popstateHandler);
|
|
1296
|
+
}
|
|
1297
|
+
};
|
|
1298
|
+
|
|
1113
1299
|
// src/query-builder.ts
|
|
1114
1300
|
var QueryBuilder = class {
|
|
1115
1301
|
constructor(http, backendId, tableName, useRLS = true) {
|
|
@@ -1397,13 +1583,14 @@ var KrisspyClient = class {
|
|
|
1397
1583
|
baseUrl: this.baseUrl,
|
|
1398
1584
|
headers: {
|
|
1399
1585
|
...options.headers,
|
|
1400
|
-
|
|
1586
|
+
"apikey": options.anonKey
|
|
1401
1587
|
},
|
|
1402
1588
|
debug: options.debug
|
|
1403
1589
|
});
|
|
1404
1590
|
this._auth = new KrisspyAuth(this.http, this.backendId);
|
|
1405
1591
|
this._storage = new KrisspyStorage(this.http, this.backendId);
|
|
1406
1592
|
this._realtime = new KrisspyRealtime(this.baseUrl, this.backendId, this.debug);
|
|
1593
|
+
this._analytics = new KrisspyAnalytics(this.http, this.backendId);
|
|
1407
1594
|
this._auth.onAuthStateChange((event) => {
|
|
1408
1595
|
if (event === "SIGNED_IN") {
|
|
1409
1596
|
const session = this._auth.session();
|
|
@@ -1464,6 +1651,25 @@ var KrisspyClient = class {
|
|
|
1464
1651
|
get storage() {
|
|
1465
1652
|
return this._storage;
|
|
1466
1653
|
}
|
|
1654
|
+
/**
|
|
1655
|
+
* Analytics module for event tracking
|
|
1656
|
+
*
|
|
1657
|
+
* @example
|
|
1658
|
+
* // Initialize tracking
|
|
1659
|
+
* krisspy.analytics.init()
|
|
1660
|
+
*
|
|
1661
|
+
* // Track custom events
|
|
1662
|
+
* krisspy.analytics.track('button_click', { label: 'signup' })
|
|
1663
|
+
*
|
|
1664
|
+
* // Identify a user
|
|
1665
|
+
* krisspy.analytics.identify('user_123', { plan: 'pro' })
|
|
1666
|
+
*
|
|
1667
|
+
* // Cleanup
|
|
1668
|
+
* krisspy.analytics.destroy()
|
|
1669
|
+
*/
|
|
1670
|
+
get analytics() {
|
|
1671
|
+
return this._analytics;
|
|
1672
|
+
}
|
|
1467
1673
|
/**
|
|
1468
1674
|
* Create a realtime channel for subscribing to database changes
|
|
1469
1675
|
*
|
|
@@ -1631,6 +1837,7 @@ function createClient(options) {
|
|
|
1631
1837
|
}
|
|
1632
1838
|
export {
|
|
1633
1839
|
HttpClient,
|
|
1840
|
+
KrisspyAnalytics,
|
|
1634
1841
|
KrisspyAuth,
|
|
1635
1842
|
KrisspyClient,
|
|
1636
1843
|
KrisspyRealtime,
|