@mobtechi/sdk-core 1.1.4 → 1.1.6

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 CHANGED
@@ -8,7 +8,12 @@ interface AuthDto {
8
8
  interface VerifyOtpDto {
9
9
  email?: string;
10
10
  mobile?: string;
11
+ user_id?: string;
11
12
  otp: string;
13
+ revoke_others?: boolean;
14
+ guest_id?: string;
15
+ device_id?: string;
16
+ referral_code?: string;
12
17
  }
13
18
  interface MobTechiUser {
14
19
  id: string;
@@ -105,6 +110,7 @@ declare class MobTechiClient {
105
110
  constructor(optionsOrBaseUrl: MobTechiClientOptions | string, appId?: string, storage?: StorageProvider, tokenKey?: string);
106
111
  setToken(token: string | null): Promise<void>;
107
112
  getToken(): Promise<string | null>;
113
+ getUserIdFromToken(): string | null;
108
114
  get<T = any>(path: string, config?: any): Promise<{
109
115
  data: T;
110
116
  status: number;
@@ -144,6 +150,7 @@ declare class MobTechiClient {
144
150
  validateToken(token: string): Promise<any>;
145
151
  refreshToken(refresh_token: string): Promise<any>;
146
152
  logout(token: string): Promise<void>;
153
+ logoutAll(token: string): Promise<void>;
147
154
  updateProfile(payload: any, token?: string): Promise<any>;
148
155
  getPlans(appKey?: string, token?: string): Promise<any>;
149
156
  getSubscriptionStatus(appKey: string, token?: string): Promise<any>;
@@ -182,7 +189,7 @@ declare class EntitlementEngine {
182
189
  hasFeature(feature: string): boolean;
183
190
  }
184
191
 
185
- type MobTechiEvent = 'signup' | 'onboarding_completed' | 'first_code_execution' | 'lesson_completed' | 'paywall_viewed' | 'subscription_started' | 'feature_used' | 'premium_feature_attempted' | 'streak_updated' | 'session_started' | 'auth_success';
192
+ type MobTechiEvent = 'signup' | 'onboarding_completed' | 'first_code_execution' | 'lesson_completed' | 'paywall_viewed' | 'subscription_started' | 'feature_used' | 'premium_feature_attempted' | 'streak_updated' | 'session_started' | 'auth_success' | 'workout_completed' | 'macro_scanned' | 'transaction_created' | 'budget_created' | 'goal_created' | 'page_view';
186
193
  interface AnalyticsEventPayload {
187
194
  event_name: MobTechiEvent | string;
188
195
  payload?: Record<string, any>;
@@ -194,8 +201,26 @@ interface AnalyticsEventPayload {
194
201
  declare class AnalyticsTracker {
195
202
  private readonly api;
196
203
  private readonly appId;
197
- constructor(api: MobTechiClient, appId: string);
204
+ private userId;
205
+ private sessionId;
198
206
  private sessionEvents;
207
+ constructor(api: MobTechiClient, appId: string);
208
+ /**
209
+ * Explicitly set the active user ID for analytics
210
+ */
211
+ setUserId(userId: string | null): void;
212
+ /**
213
+ * Explicitly set a session or guest identifier
214
+ */
215
+ setSessionId(sessionId: string | null): void;
216
+ /**
217
+ * Identify a user and emit an auth_success telemetry event
218
+ */
219
+ identify(userId: string, metadata?: Record<string, any>): void;
220
+ /**
221
+ * Retrieves or initializes a persistent device session ID saved in storage
222
+ */
223
+ getPersistentSessionId(): Promise<string>;
199
224
  /**
200
225
  * Check if the event should be deduplicated
201
226
  */
@@ -215,10 +240,32 @@ declare class AnalyticsTracker {
215
240
  private capture;
216
241
  }
217
242
 
243
+ declare class PresenceTracker {
244
+ private readonly api;
245
+ private readonly appId;
246
+ private timerId;
247
+ private currentSessionId;
248
+ private activeScreenGetter;
249
+ private intervalMs;
250
+ private visibilityHandler;
251
+ constructor(api: MobTechiClient, appId: string);
252
+ /**
253
+ * Starts periodic heartbeat to track user online presence across ecosystem applications.
254
+ * Automatically pauses heartbeat when app/tab is backgrounded.
255
+ */
256
+ startHeartbeat(sessionId: string, activeScreenProvider?: () => string, intervalSeconds?: number): void;
257
+ /**
258
+ * Stops active heartbeat timer and cleans up lifecycle listeners.
259
+ */
260
+ stopHeartbeat(): void;
261
+ private sendHeartbeat;
262
+ }
263
+
218
264
  declare class MobTechi {
219
265
  api: MobTechiClient;
220
266
  entitlements: EntitlementEngine;
221
267
  analytics: AnalyticsTracker;
268
+ presence: PresenceTracker;
222
269
  constructor(options: MobTechiClientOptions);
223
270
  /**
224
271
  * Auth helpers to standardize the flow and auto-configure internal state
@@ -236,6 +283,7 @@ declare class MobTechi {
236
283
  data: any;
237
284
  }>;
238
285
  logout(): Promise<void>;
286
+ logoutAll(): Promise<void>;
239
287
  /**
240
288
  * Synchronize the current user's subscription and entitlements state
241
289
  */
@@ -251,4 +299,4 @@ declare const MobTechiSDK: {
251
299
  isPremiumUser: () => boolean;
252
300
  };
253
301
 
254
- export { type AnalyticsEventPayload, AnalyticsTracker, type AuthDto, type AuthState, type Entitlement, EntitlementEngine, MemoryStorageProvider, MobTechi, MobTechiClient, type MobTechiClientOptions, type MobTechiEvent, MobTechiSDK, type MobTechiUser, type PlanComparison, type StorageProvider, type SubscriptionEnvironment, type SubscriptionPlan, type SubscriptionTopup, type VerifyOtpDto };
302
+ export { type AnalyticsEventPayload, AnalyticsTracker, type AuthDto, type AuthState, type Entitlement, EntitlementEngine, MemoryStorageProvider, MobTechi, MobTechiClient, type MobTechiClientOptions, type MobTechiEvent, MobTechiSDK, type MobTechiUser, type PlanComparison, PresenceTracker, type StorageProvider, type SubscriptionEnvironment, type SubscriptionPlan, type SubscriptionTopup, type VerifyOtpDto };
package/dist/index.d.ts CHANGED
@@ -8,7 +8,12 @@ interface AuthDto {
8
8
  interface VerifyOtpDto {
9
9
  email?: string;
10
10
  mobile?: string;
11
+ user_id?: string;
11
12
  otp: string;
13
+ revoke_others?: boolean;
14
+ guest_id?: string;
15
+ device_id?: string;
16
+ referral_code?: string;
12
17
  }
13
18
  interface MobTechiUser {
14
19
  id: string;
@@ -105,6 +110,7 @@ declare class MobTechiClient {
105
110
  constructor(optionsOrBaseUrl: MobTechiClientOptions | string, appId?: string, storage?: StorageProvider, tokenKey?: string);
106
111
  setToken(token: string | null): Promise<void>;
107
112
  getToken(): Promise<string | null>;
113
+ getUserIdFromToken(): string | null;
108
114
  get<T = any>(path: string, config?: any): Promise<{
109
115
  data: T;
110
116
  status: number;
@@ -144,6 +150,7 @@ declare class MobTechiClient {
144
150
  validateToken(token: string): Promise<any>;
145
151
  refreshToken(refresh_token: string): Promise<any>;
146
152
  logout(token: string): Promise<void>;
153
+ logoutAll(token: string): Promise<void>;
147
154
  updateProfile(payload: any, token?: string): Promise<any>;
148
155
  getPlans(appKey?: string, token?: string): Promise<any>;
149
156
  getSubscriptionStatus(appKey: string, token?: string): Promise<any>;
@@ -182,7 +189,7 @@ declare class EntitlementEngine {
182
189
  hasFeature(feature: string): boolean;
183
190
  }
184
191
 
185
- type MobTechiEvent = 'signup' | 'onboarding_completed' | 'first_code_execution' | 'lesson_completed' | 'paywall_viewed' | 'subscription_started' | 'feature_used' | 'premium_feature_attempted' | 'streak_updated' | 'session_started' | 'auth_success';
192
+ type MobTechiEvent = 'signup' | 'onboarding_completed' | 'first_code_execution' | 'lesson_completed' | 'paywall_viewed' | 'subscription_started' | 'feature_used' | 'premium_feature_attempted' | 'streak_updated' | 'session_started' | 'auth_success' | 'workout_completed' | 'macro_scanned' | 'transaction_created' | 'budget_created' | 'goal_created' | 'page_view';
186
193
  interface AnalyticsEventPayload {
187
194
  event_name: MobTechiEvent | string;
188
195
  payload?: Record<string, any>;
@@ -194,8 +201,26 @@ interface AnalyticsEventPayload {
194
201
  declare class AnalyticsTracker {
195
202
  private readonly api;
196
203
  private readonly appId;
197
- constructor(api: MobTechiClient, appId: string);
204
+ private userId;
205
+ private sessionId;
198
206
  private sessionEvents;
207
+ constructor(api: MobTechiClient, appId: string);
208
+ /**
209
+ * Explicitly set the active user ID for analytics
210
+ */
211
+ setUserId(userId: string | null): void;
212
+ /**
213
+ * Explicitly set a session or guest identifier
214
+ */
215
+ setSessionId(sessionId: string | null): void;
216
+ /**
217
+ * Identify a user and emit an auth_success telemetry event
218
+ */
219
+ identify(userId: string, metadata?: Record<string, any>): void;
220
+ /**
221
+ * Retrieves or initializes a persistent device session ID saved in storage
222
+ */
223
+ getPersistentSessionId(): Promise<string>;
199
224
  /**
200
225
  * Check if the event should be deduplicated
201
226
  */
@@ -215,10 +240,32 @@ declare class AnalyticsTracker {
215
240
  private capture;
216
241
  }
217
242
 
243
+ declare class PresenceTracker {
244
+ private readonly api;
245
+ private readonly appId;
246
+ private timerId;
247
+ private currentSessionId;
248
+ private activeScreenGetter;
249
+ private intervalMs;
250
+ private visibilityHandler;
251
+ constructor(api: MobTechiClient, appId: string);
252
+ /**
253
+ * Starts periodic heartbeat to track user online presence across ecosystem applications.
254
+ * Automatically pauses heartbeat when app/tab is backgrounded.
255
+ */
256
+ startHeartbeat(sessionId: string, activeScreenProvider?: () => string, intervalSeconds?: number): void;
257
+ /**
258
+ * Stops active heartbeat timer and cleans up lifecycle listeners.
259
+ */
260
+ stopHeartbeat(): void;
261
+ private sendHeartbeat;
262
+ }
263
+
218
264
  declare class MobTechi {
219
265
  api: MobTechiClient;
220
266
  entitlements: EntitlementEngine;
221
267
  analytics: AnalyticsTracker;
268
+ presence: PresenceTracker;
222
269
  constructor(options: MobTechiClientOptions);
223
270
  /**
224
271
  * Auth helpers to standardize the flow and auto-configure internal state
@@ -236,6 +283,7 @@ declare class MobTechi {
236
283
  data: any;
237
284
  }>;
238
285
  logout(): Promise<void>;
286
+ logoutAll(): Promise<void>;
239
287
  /**
240
288
  * Synchronize the current user's subscription and entitlements state
241
289
  */
@@ -251,4 +299,4 @@ declare const MobTechiSDK: {
251
299
  isPremiumUser: () => boolean;
252
300
  };
253
301
 
254
- export { type AnalyticsEventPayload, AnalyticsTracker, type AuthDto, type AuthState, type Entitlement, EntitlementEngine, MemoryStorageProvider, MobTechi, MobTechiClient, type MobTechiClientOptions, type MobTechiEvent, MobTechiSDK, type MobTechiUser, type PlanComparison, type StorageProvider, type SubscriptionEnvironment, type SubscriptionPlan, type SubscriptionTopup, type VerifyOtpDto };
302
+ export { type AnalyticsEventPayload, AnalyticsTracker, type AuthDto, type AuthState, type Entitlement, EntitlementEngine, MemoryStorageProvider, MobTechi, MobTechiClient, type MobTechiClientOptions, type MobTechiEvent, MobTechiSDK, type MobTechiUser, type PlanComparison, PresenceTracker, type StorageProvider, type SubscriptionEnvironment, type SubscriptionPlan, type SubscriptionTopup, type VerifyOtpDto };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var k=Object.create;var g=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var P=Object.getPrototypeOf,I=Object.prototype.hasOwnProperty;var x=(i,t)=>{for(var e in t)g(i,e,{get:t[e],enumerable:!0})},b=(i,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of v(t))!I.call(i,r)&&r!==e&&g(i,r,{get:()=>t[r],enumerable:!(s=_(t,r))||s.enumerable});return i};var A=(i,t,e)=>(e=i!=null?k(P(i)):{},b(t||!i||!i.__esModule?g(e,"default",{value:i,enumerable:!0}):e,i)),E=i=>b(g({},"__esModule",{value:!0}),i);var S={};x(S,{AnalyticsTracker:()=>l,EntitlementEngine:()=>u,MemoryStorageProvider:()=>o,MobTechi:()=>y,MobTechiClient:()=>c,MobTechiSDK:()=>m});module.exports=E(S);var o=class{store={};getItem(t){return this.store[t]||null}setItem(t,e){this.store[t]=e}removeItem(t){delete this.store[t]}};var T=A(require("axios"));var c=class{client;baseUrl;storage;tokenKey;currentToken=null;appId;constructor(t,e,s,r){let p,d=e,f=s,w=r;typeof t=="object"&&t!==null?(p=t.baseUrl,d=t.appId,f=t.storage,w=t.tokenKey):p=t,this.baseUrl=p,this.appId=d,this.storage=f||new o,this.tokenKey=w||"mobtechi_auth_token",this.client=T.default.create({baseURL:this.baseUrl,headers:{"Content-Type":"application/json",...d&&{"x-app-id":d}}}),this.client.interceptors.request.use(async a=>{if(!this.currentToken){let n=await this.storage.getItem(this.tokenKey);n&&(this.currentToken=n)}return this.currentToken&&a.headers&&(a.headers.Authorization=`Bearer ${this.currentToken}`),this.currentToken==="guest_access_token"&&(a.adapter=async()=>{let n=a.url||"",h={};return n.includes("/subscription/status")?h={isPremium:!0,tier:"premium",expiresAt:new Date(Date.now()+31536e6).toISOString()}:n.includes("/subscription/plans")?h=[{id:"plan_1",name:"Premium Guest",price:0}]:n.includes("/ads/config")&&(h={enabled:!1}),{data:h,status:200,statusText:"OK",headers:{},config:a,request:{}}}),a})}async setToken(t){this.currentToken=t,t?await this.storage.setItem(this.tokenKey,t):await this.storage.removeItem(this.tokenKey)}async getToken(){return this.currentToken||(this.currentToken=await this.storage.getItem(this.tokenKey)),this.currentToken}async get(t,e){let s=await this.client.get(t,e);return{data:s.data,status:s.status}}async post(t,e,s){let r=await this.client.post(t,e,s);return{data:r.data,status:r.status}}async put(t,e,s){let r=await this.client.put(t,e,s);return{data:r.data,status:r.status}}async patch(t,e,s){let r=await this.client.patch(t,e,s);return{data:r.data,status:r.status}}async delete(t,e){let s=await this.client.delete(t,e);return{data:s.data,status:s.status}}async identify(t){return(await this.client.post("/auth/identify",t)).data}async login(t){let e=await this.client.post("/auth/login",t);return{status:e.status,data:e.data}}async register(t){return(await this.client.post("/auth/register",t)).data}async verifyOtp(t){let e=await this.client.post("/auth/otp_verify",t);return{status:e.status,data:e.data}}async validateToken(t){return(await this.client.get("/auth/validate",{headers:{Authorization:`Bearer ${t}`}})).data}async refreshToken(t){return(await this.client.post("/auth/refresh",{refresh_token:t})).data}async logout(t){await this.client.delete("/auth/logout",{headers:{Authorization:`Bearer ${t}`}})}async updateProfile(t,e){let s=e?{Authorization:`Bearer ${e}`}:{};return(await this.client.put("/user/update-profile",t,{headers:s})).data}async getPlans(t,e){let s=t||this.appId||"",r=e?{headers:{Authorization:`Bearer ${e}`}}:{};return(await this.client.get(`/user/subscription/plans?appKey=${s}`,r)).data}async getSubscriptionStatus(t,e){return(await this.client.get(`/user/subscription/status?appId=${t}`)).data}async getEntitlements(t){return(await this.client.get(`/${t}/subscriptions/entitlements`)).data}async createOrder(t,e){return(await this.client.post("/user/subscription/create-order",t)).data}async createSubscription(t,e){return(await this.client.post(`/${t}/subscriptions/create`,e)).data}async createTopUp(t,e){return(await this.client.post(`/${t}/subscriptions/topup`,e)).data}async getAdsConfig(t){return(await this.client.get(`/user/ads/config?appKey=${t}`)).data}async claimReward(t){return(await this.client.post("/user/rewards/ad-claim",t)).data}};var u=class{entitlements=[];isPremiumFlag=!1;setState(t,e=[]){this.isPremiumFlag=t,this.entitlements=e}checkPremium(){return this.isPremiumFlag?!0:this.entitlements.some(t=>t.active&&t.tier!=="FREE")}hasFeature(t){return this.isPremiumFlag?!0:this.entitlements.some(e=>e.active&&e.granted_features&&e.granted_features.includes(t))}};var l=class{constructor(t,e){this.api=t;this.appId=e}api;appId;sessionEvents=new Set;async shouldDeduplicate(t){if(t==="onboarding_completed"||t==="first_code_execution"){let e=`mt_dedup_${t}`;return await this.api.storage.getItem(e)==="true"}return t==="paywall_viewed"?this.sessionEvents.has(t):!1}async markTracked(t){if(t==="onboarding_completed"||t==="first_code_execution"){let e=`mt_dedup_${t}`;await this.api.storage.setItem(e,"true")}else t==="paywall_viewed"&&this.sessionEvents.add(t)}track(t,e){(async()=>{await this.shouldDeduplicate(t)||(await this.markTracked(t),await this.capture({event_name:t,payload:e}))})().catch(s=>{console.warn(`[MobTechi Analytics] failed async track for ${t}`,s)})}trackError(t,e,s){(async()=>{await this.capture({event_name:t,is_error:!0,stack_trace:e.stack,metadata:s})})().catch(r=>{console.warn(`[MobTechi Analytics] failed async trackError for ${t}`,r)})}async capture(t){try{await this.api.post("/analytics/capture",{app_id:this.appId,...t})}catch{console.warn(`[MobTechi Analytics] Failed to track event: ${t.event_name}`)}}};var y=class{api;entitlements;analytics;constructor(t){this.api=new c(t),this.entitlements=new u,this.analytics=new l(this.api,t.appId||"unknown")}async login(t){return await this.api.login(t)}async verifyOtp(t){let e=await this.api.verifyOtp(t);return e.data&&e.data.token&&await this.api.setToken(e.data.token),e}async logout(){let t=await this.api.getToken();if(t)try{await this.api.logout(t)}catch{}await this.api.setToken(null),this.entitlements.setState(!1,[])}async syncEntitlements(t){try{let e=await this.api.getEntitlements(t);if(e){let s=!!e.isPremium,r=e.features||[];this.entitlements.setState(s,r),m.setPremiumUser(s)}return e}catch(e){throw console.error("Failed to sync entitlements",e),e}}},m={_isPremium:!1,setPremiumUser:i=>{m._isPremium=i},isPremiumUser:()=>m._isPremium};0&&(module.exports={AnalyticsTracker,EntitlementEngine,MemoryStorageProvider,MobTechi,MobTechiClient,MobTechiSDK});
1
+ "use strict";var _=Object.create;var m=Object.defineProperty;var T=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var P=Object.getPrototypeOf,S=Object.prototype.hasOwnProperty;var x=(r,t)=>{for(var e in t)m(r,e,{get:t[e],enumerable:!0})},w=(r,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of k(t))!S.call(r,i)&&i!==e&&m(r,i,{get:()=>t[i],enumerable:!(s=T(t,i))||s.enumerable});return r};var A=(r,t,e)=>(e=r!=null?_(P(r)):{},w(t||!r||!r.__esModule?m(e,"default",{value:r,enumerable:!0}):e,r)),E=r=>w(m({},"__esModule",{value:!0}),r);var $={};x($,{AnalyticsTracker:()=>u,EntitlementEngine:()=>l,MemoryStorageProvider:()=>o,MobTechi:()=>f,MobTechiClient:()=>c,MobTechiSDK:()=>y,PresenceTracker:()=>d});module.exports=E($);var o=class{store={};getItem(t){return this.store[t]||null}setItem(t,e){this.store[t]=e}removeItem(t){delete this.store[t]}};var I=A(require("axios"));var c=class{client;baseUrl;storage;tokenKey;currentToken=null;appId;constructor(t,e,s,i){let p,h=e,v=s,b=i;typeof t=="object"&&t!==null?(p=t.baseUrl,h=t.appId,v=t.storage,b=t.tokenKey):p=t,this.baseUrl=p,this.appId=h,this.storage=v||new o,this.tokenKey=b||"mobtechi_auth_token",this.client=I.default.create({baseURL:this.baseUrl,headers:{"Content-Type":"application/json",...h&&{"x-app-id":h}}}),this.client.interceptors.request.use(async n=>{if(!this.currentToken){let a=await this.storage.getItem(this.tokenKey);a&&(this.currentToken=a)}return this.currentToken&&n.headers&&(n.headers.Authorization=`Bearer ${this.currentToken}`),this.currentToken==="guest_access_token"&&(n.adapter=async()=>{let a=n.url||"",g={};return a.includes("/subscription/status")?g={isPremium:!0,tier:"premium",expiresAt:new Date(Date.now()+31536e6).toISOString()}:a.includes("/subscription/plans")?g=[{id:"plan_1",name:"Premium Guest",price:0}]:a.includes("/ads/config")&&(g={enabled:!1}),{data:g,status:200,statusText:"OK",headers:{},config:n,request:{}}}),n})}async setToken(t){this.currentToken=t,t?await this.storage.setItem(this.tokenKey,t):await this.storage.removeItem(this.tokenKey)}async getToken(){return this.currentToken||(this.currentToken=await this.storage.getItem(this.tokenKey)),this.currentToken}getUserIdFromToken(){if(!this.currentToken)return null;try{let t=this.currentToken.split(".");if(t.length!==3)return null;let e=t[1].replace(/-/g,"+").replace(/_/g,"/"),s=typeof atob=="function"?atob(e):typeof Buffer<"u"?Buffer.from(e,"base64").toString("utf8"):null;return s&&JSON.parse(s)?.sub||null}catch{return null}}async get(t,e){let s=await this.client.get(t,e);return{data:s.data,status:s.status}}async post(t,e,s){let i=await this.client.post(t,e,s);return{data:i.data,status:i.status}}async put(t,e,s){let i=await this.client.put(t,e,s);return{data:i.data,status:i.status}}async patch(t,e,s){let i=await this.client.patch(t,e,s);return{data:i.data,status:i.status}}async delete(t,e){let s=await this.client.delete(t,e);return{data:s.data,status:s.status}}async identify(t){return(await this.client.post("/auth/identify",t)).data}async login(t){let e=await this.client.post("/auth/login",t);return{status:e.status,data:e.data}}async register(t){return(await this.client.post("/auth/register",t)).data}async verifyOtp(t){let e=await this.client.post("/auth/otp_verify",t);return{status:e.status,data:e.data}}async validateToken(t){return(await this.client.get("/auth/validate",{headers:{Authorization:`Bearer ${t}`}})).data}async refreshToken(t){return(await this.client.post("/auth/refresh",{refresh_token:t})).data}async logout(t){await this.client.delete("/auth/logout",{headers:{Authorization:`Bearer ${t}`}})}async logoutAll(t){await this.client.delete("/auth/logout_all",{headers:{Authorization:`Bearer ${t}`}})}async updateProfile(t,e){let s=e?{Authorization:`Bearer ${e}`}:{};return(await this.client.put("/user/update-profile",t,{headers:s})).data}async getPlans(t,e){let s=t||this.appId||"",i=e?{headers:{Authorization:`Bearer ${e}`}}:{};return(await this.client.get(`/user/subscription/plans?appKey=${s}`,i)).data}async getSubscriptionStatus(t,e){let s=e?{headers:{Authorization:`Bearer ${e}`}}:{};return(await this.client.get(`/user/subscription/status?appId=${t}`,s)).data}async getEntitlements(t){return(await this.client.get(`/${t}/subscriptions/entitlements`)).data}async createOrder(t,e){let s=e?{headers:{Authorization:`Bearer ${e}`}}:{};return(await this.client.post("/user/subscription/create-order",t,s)).data}async createSubscription(t,e){return(await this.client.post(`/${t}/subscriptions/create`,e)).data}async createTopUp(t,e){return(await this.client.post(`/${t}/subscriptions/topup`,e)).data}async getAdsConfig(t){return(await this.client.get(`/user/ads/config?appKey=${t}`)).data}async claimReward(t){return(await this.client.post("/user/rewards/ad-claim",t)).data}};var l=class{entitlements=[];isPremiumFlag=!1;setState(t,e=[]){this.isPremiumFlag=t,this.entitlements=e}checkPremium(){return this.isPremiumFlag?!0:this.entitlements.some(t=>t.active&&t.tier!=="FREE")}hasFeature(t){return this.isPremiumFlag?!0:this.entitlements.some(e=>e.active&&e.granted_features&&e.granted_features.includes(t))}};var u=class{constructor(t,e){this.api=t;this.appId=e}api;appId;userId=null;sessionId=null;sessionEvents=new Set;setUserId(t){this.userId=t}setSessionId(t){this.sessionId=t}identify(t,e){this.userId=t,this.track("auth_success",e)}async getPersistentSessionId(){if(this.sessionId)return this.sessionId;try{let t=await this.api.storage.getItem("mt_device_session_id");return t||(t=`guest_${Date.now()}_${Math.random().toString(36).substring(2,9)}`,await this.api.storage.setItem("mt_device_session_id",t)),this.sessionId=t,t}catch{return`guest_${Date.now()}_${Math.random().toString(36).substring(2,9)}`}}async shouldDeduplicate(t){if(t==="onboarding_completed"||t==="first_code_execution"){let e=`mt_dedup_${t}`;return await this.api.storage.getItem(e)==="true"}return t==="paywall_viewed"?this.sessionEvents.has(t):!1}async markTracked(t){if(t==="onboarding_completed"||t==="first_code_execution"){let e=`mt_dedup_${t}`;await this.api.storage.setItem(e,"true")}else t==="paywall_viewed"&&this.sessionEvents.add(t)}track(t,e){(async()=>{await this.shouldDeduplicate(t)||(await this.markTracked(t),await this.capture({event_name:t,payload:e}))})().catch(s=>{console.warn(`[MobTechi Analytics] failed async track for ${t}`,s)})}trackError(t,e,s){(async()=>{await this.capture({event_name:t,is_error:!0,stack_trace:e.stack,metadata:s})})().catch(i=>{console.warn(`[MobTechi Analytics] failed async trackError for ${t}`,i)})}async capture(t){try{let e=this.api.getUserIdFromToken(),s=this.userId||e||void 0,i=await this.getPersistentSessionId();await this.api.post("/analytics/capture",{app_id:this.appId,user_id:s,session_id:i,...t})}catch{console.warn(`[MobTechi Analytics] Failed to track event: ${t.event_name}`)}}};var d=class{constructor(t,e){this.api=t;this.appId=e}api;appId;timerId=null;currentSessionId=null;activeScreenGetter=null;intervalMs=3e4;visibilityHandler=null;startHeartbeat(t,e=()=>"main",s=30){this.stopHeartbeat(),this.currentSessionId=t,this.activeScreenGetter=e,this.intervalMs=Math.max(10,s)*1e3,this.sendHeartbeat(),this.timerId=setInterval(()=>{this.sendHeartbeat()},this.intervalMs),typeof document<"u"&&typeof document.addEventListener=="function"&&(this.visibilityHandler=()=>{document.hidden?this.timerId&&(clearInterval(this.timerId),this.timerId=null):!this.timerId&&this.currentSessionId&&(this.sendHeartbeat(),this.timerId=setInterval(()=>{this.sendHeartbeat()},this.intervalMs))},document.addEventListener("visibilitychange",this.visibilityHandler))}stopHeartbeat(){this.timerId&&(clearInterval(this.timerId),this.timerId=null),typeof document<"u"&&typeof document.removeEventListener=="function"&&this.visibilityHandler&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.currentSessionId=null,this.activeScreenGetter=null}sendHeartbeat(){if(!this.currentSessionId)return;let t=this.activeScreenGetter?this.activeScreenGetter():"main";this.api.post("/analytics/presence/heartbeat",{sessionId:this.currentSessionId,activeScreen:t}).catch(e=>{})}};var f=class{api;entitlements;analytics;presence;constructor(t){this.api=new c(t),this.entitlements=new l,this.analytics=new u(this.api,t.appId||"unknown"),this.presence=new d(this.api,t.appId||"unknown")}async login(t){return await this.api.login(t)}async verifyOtp(t){let e=await this.api.verifyOtp(t);return e.data&&e.data.token&&await this.api.setToken(e.data.token),e}async logout(){let t=await this.api.getToken();if(t)try{await this.api.logout(t)}catch{}await this.api.setToken(null),this.analytics.setUserId(null),this.entitlements.setState(!1,[])}async logoutAll(){let t=await this.api.getToken();if(t)try{await this.api.logoutAll(t)}catch{}await this.api.setToken(null),this.analytics.setUserId(null),this.entitlements.setState(!1,[])}async syncEntitlements(t){try{let e=await this.api.getEntitlements(t);if(e){let s=!!e.isPremium,i=e.features||[];this.entitlements.setState(s,i),y.setPremiumUser(s)}return e}catch(e){throw console.error("Failed to sync entitlements",e),e}}},y={_isPremium:!1,setPremiumUser:r=>{y._isPremium=r},isPremiumUser:()=>y._isPremium};0&&(module.exports={AnalyticsTracker,EntitlementEngine,MemoryStorageProvider,MobTechi,MobTechiClient,MobTechiSDK,PresenceTracker});
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- var l=class{store={};getItem(t){return this.store[t]||null}setItem(t,e){this.store[t]=e}removeItem(t){delete this.store[t]}};import w from"axios";var p=class{client;baseUrl;storage;tokenKey;currentToken=null;appId;constructor(t,e,s,r){let o,c=e,m=s,y=r;typeof t=="object"&&t!==null?(o=t.baseUrl,c=t.appId,m=t.storage,y=t.tokenKey):o=t,this.baseUrl=o,this.appId=c,this.storage=m||new l,this.tokenKey=y||"mobtechi_auth_token",this.client=w.create({baseURL:this.baseUrl,headers:{"Content-Type":"application/json",...c&&{"x-app-id":c}}}),this.client.interceptors.request.use(async a=>{if(!this.currentToken){let n=await this.storage.getItem(this.tokenKey);n&&(this.currentToken=n)}return this.currentToken&&a.headers&&(a.headers.Authorization=`Bearer ${this.currentToken}`),this.currentToken==="guest_access_token"&&(a.adapter=async()=>{let n=a.url||"",u={};return n.includes("/subscription/status")?u={isPremium:!0,tier:"premium",expiresAt:new Date(Date.now()+31536e6).toISOString()}:n.includes("/subscription/plans")?u=[{id:"plan_1",name:"Premium Guest",price:0}]:n.includes("/ads/config")&&(u={enabled:!1}),{data:u,status:200,statusText:"OK",headers:{},config:a,request:{}}}),a})}async setToken(t){this.currentToken=t,t?await this.storage.setItem(this.tokenKey,t):await this.storage.removeItem(this.tokenKey)}async getToken(){return this.currentToken||(this.currentToken=await this.storage.getItem(this.tokenKey)),this.currentToken}async get(t,e){let s=await this.client.get(t,e);return{data:s.data,status:s.status}}async post(t,e,s){let r=await this.client.post(t,e,s);return{data:r.data,status:r.status}}async put(t,e,s){let r=await this.client.put(t,e,s);return{data:r.data,status:r.status}}async patch(t,e,s){let r=await this.client.patch(t,e,s);return{data:r.data,status:r.status}}async delete(t,e){let s=await this.client.delete(t,e);return{data:s.data,status:s.status}}async identify(t){return(await this.client.post("/auth/identify",t)).data}async login(t){let e=await this.client.post("/auth/login",t);return{status:e.status,data:e.data}}async register(t){return(await this.client.post("/auth/register",t)).data}async verifyOtp(t){let e=await this.client.post("/auth/otp_verify",t);return{status:e.status,data:e.data}}async validateToken(t){return(await this.client.get("/auth/validate",{headers:{Authorization:`Bearer ${t}`}})).data}async refreshToken(t){return(await this.client.post("/auth/refresh",{refresh_token:t})).data}async logout(t){await this.client.delete("/auth/logout",{headers:{Authorization:`Bearer ${t}`}})}async updateProfile(t,e){let s=e?{Authorization:`Bearer ${e}`}:{};return(await this.client.put("/user/update-profile",t,{headers:s})).data}async getPlans(t,e){let s=t||this.appId||"",r=e?{headers:{Authorization:`Bearer ${e}`}}:{};return(await this.client.get(`/user/subscription/plans?appKey=${s}`,r)).data}async getSubscriptionStatus(t,e){return(await this.client.get(`/user/subscription/status?appId=${t}`)).data}async getEntitlements(t){return(await this.client.get(`/${t}/subscriptions/entitlements`)).data}async createOrder(t,e){return(await this.client.post("/user/subscription/create-order",t)).data}async createSubscription(t,e){return(await this.client.post(`/${t}/subscriptions/create`,e)).data}async createTopUp(t,e){return(await this.client.post(`/${t}/subscriptions/topup`,e)).data}async getAdsConfig(t){return(await this.client.get(`/user/ads/config?appKey=${t}`)).data}async claimReward(t){return(await this.client.post("/user/rewards/ad-claim",t)).data}};var d=class{entitlements=[];isPremiumFlag=!1;setState(t,e=[]){this.isPremiumFlag=t,this.entitlements=e}checkPremium(){return this.isPremiumFlag?!0:this.entitlements.some(t=>t.active&&t.tier!=="FREE")}hasFeature(t){return this.isPremiumFlag?!0:this.entitlements.some(e=>e.active&&e.granted_features&&e.granted_features.includes(t))}};var h=class{constructor(t,e){this.api=t;this.appId=e}api;appId;sessionEvents=new Set;async shouldDeduplicate(t){if(t==="onboarding_completed"||t==="first_code_execution"){let e=`mt_dedup_${t}`;return await this.api.storage.getItem(e)==="true"}return t==="paywall_viewed"?this.sessionEvents.has(t):!1}async markTracked(t){if(t==="onboarding_completed"||t==="first_code_execution"){let e=`mt_dedup_${t}`;await this.api.storage.setItem(e,"true")}else t==="paywall_viewed"&&this.sessionEvents.add(t)}track(t,e){(async()=>{await this.shouldDeduplicate(t)||(await this.markTracked(t),await this.capture({event_name:t,payload:e}))})().catch(s=>{console.warn(`[MobTechi Analytics] failed async track for ${t}`,s)})}trackError(t,e,s){(async()=>{await this.capture({event_name:t,is_error:!0,stack_trace:e.stack,metadata:s})})().catch(r=>{console.warn(`[MobTechi Analytics] failed async trackError for ${t}`,r)})}async capture(t){try{await this.api.post("/analytics/capture",{app_id:this.appId,...t})}catch{console.warn(`[MobTechi Analytics] Failed to track event: ${t.event_name}`)}}};var f=class{api;entitlements;analytics;constructor(t){this.api=new p(t),this.entitlements=new d,this.analytics=new h(this.api,t.appId||"unknown")}async login(t){return await this.api.login(t)}async verifyOtp(t){let e=await this.api.verifyOtp(t);return e.data&&e.data.token&&await this.api.setToken(e.data.token),e}async logout(){let t=await this.api.getToken();if(t)try{await this.api.logout(t)}catch{}await this.api.setToken(null),this.entitlements.setState(!1,[])}async syncEntitlements(t){try{let e=await this.api.getEntitlements(t);if(e){let s=!!e.isPremium,r=e.features||[];this.entitlements.setState(s,r),g.setPremiumUser(s)}return e}catch(e){throw console.error("Failed to sync entitlements",e),e}}},g={_isPremium:!1,setPremiumUser:i=>{g._isPremium=i},isPremiumUser:()=>g._isPremium};export{h as AnalyticsTracker,d as EntitlementEngine,l as MemoryStorageProvider,f as MobTechi,p as MobTechiClient,g as MobTechiSDK};
1
+ var u=class{store={};getItem(t){return this.store[t]||null}setItem(t,e){this.store[t]=e}removeItem(t){delete this.store[t]}};import b from"axios";var d=class{client;baseUrl;storage;tokenKey;currentToken=null;appId;constructor(t,e,s,i){let o,c=e,y=s,f=i;typeof t=="object"&&t!==null?(o=t.baseUrl,c=t.appId,y=t.storage,f=t.tokenKey):o=t,this.baseUrl=o,this.appId=c,this.storage=y||new u,this.tokenKey=f||"mobtechi_auth_token",this.client=b.create({baseURL:this.baseUrl,headers:{"Content-Type":"application/json",...c&&{"x-app-id":c}}}),this.client.interceptors.request.use(async n=>{if(!this.currentToken){let a=await this.storage.getItem(this.tokenKey);a&&(this.currentToken=a)}return this.currentToken&&n.headers&&(n.headers.Authorization=`Bearer ${this.currentToken}`),this.currentToken==="guest_access_token"&&(n.adapter=async()=>{let a=n.url||"",l={};return a.includes("/subscription/status")?l={isPremium:!0,tier:"premium",expiresAt:new Date(Date.now()+31536e6).toISOString()}:a.includes("/subscription/plans")?l=[{id:"plan_1",name:"Premium Guest",price:0}]:a.includes("/ads/config")&&(l={enabled:!1}),{data:l,status:200,statusText:"OK",headers:{},config:n,request:{}}}),n})}async setToken(t){this.currentToken=t,t?await this.storage.setItem(this.tokenKey,t):await this.storage.removeItem(this.tokenKey)}async getToken(){return this.currentToken||(this.currentToken=await this.storage.getItem(this.tokenKey)),this.currentToken}getUserIdFromToken(){if(!this.currentToken)return null;try{let t=this.currentToken.split(".");if(t.length!==3)return null;let e=t[1].replace(/-/g,"+").replace(/_/g,"/"),s=typeof atob=="function"?atob(e):typeof Buffer<"u"?Buffer.from(e,"base64").toString("utf8"):null;return s&&JSON.parse(s)?.sub||null}catch{return null}}async get(t,e){let s=await this.client.get(t,e);return{data:s.data,status:s.status}}async post(t,e,s){let i=await this.client.post(t,e,s);return{data:i.data,status:i.status}}async put(t,e,s){let i=await this.client.put(t,e,s);return{data:i.data,status:i.status}}async patch(t,e,s){let i=await this.client.patch(t,e,s);return{data:i.data,status:i.status}}async delete(t,e){let s=await this.client.delete(t,e);return{data:s.data,status:s.status}}async identify(t){return(await this.client.post("/auth/identify",t)).data}async login(t){let e=await this.client.post("/auth/login",t);return{status:e.status,data:e.data}}async register(t){return(await this.client.post("/auth/register",t)).data}async verifyOtp(t){let e=await this.client.post("/auth/otp_verify",t);return{status:e.status,data:e.data}}async validateToken(t){return(await this.client.get("/auth/validate",{headers:{Authorization:`Bearer ${t}`}})).data}async refreshToken(t){return(await this.client.post("/auth/refresh",{refresh_token:t})).data}async logout(t){await this.client.delete("/auth/logout",{headers:{Authorization:`Bearer ${t}`}})}async logoutAll(t){await this.client.delete("/auth/logout_all",{headers:{Authorization:`Bearer ${t}`}})}async updateProfile(t,e){let s=e?{Authorization:`Bearer ${e}`}:{};return(await this.client.put("/user/update-profile",t,{headers:s})).data}async getPlans(t,e){let s=t||this.appId||"",i=e?{headers:{Authorization:`Bearer ${e}`}}:{};return(await this.client.get(`/user/subscription/plans?appKey=${s}`,i)).data}async getSubscriptionStatus(t,e){let s=e?{headers:{Authorization:`Bearer ${e}`}}:{};return(await this.client.get(`/user/subscription/status?appId=${t}`,s)).data}async getEntitlements(t){return(await this.client.get(`/${t}/subscriptions/entitlements`)).data}async createOrder(t,e){let s=e?{headers:{Authorization:`Bearer ${e}`}}:{};return(await this.client.post("/user/subscription/create-order",t,s)).data}async createSubscription(t,e){return(await this.client.post(`/${t}/subscriptions/create`,e)).data}async createTopUp(t,e){return(await this.client.post(`/${t}/subscriptions/topup`,e)).data}async getAdsConfig(t){return(await this.client.get(`/user/ads/config?appKey=${t}`)).data}async claimReward(t){return(await this.client.post("/user/rewards/ad-claim",t)).data}};var p=class{entitlements=[];isPremiumFlag=!1;setState(t,e=[]){this.isPremiumFlag=t,this.entitlements=e}checkPremium(){return this.isPremiumFlag?!0:this.entitlements.some(t=>t.active&&t.tier!=="FREE")}hasFeature(t){return this.isPremiumFlag?!0:this.entitlements.some(e=>e.active&&e.granted_features&&e.granted_features.includes(t))}};var h=class{constructor(t,e){this.api=t;this.appId=e}api;appId;userId=null;sessionId=null;sessionEvents=new Set;setUserId(t){this.userId=t}setSessionId(t){this.sessionId=t}identify(t,e){this.userId=t,this.track("auth_success",e)}async getPersistentSessionId(){if(this.sessionId)return this.sessionId;try{let t=await this.api.storage.getItem("mt_device_session_id");return t||(t=`guest_${Date.now()}_${Math.random().toString(36).substring(2,9)}`,await this.api.storage.setItem("mt_device_session_id",t)),this.sessionId=t,t}catch{return`guest_${Date.now()}_${Math.random().toString(36).substring(2,9)}`}}async shouldDeduplicate(t){if(t==="onboarding_completed"||t==="first_code_execution"){let e=`mt_dedup_${t}`;return await this.api.storage.getItem(e)==="true"}return t==="paywall_viewed"?this.sessionEvents.has(t):!1}async markTracked(t){if(t==="onboarding_completed"||t==="first_code_execution"){let e=`mt_dedup_${t}`;await this.api.storage.setItem(e,"true")}else t==="paywall_viewed"&&this.sessionEvents.add(t)}track(t,e){(async()=>{await this.shouldDeduplicate(t)||(await this.markTracked(t),await this.capture({event_name:t,payload:e}))})().catch(s=>{console.warn(`[MobTechi Analytics] failed async track for ${t}`,s)})}trackError(t,e,s){(async()=>{await this.capture({event_name:t,is_error:!0,stack_trace:e.stack,metadata:s})})().catch(i=>{console.warn(`[MobTechi Analytics] failed async trackError for ${t}`,i)})}async capture(t){try{let e=this.api.getUserIdFromToken(),s=this.userId||e||void 0,i=await this.getPersistentSessionId();await this.api.post("/analytics/capture",{app_id:this.appId,user_id:s,session_id:i,...t})}catch{console.warn(`[MobTechi Analytics] Failed to track event: ${t.event_name}`)}}};var g=class{constructor(t,e){this.api=t;this.appId=e}api;appId;timerId=null;currentSessionId=null;activeScreenGetter=null;intervalMs=3e4;visibilityHandler=null;startHeartbeat(t,e=()=>"main",s=30){this.stopHeartbeat(),this.currentSessionId=t,this.activeScreenGetter=e,this.intervalMs=Math.max(10,s)*1e3,this.sendHeartbeat(),this.timerId=setInterval(()=>{this.sendHeartbeat()},this.intervalMs),typeof document<"u"&&typeof document.addEventListener=="function"&&(this.visibilityHandler=()=>{document.hidden?this.timerId&&(clearInterval(this.timerId),this.timerId=null):!this.timerId&&this.currentSessionId&&(this.sendHeartbeat(),this.timerId=setInterval(()=>{this.sendHeartbeat()},this.intervalMs))},document.addEventListener("visibilitychange",this.visibilityHandler))}stopHeartbeat(){this.timerId&&(clearInterval(this.timerId),this.timerId=null),typeof document<"u"&&typeof document.removeEventListener=="function"&&this.visibilityHandler&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.currentSessionId=null,this.activeScreenGetter=null}sendHeartbeat(){if(!this.currentSessionId)return;let t=this.activeScreenGetter?this.activeScreenGetter():"main";this.api.post("/analytics/presence/heartbeat",{sessionId:this.currentSessionId,activeScreen:t}).catch(e=>{})}};var v=class{api;entitlements;analytics;presence;constructor(t){this.api=new d(t),this.entitlements=new p,this.analytics=new h(this.api,t.appId||"unknown"),this.presence=new g(this.api,t.appId||"unknown")}async login(t){return await this.api.login(t)}async verifyOtp(t){let e=await this.api.verifyOtp(t);return e.data&&e.data.token&&await this.api.setToken(e.data.token),e}async logout(){let t=await this.api.getToken();if(t)try{await this.api.logout(t)}catch{}await this.api.setToken(null),this.analytics.setUserId(null),this.entitlements.setState(!1,[])}async logoutAll(){let t=await this.api.getToken();if(t)try{await this.api.logoutAll(t)}catch{}await this.api.setToken(null),this.analytics.setUserId(null),this.entitlements.setState(!1,[])}async syncEntitlements(t){try{let e=await this.api.getEntitlements(t);if(e){let s=!!e.isPremium,i=e.features||[];this.entitlements.setState(s,i),m.setPremiumUser(s)}return e}catch(e){throw console.error("Failed to sync entitlements",e),e}}},m={_isPremium:!1,setPremiumUser:r=>{m._isPremium=r},isPremiumUser:()=>m._isPremium};export{h as AnalyticsTracker,p as EntitlementEngine,u as MemoryStorageProvider,v as MobTechi,d as MobTechiClient,m as MobTechiSDK,g as PresenceTracker};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mobtechi/sdk-core",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "Framework-agnostic core logic and API client for the MobTechi platform",
5
5
  "author": "MobTechi",
6
6
  "license": "MIT",