rampkit-expo-dev 0.0.18 → 0.0.22

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/build/RampKit.js CHANGED
@@ -1,66 +1,179 @@
1
1
  "use strict";
2
+ /**
3
+ * RampKit Core SDK
4
+ * Main SDK class for RampKit Expo integration
5
+ */
2
6
  Object.defineProperty(exports, "__esModule", { value: true });
3
7
  exports.RampKitCore = void 0;
8
+ const react_native_1 = require("react-native");
4
9
  const RampkitOverlay_1 = require("./RampkitOverlay");
5
10
  const userId_1 = require("./userId");
11
+ const DeviceInfoCollector_1 = require("./DeviceInfoCollector");
12
+ const EventManager_1 = require("./EventManager");
13
+ const constants_1 = require("./constants");
6
14
  class RampKitCore {
7
15
  constructor() {
8
- this.config = {};
16
+ this.config = null;
9
17
  this.onboardingData = null;
10
18
  this.userId = null;
19
+ this.appId = null;
20
+ this.deviceInfo = null;
21
+ this.appStateSubscription = null;
22
+ this.lastAppState = "active";
23
+ this.initialized = false;
11
24
  }
12
25
  static get instance() {
13
26
  if (!this._instance)
14
27
  this._instance = new RampKitCore();
15
28
  return this._instance;
16
29
  }
30
+ /**
31
+ * Initialize the RampKit SDK
32
+ */
17
33
  async init(config) {
18
34
  this.config = config;
35
+ this.appId = config.appId;
19
36
  this.onOnboardingFinished = config.onOnboardingFinished;
20
37
  this.onShowPaywall = config.onShowPaywall || config.showPaywall;
21
38
  try {
22
- // Ensure a stable, encrypted user id exists on first init
23
- this.userId = await (0, userId_1.getRampKitUserId)();
39
+ // Step 1: Collect device info (includes user ID generation)
40
+ console.log("[RampKit] Init: Collecting device info...");
41
+ this.deviceInfo = await (0, DeviceInfoCollector_1.collectDeviceInfo)();
42
+ this.userId = this.deviceInfo.appUserId;
24
43
  console.log("[RampKit] Init: userId", this.userId);
44
+ // Step 2: Send device info to /app-users endpoint
45
+ console.log("[RampKit] Init: Sending user data to backend...");
46
+ await this.sendUserDataToBackend(this.deviceInfo);
47
+ // Step 3: Initialize event manager
48
+ console.log("[RampKit] Init: Initializing event manager...");
49
+ EventManager_1.eventManager.initialize(config.appId, this.deviceInfo);
50
+ // Step 4: Track app session started
51
+ EventManager_1.eventManager.trackAppSessionStarted(this.deviceInfo.isFirstLaunch, this.deviceInfo.launchCount);
52
+ // Step 5: Setup app state listener for background/foreground tracking
53
+ this.setupAppStateListener();
54
+ this.initialized = true;
25
55
  }
26
56
  catch (e) {
27
- console.log("[RampKit] Init: failed to resolve user id", e);
57
+ console.log("[RampKit] Init: Failed to initialize device info", e);
58
+ // Fallback to just getting user ID
59
+ try {
60
+ this.userId = await (0, userId_1.getRampKitUserId)();
61
+ }
62
+ catch (e2) {
63
+ console.log("[RampKit] Init: Failed to resolve user id", e2);
64
+ }
28
65
  }
29
- console.log("[RampKit] Init: starting onboarding load");
66
+ // Load onboarding data
67
+ console.log("[RampKit] Init: Starting onboarding load...");
30
68
  try {
31
- const response = await globalThis.fetch(RampKitCore.ONBOARDING_URL);
32
- const json = await response.json();
33
- this.onboardingData = json;
34
- try {
35
- console.log("[RampKit] Init: onboardingId", json && json.onboardingId);
69
+ const manifestUrl = `${constants_1.MANIFEST_BASE_URL}/${config.appId}/manifest.json`;
70
+ console.log("[RampKit] Init: Fetching manifest from", manifestUrl);
71
+ const manifestResponse = await globalThis.fetch(manifestUrl);
72
+ const manifest = await manifestResponse.json();
73
+ if (!manifest.onboardings || manifest.onboardings.length === 0) {
74
+ throw new Error("No onboardings found in manifest");
36
75
  }
37
- catch (_) { }
38
- console.log("[RampKit] Init: onboarding loaded");
76
+ // Use the first onboarding
77
+ const firstOnboarding = manifest.onboardings[0];
78
+ console.log("[RampKit] Init: Using onboarding", firstOnboarding.name, firstOnboarding.id);
79
+ // Fetch the actual onboarding data
80
+ const onboardingResponse = await globalThis.fetch(firstOnboarding.url);
81
+ const json = await onboardingResponse.json();
82
+ this.onboardingData = json;
83
+ console.log("[RampKit] Init: onboardingId", json && json.onboardingId);
84
+ console.log("[RampKit] Init: Onboarding loaded");
39
85
  }
40
86
  catch (error) {
41
- console.log("[RampKit] Init: onboarding load failed", error);
87
+ console.log("[RampKit] Init: Onboarding load failed", error);
42
88
  this.onboardingData = null;
43
89
  }
44
- console.log("[RampKit] Init: finished", config);
90
+ console.log("[RampKit] Init: Finished", config);
45
91
  // Optionally auto-show onboarding overlay
46
92
  try {
47
93
  if (this.onboardingData && config.autoShowOnboarding) {
48
- console.log("[RampKit] Init: auto-show onboarding");
94
+ console.log("[RampKit] Init: Auto-show onboarding");
49
95
  this.showOnboarding();
50
96
  }
51
97
  }
52
98
  catch (_) { }
53
99
  }
100
+ /**
101
+ * Send user/device data to the /app-users endpoint
102
+ */
103
+ async sendUserDataToBackend(deviceInfo) {
104
+ try {
105
+ const url = `${constants_1.ENDPOINTS.BASE_URL}${constants_1.ENDPOINTS.APP_USERS}?appId=${this.appId}`;
106
+ const response = await fetch(url, {
107
+ method: "POST",
108
+ headers: {
109
+ "Content-Type": "application/json",
110
+ apikey: constants_1.SUPABASE_ANON_KEY,
111
+ Authorization: `Bearer ${constants_1.SUPABASE_ANON_KEY}`,
112
+ },
113
+ body: JSON.stringify(deviceInfo),
114
+ });
115
+ if (!response.ok) {
116
+ console.warn("[RampKit] Init: Failed to send user data:", response.status);
117
+ }
118
+ else {
119
+ console.log("[RampKit] Init: User data sent successfully");
120
+ }
121
+ }
122
+ catch (error) {
123
+ console.warn("[RampKit] Init: Error sending user data:", error);
124
+ }
125
+ }
126
+ /**
127
+ * Setup app state listener for background/foreground tracking
128
+ */
129
+ setupAppStateListener() {
130
+ this.appStateSubscription = react_native_1.AppState.addEventListener("change", (nextAppState) => {
131
+ if (this.lastAppState === "active" &&
132
+ (nextAppState === "background" || nextAppState === "inactive")) {
133
+ // App went to background
134
+ const sessionDuration = (0, DeviceInfoCollector_1.getSessionDurationSeconds)();
135
+ EventManager_1.eventManager.trackAppBackgrounded(sessionDuration);
136
+ }
137
+ else if ((this.lastAppState === "background" ||
138
+ this.lastAppState === "inactive") &&
139
+ nextAppState === "active") {
140
+ // App came to foreground
141
+ EventManager_1.eventManager.trackAppForegrounded();
142
+ }
143
+ this.lastAppState = nextAppState;
144
+ });
145
+ }
146
+ /**
147
+ * Get the onboarding data
148
+ */
54
149
  getOnboardingData() {
55
150
  return this.onboardingData;
56
151
  }
152
+ /**
153
+ * Get the user ID
154
+ */
57
155
  getUserId() {
58
156
  return this.userId;
59
157
  }
158
+ /**
159
+ * Get the device info
160
+ */
161
+ getDeviceInfo() {
162
+ return this.deviceInfo;
163
+ }
164
+ /**
165
+ * Check if SDK is initialized
166
+ */
167
+ isInitialized() {
168
+ return this.initialized;
169
+ }
170
+ /**
171
+ * Show the onboarding overlay
172
+ */
60
173
  showOnboarding(opts) {
61
174
  const data = this.onboardingData;
62
175
  if (!data || !Array.isArray(data.screens) || data.screens.length === 0) {
63
- console.log("[RampKit] ShowOnboarding: no onboarding data available");
176
+ console.log("[RampKit] ShowOnboarding: No onboarding data available");
64
177
  return;
65
178
  }
66
179
  try {
@@ -81,17 +194,20 @@ class RampKitCore {
81
194
  const screens = data.screens.map((s) => ({
82
195
  id: s.id,
83
196
  html: s.html ||
84
- `<div style=\"padding:24px\"><h1>${s.label || s.id}</h1><button onclick=\"window.ReactNativeWebView && window.ReactNativeWebView.postMessage('rampkit:tap')\">Continue</button></div>`,
197
+ `<div style="padding:24px"><h1>${s.label || s.id}</h1><button onclick="window.ReactNativeWebView && window.ReactNativeWebView.postMessage('rampkit:tap')">Continue</button></div>`,
85
198
  css: s.css,
86
199
  js: s.js,
87
200
  }));
88
201
  const requiredScripts = Array.isArray(data.requiredScripts)
89
202
  ? data.requiredScripts
90
203
  : [];
204
+ // Track onboarding started event
205
+ const onboardingId = data.onboardingId || data.id || "unknown";
206
+ EventManager_1.eventManager.trackOnboardingStarted(onboardingId, screens.length);
91
207
  // Optional warm-up
92
208
  try {
93
209
  (0, RampkitOverlay_1.preloadRampkitOverlay)({
94
- onboardingId: data.onboardingId,
210
+ onboardingId,
95
211
  screens,
96
212
  variables,
97
213
  requiredScripts,
@@ -99,27 +215,114 @@ class RampKitCore {
99
215
  }
100
216
  catch (_) { }
101
217
  (0, RampkitOverlay_1.showRampkitOverlay)({
102
- onboardingId: data.onboardingId,
218
+ onboardingId,
103
219
  screens,
104
220
  variables,
105
221
  requiredScripts,
106
222
  onOnboardingFinished: (payload) => {
107
223
  var _a;
224
+ // Track onboarding completed
225
+ EventManager_1.eventManager.trackOnboardingCompleted(screens.length, screens.length, onboardingId);
108
226
  try {
109
227
  (_a = this.onOnboardingFinished) === null || _a === void 0 ? void 0 : _a.call(this, payload);
110
228
  }
111
229
  catch (_) { }
112
230
  },
113
231
  onShowPaywall: (opts === null || opts === void 0 ? void 0 : opts.onShowPaywall) || (opts === null || opts === void 0 ? void 0 : opts.showPaywall) || this.onShowPaywall,
232
+ onScreenChange: (screenIndex, screenId) => {
233
+ // Track screen view within onboarding
234
+ EventManager_1.eventManager.trackOnboardingScreenViewed(screenId, screenIndex, screens.length, onboardingId);
235
+ },
236
+ onOnboardingAbandoned: (reason, lastScreenIndex, lastScreenId) => {
237
+ // Track onboarding abandoned
238
+ EventManager_1.eventManager.trackOnboardingAbandoned(reason, lastScreenId, onboardingId);
239
+ },
240
+ onNotificationPermissionRequested: () => {
241
+ EventManager_1.eventManager.trackNotificationsPromptShown();
242
+ },
243
+ onNotificationPermissionResult: (granted) => {
244
+ EventManager_1.eventManager.trackNotificationsResponse(granted ? "granted" : "denied");
245
+ },
114
246
  });
115
247
  }
116
248
  catch (e) {
117
- console.log("[RampKit] ShowOnboarding: failed to show overlay", e);
249
+ console.log("[RampKit] ShowOnboarding: Failed to show overlay", e);
118
250
  }
119
251
  }
252
+ /**
253
+ * Close the onboarding overlay
254
+ */
120
255
  closeOnboarding() {
121
256
  (0, RampkitOverlay_1.closeRampkitOverlay)();
122
257
  }
258
+ // ============================================================================
259
+ // Public Event Tracking API
260
+ // ============================================================================
261
+ /**
262
+ * Track a custom event
263
+ */
264
+ trackEvent(eventName, properties = {}, context) {
265
+ EventManager_1.eventManager.track(eventName, properties, context);
266
+ }
267
+ /**
268
+ * Track a screen view
269
+ */
270
+ trackScreenView(screenName, referrer) {
271
+ EventManager_1.eventManager.trackScreenView(screenName, referrer);
272
+ }
273
+ /**
274
+ * Track a CTA tap
275
+ */
276
+ trackCtaTap(buttonId, buttonText) {
277
+ EventManager_1.eventManager.trackCtaTap(buttonId, buttonText);
278
+ }
279
+ /**
280
+ * Track paywall shown
281
+ */
282
+ trackPaywallShown(paywallId, placement, products) {
283
+ EventManager_1.eventManager.trackPaywallShown(paywallId, placement, products);
284
+ }
285
+ /**
286
+ * Track paywall primary action tap
287
+ */
288
+ trackPaywallPrimaryActionTap(paywallId, productId) {
289
+ EventManager_1.eventManager.trackPaywallPrimaryActionTap(paywallId, productId);
290
+ }
291
+ /**
292
+ * Track paywall closed
293
+ */
294
+ trackPaywallClosed(paywallId, reason) {
295
+ EventManager_1.eventManager.trackPaywallClosed(paywallId, reason);
296
+ }
297
+ /**
298
+ * Track purchase started
299
+ */
300
+ trackPurchaseStarted(productId, amount, currency) {
301
+ EventManager_1.eventManager.trackPurchaseStarted(productId, amount, currency);
302
+ }
303
+ /**
304
+ * Track purchase completed
305
+ */
306
+ trackPurchaseCompleted(properties) {
307
+ EventManager_1.eventManager.trackPurchaseCompleted(properties);
308
+ }
309
+ /**
310
+ * Track purchase failed
311
+ */
312
+ trackPurchaseFailed(productId, errorCode, errorMessage) {
313
+ EventManager_1.eventManager.trackPurchaseFailed(productId, errorCode, errorMessage);
314
+ }
315
+ /**
316
+ * Cleanup SDK resources
317
+ */
318
+ cleanup() {
319
+ if (this.appStateSubscription) {
320
+ this.appStateSubscription.remove();
321
+ this.appStateSubscription = null;
322
+ }
323
+ EventManager_1.eventManager.reset();
324
+ (0, DeviceInfoCollector_1.resetSession)();
325
+ this.initialized = false;
326
+ }
123
327
  }
124
328
  exports.RampKitCore = RampKitCore;
125
- RampKitCore.ONBOARDING_URL = "https://dqplcvw3fzili.cloudfront.net/labelaiOnboarding.json";
@@ -0,0 +1,151 @@
1
+ /**
2
+ * RampKit Native Module Bridge
3
+ * TypeScript interface to the native iOS/Android module
4
+ */
5
+ interface RampKitNativeModule {
6
+ getDeviceInfo(): Promise<NativeDeviceInfo>;
7
+ getUserId(): Promise<string>;
8
+ getStoredValue(key: string): Promise<string | null>;
9
+ setStoredValue(key: string, value: string): Promise<void>;
10
+ getLaunchTrackingData(): Promise<NativeLaunchData>;
11
+ impactAsync(style: string): Promise<void>;
12
+ notificationAsync(type: string): Promise<void>;
13
+ selectionAsync(): Promise<void>;
14
+ requestReview(): Promise<boolean | void>;
15
+ isReviewAvailable(): Promise<boolean>;
16
+ getStoreUrl(): Promise<string | null>;
17
+ requestNotificationPermissions(options?: NotificationOptions): Promise<NotificationPermissionResult>;
18
+ getNotificationPermissions(): Promise<NotificationPermissionResult>;
19
+ }
20
+ export interface NativeDeviceInfo {
21
+ appUserId: string;
22
+ vendorId: string | null;
23
+ appSessionId: string;
24
+ installDate: string;
25
+ isFirstLaunch: boolean;
26
+ launchCount: number;
27
+ lastLaunchAt: string | null;
28
+ bundleId: string | null;
29
+ appName: string | null;
30
+ appVersion: string | null;
31
+ buildNumber: string | null;
32
+ platform: string;
33
+ platformVersion: string;
34
+ deviceModel: string;
35
+ deviceName: string;
36
+ isSimulator: boolean;
37
+ deviceLanguageCode: string | null;
38
+ deviceLocale: string;
39
+ regionCode: string | null;
40
+ preferredLanguage: string | null;
41
+ preferredLanguages: string[];
42
+ deviceCurrencyCode: string | null;
43
+ deviceCurrencySymbol: string | null;
44
+ timezoneIdentifier: string;
45
+ timezoneOffsetSeconds: number;
46
+ interfaceStyle: string;
47
+ screenWidth: number;
48
+ screenHeight: number;
49
+ screenScale: number;
50
+ isLowPowerMode: boolean;
51
+ totalMemoryBytes: number;
52
+ collectedAt: string;
53
+ }
54
+ export interface NativeLaunchData {
55
+ installDate: string;
56
+ isFirstLaunch: boolean;
57
+ launchCount: number;
58
+ lastLaunchAt: string | null;
59
+ }
60
+ export interface NotificationOptions {
61
+ ios?: {
62
+ allowAlert?: boolean;
63
+ allowBadge?: boolean;
64
+ allowSound?: boolean;
65
+ };
66
+ android?: {
67
+ channelId?: string;
68
+ name?: string;
69
+ importance?: "MAX" | "HIGH" | "DEFAULT" | "LOW" | "MIN";
70
+ };
71
+ }
72
+ export interface NotificationPermissionResult {
73
+ granted: boolean;
74
+ status: "undetermined" | "denied" | "granted" | "provisional" | "ephemeral";
75
+ canAskAgain: boolean;
76
+ ios?: {
77
+ alertSetting?: string;
78
+ badgeSetting?: string;
79
+ soundSetting?: string;
80
+ lockScreenSetting?: string;
81
+ notificationCenterSetting?: string;
82
+ };
83
+ error?: string;
84
+ }
85
+ export type ImpactStyle = "light" | "medium" | "heavy" | "rigid" | "soft";
86
+ export type NotificationType = "success" | "warning" | "error";
87
+ declare let RampKitNativeModule: RampKitNativeModule;
88
+ export default RampKitNativeModule;
89
+ export declare function getDeviceInfo(): Promise<NativeDeviceInfo>;
90
+ export declare function getUserId(): Promise<string>;
91
+ export declare function getStoredValue(key: string): Promise<string | null>;
92
+ export declare function setStoredValue(key: string, value: string): Promise<void>;
93
+ export declare function getLaunchTrackingData(): Promise<NativeLaunchData>;
94
+ export declare const Haptics: {
95
+ /**
96
+ * Trigger an impact haptic feedback
97
+ */
98
+ impactAsync(style?: ImpactStyle): Promise<void>;
99
+ /**
100
+ * Trigger a notification haptic feedback
101
+ */
102
+ notificationAsync(type?: NotificationType): Promise<void>;
103
+ /**
104
+ * Trigger a selection haptic feedback
105
+ */
106
+ selectionAsync(): Promise<void>;
107
+ };
108
+ export declare const StoreReview: {
109
+ /**
110
+ * Request an in-app review
111
+ */
112
+ requestReview(): Promise<void>;
113
+ /**
114
+ * Check if in-app review is available
115
+ */
116
+ isAvailableAsync(): Promise<boolean>;
117
+ /**
118
+ * Check if the review action is available
119
+ */
120
+ hasAction(): Promise<boolean>;
121
+ /**
122
+ * Get the store URL for the app
123
+ */
124
+ storeUrl(): string | null;
125
+ };
126
+ export declare const Notifications: {
127
+ /**
128
+ * Request notification permissions
129
+ */
130
+ requestPermissionsAsync(options?: NotificationOptions): Promise<NotificationPermissionResult>;
131
+ /**
132
+ * Get current notification permissions
133
+ */
134
+ getPermissionsAsync(): Promise<NotificationPermissionResult>;
135
+ /**
136
+ * Set notification handler (no-op in native implementation)
137
+ * The app should handle this separately if needed
138
+ */
139
+ setNotificationHandler(_handler: any): void;
140
+ /**
141
+ * Android notification channel creation is handled in requestPermissionsAsync
142
+ */
143
+ setNotificationChannelAsync(_channelId: string, _options: any): Promise<void>;
144
+ AndroidImportance: {
145
+ MAX: number;
146
+ HIGH: number;
147
+ DEFAULT: number;
148
+ LOW: number;
149
+ MIN: number;
150
+ };
151
+ };