@virex-tech/paywallo-sdk 2.2.3 → 2.2.4
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/android/src/main/AndroidManifest.xml +7 -0
- package/dist/index.d.mts +70 -9
- package/dist/index.d.ts +70 -9
- package/dist/index.js +258 -175
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +277 -192
- package/dist/index.mjs.map +1 -1
- package/ios/PaywalloWebView.m +5 -0
- package/package.json +6 -2
package/dist/index.js
CHANGED
|
@@ -1067,7 +1067,7 @@ var init_sessionTracking = __esm({
|
|
|
1067
1067
|
});
|
|
1068
1068
|
|
|
1069
1069
|
// src/domains/session/SessionManager.ts
|
|
1070
|
-
var import_react_native4, SESSION_ID_KEY, SESSION_START_KEY,
|
|
1070
|
+
var import_react_native4, SESSION_ID_KEY, SESSION_START_KEY, LEGACY_SESSION_ID_KEY, LEGACY_SESSION_START_KEY, SESSION_TIMEOUT_MS, SessionManager, sessionManager;
|
|
1071
1071
|
var init_SessionManager = __esm({
|
|
1072
1072
|
"src/domains/session/SessionManager.ts"() {
|
|
1073
1073
|
"use strict";
|
|
@@ -1079,11 +1079,9 @@ var init_SessionManager = __esm({
|
|
|
1079
1079
|
init_sessionTracking();
|
|
1080
1080
|
SESSION_ID_KEY = "@paywallo:current_session_id";
|
|
1081
1081
|
SESSION_START_KEY = "@paywallo:session_start";
|
|
1082
|
-
EMERGENCY_PAYWALL_SHOWN_KEY = "@paywallo:emergency_paywall_shown";
|
|
1083
1082
|
LEGACY_SESSION_ID_KEY = "current_session_id";
|
|
1084
1083
|
LEGACY_SESSION_START_KEY = "session_start";
|
|
1085
1084
|
SESSION_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
1086
|
-
BACKGROUND_FLUSH_TIMEOUT_MS = 2e3;
|
|
1087
1085
|
SessionManager = class {
|
|
1088
1086
|
constructor() {
|
|
1089
1087
|
this.sessionId = null;
|
|
@@ -1145,8 +1143,7 @@ var init_SessionManager = __esm({
|
|
|
1145
1143
|
this.emergencyPaywallShownInSession = false;
|
|
1146
1144
|
await Promise.all([
|
|
1147
1145
|
this.secureStorage.set(SESSION_ID_KEY, this.sessionId),
|
|
1148
|
-
this.secureStorage.set(SESSION_START_KEY, this.sessionStartedAt.toISOString())
|
|
1149
|
-
this.secureStorage.remove(EMERGENCY_PAYWALL_SHOWN_KEY)
|
|
1146
|
+
this.secureStorage.set(SESSION_START_KEY, this.sessionStartedAt.toISOString())
|
|
1150
1147
|
]);
|
|
1151
1148
|
await this.trackSessionStart();
|
|
1152
1149
|
return this.sessionId;
|
|
@@ -1156,10 +1153,10 @@ var init_SessionManager = __esm({
|
|
|
1156
1153
|
if (!this.sessionId || !this.sessionStartedAt) {
|
|
1157
1154
|
return;
|
|
1158
1155
|
}
|
|
1156
|
+
await this.trackSessionEnd();
|
|
1159
1157
|
if (this.apiClient) {
|
|
1160
1158
|
await this.apiClient.flushEventBatch();
|
|
1161
1159
|
}
|
|
1162
|
-
await this.trackSessionEnd();
|
|
1163
1160
|
this.sessionId = null;
|
|
1164
1161
|
this.sessionStartedAt = null;
|
|
1165
1162
|
await Promise.all([
|
|
@@ -1244,7 +1241,6 @@ var init_SessionManager = __esm({
|
|
|
1244
1241
|
async handleBackground() {
|
|
1245
1242
|
this.backgroundTimestamp = Date.now();
|
|
1246
1243
|
await this.trackAppBackground();
|
|
1247
|
-
await this.flushEventsWithTimeout(BACKGROUND_FLUSH_TIMEOUT_MS);
|
|
1248
1244
|
await this.endSession();
|
|
1249
1245
|
}
|
|
1250
1246
|
async flushEventsWithTimeout(timeoutMs) {
|
|
@@ -1263,7 +1259,6 @@ var init_SessionManager = __esm({
|
|
|
1263
1259
|
const response = await this.apiClient.getEmergencyPaywall().catch(() => null);
|
|
1264
1260
|
if (response?.enabled && response.paywallId) {
|
|
1265
1261
|
this.emergencyPaywallShownInSession = true;
|
|
1266
|
-
await this.secureStorage.set(EMERGENCY_PAYWALL_SHOWN_KEY, "true");
|
|
1267
1262
|
await this.emergencyPaywallHandler(response.paywallId);
|
|
1268
1263
|
}
|
|
1269
1264
|
}
|
|
@@ -1563,7 +1558,7 @@ var init_MetaBridge = __esm({
|
|
|
1563
1558
|
try {
|
|
1564
1559
|
await NativeBridge.logEvent(name, params);
|
|
1565
1560
|
} catch (error) {
|
|
1566
|
-
|
|
1561
|
+
console.error("[Paywallo:MetaBridge] logEvent failed", { name, error });
|
|
1567
1562
|
}
|
|
1568
1563
|
}
|
|
1569
1564
|
async logPurchase(amount, currency, params = {}) {
|
|
@@ -1571,7 +1566,7 @@ var init_MetaBridge = __esm({
|
|
|
1571
1566
|
try {
|
|
1572
1567
|
await NativeBridge.logPurchase(amount, currency, params);
|
|
1573
1568
|
} catch (error) {
|
|
1574
|
-
|
|
1569
|
+
console.error("[Paywallo:MetaBridge] logPurchase failed", { amount, currency, error });
|
|
1575
1570
|
}
|
|
1576
1571
|
}
|
|
1577
1572
|
setUserID(userId) {
|
|
@@ -1579,7 +1574,7 @@ var init_MetaBridge = __esm({
|
|
|
1579
1574
|
try {
|
|
1580
1575
|
NativeBridge.setUserID(userId);
|
|
1581
1576
|
} catch (error) {
|
|
1582
|
-
|
|
1577
|
+
console.error("[Paywallo:MetaBridge] setUserID failed", { error });
|
|
1583
1578
|
}
|
|
1584
1579
|
}
|
|
1585
1580
|
flush() {
|
|
@@ -1587,7 +1582,7 @@ var init_MetaBridge = __esm({
|
|
|
1587
1582
|
try {
|
|
1588
1583
|
NativeBridge.flush();
|
|
1589
1584
|
} catch (error) {
|
|
1590
|
-
|
|
1585
|
+
console.error("[Paywallo:MetaBridge] flush failed", { error });
|
|
1591
1586
|
}
|
|
1592
1587
|
}
|
|
1593
1588
|
};
|
|
@@ -1803,7 +1798,7 @@ var init_InstallTracker = __esm({
|
|
|
1803
1798
|
screenWidth: deviceData.screenWidth,
|
|
1804
1799
|
screenHeight: deviceData.screenHeight,
|
|
1805
1800
|
timezone: deviceData.timezone,
|
|
1806
|
-
|
|
1801
|
+
language: deviceData.locale,
|
|
1807
1802
|
fbAnonId: anonId,
|
|
1808
1803
|
installTimestamp: new Date(installedAt).toISOString()
|
|
1809
1804
|
}),
|
|
@@ -2177,7 +2172,7 @@ function setupForegroundHandler(deps, onReceive) {
|
|
|
2177
2172
|
title: data["title"] ?? message.notification?.title ?? "",
|
|
2178
2173
|
body: data["body"] ?? message.notification?.body ?? ""
|
|
2179
2174
|
});
|
|
2180
|
-
if (debug) console.
|
|
2175
|
+
if (debug) console.log("[Paywallo PUSH] foreground message received:", payload.notificationId);
|
|
2181
2176
|
onReceive(payload);
|
|
2182
2177
|
const messageId = message.messageId ?? payload.notificationId;
|
|
2183
2178
|
await tracker.track("notification_delivered", {
|
|
@@ -2207,14 +2202,21 @@ function getTimezone() {
|
|
|
2207
2202
|
function detectPlatform() {
|
|
2208
2203
|
return import_react_native10.Platform.OS === "ios" ? "ios" : "android";
|
|
2209
2204
|
}
|
|
2210
|
-
var import_react_native10, SEEN_MESSAGES_KEY, SEEN_TTL_MS, MAX_SEEN_SIZE, NotificationEventTracker;
|
|
2205
|
+
var import_react_native10, SEEN_MESSAGES_KEY, LEGACY_SEEN_MESSAGES_KEY, SEEN_TTL_MS, MAX_SEEN_SIZE, NOTIFICATION_TYPE_TO_FAMILY, NotificationEventTracker;
|
|
2211
2206
|
var init_NotificationEventTracker = __esm({
|
|
2212
2207
|
"src/domains/notifications/NotificationEventTracker.ts"() {
|
|
2213
2208
|
"use strict";
|
|
2214
2209
|
import_react_native10 = require("react-native");
|
|
2215
|
-
SEEN_MESSAGES_KEY = "seen_messages";
|
|
2210
|
+
SEEN_MESSAGES_KEY = "@paywallo:seen_messages";
|
|
2211
|
+
LEGACY_SEEN_MESSAGES_KEY = "seen_messages";
|
|
2216
2212
|
SEEN_TTL_MS = 60 * 60 * 1e3;
|
|
2217
2213
|
MAX_SEEN_SIZE = 1e3;
|
|
2214
|
+
NOTIFICATION_TYPE_TO_FAMILY = {
|
|
2215
|
+
notification_delivered: "delivered",
|
|
2216
|
+
notification_displayed: "displayed",
|
|
2217
|
+
notification_clicked: "clicked",
|
|
2218
|
+
notification_dismissed: "dismissed"
|
|
2219
|
+
};
|
|
2218
2220
|
NotificationEventTracker = class {
|
|
2219
2221
|
constructor(batcher, config, secureStorage2) {
|
|
2220
2222
|
this.batcher = batcher;
|
|
@@ -2235,9 +2237,13 @@ var init_NotificationEventTracker = __esm({
|
|
|
2235
2237
|
if (this.config.debug) console.log("[Paywallo PUSH] skipped (no distinctId):", eventType);
|
|
2236
2238
|
return;
|
|
2237
2239
|
}
|
|
2240
|
+
const canonicalType = NOTIFICATION_TYPE_TO_FAMILY[eventType];
|
|
2241
|
+
if (!canonicalType) {
|
|
2242
|
+
if (this.config.debug) console.log("[Paywallo PUSH] eventType not mapped to family schema, skipping ingest:", eventType);
|
|
2243
|
+
return;
|
|
2244
|
+
}
|
|
2238
2245
|
const properties = {
|
|
2239
|
-
|
|
2240
|
-
type: eventType,
|
|
2246
|
+
type: canonicalType,
|
|
2241
2247
|
notification_id: notificationId,
|
|
2242
2248
|
campaign_id: campaignId,
|
|
2243
2249
|
variant_key: variantKey ?? null,
|
|
@@ -2249,7 +2255,7 @@ var init_NotificationEventTracker = __esm({
|
|
|
2249
2255
|
if (payload.failureReason) properties.failure_reason = payload.failureReason;
|
|
2250
2256
|
if (payload.appUserId) properties.app_user_id = payload.appUserId;
|
|
2251
2257
|
if (payload.properties) Object.assign(properties, payload.properties);
|
|
2252
|
-
if (this.config.debug) console.log("[Paywallo PUSH] tracking event:",
|
|
2258
|
+
if (this.config.debug) console.log("[Paywallo PUSH] tracking event:", canonicalType, notificationId);
|
|
2253
2259
|
await this.batcher.trackEvent("notification", distinctId, properties);
|
|
2254
2260
|
}
|
|
2255
2261
|
async isDuplicate(messageId, eventType) {
|
|
@@ -2294,7 +2300,10 @@ var init_NotificationEventTracker = __esm({
|
|
|
2294
2300
|
return;
|
|
2295
2301
|
}
|
|
2296
2302
|
try {
|
|
2297
|
-
|
|
2303
|
+
let raw = await this.secureStorage.get(SEEN_MESSAGES_KEY);
|
|
2304
|
+
if (!raw) {
|
|
2305
|
+
raw = await this.secureStorage.get(LEGACY_SEEN_MESSAGES_KEY).catch(() => null);
|
|
2306
|
+
}
|
|
2298
2307
|
if (raw) {
|
|
2299
2308
|
const parsed = JSON.parse(raw);
|
|
2300
2309
|
const now = Date.now();
|
|
@@ -2368,8 +2377,8 @@ var init_NotificationHandlerSetup = __esm({
|
|
|
2368
2377
|
// src/core/version.ts
|
|
2369
2378
|
function resolveVersion() {
|
|
2370
2379
|
try {
|
|
2371
|
-
if ("2.2.
|
|
2372
|
-
return "2.2.
|
|
2380
|
+
if ("2.2.4") {
|
|
2381
|
+
return "2.2.4";
|
|
2373
2382
|
}
|
|
2374
2383
|
} catch {
|
|
2375
2384
|
}
|
|
@@ -2501,7 +2510,7 @@ async function buildRegistration(token, getDeviceId, getDistinctId) {
|
|
|
2501
2510
|
async function registerToken(deps, token) {
|
|
2502
2511
|
const { httpClient, appKey, getDeviceId, getDistinctId, debug } = deps;
|
|
2503
2512
|
if (!httpClient || !appKey) {
|
|
2504
|
-
if (debug) console.
|
|
2513
|
+
if (debug) console.log("[Paywallo PUSH] httpClient not ready, skipping token registration");
|
|
2505
2514
|
return;
|
|
2506
2515
|
}
|
|
2507
2516
|
const registration = await buildRegistration(token, getDeviceId, getDistinctId);
|
|
@@ -2511,22 +2520,25 @@ async function registerToken(deps, token) {
|
|
|
2511
2520
|
registration,
|
|
2512
2521
|
{ headers: { "X-App-Key": appKey } }
|
|
2513
2522
|
);
|
|
2514
|
-
if (debug) console.
|
|
2523
|
+
if (debug) console.log("[Paywallo PUSH] token registered successfully");
|
|
2515
2524
|
} catch (err) {
|
|
2516
|
-
|
|
2525
|
+
console.error("[Paywallo PUSH] token registration failed:", err);
|
|
2517
2526
|
throw new RegistrationFailedError("Token registration failed", err);
|
|
2518
2527
|
}
|
|
2519
2528
|
}
|
|
2520
|
-
async function unregisterToken(httpClient, appKey, debug) {
|
|
2529
|
+
async function unregisterToken(httpClient, appKey, debug, token, distinctId) {
|
|
2521
2530
|
if (!httpClient || !appKey) return;
|
|
2531
|
+
if (!token || !distinctId) return;
|
|
2522
2532
|
try {
|
|
2533
|
+
const body = JSON.stringify({ token, distinct_id: distinctId });
|
|
2523
2534
|
await httpClient.request(TOKEN_ENDPOINT, {
|
|
2524
2535
|
method: "DELETE",
|
|
2525
|
-
headers: { "X-App-Key": appKey },
|
|
2536
|
+
headers: { "X-App-Key": appKey, "Content-Type": "application/json" },
|
|
2537
|
+
body,
|
|
2526
2538
|
timeout: 1e4
|
|
2527
2539
|
});
|
|
2528
2540
|
} catch (err) {
|
|
2529
|
-
|
|
2541
|
+
console.error("[Paywallo PUSH] optOut error:", err);
|
|
2530
2542
|
}
|
|
2531
2543
|
}
|
|
2532
2544
|
var FCM_TOKEN_KEY, TOKEN_ENDPOINT;
|
|
@@ -2558,7 +2570,7 @@ async function registerAndPersistToken(deps, token) {
|
|
|
2558
2570
|
}
|
|
2559
2571
|
function subscribeTokenRefresh(bridge, deps, onToken) {
|
|
2560
2572
|
return bridge.onTokenRefresh((newToken) => {
|
|
2561
|
-
if (deps.debug) console.
|
|
2573
|
+
if (deps.debug) console.log("[Paywallo PUSH] token refreshed");
|
|
2562
2574
|
onToken(newToken);
|
|
2563
2575
|
persistToken(deps.secureStorage, newToken).catch(() => void 0);
|
|
2564
2576
|
registerToken(
|
|
@@ -2574,8 +2586,8 @@ function subscribeTokenRefresh(bridge, deps, onToken) {
|
|
|
2574
2586
|
).catch(() => void 0);
|
|
2575
2587
|
});
|
|
2576
2588
|
}
|
|
2577
|
-
async function optOutToken(httpClient, secureStorage2, appKey, debug) {
|
|
2578
|
-
await unregisterToken(httpClient, appKey, debug);
|
|
2589
|
+
async function optOutToken(httpClient, secureStorage2, appKey, debug, token, distinctId) {
|
|
2590
|
+
await unregisterToken(httpClient, appKey, debug, token, distinctId);
|
|
2579
2591
|
await clearPersistedToken(secureStorage2);
|
|
2580
2592
|
}
|
|
2581
2593
|
async function invalidateLocalTokenStorage(secureStorage2, debug) {
|
|
@@ -2595,7 +2607,7 @@ async function captureAndRegisterToken(bridge, deps, onTokenCaptured, subscribeR
|
|
|
2595
2607
|
await waitForApnsToken(bridge, deps.debug);
|
|
2596
2608
|
const token = await bridge.getToken();
|
|
2597
2609
|
if (!token) {
|
|
2598
|
-
if (deps.debug) console.
|
|
2610
|
+
if (deps.debug) console.log("[Paywallo PUSH] token unavailable after grant");
|
|
2599
2611
|
return;
|
|
2600
2612
|
}
|
|
2601
2613
|
onTokenCaptured(token);
|
|
@@ -2662,18 +2674,18 @@ var init_PermissionManager = __esm({
|
|
|
2662
2674
|
}
|
|
2663
2675
|
async requestPermission(options) {
|
|
2664
2676
|
const platform = this.platformOverride ?? getPlatform();
|
|
2665
|
-
if (this.debug) console.
|
|
2677
|
+
if (this.debug) console.log("[paywallo-push] platform detected:", platform.OS, "version:", String(platform.Version ?? "n/a"));
|
|
2666
2678
|
if (platform.OS === "ios") {
|
|
2667
|
-
if (this.debug) console.
|
|
2679
|
+
if (this.debug) console.log("[paywallo-push] requestPermission iOS \u2014 calling bridge...");
|
|
2668
2680
|
try {
|
|
2669
2681
|
const raw2 = await this.bridge.requestPermission(options);
|
|
2670
|
-
if (this.debug) console.
|
|
2682
|
+
if (this.debug) console.log("[paywallo-push] bridge returned raw:", raw2);
|
|
2671
2683
|
const status2 = mapPermissionStatus2(raw2);
|
|
2672
|
-
if (this.debug) console.
|
|
2684
|
+
if (this.debug) console.log("[paywallo-push] mapped status:", status2);
|
|
2673
2685
|
this.emitOsEvent(status2);
|
|
2674
2686
|
return status2;
|
|
2675
2687
|
} catch (err) {
|
|
2676
|
-
|
|
2688
|
+
console.error("[paywallo-push] requestPermission iOS CRASHED:", err instanceof Error ? err.message : String(err));
|
|
2677
2689
|
throw err;
|
|
2678
2690
|
}
|
|
2679
2691
|
}
|
|
@@ -2806,11 +2818,11 @@ var init_NotificationsManager = __esm({
|
|
|
2806
2818
|
await waitForApnsToken(this.bridge, this.debug);
|
|
2807
2819
|
const token = await this.bridge.getToken();
|
|
2808
2820
|
if (!token) {
|
|
2809
|
-
if (this.debug) console.
|
|
2821
|
+
if (this.debug) console.log("[Paywallo PUSH] token unavailable, skipping registration");
|
|
2810
2822
|
this.isInitialized = true;
|
|
2811
2823
|
return;
|
|
2812
2824
|
}
|
|
2813
|
-
if (this.debug) console.
|
|
2825
|
+
if (this.debug) console.log("[Paywallo PUSH] token acquired:", token);
|
|
2814
2826
|
this.currentToken = token;
|
|
2815
2827
|
await this.doRegisterToken(token);
|
|
2816
2828
|
this.subscribeTokenRefresh();
|
|
@@ -2828,7 +2840,7 @@ var init_NotificationsManager = __esm({
|
|
|
2828
2840
|
async refreshPermissionStatus() {
|
|
2829
2841
|
const permStatus = await this.bridge.hasPermission();
|
|
2830
2842
|
this.permissionStatus = mapPermissionStatus(permStatus);
|
|
2831
|
-
if (this.debug) console.
|
|
2843
|
+
if (this.debug) console.log("[Paywallo PUSH] permission status:", this.permissionStatus);
|
|
2832
2844
|
}
|
|
2833
2845
|
tokenDeps() {
|
|
2834
2846
|
return {
|
|
@@ -2856,7 +2868,7 @@ var init_NotificationsManager = __esm({
|
|
|
2856
2868
|
async optOut() {
|
|
2857
2869
|
await optOutToken(this.httpClient, this.secureStorage, this.appKey, this.debug);
|
|
2858
2870
|
this.currentToken = null;
|
|
2859
|
-
if (this.debug) console.
|
|
2871
|
+
if (this.debug) console.log("[Paywallo PUSH] opted out");
|
|
2860
2872
|
}
|
|
2861
2873
|
/** Clears token locally without server call (used on sign-out/reset). */
|
|
2862
2874
|
async invalidateLocalToken() {
|
|
@@ -2873,21 +2885,21 @@ var init_NotificationsManager = __esm({
|
|
|
2873
2885
|
}
|
|
2874
2886
|
/** Requests OS permission and, on success, captures + registers the push token. */
|
|
2875
2887
|
async requestPushPermission(options) {
|
|
2876
|
-
if (this.debug) console.
|
|
2888
|
+
if (this.debug) console.log("[Paywallo PUSH] requestPushPermission called");
|
|
2877
2889
|
try {
|
|
2878
2890
|
const status = await this.permissionManager.requestPermission(options);
|
|
2879
|
-
if (this.debug) console.
|
|
2891
|
+
if (this.debug) console.log("[Paywallo PUSH] permissionManager returned:", status);
|
|
2880
2892
|
this.permissionStatus = status;
|
|
2881
2893
|
if (status === "granted" || status === "provisional") {
|
|
2882
|
-
if (this.debug) console.
|
|
2894
|
+
if (this.debug) console.log("[Paywallo PUSH] permission granted \u2014 capturing token...");
|
|
2883
2895
|
await this.captureAndRegisterToken();
|
|
2884
|
-
if (this.debug) console.
|
|
2896
|
+
if (this.debug) console.log("[Paywallo PUSH] token capture complete");
|
|
2885
2897
|
} else {
|
|
2886
|
-
if (this.debug) console.
|
|
2898
|
+
if (this.debug) console.log("[Paywallo PUSH] permission not granted, skipping token register:", status);
|
|
2887
2899
|
}
|
|
2888
2900
|
return status;
|
|
2889
2901
|
} catch (err) {
|
|
2890
|
-
|
|
2902
|
+
console.error("[Paywallo PUSH] requestPushPermission CRASHED:", err instanceof Error ? err.message : String(err));
|
|
2891
2903
|
throw err;
|
|
2892
2904
|
}
|
|
2893
2905
|
}
|
|
@@ -3049,7 +3061,9 @@ function parseWebViewMessage(raw) {
|
|
|
3049
3061
|
const safePayload = payload !== null && typeof payload === "object" ? {
|
|
3050
3062
|
productId: typeof payload.productId === "string" ? String(payload.productId) : void 0,
|
|
3051
3063
|
url: typeof payload.url === "string" ? String(payload.url) : void 0,
|
|
3052
|
-
timestamp: typeof payload.timestamp === "number" ? Number(payload.timestamp) : void 0
|
|
3064
|
+
timestamp: typeof payload.timestamp === "number" ? Number(payload.timestamp) : void 0,
|
|
3065
|
+
variantKey: typeof payload.variantKey === "string" ? String(payload.variantKey) : void 0,
|
|
3066
|
+
style: HAPTIC_STYLES.has(String(payload.style)) ? String(payload.style) : typeof payload.style !== "undefined" ? "light" : void 0
|
|
3053
3067
|
} : void 0;
|
|
3054
3068
|
return {
|
|
3055
3069
|
type: parsed.type,
|
|
@@ -3060,17 +3074,19 @@ function parseWebViewMessage(raw) {
|
|
|
3060
3074
|
return null;
|
|
3061
3075
|
}
|
|
3062
3076
|
}
|
|
3063
|
-
var ALLOWED_MESSAGE_TYPES;
|
|
3077
|
+
var HAPTIC_STYLES, ALLOWED_MESSAGE_TYPES;
|
|
3064
3078
|
var init_parseWebViewMessage = __esm({
|
|
3065
3079
|
"src/domains/paywall/parseWebViewMessage.ts"() {
|
|
3066
3080
|
"use strict";
|
|
3081
|
+
HAPTIC_STYLES = /* @__PURE__ */ new Set(["light", "medium", "heavy"]);
|
|
3067
3082
|
ALLOWED_MESSAGE_TYPES = /* @__PURE__ */ new Set([
|
|
3068
3083
|
"purchase",
|
|
3069
3084
|
"close",
|
|
3070
3085
|
"restore",
|
|
3071
3086
|
"select-product",
|
|
3072
3087
|
"open-url",
|
|
3073
|
-
"ready"
|
|
3088
|
+
"ready",
|
|
3089
|
+
"haptic"
|
|
3074
3090
|
]);
|
|
3075
3091
|
}
|
|
3076
3092
|
});
|
|
@@ -3112,7 +3128,7 @@ var init_PaywallErrorBoundary = __esm({
|
|
|
3112
3128
|
return { hasError: true };
|
|
3113
3129
|
}
|
|
3114
3130
|
componentDidCatch(error) {
|
|
3115
|
-
|
|
3131
|
+
console.error("[Paywallo] Paywall render error:", error);
|
|
3116
3132
|
try {
|
|
3117
3133
|
PaywalloClient.getApiClient()?.reportError("PAYWALL_RENDER_ERROR", error.message);
|
|
3118
3134
|
} catch {
|
|
@@ -3279,7 +3295,9 @@ function buildPaywallInjectionScript(data) {
|
|
|
3279
3295
|
craftData: data.craftData,
|
|
3280
3296
|
products: data.products,
|
|
3281
3297
|
primaryProductId: data.primaryProductId,
|
|
3282
|
-
secondaryProductId: data.secondaryProductId
|
|
3298
|
+
secondaryProductId: data.secondaryProductId,
|
|
3299
|
+
currentLanguage: getCurrentLanguage(),
|
|
3300
|
+
defaultLanguage: getDefaultLanguage()
|
|
3283
3301
|
}
|
|
3284
3302
|
};
|
|
3285
3303
|
return `(function(){var d=${JSON.stringify(paywallData)},a=0,m=50;function t(){a++;if(window.receiveNativeMessage){window.receiveNativeMessage(d);return;}if(a<m){setTimeout(t,100);}}t();})();true;`;
|
|
@@ -3287,9 +3305,28 @@ function buildPaywallInjectionScript(data) {
|
|
|
3287
3305
|
function buildPurchaseStateScript(isPurchasing) {
|
|
3288
3306
|
return `if(window.receiveNativeMessage){window.receiveNativeMessage({type:"purchaseState",data:{isPurchasing:${isPurchasing}}});}true;`;
|
|
3289
3307
|
}
|
|
3308
|
+
function buildBackButtonScript(nonce = Date.now()) {
|
|
3309
|
+
return [
|
|
3310
|
+
`/*${nonce}*/`,
|
|
3311
|
+
"(function(){",
|
|
3312
|
+
"try{",
|
|
3313
|
+
"var h=window.__paywalloHandleBackPress;",
|
|
3314
|
+
"var consumed=typeof h==='function'?!!h():false;",
|
|
3315
|
+
"if(!consumed&&window.ReactNativeWebView){",
|
|
3316
|
+
'window.ReactNativeWebView.postMessage(JSON.stringify({type:"close"}));',
|
|
3317
|
+
"}",
|
|
3318
|
+
"}catch(e){",
|
|
3319
|
+
"if(window.ReactNativeWebView){",
|
|
3320
|
+
'window.ReactNativeWebView.postMessage(JSON.stringify({type:"close"}));',
|
|
3321
|
+
"}",
|
|
3322
|
+
"}",
|
|
3323
|
+
"})();true;"
|
|
3324
|
+
].join("");
|
|
3325
|
+
}
|
|
3290
3326
|
var init_paywallScripts = __esm({
|
|
3291
3327
|
"src/domains/paywall/paywallScripts.ts"() {
|
|
3292
3328
|
"use strict";
|
|
3329
|
+
init_localization();
|
|
3293
3330
|
}
|
|
3294
3331
|
});
|
|
3295
3332
|
|
|
@@ -3312,6 +3349,24 @@ function getWebViewEmitter() {
|
|
|
3312
3349
|
webViewEmitter = new import_react_native14.NativeEventEmitter(mod);
|
|
3313
3350
|
return webViewEmitter;
|
|
3314
3351
|
}
|
|
3352
|
+
async function triggerNativeHaptic(style) {
|
|
3353
|
+
try {
|
|
3354
|
+
const module2 = await import("react-native-haptic-feedback");
|
|
3355
|
+
const hapticModule = module2.default ?? module2;
|
|
3356
|
+
const trigger = hapticModule.trigger;
|
|
3357
|
+
if (typeof trigger !== "function") return;
|
|
3358
|
+
const typeMap = {
|
|
3359
|
+
light: "impactLight",
|
|
3360
|
+
medium: "impactMedium",
|
|
3361
|
+
heavy: "impactHeavy"
|
|
3362
|
+
};
|
|
3363
|
+
trigger(typeMap[style], {
|
|
3364
|
+
enableVibrateFallback: true,
|
|
3365
|
+
ignoreAndroidSystemSettings: false
|
|
3366
|
+
});
|
|
3367
|
+
} catch {
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3315
3370
|
function parseErrorEvent(raw) {
|
|
3316
3371
|
return {
|
|
3317
3372
|
code: typeof raw["code"] === "number" ? raw["code"] : -1,
|
|
@@ -3336,6 +3391,7 @@ function PaywallWebView({
|
|
|
3336
3391
|
const paywallDataSent = (0, import_react3.useRef)(false);
|
|
3337
3392
|
const loadEndReceived = (0, import_react3.useRef)(false);
|
|
3338
3393
|
const [scriptToInject, setScriptToInject] = (0, import_react3.useState)(void 0);
|
|
3394
|
+
const webViewRef = (0, import_react3.useRef)(null);
|
|
3339
3395
|
const onErrorRef = (0, import_react3.useRef)(onError);
|
|
3340
3396
|
onErrorRef.current = onError;
|
|
3341
3397
|
const onReadyRef = (0, import_react3.useRef)(onReady);
|
|
@@ -3379,6 +3435,15 @@ function PaywallWebView({
|
|
|
3379
3435
|
});
|
|
3380
3436
|
}
|
|
3381
3437
|
}, []);
|
|
3438
|
+
const injectScript = (0, import_react3.useCallback)((script) => {
|
|
3439
|
+
if (import_react_native14.Platform.OS === "android") {
|
|
3440
|
+
const handle = (0, import_react_native14.findNodeHandle)(webViewRef.current);
|
|
3441
|
+
if (handle == null) return;
|
|
3442
|
+
import_react_native14.UIManager.dispatchViewManagerCommand(handle, "injectJavaScript", [script]);
|
|
3443
|
+
return;
|
|
3444
|
+
}
|
|
3445
|
+
setScriptToInject(script);
|
|
3446
|
+
}, []);
|
|
3382
3447
|
const buildAndSetInjectionScript = (0, import_react3.useCallback)(() => {
|
|
3383
3448
|
if (!craftData || paywallDataSent.current) return;
|
|
3384
3449
|
paywallDataSent.current = true;
|
|
@@ -3388,8 +3453,8 @@ function PaywallWebView({
|
|
|
3388
3453
|
primaryProductId,
|
|
3389
3454
|
secondaryProductId
|
|
3390
3455
|
});
|
|
3391
|
-
|
|
3392
|
-
}, [craftData, products, primaryProductId, secondaryProductId]);
|
|
3456
|
+
injectScript(script);
|
|
3457
|
+
}, [craftData, products, primaryProductId, secondaryProductId, injectScript]);
|
|
3393
3458
|
const processedIdsRef = (0, import_react3.useRef)(/* @__PURE__ */ new Set());
|
|
3394
3459
|
const dedupeTimersRef = (0, import_react3.useRef)(/* @__PURE__ */ new Map());
|
|
3395
3460
|
(0, import_react3.useEffect)(() => {
|
|
@@ -3426,6 +3491,9 @@ function PaywallWebView({
|
|
|
3426
3491
|
case "restore":
|
|
3427
3492
|
onRestore();
|
|
3428
3493
|
break;
|
|
3494
|
+
case "select-product":
|
|
3495
|
+
console.log("[Paywallo:PaywallWebView] select-product received", message.payload?.productId);
|
|
3496
|
+
break;
|
|
3429
3497
|
case "open-url":
|
|
3430
3498
|
if (message.payload?.url) {
|
|
3431
3499
|
const url = message.payload.url;
|
|
@@ -3434,6 +3502,9 @@ function PaywallWebView({
|
|
|
3434
3502
|
}
|
|
3435
3503
|
}
|
|
3436
3504
|
break;
|
|
3505
|
+
case "haptic":
|
|
3506
|
+
void triggerNativeHaptic(message.payload?.style ?? "light");
|
|
3507
|
+
break;
|
|
3437
3508
|
}
|
|
3438
3509
|
},
|
|
3439
3510
|
[buildAndSetInjectionScript, onPurchase, onClose, onRestore]
|
|
@@ -3505,13 +3576,24 @@ function PaywallWebView({
|
|
|
3505
3576
|
);
|
|
3506
3577
|
(0, import_react3.useEffect)(() => {
|
|
3507
3578
|
if (!paywallDataSent.current) return;
|
|
3508
|
-
|
|
3509
|
-
}, [isPurchasing]);
|
|
3579
|
+
injectScript(buildPurchaseStateScript(isPurchasing));
|
|
3580
|
+
}, [isPurchasing, injectScript]);
|
|
3581
|
+
(0, import_react3.useEffect)(() => {
|
|
3582
|
+
if (import_react_native14.Platform.OS !== "android") return;
|
|
3583
|
+
const onBackPress = () => {
|
|
3584
|
+
if (!paywallDataSent.current) return false;
|
|
3585
|
+
injectScript(buildBackButtonScript());
|
|
3586
|
+
return true;
|
|
3587
|
+
};
|
|
3588
|
+
const subscription = import_react_native14.BackHandler.addEventListener("hardwareBackPress", onBackPress);
|
|
3589
|
+
return () => subscription.remove();
|
|
3590
|
+
}, [injectScript]);
|
|
3510
3591
|
if (!resolvedWebUrl || !NativeWebView) return null;
|
|
3511
3592
|
const paywallUrl = `${resolvedWebUrl}/paywall/${paywallId}`;
|
|
3512
3593
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native14.View, { style: styles.container, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
3513
3594
|
NativeWebView,
|
|
3514
3595
|
{
|
|
3596
|
+
ref: webViewRef,
|
|
3515
3597
|
sourceUrl: paywallUrl,
|
|
3516
3598
|
injectedJavaScript: scriptToInject,
|
|
3517
3599
|
onMessage: handleMessage,
|
|
@@ -3741,7 +3823,7 @@ var init_NativeStoreKit = __esm({
|
|
|
3741
3823
|
try {
|
|
3742
3824
|
await PaywalloStoreKitNative.finishTransaction(transactionId);
|
|
3743
3825
|
} catch (err) {
|
|
3744
|
-
|
|
3826
|
+
console.error("[Paywallo] finishTransaction native error", err);
|
|
3745
3827
|
}
|
|
3746
3828
|
},
|
|
3747
3829
|
async getActiveTransactions() {
|
|
@@ -3750,7 +3832,7 @@ var init_NativeStoreKit = __esm({
|
|
|
3750
3832
|
const results = await PaywalloStoreKitNative.getActiveTransactions();
|
|
3751
3833
|
return results.map(mapNativePurchase);
|
|
3752
3834
|
} catch (err) {
|
|
3753
|
-
|
|
3835
|
+
console.error("[Paywallo] getActiveTransactions failed", err);
|
|
3754
3836
|
return [];
|
|
3755
3837
|
}
|
|
3756
3838
|
},
|
|
@@ -4601,7 +4683,7 @@ var init_QueueProcessor = __esm({
|
|
|
4601
4683
|
}
|
|
4602
4684
|
const allItems = offlineQueue.getQueue();
|
|
4603
4685
|
const eventItems = allItems.filter(
|
|
4604
|
-
(i) =>
|
|
4686
|
+
(i) => i.url.includes("/events") || i.url.includes("/ingest")
|
|
4605
4687
|
);
|
|
4606
4688
|
const eventItemIds = new Set(eventItems.map((i) => i.id));
|
|
4607
4689
|
const { processed: batchProcessed, failed: batchFailed, retryIds } = await this.processEventBatches(eventItems);
|
|
@@ -4641,7 +4723,7 @@ var init_QueueProcessor = __esm({
|
|
|
4641
4723
|
const freshHeaders = this.config.getFreshHeaders?.() ?? {};
|
|
4642
4724
|
const headers = { ...persistedHeaders, ...freshHeaders };
|
|
4643
4725
|
this.log("Sending event batch", { size: batch.length, batchIndex: Math.floor(i / BATCH_SIZE) });
|
|
4644
|
-
const response = await this.httpClient.request("/sdk/
|
|
4726
|
+
const response = await this.httpClient.request("/sdk/ingest/batch", {
|
|
4645
4727
|
method: "POST",
|
|
4646
4728
|
body: { events: bodies },
|
|
4647
4729
|
headers,
|
|
@@ -4836,19 +4918,19 @@ var init_IAPValidator = __esm({
|
|
|
4836
4918
|
const appKey = apiClient.getAppKey();
|
|
4837
4919
|
const body = {
|
|
4838
4920
|
platform,
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4921
|
+
receipt_data: purchase.receipt,
|
|
4922
|
+
product_id: purchase.productId,
|
|
4923
|
+
transaction_id: purchase.transactionId,
|
|
4924
|
+
price_local: product?.priceValue ?? 0,
|
|
4843
4925
|
currency: product?.currency ?? "USD",
|
|
4844
4926
|
country: this.getDeviceCountry(),
|
|
4845
|
-
distinctId
|
|
4927
|
+
distinct_id: distinctId
|
|
4846
4928
|
};
|
|
4847
|
-
if (options?.paywallPlacement !== void 0) body.
|
|
4848
|
-
if (options?.variantKey !== void 0) body.
|
|
4929
|
+
if (options?.paywallPlacement !== void 0) body.paywall_placement = options.paywallPlacement;
|
|
4930
|
+
if (options?.variantKey !== void 0) body.variant_key = options.variantKey;
|
|
4849
4931
|
await offlineQueue.enqueue(
|
|
4850
4932
|
"POST",
|
|
4851
|
-
"/purchases/validate",
|
|
4933
|
+
"/sdk/purchases/validate",
|
|
4852
4934
|
body,
|
|
4853
4935
|
{ "X-App-Key": appKey },
|
|
4854
4936
|
`validate:${purchase.transactionId}`,
|
|
@@ -4856,7 +4938,7 @@ var init_IAPValidator = __esm({
|
|
|
4856
4938
|
);
|
|
4857
4939
|
if (this.getDebug()) console.log("[Paywallo PURCHASE] validation retry enqueued", purchase.transactionId);
|
|
4858
4940
|
} catch (err) {
|
|
4859
|
-
|
|
4941
|
+
console.error("[Paywallo PURCHASE] failed to enqueue validation retry", err);
|
|
4860
4942
|
}
|
|
4861
4943
|
}
|
|
4862
4944
|
};
|
|
@@ -4935,7 +5017,7 @@ var init_IAPService = __esm({
|
|
|
4935
5017
|
}
|
|
4936
5018
|
return products;
|
|
4937
5019
|
} catch (err) {
|
|
4938
|
-
|
|
5020
|
+
console.error("[Paywallo] loadProducts failed", err);
|
|
4939
5021
|
return [];
|
|
4940
5022
|
}
|
|
4941
5023
|
}
|
|
@@ -4954,7 +5036,7 @@ var init_IAPService = __esm({
|
|
|
4954
5036
|
await nativeStoreKit.finishTransaction(transactionId);
|
|
4955
5037
|
this.finishedTransactions.add(transactionId);
|
|
4956
5038
|
} catch (err) {
|
|
4957
|
-
|
|
5039
|
+
console.error("[Paywallo] finishTransaction failed", err);
|
|
4958
5040
|
}
|
|
4959
5041
|
}
|
|
4960
5042
|
startTransactionListener() {
|
|
@@ -5003,7 +5085,7 @@ var init_IAPService = __esm({
|
|
|
5003
5085
|
await this.finishTransaction(purchase.transactionId);
|
|
5004
5086
|
return;
|
|
5005
5087
|
}
|
|
5006
|
-
|
|
5088
|
+
console.error("[Paywallo PURCHASE] background validation failed (network) \u2014 queued for retry", err);
|
|
5007
5089
|
await this.validator.enqueueValidationRetry(purchase, productId, {
|
|
5008
5090
|
paywallPlacement: options?.paywallPlacement,
|
|
5009
5091
|
variantKey: options?.variantKey
|
|
@@ -5011,7 +5093,7 @@ var init_IAPService = __esm({
|
|
|
5011
5093
|
});
|
|
5012
5094
|
return { success: true, purchase };
|
|
5013
5095
|
} catch (error) {
|
|
5014
|
-
|
|
5096
|
+
console.error(`[Paywallo PURCHASE] ${productId} failed`, error);
|
|
5015
5097
|
const e = error instanceof PurchaseError ? error : new PurchaseError(PURCHASE_ERROR_CODES.PURCHASE_FAILED, error instanceof Error ? error.message : String(error));
|
|
5016
5098
|
return { success: false, error: e };
|
|
5017
5099
|
} finally {
|
|
@@ -5055,7 +5137,7 @@ var init_IAPService = __esm({
|
|
|
5055
5137
|
if (this.debug) console.log("[Paywallo RESTORE] validation rejected (4xx) \u2014 dropping", tx.transactionId);
|
|
5056
5138
|
await this.finishTransaction(tx.transactionId);
|
|
5057
5139
|
} else {
|
|
5058
|
-
|
|
5140
|
+
console.error("[Paywallo RESTORE] validation failed (network) \u2014 queued for retry", r.reason);
|
|
5059
5141
|
await this.validator.enqueueValidationRetry(tx, tx.productId);
|
|
5060
5142
|
}
|
|
5061
5143
|
} else if (r.status === "fulfilled" && !r.value.success) {
|
|
@@ -5065,7 +5147,7 @@ var init_IAPService = __esm({
|
|
|
5065
5147
|
}
|
|
5066
5148
|
return validated;
|
|
5067
5149
|
} catch (err) {
|
|
5068
|
-
|
|
5150
|
+
console.error("[Paywallo] restore failed", err);
|
|
5069
5151
|
return [];
|
|
5070
5152
|
}
|
|
5071
5153
|
}
|
|
@@ -5281,7 +5363,7 @@ function usePaywallLoader(placement, visible, preloadedConfig, preloadedProducts
|
|
|
5281
5363
|
setProducts(map);
|
|
5282
5364
|
}
|
|
5283
5365
|
} catch (err) {
|
|
5284
|
-
|
|
5366
|
+
console.error("[Paywallo] loadProducts in paywall failed", err);
|
|
5285
5367
|
if (!cancelled) setProducts(/* @__PURE__ */ new Map());
|
|
5286
5368
|
}
|
|
5287
5369
|
} else {
|
|
@@ -6410,11 +6492,9 @@ var init_SubscriptionManager = __esm({
|
|
|
6410
6492
|
if (!this.config) {
|
|
6411
6493
|
return this.getEmptyStatus();
|
|
6412
6494
|
}
|
|
6413
|
-
const
|
|
6414
|
-
|
|
6415
|
-
|
|
6416
|
-
}
|
|
6417
|
-
const response = await fetch(url.toString(), {
|
|
6495
|
+
const userId = this.userId ?? "";
|
|
6496
|
+
const url = `${this.config.serverUrl}/sdk/purchases/status?distinctId=${encodeURIComponent(userId)}`;
|
|
6497
|
+
const response = await fetch(url, {
|
|
6418
6498
|
method: "GET",
|
|
6419
6499
|
headers: {
|
|
6420
6500
|
"Content-Type": "application/json",
|
|
@@ -6427,17 +6507,32 @@ var init_SubscriptionManager = __esm({
|
|
|
6427
6507
|
`Failed to fetch subscription status: ${response.status}`
|
|
6428
6508
|
);
|
|
6429
6509
|
}
|
|
6430
|
-
const
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
|
|
6436
|
-
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6510
|
+
const envelope = await response.json();
|
|
6511
|
+
const raw = envelope.data ?? envelope;
|
|
6512
|
+
const data = {
|
|
6513
|
+
hasActiveSubscription: !!(raw["has_active_subscription"] ?? raw["hasActiveSubscription"]),
|
|
6514
|
+
subscription: null,
|
|
6515
|
+
entitlements: raw["entitlements"] ?? []
|
|
6516
|
+
};
|
|
6517
|
+
const sub = raw["subscription"];
|
|
6518
|
+
if (sub) {
|
|
6519
|
+
const cancellationRaw = sub["cancellationDate"] ?? sub["cancellation_date"];
|
|
6520
|
+
const gracePeriodRaw = sub["gracePeriodExpiresAt"] ?? sub["grace_period_expires_at"];
|
|
6521
|
+
data.subscription = {
|
|
6522
|
+
id: sub["id"],
|
|
6523
|
+
productId: sub["product_id"] ?? sub["productId"],
|
|
6524
|
+
status: sub["status"],
|
|
6525
|
+
expiresAt: new Date(sub["expires_at"] ?? sub["expiresAt"]),
|
|
6526
|
+
originalPurchaseDate: new Date(sub["originalPurchaseDate"] ?? sub["original_purchase_date"]),
|
|
6527
|
+
latestPurchaseDate: new Date(sub["latestPurchaseDate"] ?? sub["latest_purchase_date"]),
|
|
6528
|
+
willRenew: !!(sub["will_renew"] ?? sub["willRenew"] ?? sub["auto_renew_enabled"] ?? sub["autoRenewEnabled"]),
|
|
6529
|
+
isTrial: !!(sub["is_trial"] ?? sub["isTrial"]),
|
|
6530
|
+
isIntroductoryPeriod: !!(sub["is_introductory_period"] ?? sub["isIntroductoryPeriod"]),
|
|
6531
|
+
platform: sub["platform"],
|
|
6532
|
+
storeTransactionId: sub["store_transaction_id"] ?? sub["storeTransactionId"],
|
|
6533
|
+
cancellationDate: cancellationRaw ? new Date(cancellationRaw) : void 0,
|
|
6534
|
+
gracePeriodExpiresAt: gracePeriodRaw ? new Date(gracePeriodRaw) : void 0
|
|
6535
|
+
};
|
|
6441
6536
|
}
|
|
6442
6537
|
return data;
|
|
6443
6538
|
}
|
|
@@ -6475,15 +6570,15 @@ async function validatePurchase(client, appKey, platform, receipt, productId, tr
|
|
|
6475
6570
|
"/sdk/purchases/validate",
|
|
6476
6571
|
{
|
|
6477
6572
|
platform,
|
|
6478
|
-
receipt,
|
|
6479
|
-
productId,
|
|
6480
|
-
transactionId,
|
|
6481
|
-
priceLocal,
|
|
6573
|
+
receipt_data: receipt,
|
|
6574
|
+
product_id: productId,
|
|
6575
|
+
transaction_id: transactionId,
|
|
6576
|
+
price_local: priceLocal,
|
|
6482
6577
|
currency,
|
|
6483
6578
|
country,
|
|
6484
|
-
distinctId,
|
|
6485
|
-
...paywallPlacement !== void 0 && { paywallPlacement },
|
|
6486
|
-
...variantKey !== void 0 && { variantKey }
|
|
6579
|
+
distinct_id: distinctId,
|
|
6580
|
+
...paywallPlacement !== void 0 && { paywall_placement: paywallPlacement },
|
|
6581
|
+
...variantKey !== void 0 && { variant_key: variantKey }
|
|
6487
6582
|
},
|
|
6488
6583
|
false
|
|
6489
6584
|
);
|
|
@@ -6495,7 +6590,7 @@ async function validatePurchase(client, appKey, platform, receipt, productId, tr
|
|
|
6495
6590
|
response.status
|
|
6496
6591
|
);
|
|
6497
6592
|
}
|
|
6498
|
-
return response.data;
|
|
6593
|
+
return response.data.data;
|
|
6499
6594
|
}
|
|
6500
6595
|
async function getSubscriptionStatus(client, baseUrl, appKey, distinctId) {
|
|
6501
6596
|
const url = new URL(`${baseUrl}/sdk/purchases/status`);
|
|
@@ -6504,7 +6599,7 @@ async function getSubscriptionStatus(client, baseUrl, appKey, distinctId) {
|
|
|
6504
6599
|
if (!response.ok) {
|
|
6505
6600
|
throw new PurchaseError(PURCHASE_ERROR_CODES.NETWORK_ERROR, `Subscription status check failed: HTTP ${response.status}`);
|
|
6506
6601
|
}
|
|
6507
|
-
return response.data;
|
|
6602
|
+
return response.data.data;
|
|
6508
6603
|
}
|
|
6509
6604
|
async function getEmergencyPaywall(client) {
|
|
6510
6605
|
try {
|
|
@@ -6713,7 +6808,7 @@ async function evaluateFlags2(deps, keys, distinctId) {
|
|
|
6713
6808
|
const result = {};
|
|
6714
6809
|
for (const key of Object.keys(record)) {
|
|
6715
6810
|
const value = record[key];
|
|
6716
|
-
const variant = typeof value === "
|
|
6811
|
+
const variant = typeof value === "string" ? value : null;
|
|
6717
6812
|
result[key] = variant;
|
|
6718
6813
|
const flagVariant = { variant };
|
|
6719
6814
|
deps.cache.setVariant(`${key}:${distinctId}`, flagVariant);
|
|
@@ -7026,7 +7121,7 @@ var init_eventEnvelopeV2 = __esm({
|
|
|
7026
7121
|
payload: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.unknown())
|
|
7027
7122
|
});
|
|
7028
7123
|
v2ContextSchema = import_zod2.z.object({
|
|
7029
|
-
distinct_id: import_zod2.z.string().
|
|
7124
|
+
distinct_id: import_zod2.z.string().min(1),
|
|
7030
7125
|
session_id: import_zod2.z.string().optional(),
|
|
7031
7126
|
device_id: import_zod2.z.string().optional(),
|
|
7032
7127
|
app_version: import_zod2.z.string().optional(),
|
|
@@ -7069,7 +7164,7 @@ var init_events = __esm({
|
|
|
7069
7164
|
});
|
|
7070
7165
|
|
|
7071
7166
|
// src/core/EventBatcher.ts
|
|
7072
|
-
var import_react_native22, BATCH_MAX_SIZE, BATCH_FLUSH_MS, EVENT_NAME_REGEX, V2_BATCH_ENDPOINT,
|
|
7167
|
+
var import_react_native22, BATCH_MAX_SIZE, BATCH_FLUSH_MS, EVENT_NAME_REGEX, V2_BATCH_ENDPOINT, EventBatcher;
|
|
7073
7168
|
var init_EventBatcher = __esm({
|
|
7074
7169
|
"src/core/EventBatcher.ts"() {
|
|
7075
7170
|
"use strict";
|
|
@@ -7080,15 +7175,12 @@ var init_EventBatcher = __esm({
|
|
|
7080
7175
|
BATCH_FLUSH_MS = 1e4;
|
|
7081
7176
|
EVENT_NAME_REGEX = /^(\$[a-zA-Z0-9_]+|[a-z][a-z0-9_]*)$/;
|
|
7082
7177
|
V2_BATCH_ENDPOINT = "/sdk/ingest/batch";
|
|
7083
|
-
V1_BATCH_ENDPOINT = "/sdk/events/batch";
|
|
7084
|
-
V1_SINGLE_ENDPOINT = "/sdk/events";
|
|
7085
7178
|
EventBatcher = class {
|
|
7086
7179
|
constructor(post, debug = false, contextProvider = null) {
|
|
7087
7180
|
this.criticalQueue = [];
|
|
7088
7181
|
this.normalQueue = [];
|
|
7089
7182
|
this.normalTimer = null;
|
|
7090
7183
|
this.criticalScheduled = false;
|
|
7091
|
-
this.v2Disabled = false;
|
|
7092
7184
|
this.post = post;
|
|
7093
7185
|
this.debug = debug;
|
|
7094
7186
|
this.contextProvider = contextProvider;
|
|
@@ -7184,11 +7276,7 @@ var init_EventBatcher = __esm({
|
|
|
7184
7276
|
try {
|
|
7185
7277
|
await this.postBatch([event], `event_critical:${event.eventName}`, "critical");
|
|
7186
7278
|
} catch {
|
|
7187
|
-
|
|
7188
|
-
await this.post(V1_SINGLE_ENDPOINT, event, `event:${event.eventName}`, "critical");
|
|
7189
|
-
} catch {
|
|
7190
|
-
if (this.debug) console.log(`[Paywallo] critical event ${event.eventName} post failed`);
|
|
7191
|
-
}
|
|
7279
|
+
if (this.debug) console.log(`[Paywallo] critical event ${event.eventName} post failed`);
|
|
7192
7280
|
}
|
|
7193
7281
|
}
|
|
7194
7282
|
}
|
|
@@ -7202,50 +7290,24 @@ var init_EventBatcher = __esm({
|
|
|
7202
7290
|
try {
|
|
7203
7291
|
await this.postBatch(batch, `event_batch:${batch.length}`);
|
|
7204
7292
|
} catch {
|
|
7205
|
-
|
|
7206
|
-
await this.post(V1_SINGLE_ENDPOINT, event, `event:${event.eventName}`);
|
|
7207
|
-
}
|
|
7293
|
+
if (this.debug) console.log(`[Paywallo] normal batch post failed \u2014 OfflineQueue will handle durability`);
|
|
7208
7294
|
}
|
|
7209
7295
|
}
|
|
7210
|
-
/**
|
|
7211
|
-
* POST the batch with V2 envelope semantics. Tries `/ingest/batch`
|
|
7212
|
-
* first; on failure (404/network) falls back to `/events/batch`
|
|
7213
|
-
* with the legacy per-event shape for retrocompat.
|
|
7214
|
-
*
|
|
7215
|
-
* After a single V2 failure we flip `v2Disabled` and stop trying V2 for
|
|
7216
|
-
* the lifetime of this EventBatcher — avoids N retries per batch on old
|
|
7217
|
-
* servers that will never have the endpoint. A fresh `new EventBatcher()`
|
|
7218
|
-
* (e.g. after `Paywallo.init` on a new server URL) resets the flag.
|
|
7219
|
-
*/
|
|
7220
7296
|
async postBatch(events, label, priority = "normal") {
|
|
7221
|
-
|
|
7222
|
-
|
|
7223
|
-
|
|
7224
|
-
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
if (this.debug) console.log("[Paywallo EVENTS] V2 envelope schema validation failed:", parsed.error.issues);
|
|
7234
|
-
throw parsed.error;
|
|
7235
|
-
}
|
|
7236
|
-
await this.post(V2_BATCH_ENDPOINT, parsed.data, label, priority);
|
|
7237
|
-
return;
|
|
7238
|
-
} catch (error) {
|
|
7239
|
-
this.v2Disabled = true;
|
|
7240
|
-
if (this.debug) {
|
|
7241
|
-
console.log(
|
|
7242
|
-
"[Paywallo EVENTS] V2 ingest unavailable, falling back to /events/batch:",
|
|
7243
|
-
error
|
|
7244
|
-
);
|
|
7245
|
-
}
|
|
7246
|
-
}
|
|
7297
|
+
const providerContext = resolveProviderContext(this.contextProvider);
|
|
7298
|
+
const inputs = events.map((e) => ({
|
|
7299
|
+
eventName: e.eventName,
|
|
7300
|
+
distinctId: e.distinctId,
|
|
7301
|
+
properties: e.properties,
|
|
7302
|
+
timestamp: e.timestamp
|
|
7303
|
+
}));
|
|
7304
|
+
const envelope = buildV2Envelope(inputs, providerContext);
|
|
7305
|
+
const parsed = v2EnvelopeSchema.safeParse(envelope);
|
|
7306
|
+
if (!parsed.success) {
|
|
7307
|
+
if (this.debug) console.log("[Paywallo EVENTS] V2 envelope schema validation failed:", parsed.error.issues);
|
|
7308
|
+
throw parsed.error;
|
|
7247
7309
|
}
|
|
7248
|
-
await this.post(
|
|
7310
|
+
await this.post(V2_BATCH_ENDPOINT, parsed.data, label, priority);
|
|
7249
7311
|
}
|
|
7250
7312
|
};
|
|
7251
7313
|
}
|
|
@@ -7632,6 +7694,26 @@ var init_ApiClient = __esm({
|
|
|
7632
7694
|
this.batcher.dispose();
|
|
7633
7695
|
}
|
|
7634
7696
|
async identify(distinctId, properties, email, deviceId, pii) {
|
|
7697
|
+
const rawTraits = {
|
|
7698
|
+
email: email || void 0,
|
|
7699
|
+
platform: import_react_native23.Platform.OS,
|
|
7700
|
+
name: properties?.name,
|
|
7701
|
+
country: properties?.country,
|
|
7702
|
+
locale: properties?.locale,
|
|
7703
|
+
app_version: properties?.appVersion ?? properties?.["app_version"]
|
|
7704
|
+
};
|
|
7705
|
+
const traits = Object.fromEntries(
|
|
7706
|
+
Object.entries(rawTraits).filter(([, v]) => v !== void 0)
|
|
7707
|
+
);
|
|
7708
|
+
const attributionKeys = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content", "fbclid", "gclid", "ttclid", "referrer"];
|
|
7709
|
+
const rawAttribution = {};
|
|
7710
|
+
if (properties) {
|
|
7711
|
+
for (const key of attributionKeys) {
|
|
7712
|
+
const val = properties[key];
|
|
7713
|
+
if (val !== void 0) rawAttribution[key] = val;
|
|
7714
|
+
}
|
|
7715
|
+
}
|
|
7716
|
+
const attribution = Object.keys(rawAttribution).length > 0 ? rawAttribution : void 0;
|
|
7635
7717
|
await postWithQueue(
|
|
7636
7718
|
{
|
|
7637
7719
|
isOfflineQueueEnabled: () => this.offlineQueueEnabled,
|
|
@@ -7639,12 +7721,11 @@ var init_ApiClient = __esm({
|
|
|
7639
7721
|
isDebug: () => this.debug,
|
|
7640
7722
|
post: (path, body, skipRetry) => this.post(path, body, skipRetry)
|
|
7641
7723
|
},
|
|
7642
|
-
"/sdk/identify",
|
|
7724
|
+
"/sdk/identity/identify",
|
|
7643
7725
|
{
|
|
7644
|
-
distinctId,
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
platform: import_react_native23.Platform.OS,
|
|
7726
|
+
distinct_id: distinctId,
|
|
7727
|
+
traits,
|
|
7728
|
+
...attribution && { attribution },
|
|
7648
7729
|
...deviceId && { deviceId },
|
|
7649
7730
|
...pii?.phone && { phone: pii.phone },
|
|
7650
7731
|
...pii?.firstName && { firstName: pii.firstName },
|
|
@@ -7655,10 +7736,9 @@ var init_ApiClient = __esm({
|
|
|
7655
7736
|
"identify"
|
|
7656
7737
|
);
|
|
7657
7738
|
}
|
|
7658
|
-
// Session lifecycle endpoints
|
|
7659
|
-
//
|
|
7660
|
-
//
|
|
7661
|
-
// EventBatcher pipeline.
|
|
7739
|
+
// Session lifecycle endpoints were dropped. All session bookkeeping is now
|
|
7740
|
+
// derived on the server from `$session_start` and `session.end` events that
|
|
7741
|
+
// flow through the unified EventBatcher pipeline.
|
|
7662
7742
|
async getVariant(flagKey, distinctId) {
|
|
7663
7743
|
return getVariant2(this.flagDeps(), flagKey, distinctId);
|
|
7664
7744
|
}
|
|
@@ -7716,7 +7796,7 @@ var init_ApiClient = __esm({
|
|
|
7716
7796
|
const hit = this.cache.getCampaign(key);
|
|
7717
7797
|
if (hit !== void 0) return hit;
|
|
7718
7798
|
try {
|
|
7719
|
-
const res = await this.get(`/
|
|
7799
|
+
const res = await this.get(`/campaigns/public/primary?distinctId=${encodeURIComponent(distinctId)}`);
|
|
7720
7800
|
if (res.status === 404) {
|
|
7721
7801
|
this.cache.setCampaign(key, null, this.cache.nullTTL);
|
|
7722
7802
|
return null;
|
|
@@ -7816,10 +7896,10 @@ function setupNotifications(apiClient, config, environment, eventPipeline) {
|
|
|
7816
7896
|
debug: config.debug,
|
|
7817
7897
|
environment: environment === "Sandbox" ? "sandbox" : "production"
|
|
7818
7898
|
}).catch((err) => {
|
|
7819
|
-
|
|
7899
|
+
console.error("[Paywallo PUSH] initialization warning:", err instanceof Error ? err.message : String(err));
|
|
7820
7900
|
});
|
|
7821
7901
|
} catch (err) {
|
|
7822
|
-
|
|
7902
|
+
console.error("[Paywallo PUSH] setup warning:", err instanceof Error ? err.message : String(err));
|
|
7823
7903
|
}
|
|
7824
7904
|
}
|
|
7825
7905
|
function setupAutoPreload(state, apiClient, config, distinctId) {
|
|
@@ -7944,7 +8024,7 @@ function reportInitFailure(state, config, error, reason) {
|
|
|
7944
8024
|
error: error instanceof Error ? error.message : String(error)
|
|
7945
8025
|
});
|
|
7946
8026
|
} catch (err) {
|
|
7947
|
-
|
|
8027
|
+
console.error("[Paywallo] reportInitFailure error", err);
|
|
7948
8028
|
}
|
|
7949
8029
|
}
|
|
7950
8030
|
function reportInitSuccess(state, config, attempts) {
|
|
@@ -7953,7 +8033,7 @@ function reportInitSuccess(state, config, attempts) {
|
|
|
7953
8033
|
void state.apiClient.reportError("INIT_RECOVERED", `Succeeded after ${attempts} retries`, { attempts });
|
|
7954
8034
|
}
|
|
7955
8035
|
} catch (err) {
|
|
7956
|
-
|
|
8036
|
+
console.error("[Paywallo] reportInitSuccess error", err);
|
|
7957
8037
|
}
|
|
7958
8038
|
}
|
|
7959
8039
|
async function resolveSessionFlags(state, keys, apiClient, distinctId) {
|
|
@@ -8007,7 +8087,7 @@ async function doInit(state, config) {
|
|
|
8007
8087
|
try {
|
|
8008
8088
|
await identityManager.identify(pending);
|
|
8009
8089
|
} catch (err) {
|
|
8010
|
-
|
|
8090
|
+
console.error("[Paywallo INIT] pending identify replay failed", err);
|
|
8011
8091
|
}
|
|
8012
8092
|
}
|
|
8013
8093
|
state.pendingIdentifies = [];
|
|
@@ -8085,7 +8165,7 @@ async function doInit(state, config) {
|
|
|
8085
8165
|
setupNotifications(apiClient, config, environment, eventPipeline);
|
|
8086
8166
|
if (config.autoStartSession !== false) {
|
|
8087
8167
|
sessionManager.startSession().catch((err) => {
|
|
8088
|
-
|
|
8168
|
+
console.error("[Paywallo INIT] autoStart session error", err);
|
|
8089
8169
|
});
|
|
8090
8170
|
}
|
|
8091
8171
|
new InstallTracker(config.debug, {
|
|
@@ -8103,7 +8183,7 @@ async function doInit(state, config) {
|
|
|
8103
8183
|
state.resolveReady();
|
|
8104
8184
|
state.resolveReady = null;
|
|
8105
8185
|
}
|
|
8106
|
-
if (config.debug) console.
|
|
8186
|
+
if (config.debug) console.log("[Paywallo] initialized successfully");
|
|
8107
8187
|
if (distinctId) {
|
|
8108
8188
|
apiClient.getSubscriptionStatus(distinctId).then(() => {
|
|
8109
8189
|
if (config.debug) console.log("[Paywallo SUB] preloaded on boot");
|
|
@@ -8220,7 +8300,7 @@ async function checkActiveSubscription(state) {
|
|
|
8220
8300
|
if (state.config?.debug) console.log("[Paywallo SUB] hasActiveSubscription (server):", isActive);
|
|
8221
8301
|
return isActive;
|
|
8222
8302
|
} catch (error) {
|
|
8223
|
-
|
|
8303
|
+
console.error("[Paywallo SUB] hasActiveSubscription error", error);
|
|
8224
8304
|
if (state.apiClient) void state.apiClient.reportError("SUBSCRIPTION_CHECK_FAILED", error instanceof Error ? error.message : "hasActiveSubscription failed");
|
|
8225
8305
|
return false;
|
|
8226
8306
|
}
|
|
@@ -8665,6 +8745,7 @@ var init_OfferingService = __esm({
|
|
|
8665
8745
|
var index_exports = {};
|
|
8666
8746
|
__export(index_exports, {
|
|
8667
8747
|
ApiClient: () => ApiClient,
|
|
8748
|
+
AttributionTracker: () => AttributionTracker,
|
|
8668
8749
|
CAMPAIGN_ERROR_CODES: () => CAMPAIGN_ERROR_CODES,
|
|
8669
8750
|
CampaignError: () => CampaignError,
|
|
8670
8751
|
ERROR_CODES: () => PURCHASE_ERROR_CODES,
|
|
@@ -8699,6 +8780,7 @@ __export(index_exports, {
|
|
|
8699
8780
|
SessionError: () => SessionError,
|
|
8700
8781
|
SessionManager: () => SessionManager,
|
|
8701
8782
|
SubscriptionCache: () => SubscriptionCache,
|
|
8783
|
+
attributionTracker: () => attributionTracker,
|
|
8702
8784
|
createPurchaseError: () => createPurchaseError,
|
|
8703
8785
|
default: () => index_default,
|
|
8704
8786
|
detectDeviceLanguage: () => detectDeviceLanguage,
|
|
@@ -8761,6 +8843,7 @@ init_PurchaseError();
|
|
|
8761
8843
|
// src/index.ts
|
|
8762
8844
|
init_identity();
|
|
8763
8845
|
init_identity();
|
|
8846
|
+
init_identity();
|
|
8764
8847
|
init_notifications();
|
|
8765
8848
|
|
|
8766
8849
|
// src/domains/offering/index.ts
|
|
@@ -9432,7 +9515,6 @@ function useCampaignPreload() {
|
|
|
9432
9515
|
|
|
9433
9516
|
// src/hooks/useProductLoader.ts
|
|
9434
9517
|
var import_react22 = require("react");
|
|
9435
|
-
init_PaywalloClient();
|
|
9436
9518
|
function useProductLoader() {
|
|
9437
9519
|
const [products, setProducts] = (0, import_react22.useState)(/* @__PURE__ */ new Map());
|
|
9438
9520
|
const [isLoadingProducts, setIsLoadingProducts] = (0, import_react22.useState)(false);
|
|
@@ -9445,7 +9527,7 @@ function useProductLoader() {
|
|
|
9445
9527
|
for (const p of loaded) map.set(p.productId, p);
|
|
9446
9528
|
setProducts(map);
|
|
9447
9529
|
} catch (err) {
|
|
9448
|
-
|
|
9530
|
+
console.error("[Paywallo] refreshProducts failed", err);
|
|
9449
9531
|
} finally {
|
|
9450
9532
|
setIsLoadingProducts(false);
|
|
9451
9533
|
}
|
|
@@ -9455,7 +9537,6 @@ function useProductLoader() {
|
|
|
9455
9537
|
|
|
9456
9538
|
// src/hooks/usePurchaseOrchestrator.ts
|
|
9457
9539
|
var import_react23 = require("react");
|
|
9458
|
-
init_PaywalloClient();
|
|
9459
9540
|
init_paywall();
|
|
9460
9541
|
function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clearPreloadedWebView, setShowingPreloadedWebView, presentedAtRef, invalidateSubscriptionCache) {
|
|
9461
9542
|
const { trackDismissed, trackProductSelected, trackPurchased } = usePaywallTracking();
|
|
@@ -9489,7 +9570,7 @@ function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clea
|
|
|
9489
9570
|
clearPreloadedWebView();
|
|
9490
9571
|
resolvePreloadedPaywall({ presented: true, purchased: true, cancelled: false, restored: false });
|
|
9491
9572
|
} catch (error) {
|
|
9492
|
-
|
|
9573
|
+
console.error("[Paywallo] preloaded purchase failed", error);
|
|
9493
9574
|
setShowingPreloadedWebView(false);
|
|
9494
9575
|
clearPreloadedWebView();
|
|
9495
9576
|
resolvePreloadedPaywall({ presented: true, purchased: false, cancelled: false, restored: false });
|
|
@@ -9510,7 +9591,7 @@ function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clea
|
|
|
9510
9591
|
clearPreloadedWebView();
|
|
9511
9592
|
resolvePreloadedPaywall({ presented: true, purchased: false, cancelled: false, restored: true });
|
|
9512
9593
|
} catch (error) {
|
|
9513
|
-
|
|
9594
|
+
console.error("[Paywallo] preloaded restore failed", error);
|
|
9514
9595
|
setShowingPreloadedWebView(false);
|
|
9515
9596
|
clearPreloadedWebView();
|
|
9516
9597
|
resolvePreloadedPaywall({ presented: true, purchased: false, cancelled: false, restored: false });
|
|
@@ -10163,6 +10244,7 @@ var index_default = Paywallo;
|
|
|
10163
10244
|
// Annotate the CommonJS export names for ESM import in node:
|
|
10164
10245
|
0 && (module.exports = {
|
|
10165
10246
|
ApiClient,
|
|
10247
|
+
AttributionTracker,
|
|
10166
10248
|
CAMPAIGN_ERROR_CODES,
|
|
10167
10249
|
CampaignError,
|
|
10168
10250
|
ERROR_CODES,
|
|
@@ -10197,6 +10279,7 @@ var index_default = Paywallo;
|
|
|
10197
10279
|
SessionError,
|
|
10198
10280
|
SessionManager,
|
|
10199
10281
|
SubscriptionCache,
|
|
10282
|
+
attributionTracker,
|
|
10200
10283
|
createPurchaseError,
|
|
10201
10284
|
detectDeviceLanguage,
|
|
10202
10285
|
getCurrentLanguage,
|