@virex-tech/paywallo-sdk 2.2.5 → 2.2.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/android/src/main/java/com/paywallo/sdk/PaywalloEnvModule.kt +31 -0
- package/android/src/main/java/com/paywallo/sdk/PaywalloSdkPackage.kt +2 -1
- package/dist/index.d.mts +15 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +579 -247
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +569 -238
- package/dist/index.mjs.map +1 -1
- package/ios/PaywalloEnv.m +8 -0
- package/ios/PaywalloEnv.swift +28 -0
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -814,9 +814,9 @@ var init_CampaignGateService = __esm({
|
|
|
814
814
|
}
|
|
815
815
|
}
|
|
816
816
|
getPreloadedCampaign(placement) {
|
|
817
|
-
const
|
|
818
|
-
if (!
|
|
819
|
-
const age = Date.now() -
|
|
817
|
+
const cached2 = this.preloadedCampaigns.get(placement);
|
|
818
|
+
if (!cached2) return null;
|
|
819
|
+
const age = Date.now() - cached2.preloadedAt;
|
|
820
820
|
if (age >= PRELOAD_CACHE_TTL_MS) {
|
|
821
821
|
this.preloadedCampaigns.delete(placement);
|
|
822
822
|
return null;
|
|
@@ -825,7 +825,7 @@ var init_CampaignGateService = __esm({
|
|
|
825
825
|
void this.preloadCampaign(this.apiClientRef, placement).catch(() => {
|
|
826
826
|
});
|
|
827
827
|
}
|
|
828
|
-
return
|
|
828
|
+
return cached2.campaign;
|
|
829
829
|
}
|
|
830
830
|
async preloadAllActive(apiClient, debug) {
|
|
831
831
|
this.apiClientRef = apiClient;
|
|
@@ -2157,7 +2157,7 @@ function extractPayload(data) {
|
|
|
2157
2157
|
}
|
|
2158
2158
|
function setupForegroundHandler(deps, onReceive) {
|
|
2159
2159
|
const { bridge, tracker, debug } = deps;
|
|
2160
|
-
const
|
|
2160
|
+
const unsubscribe2 = bridge.onMessage(async (message) => {
|
|
2161
2161
|
const data = message.data ?? {};
|
|
2162
2162
|
const payload = extractPayload({
|
|
2163
2163
|
...data,
|
|
@@ -2175,7 +2175,7 @@ function setupForegroundHandler(deps, onReceive) {
|
|
|
2175
2175
|
messageId
|
|
2176
2176
|
});
|
|
2177
2177
|
});
|
|
2178
|
-
return
|
|
2178
|
+
return unsubscribe2;
|
|
2179
2179
|
}
|
|
2180
2180
|
var init_ForegroundHandler = __esm({
|
|
2181
2181
|
"src/domains/notifications/handlers/ForegroundHandler.ts"() {
|
|
@@ -2370,8 +2370,8 @@ var init_NotificationHandlerSetup = __esm({
|
|
|
2370
2370
|
// src/core/version.ts
|
|
2371
2371
|
function resolveVersion() {
|
|
2372
2372
|
try {
|
|
2373
|
-
if ("2.2.
|
|
2374
|
-
return "2.2.
|
|
2373
|
+
if ("2.2.6") {
|
|
2374
|
+
return "2.2.6";
|
|
2375
2375
|
}
|
|
2376
2376
|
} catch {
|
|
2377
2377
|
}
|
|
@@ -2444,9 +2444,6 @@ function mapPermissionStatus(status) {
|
|
|
2444
2444
|
function detectPlatform2() {
|
|
2445
2445
|
return Platform6.OS === "ios" ? "ios" : "android";
|
|
2446
2446
|
}
|
|
2447
|
-
function detectEnvironment() {
|
|
2448
|
-
return typeof __DEV__ !== "undefined" && __DEV__ ? "sandbox" : "production";
|
|
2449
|
-
}
|
|
2450
2447
|
async function getAppVersion() {
|
|
2451
2448
|
try {
|
|
2452
2449
|
const { collectDeviceInfo: collectDeviceInfo2 } = await Promise.resolve().then(() => (init_deviceInfo(), deviceInfo_exports));
|
|
@@ -2486,7 +2483,7 @@ async function clearPersistedToken(secureStorage2) {
|
|
|
2486
2483
|
} catch {
|
|
2487
2484
|
}
|
|
2488
2485
|
}
|
|
2489
|
-
async function buildRegistration(token, getDeviceId, getDistinctId) {
|
|
2486
|
+
async function buildRegistration(token, getDeviceId, getDistinctId, environment) {
|
|
2490
2487
|
const appVersion = await getAppVersion();
|
|
2491
2488
|
return {
|
|
2492
2489
|
token,
|
|
@@ -2497,7 +2494,7 @@ async function buildRegistration(token, getDeviceId, getDistinctId) {
|
|
|
2497
2494
|
deviceId: getDeviceId?.() ?? void 0,
|
|
2498
2495
|
locale: await getLocale(),
|
|
2499
2496
|
timezone: getTimezone2(),
|
|
2500
|
-
environment
|
|
2497
|
+
environment
|
|
2501
2498
|
};
|
|
2502
2499
|
}
|
|
2503
2500
|
async function registerToken(deps, token) {
|
|
@@ -2506,7 +2503,8 @@ async function registerToken(deps, token) {
|
|
|
2506
2503
|
if (debug) console.log("[Paywallo PUSH] httpClient not ready, skipping token registration");
|
|
2507
2504
|
return;
|
|
2508
2505
|
}
|
|
2509
|
-
const
|
|
2506
|
+
const { environment } = deps;
|
|
2507
|
+
const registration = await buildRegistration(token, getDeviceId, getDistinctId, environment);
|
|
2510
2508
|
try {
|
|
2511
2509
|
await httpClient.post(
|
|
2512
2510
|
TOKEN_ENDPOINT,
|
|
@@ -2556,7 +2554,8 @@ async function registerAndPersistToken(deps, token) {
|
|
|
2556
2554
|
appKey: deps.appKey,
|
|
2557
2555
|
getDeviceId: deps.getDeviceId,
|
|
2558
2556
|
getDistinctId: deps.getDistinctId,
|
|
2559
|
-
debug: deps.debug
|
|
2557
|
+
debug: deps.debug,
|
|
2558
|
+
environment: deps.environment
|
|
2560
2559
|
},
|
|
2561
2560
|
token
|
|
2562
2561
|
);
|
|
@@ -2573,7 +2572,8 @@ function subscribeTokenRefresh(bridge, deps, onToken) {
|
|
|
2573
2572
|
appKey: deps.appKey,
|
|
2574
2573
|
getDeviceId: deps.getDeviceId,
|
|
2575
2574
|
getDistinctId: deps.getDistinctId,
|
|
2576
|
-
debug: deps.debug
|
|
2575
|
+
debug: deps.debug,
|
|
2576
|
+
environment: deps.environment
|
|
2577
2577
|
},
|
|
2578
2578
|
newToken
|
|
2579
2579
|
).catch(() => void 0);
|
|
@@ -2781,6 +2781,7 @@ var init_NotificationsManager = __esm({
|
|
|
2781
2781
|
this.getDistinctId = null;
|
|
2782
2782
|
this.appKey = null;
|
|
2783
2783
|
this.apiBaseUrl = null;
|
|
2784
|
+
this.environment = "production";
|
|
2784
2785
|
this.tokenRefreshCleanup = null;
|
|
2785
2786
|
this.foregroundCleanup = null;
|
|
2786
2787
|
this.pendingHandlersConfig = null;
|
|
@@ -2800,6 +2801,7 @@ var init_NotificationsManager = __esm({
|
|
|
2800
2801
|
this.secureStorage = deps.secureStorage;
|
|
2801
2802
|
this.getDeviceId = deps.getDeviceId;
|
|
2802
2803
|
if (deps.getDistinctId) this.getDistinctId = deps.getDistinctId;
|
|
2804
|
+
if (deps.environment) this.environment = deps.environment;
|
|
2803
2805
|
}
|
|
2804
2806
|
async initialize(config) {
|
|
2805
2807
|
this.applyConfig(config);
|
|
@@ -2842,7 +2844,8 @@ var init_NotificationsManager = __esm({
|
|
|
2842
2844
|
appKey: this.appKey,
|
|
2843
2845
|
getDeviceId: this.getDeviceId,
|
|
2844
2846
|
getDistinctId: this.getDistinctId,
|
|
2845
|
-
debug: this.debug
|
|
2847
|
+
debug: this.debug,
|
|
2848
|
+
environment: this.environment
|
|
2846
2849
|
};
|
|
2847
2850
|
}
|
|
2848
2851
|
async doRegisterToken(token) {
|
|
@@ -3914,6 +3917,32 @@ var init_IAPTransactionEmitter = __esm({
|
|
|
3914
3917
|
if (this.getDebug()) console.log("[Paywallo PURCHASE] transaction event emission failed", err);
|
|
3915
3918
|
}
|
|
3916
3919
|
}
|
|
3920
|
+
/**
|
|
3921
|
+
* Emits `checkout_started` quando o usuário inicia a compra (toca em comprar),
|
|
3922
|
+
* antes do StoreKit/Billing abrir — conta mesmo que a sheet nativa seja cancelada.
|
|
3923
|
+
* Vira InitiateCheckout no Meta/TikTok. Fire-and-forget — uma falha de tracking
|
|
3924
|
+
* nunca pode travar a compra.
|
|
3925
|
+
*/
|
|
3926
|
+
async emitCheckoutStarted(productId) {
|
|
3927
|
+
try {
|
|
3928
|
+
const apiClient = this.getApiClientFn();
|
|
3929
|
+
if (!apiClient) return;
|
|
3930
|
+
const distinctId = PaywalloClient.getDistinctId();
|
|
3931
|
+
if (!distinctId) return;
|
|
3932
|
+
const product = this.getProductFromCache(productId);
|
|
3933
|
+
const properties = {
|
|
3934
|
+
product_id: productId,
|
|
3935
|
+
amount: product?.priceValue ?? 0,
|
|
3936
|
+
currency: product?.currency ?? "USD"
|
|
3937
|
+
};
|
|
3938
|
+
await apiClient.trackEvent("checkout_started", distinctId, properties, void 0, {
|
|
3939
|
+
priority: "critical"
|
|
3940
|
+
});
|
|
3941
|
+
if (this.getDebug()) console.log("[Paywallo PURCHASE] emitted checkout_started", productId);
|
|
3942
|
+
} catch (err) {
|
|
3943
|
+
if (this.getDebug()) console.log("[Paywallo PURCHASE] checkout_started emission failed", err);
|
|
3944
|
+
}
|
|
3945
|
+
}
|
|
3917
3946
|
/**
|
|
3918
3947
|
* Forwards a native transaction update to the EventBatcher.
|
|
3919
3948
|
* Public so tests can exercise the wiring without a fake NativeEventEmitter.
|
|
@@ -3936,9 +3965,9 @@ var init_IAPTransactionEmitter = __esm({
|
|
|
3936
3965
|
product_id: update.productId
|
|
3937
3966
|
};
|
|
3938
3967
|
if (update.type !== "canceled") {
|
|
3939
|
-
const
|
|
3940
|
-
const amount = update.amount ??
|
|
3941
|
-
const currency = update.currency ??
|
|
3968
|
+
const cached2 = this.getProductFromCache(update.productId);
|
|
3969
|
+
const amount = update.amount ?? cached2?.priceValue;
|
|
3970
|
+
const currency = update.currency ?? cached2?.currency;
|
|
3942
3971
|
if (typeof amount === "number" && amount > 0) properties.amount = amount;
|
|
3943
3972
|
if (currency) properties.currency = currency;
|
|
3944
3973
|
}
|
|
@@ -4117,10 +4146,10 @@ var init_OfflineQueueStorage = __esm({
|
|
|
4117
4146
|
init_NativeStorage();
|
|
4118
4147
|
init_QueueJournal();
|
|
4119
4148
|
OfflineQueueStorage = class {
|
|
4120
|
-
constructor(config, emit,
|
|
4149
|
+
constructor(config, emit, log2) {
|
|
4121
4150
|
this.config = config;
|
|
4122
4151
|
this.emit = emit;
|
|
4123
|
-
this.log =
|
|
4152
|
+
this.log = log2;
|
|
4124
4153
|
}
|
|
4125
4154
|
async loadFromStorage(queue) {
|
|
4126
4155
|
const { merged, recovered, hadJournal } = await mergeJournalIntoMain(
|
|
@@ -4739,6 +4768,7 @@ var init_QueueProcessor = __esm({
|
|
|
4739
4768
|
for (const item of batch) {
|
|
4740
4769
|
retryIds.add(item.id);
|
|
4741
4770
|
}
|
|
4771
|
+
console.error("[Paywallo:QUEUE] event batch network error \u2014 items will retry", { size: batch.length, error: error instanceof Error ? error.message : String(error) });
|
|
4742
4772
|
this.log("Event batch threw network error - will retry", {
|
|
4743
4773
|
size: batch.length,
|
|
4744
4774
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -4756,14 +4786,25 @@ var init_QueueProcessor = __esm({
|
|
|
4756
4786
|
await offlineQueue.removeItem(item.id);
|
|
4757
4787
|
failed++;
|
|
4758
4788
|
}
|
|
4789
|
+
const responseError = typeof response.data === "object" && response.data !== null && "error" in response.data ? response.data.error : void 0;
|
|
4790
|
+
const isDuplicate = typeof responseError === "string" && responseError.toUpperCase().includes("DUPLICATE");
|
|
4791
|
+
if (isDuplicate) {
|
|
4792
|
+
if (this.config.debug) {
|
|
4793
|
+
console.log("[Paywallo:QUEUE] event batch deduplicated by server \u2014 items dropped (benign)", { status: response.status, size: batch.length, error: responseError });
|
|
4794
|
+
}
|
|
4795
|
+
} else {
|
|
4796
|
+
console.error("[Paywallo:QUEUE] event batch failed PERMANENTLY (4xx) \u2014 items dropped", { status: response.status, size: batch.length, responseBody: typeof response.data === "string" ? response.data.slice(0, 1e3) : JSON.stringify(response.data).slice(0, 1e3), firstItemBody: typeof batch[0].body === "string" ? batch[0].body.slice(0, 1e3) : JSON.stringify(batch[0].body).slice(0, 1e3) });
|
|
4797
|
+
}
|
|
4759
4798
|
this.log("Event batch failed permanently (4xx) - removing from queue", {
|
|
4760
4799
|
status: response.status,
|
|
4761
|
-
size: batch.length
|
|
4800
|
+
size: batch.length,
|
|
4801
|
+
isDuplicate
|
|
4762
4802
|
});
|
|
4763
4803
|
} else {
|
|
4764
4804
|
for (const item of batch) {
|
|
4765
4805
|
retryIds.add(item.id);
|
|
4766
4806
|
}
|
|
4807
|
+
console.error("[Paywallo:QUEUE] event batch server error (5xx) \u2014 will retry", { status: response.status, size: batch.length });
|
|
4767
4808
|
this.log("Event batch failed with server error - will retry", {
|
|
4768
4809
|
status: response.status,
|
|
4769
4810
|
size: batch.length
|
|
@@ -4793,6 +4834,7 @@ var init_QueueProcessor = __esm({
|
|
|
4793
4834
|
skipRetry: false
|
|
4794
4835
|
});
|
|
4795
4836
|
} catch (error) {
|
|
4837
|
+
console.error("[Paywallo:QUEUE] individual item network error \u2014 will retry", { id: item.id, url: item.url, error: error instanceof Error ? error.message : String(error) });
|
|
4796
4838
|
this.log("Request threw network error - will retry", {
|
|
4797
4839
|
id: item.id,
|
|
4798
4840
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -5089,6 +5131,7 @@ var init_IAPService = __esm({
|
|
|
5089
5131
|
this.purchaseInFlight = productId;
|
|
5090
5132
|
if (this.debug) console.log(`[Paywallo PURCHASE] starting ${productId}`);
|
|
5091
5133
|
try {
|
|
5134
|
+
void this.emitter.emitCheckoutStarted(productId);
|
|
5092
5135
|
const purchase = await nativeStoreKit.purchase(productId);
|
|
5093
5136
|
if (!purchase) {
|
|
5094
5137
|
if (this.debug) console.log(`[Paywallo PURCHASE] ${productId} cancelled`);
|
|
@@ -5883,10 +5926,10 @@ var init_PlanService = __esm({
|
|
|
5883
5926
|
}
|
|
5884
5927
|
async getCurrentPlan(forceRefresh = false) {
|
|
5885
5928
|
if (!forceRefresh) {
|
|
5886
|
-
const
|
|
5887
|
-
if (
|
|
5888
|
-
const current =
|
|
5889
|
-
(p) => p.identifier ===
|
|
5929
|
+
const cached2 = this.cache.get();
|
|
5930
|
+
if (cached2 && !cached2.isStale) {
|
|
5931
|
+
const current = cached2.data.plans.find(
|
|
5932
|
+
(p) => p.identifier === cached2.data.currentIdentifier
|
|
5890
5933
|
);
|
|
5891
5934
|
return current ?? null;
|
|
5892
5935
|
}
|
|
@@ -5913,8 +5956,8 @@ var init_PlanService = __esm({
|
|
|
5913
5956
|
}
|
|
5914
5957
|
async getAllPlans(forceRefresh = false) {
|
|
5915
5958
|
if (!forceRefresh) {
|
|
5916
|
-
const
|
|
5917
|
-
if (
|
|
5959
|
+
const cached2 = this.cache.get();
|
|
5960
|
+
if (cached2 && !cached2.isStale) return cached2.data;
|
|
5918
5961
|
}
|
|
5919
5962
|
if (!this.cache.get()) {
|
|
5920
5963
|
try {
|
|
@@ -6032,6 +6075,163 @@ var init_analytics = __esm({
|
|
|
6032
6075
|
}
|
|
6033
6076
|
});
|
|
6034
6077
|
|
|
6078
|
+
// src/core/events/schemas.ts
|
|
6079
|
+
import { z } from "zod";
|
|
6080
|
+
var lifecycleEventSchema, identifyEventSchema, paywallEventSchema, transactionEventSchema, onboardingEventSchema, notificationEventSchema, customEventSchema, EVENT_SCHEMAS;
|
|
6081
|
+
var init_schemas = __esm({
|
|
6082
|
+
"src/core/events/schemas.ts"() {
|
|
6083
|
+
"use strict";
|
|
6084
|
+
lifecycleEventSchema = z.object({
|
|
6085
|
+
type: z.enum([
|
|
6086
|
+
"install",
|
|
6087
|
+
"cold_start",
|
|
6088
|
+
"foreground",
|
|
6089
|
+
"background",
|
|
6090
|
+
"session_start",
|
|
6091
|
+
"session_end"
|
|
6092
|
+
]),
|
|
6093
|
+
session_id: z.string().optional(),
|
|
6094
|
+
duration_s: z.number().nonnegative().optional(),
|
|
6095
|
+
first_ever: z.boolean().optional(),
|
|
6096
|
+
// Contexto leve transportado em lifecycle (útil pra cold_start/install)
|
|
6097
|
+
app_version: z.string().optional(),
|
|
6098
|
+
device_type: z.enum(["ios", "android"]).optional(),
|
|
6099
|
+
os_version: z.string().optional(),
|
|
6100
|
+
// Timestamps opcionais — o EventBatcher injeta `timestamp` no envelope
|
|
6101
|
+
started_at: z.string().optional(),
|
|
6102
|
+
ended_at: z.string().optional()
|
|
6103
|
+
}).strict();
|
|
6104
|
+
identifyEventSchema = z.object({
|
|
6105
|
+
distinct_id: z.string().min(1),
|
|
6106
|
+
email: z.email().optional(),
|
|
6107
|
+
traits: z.record(z.string(), z.unknown()).optional(),
|
|
6108
|
+
attribution: z.record(z.string(), z.unknown()).optional(),
|
|
6109
|
+
device: z.record(z.string(), z.unknown()).optional()
|
|
6110
|
+
}).strict();
|
|
6111
|
+
paywallEventSchema = z.object({
|
|
6112
|
+
type: z.enum(["viewed", "closed", "purchased"]),
|
|
6113
|
+
paywall_id: z.string().min(1),
|
|
6114
|
+
placement: z.string().optional(),
|
|
6115
|
+
variant_id: z.string().optional(),
|
|
6116
|
+
variant_key: z.string().optional(),
|
|
6117
|
+
campaign_id: z.string().optional(),
|
|
6118
|
+
// `closed`-specific
|
|
6119
|
+
closed_at: z.string().optional(),
|
|
6120
|
+
duration_s: z.number().nonnegative().optional(),
|
|
6121
|
+
close_reason: z.enum(["dismiss", "cta", "purchase", "error", "timeout"]).optional(),
|
|
6122
|
+
scroll_depth: z.number().min(0).max(1).optional(),
|
|
6123
|
+
// `purchased`-specific (mínimo — transaction canônica leva detalhes)
|
|
6124
|
+
product_id: z.string().optional()
|
|
6125
|
+
}).strict();
|
|
6126
|
+
transactionEventSchema = z.object({
|
|
6127
|
+
type: z.enum([
|
|
6128
|
+
"completed",
|
|
6129
|
+
"failed",
|
|
6130
|
+
"refunded",
|
|
6131
|
+
"renewed",
|
|
6132
|
+
"canceled",
|
|
6133
|
+
"expired"
|
|
6134
|
+
]),
|
|
6135
|
+
tx_id: z.string().min(1),
|
|
6136
|
+
amount: z.number().optional(),
|
|
6137
|
+
currency: z.string().length(3).optional(),
|
|
6138
|
+
product_id: z.string().optional(),
|
|
6139
|
+
subscription_id: z.string().optional(),
|
|
6140
|
+
paywall_id: z.string().optional(),
|
|
6141
|
+
variant_id: z.string().optional(),
|
|
6142
|
+
reason: z.string().optional()
|
|
6143
|
+
}).strict();
|
|
6144
|
+
onboardingEventSchema = z.object({
|
|
6145
|
+
type: z.enum(["step", "complete", "drop"]),
|
|
6146
|
+
step_index: z.number().int().nonnegative().optional(),
|
|
6147
|
+
step_name: z.string().optional(),
|
|
6148
|
+
variant_key: z.string().optional(),
|
|
6149
|
+
time_on_prev_s: z.number().nonnegative().optional()
|
|
6150
|
+
}).strict();
|
|
6151
|
+
notificationEventSchema = z.object({
|
|
6152
|
+
type: z.enum(["delivered", "displayed", "clicked", "dismissed"]),
|
|
6153
|
+
notification_id: z.string().optional(),
|
|
6154
|
+
campaign_id: z.string().optional(),
|
|
6155
|
+
variant_key: z.string().nullable().optional(),
|
|
6156
|
+
message_id: z.string().optional(),
|
|
6157
|
+
device_id: z.string().optional(),
|
|
6158
|
+
push_platform: z.enum(["ios", "android"]).optional(),
|
|
6159
|
+
timezone: z.string().optional(),
|
|
6160
|
+
failure_reason: z.string().optional(),
|
|
6161
|
+
app_user_id: z.string().optional()
|
|
6162
|
+
}).strict();
|
|
6163
|
+
customEventSchema = z.object({
|
|
6164
|
+
name: z.string().min(1).regex(
|
|
6165
|
+
/^(\$[a-zA-Z0-9_]+|[a-z][a-z0-9_]*)$/,
|
|
6166
|
+
"custom event name must be snake_case or $reserved"
|
|
6167
|
+
),
|
|
6168
|
+
props: z.record(z.string(), z.unknown()).optional()
|
|
6169
|
+
}).strict();
|
|
6170
|
+
EVENT_SCHEMAS = {
|
|
6171
|
+
lifecycle: lifecycleEventSchema,
|
|
6172
|
+
identify: identifyEventSchema,
|
|
6173
|
+
paywall: paywallEventSchema,
|
|
6174
|
+
transaction: transactionEventSchema,
|
|
6175
|
+
onboarding: onboardingEventSchema,
|
|
6176
|
+
notification: notificationEventSchema,
|
|
6177
|
+
custom: customEventSchema
|
|
6178
|
+
};
|
|
6179
|
+
}
|
|
6180
|
+
});
|
|
6181
|
+
|
|
6182
|
+
// src/core/events/eventFamilies.ts
|
|
6183
|
+
function isDeprecatedEvent(eventName) {
|
|
6184
|
+
return DEPRECATED_EVENT_NAMES.includes(eventName);
|
|
6185
|
+
}
|
|
6186
|
+
function isCanonicalFamily(name) {
|
|
6187
|
+
return CANONICAL_FAMILIES.includes(name);
|
|
6188
|
+
}
|
|
6189
|
+
function detectFamily(eventName) {
|
|
6190
|
+
if (isCanonicalFamily(eventName) && eventName !== "custom") {
|
|
6191
|
+
return eventName;
|
|
6192
|
+
}
|
|
6193
|
+
return "custom";
|
|
6194
|
+
}
|
|
6195
|
+
function validateEvent(eventName, properties) {
|
|
6196
|
+
const family = detectFamily(eventName);
|
|
6197
|
+
const schema = EVENT_SCHEMAS[family];
|
|
6198
|
+
const input = family === "custom" ? { name: eventName, ...properties ? { props: properties } : {} } : properties ?? {};
|
|
6199
|
+
const parsed = schema.safeParse(input);
|
|
6200
|
+
if (parsed.success) {
|
|
6201
|
+
return { ok: true, family, data: parsed.data };
|
|
6202
|
+
}
|
|
6203
|
+
return { ok: false, family, error: parsed.error };
|
|
6204
|
+
}
|
|
6205
|
+
function formatValidationError(error) {
|
|
6206
|
+
return error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
|
|
6207
|
+
}
|
|
6208
|
+
var CANONICAL_FAMILIES, DEPRECATED_EVENT_NAMES;
|
|
6209
|
+
var init_eventFamilies = __esm({
|
|
6210
|
+
"src/core/events/eventFamilies.ts"() {
|
|
6211
|
+
"use strict";
|
|
6212
|
+
init_schemas();
|
|
6213
|
+
CANONICAL_FAMILIES = [
|
|
6214
|
+
"lifecycle",
|
|
6215
|
+
"identify",
|
|
6216
|
+
"paywall",
|
|
6217
|
+
"transaction",
|
|
6218
|
+
"onboarding",
|
|
6219
|
+
"notification",
|
|
6220
|
+
"custom"
|
|
6221
|
+
];
|
|
6222
|
+
DEPRECATED_EVENT_NAMES = [
|
|
6223
|
+
"$paywall_purchased",
|
|
6224
|
+
"$paywall_product_selected",
|
|
6225
|
+
"$core_action",
|
|
6226
|
+
"$campaign_impression",
|
|
6227
|
+
"$app_open",
|
|
6228
|
+
"$app_background",
|
|
6229
|
+
"$app_foreground",
|
|
6230
|
+
"session.end"
|
|
6231
|
+
];
|
|
6232
|
+
}
|
|
6233
|
+
});
|
|
6234
|
+
|
|
6035
6235
|
// src/core/PaywalloAnalytics.ts
|
|
6036
6236
|
function isValidEventName(name) {
|
|
6037
6237
|
if (name.startsWith("$")) return /^\$[a-z][a-z0-9]*(_[a-z0-9]+)*$/.test(name);
|
|
@@ -6040,7 +6240,7 @@ function isValidEventName(name) {
|
|
|
6040
6240
|
async function trackEvent(apiClient, state, eventName, options) {
|
|
6041
6241
|
const distinctId = identityManager.getDistinctId();
|
|
6042
6242
|
if (!distinctId) {
|
|
6043
|
-
|
|
6243
|
+
console.error("[Paywallo:DROP] event dropped \u2014 no distinctId available yet", { eventName });
|
|
6044
6244
|
return;
|
|
6045
6245
|
}
|
|
6046
6246
|
if (!isValidEventName(eventName)) {
|
|
@@ -6049,10 +6249,14 @@ async function trackEvent(apiClient, state, eventName, options) {
|
|
|
6049
6249
|
}
|
|
6050
6250
|
if (state.config?.debug && eventName.startsWith("$purchase")) console.log(`[Paywallo TRACK] ${eventName}`, options?.properties ?? {});
|
|
6051
6251
|
const sessionId = sessionManager.getSessionId();
|
|
6252
|
+
const family = detectFamily(eventName);
|
|
6253
|
+
const isCustomFamily = family === "custom";
|
|
6254
|
+
const identityProps = isCustomFamily ? identityManager.getProperties() : {};
|
|
6255
|
+
const sessionProp = isCustomFamily && sessionId ? { sessionId } : {};
|
|
6052
6256
|
await apiClient.trackEvent(
|
|
6053
6257
|
eventName,
|
|
6054
6258
|
distinctId,
|
|
6055
|
-
{ ...
|
|
6259
|
+
{ ...identityProps, ...options?.properties, ...sessionProp },
|
|
6056
6260
|
options?.timestamp,
|
|
6057
6261
|
options?.priority ? { priority: options.priority } : void 0
|
|
6058
6262
|
);
|
|
@@ -6082,6 +6286,7 @@ var init_PaywalloAnalytics = __esm({
|
|
|
6082
6286
|
init_identity();
|
|
6083
6287
|
init_session();
|
|
6084
6288
|
init_ClientError();
|
|
6289
|
+
init_eventFamilies();
|
|
6085
6290
|
}
|
|
6086
6291
|
});
|
|
6087
6292
|
|
|
@@ -6346,49 +6551,49 @@ var init_SubscriptionCache = __esm({
|
|
|
6346
6551
|
await this.storage.remove(keyFor(distinctId));
|
|
6347
6552
|
return null;
|
|
6348
6553
|
}
|
|
6349
|
-
const
|
|
6350
|
-
if (
|
|
6351
|
-
|
|
6554
|
+
const cached2 = parsed;
|
|
6555
|
+
if (cached2.data.subscription?.expiresAt) {
|
|
6556
|
+
cached2.data.subscription.expiresAt = new Date(cached2.data.subscription.expiresAt);
|
|
6352
6557
|
}
|
|
6353
|
-
if (
|
|
6354
|
-
|
|
6355
|
-
|
|
6558
|
+
if (cached2.data.subscription?.originalPurchaseDate) {
|
|
6559
|
+
cached2.data.subscription.originalPurchaseDate = new Date(
|
|
6560
|
+
cached2.data.subscription.originalPurchaseDate
|
|
6356
6561
|
);
|
|
6357
6562
|
}
|
|
6358
|
-
if (
|
|
6359
|
-
|
|
6360
|
-
|
|
6563
|
+
if (cached2.data.subscription?.latestPurchaseDate) {
|
|
6564
|
+
cached2.data.subscription.latestPurchaseDate = new Date(
|
|
6565
|
+
cached2.data.subscription.latestPurchaseDate
|
|
6361
6566
|
);
|
|
6362
6567
|
}
|
|
6363
|
-
if (
|
|
6364
|
-
|
|
6365
|
-
|
|
6568
|
+
if (cached2.data.subscription?.cancellationDate) {
|
|
6569
|
+
cached2.data.subscription.cancellationDate = new Date(
|
|
6570
|
+
cached2.data.subscription.cancellationDate
|
|
6366
6571
|
);
|
|
6367
6572
|
}
|
|
6368
|
-
if (
|
|
6369
|
-
|
|
6370
|
-
|
|
6573
|
+
if (cached2.data.subscription?.gracePeriodExpiresAt) {
|
|
6574
|
+
cached2.data.subscription.gracePeriodExpiresAt = new Date(
|
|
6575
|
+
cached2.data.subscription.gracePeriodExpiresAt
|
|
6371
6576
|
);
|
|
6372
6577
|
}
|
|
6373
|
-
|
|
6374
|
-
if (!
|
|
6375
|
-
this.memoryCache.set(distinctId,
|
|
6578
|
+
cached2.isStale = this.isExpired(cached2);
|
|
6579
|
+
if (!cached2.isStale) {
|
|
6580
|
+
this.memoryCache.set(distinctId, cached2);
|
|
6376
6581
|
}
|
|
6377
|
-
return
|
|
6582
|
+
return cached2;
|
|
6378
6583
|
} catch {
|
|
6379
6584
|
return null;
|
|
6380
6585
|
}
|
|
6381
6586
|
}
|
|
6382
6587
|
async set(distinctId, data) {
|
|
6383
6588
|
if (!distinctId) return;
|
|
6384
|
-
const
|
|
6589
|
+
const cached2 = {
|
|
6385
6590
|
data,
|
|
6386
6591
|
cachedAt: Date.now(),
|
|
6387
6592
|
isStale: false
|
|
6388
6593
|
};
|
|
6389
|
-
this.memoryCache.set(distinctId,
|
|
6594
|
+
this.memoryCache.set(distinctId, cached2);
|
|
6390
6595
|
try {
|
|
6391
|
-
await this.storage.set(keyFor(distinctId), JSON.stringify(
|
|
6596
|
+
await this.storage.set(keyFor(distinctId), JSON.stringify(cached2));
|
|
6392
6597
|
await this.addToIndex(distinctId);
|
|
6393
6598
|
} catch {
|
|
6394
6599
|
}
|
|
@@ -6432,8 +6637,8 @@ var init_SubscriptionCache = __esm({
|
|
|
6432
6637
|
...allKeys.map((k) => this.storage.remove(keyFor(k)))
|
|
6433
6638
|
]);
|
|
6434
6639
|
}
|
|
6435
|
-
isExpired(
|
|
6436
|
-
return Date.now() -
|
|
6640
|
+
isExpired(cached2) {
|
|
6641
|
+
return Date.now() - cached2.cachedAt > this.ttl;
|
|
6437
6642
|
}
|
|
6438
6643
|
setTTL(ttl) {
|
|
6439
6644
|
this.ttl = ttl;
|
|
@@ -6489,9 +6694,9 @@ var init_SubscriptionManager = __esm({
|
|
|
6489
6694
|
return this.getEmptyStatus();
|
|
6490
6695
|
}
|
|
6491
6696
|
if (!forceRefresh) {
|
|
6492
|
-
const
|
|
6493
|
-
if (
|
|
6494
|
-
return
|
|
6697
|
+
const cached2 = await this.cache.get(this.cacheKey());
|
|
6698
|
+
if (cached2 && !cached2.isStale) {
|
|
6699
|
+
return cached2.data;
|
|
6495
6700
|
}
|
|
6496
6701
|
}
|
|
6497
6702
|
try {
|
|
@@ -6501,9 +6706,9 @@ var init_SubscriptionManager = __esm({
|
|
|
6501
6706
|
return status;
|
|
6502
6707
|
} catch (error) {
|
|
6503
6708
|
this.log("Failed to fetch subscription status", error);
|
|
6504
|
-
const
|
|
6505
|
-
if (
|
|
6506
|
-
return
|
|
6709
|
+
const cached2 = await this.cache.get(this.cacheKey());
|
|
6710
|
+
if (cached2) {
|
|
6711
|
+
return cached2.data;
|
|
6507
6712
|
}
|
|
6508
6713
|
return this.getEmptyStatus();
|
|
6509
6714
|
}
|
|
@@ -6918,163 +7123,6 @@ var init_ApiClientQueue = __esm({
|
|
|
6918
7123
|
}
|
|
6919
7124
|
});
|
|
6920
7125
|
|
|
6921
|
-
// src/core/events/schemas.ts
|
|
6922
|
-
import { z } from "zod";
|
|
6923
|
-
var lifecycleEventSchema, identifyEventSchema, paywallEventSchema, transactionEventSchema, onboardingEventSchema, notificationEventSchema, customEventSchema, EVENT_SCHEMAS;
|
|
6924
|
-
var init_schemas = __esm({
|
|
6925
|
-
"src/core/events/schemas.ts"() {
|
|
6926
|
-
"use strict";
|
|
6927
|
-
lifecycleEventSchema = z.object({
|
|
6928
|
-
type: z.enum([
|
|
6929
|
-
"install",
|
|
6930
|
-
"cold_start",
|
|
6931
|
-
"foreground",
|
|
6932
|
-
"background",
|
|
6933
|
-
"session_start",
|
|
6934
|
-
"session_end"
|
|
6935
|
-
]),
|
|
6936
|
-
session_id: z.string().optional(),
|
|
6937
|
-
duration_s: z.number().nonnegative().optional(),
|
|
6938
|
-
first_ever: z.boolean().optional(),
|
|
6939
|
-
// Contexto leve transportado em lifecycle (útil pra cold_start/install)
|
|
6940
|
-
app_version: z.string().optional(),
|
|
6941
|
-
device_type: z.enum(["ios", "android"]).optional(),
|
|
6942
|
-
os_version: z.string().optional(),
|
|
6943
|
-
// Timestamps opcionais — o EventBatcher injeta `timestamp` no envelope
|
|
6944
|
-
started_at: z.string().optional(),
|
|
6945
|
-
ended_at: z.string().optional()
|
|
6946
|
-
}).strict();
|
|
6947
|
-
identifyEventSchema = z.object({
|
|
6948
|
-
distinct_id: z.string().min(1),
|
|
6949
|
-
email: z.email().optional(),
|
|
6950
|
-
traits: z.record(z.string(), z.unknown()).optional(),
|
|
6951
|
-
attribution: z.record(z.string(), z.unknown()).optional(),
|
|
6952
|
-
device: z.record(z.string(), z.unknown()).optional()
|
|
6953
|
-
}).strict();
|
|
6954
|
-
paywallEventSchema = z.object({
|
|
6955
|
-
type: z.enum(["viewed", "closed", "purchased"]),
|
|
6956
|
-
paywall_id: z.string().min(1),
|
|
6957
|
-
placement: z.string().optional(),
|
|
6958
|
-
variant_id: z.string().optional(),
|
|
6959
|
-
variant_key: z.string().optional(),
|
|
6960
|
-
campaign_id: z.string().optional(),
|
|
6961
|
-
// `closed`-specific
|
|
6962
|
-
closed_at: z.string().optional(),
|
|
6963
|
-
duration_s: z.number().nonnegative().optional(),
|
|
6964
|
-
close_reason: z.enum(["dismiss", "cta", "purchase", "error", "timeout"]).optional(),
|
|
6965
|
-
scroll_depth: z.number().min(0).max(1).optional(),
|
|
6966
|
-
// `purchased`-specific (mínimo — transaction canônica leva detalhes)
|
|
6967
|
-
product_id: z.string().optional()
|
|
6968
|
-
}).strict();
|
|
6969
|
-
transactionEventSchema = z.object({
|
|
6970
|
-
type: z.enum([
|
|
6971
|
-
"completed",
|
|
6972
|
-
"failed",
|
|
6973
|
-
"refunded",
|
|
6974
|
-
"renewed",
|
|
6975
|
-
"canceled",
|
|
6976
|
-
"expired"
|
|
6977
|
-
]),
|
|
6978
|
-
tx_id: z.string().min(1),
|
|
6979
|
-
amount: z.number().optional(),
|
|
6980
|
-
currency: z.string().length(3).optional(),
|
|
6981
|
-
product_id: z.string().optional(),
|
|
6982
|
-
subscription_id: z.string().optional(),
|
|
6983
|
-
paywall_id: z.string().optional(),
|
|
6984
|
-
variant_id: z.string().optional(),
|
|
6985
|
-
reason: z.string().optional()
|
|
6986
|
-
}).strict();
|
|
6987
|
-
onboardingEventSchema = z.object({
|
|
6988
|
-
type: z.enum(["step", "complete", "drop"]),
|
|
6989
|
-
step_index: z.number().int().nonnegative().optional(),
|
|
6990
|
-
step_name: z.string().optional(),
|
|
6991
|
-
variant_key: z.string().optional(),
|
|
6992
|
-
time_on_prev_s: z.number().nonnegative().optional()
|
|
6993
|
-
}).strict();
|
|
6994
|
-
notificationEventSchema = z.object({
|
|
6995
|
-
type: z.enum(["delivered", "displayed", "clicked", "dismissed"]),
|
|
6996
|
-
notification_id: z.string().optional(),
|
|
6997
|
-
campaign_id: z.string().optional(),
|
|
6998
|
-
variant_key: z.string().nullable().optional(),
|
|
6999
|
-
message_id: z.string().optional(),
|
|
7000
|
-
device_id: z.string().optional(),
|
|
7001
|
-
push_platform: z.enum(["ios", "android"]).optional(),
|
|
7002
|
-
timezone: z.string().optional(),
|
|
7003
|
-
failure_reason: z.string().optional(),
|
|
7004
|
-
app_user_id: z.string().optional()
|
|
7005
|
-
}).strict();
|
|
7006
|
-
customEventSchema = z.object({
|
|
7007
|
-
name: z.string().min(1).regex(
|
|
7008
|
-
/^(\$[a-zA-Z0-9_]+|[a-z][a-z0-9_]*)$/,
|
|
7009
|
-
"custom event name must be snake_case or $reserved"
|
|
7010
|
-
),
|
|
7011
|
-
props: z.record(z.string(), z.unknown()).optional()
|
|
7012
|
-
}).strict();
|
|
7013
|
-
EVENT_SCHEMAS = {
|
|
7014
|
-
lifecycle: lifecycleEventSchema,
|
|
7015
|
-
identify: identifyEventSchema,
|
|
7016
|
-
paywall: paywallEventSchema,
|
|
7017
|
-
transaction: transactionEventSchema,
|
|
7018
|
-
onboarding: onboardingEventSchema,
|
|
7019
|
-
notification: notificationEventSchema,
|
|
7020
|
-
custom: customEventSchema
|
|
7021
|
-
};
|
|
7022
|
-
}
|
|
7023
|
-
});
|
|
7024
|
-
|
|
7025
|
-
// src/core/events/eventFamilies.ts
|
|
7026
|
-
function isDeprecatedEvent(eventName) {
|
|
7027
|
-
return DEPRECATED_EVENT_NAMES.includes(eventName);
|
|
7028
|
-
}
|
|
7029
|
-
function isCanonicalFamily(name) {
|
|
7030
|
-
return CANONICAL_FAMILIES.includes(name);
|
|
7031
|
-
}
|
|
7032
|
-
function detectFamily(eventName) {
|
|
7033
|
-
if (isCanonicalFamily(eventName) && eventName !== "custom") {
|
|
7034
|
-
return eventName;
|
|
7035
|
-
}
|
|
7036
|
-
return "custom";
|
|
7037
|
-
}
|
|
7038
|
-
function validateEvent(eventName, properties) {
|
|
7039
|
-
const family = detectFamily(eventName);
|
|
7040
|
-
const schema = EVENT_SCHEMAS[family];
|
|
7041
|
-
const input = family === "custom" ? { name: eventName, ...properties ? { props: properties } : {} } : properties ?? {};
|
|
7042
|
-
const parsed = schema.safeParse(input);
|
|
7043
|
-
if (parsed.success) {
|
|
7044
|
-
return { ok: true, family, data: parsed.data };
|
|
7045
|
-
}
|
|
7046
|
-
return { ok: false, family, error: parsed.error };
|
|
7047
|
-
}
|
|
7048
|
-
function formatValidationError(error) {
|
|
7049
|
-
return error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
|
|
7050
|
-
}
|
|
7051
|
-
var CANONICAL_FAMILIES, DEPRECATED_EVENT_NAMES;
|
|
7052
|
-
var init_eventFamilies = __esm({
|
|
7053
|
-
"src/core/events/eventFamilies.ts"() {
|
|
7054
|
-
"use strict";
|
|
7055
|
-
init_schemas();
|
|
7056
|
-
CANONICAL_FAMILIES = [
|
|
7057
|
-
"lifecycle",
|
|
7058
|
-
"identify",
|
|
7059
|
-
"paywall",
|
|
7060
|
-
"transaction",
|
|
7061
|
-
"onboarding",
|
|
7062
|
-
"notification",
|
|
7063
|
-
"custom"
|
|
7064
|
-
];
|
|
7065
|
-
DEPRECATED_EVENT_NAMES = [
|
|
7066
|
-
"$paywall_purchased",
|
|
7067
|
-
"$paywall_product_selected",
|
|
7068
|
-
"$core_action",
|
|
7069
|
-
"$campaign_impression",
|
|
7070
|
-
"$app_open",
|
|
7071
|
-
"$app_background",
|
|
7072
|
-
"$app_foreground",
|
|
7073
|
-
"session.end"
|
|
7074
|
-
];
|
|
7075
|
-
}
|
|
7076
|
-
});
|
|
7077
|
-
|
|
7078
7126
|
// src/core/eventEnvelopeV2.ts
|
|
7079
7127
|
import { Platform as Platform13 } from "react-native";
|
|
7080
7128
|
import { z as z2 } from "zod";
|
|
@@ -7104,6 +7152,9 @@ function buildV2Envelope(events, providerContext) {
|
|
|
7104
7152
|
if (context.distinct_id === void 0 && events.length > 0) {
|
|
7105
7153
|
context.distinct_id = events[0].distinctId;
|
|
7106
7154
|
}
|
|
7155
|
+
if (!context.distinct_id || context.distinct_id.length === 0) {
|
|
7156
|
+
console.error("[Paywallo:ENVELOPE] distinct_id is empty after resolution \u2014 envelope will fail schema", { providerContext, eventCount: events.length, firstEventName: events[0]?.eventName });
|
|
7157
|
+
}
|
|
7107
7158
|
return { context, events: v2Events };
|
|
7108
7159
|
}
|
|
7109
7160
|
function resolveProviderContext(provider) {
|
|
@@ -7155,12 +7206,18 @@ var init_eventEnvelopeV2 = __esm({
|
|
|
7155
7206
|
session_id: z2.string().optional(),
|
|
7156
7207
|
device_id: z2.string().optional(),
|
|
7157
7208
|
app_version: z2.string().optional(),
|
|
7209
|
+
app_build: z2.string().optional(),
|
|
7210
|
+
bundle_id: z2.string().optional(),
|
|
7158
7211
|
sdk_version: z2.string().optional(),
|
|
7159
7212
|
platform: z2.string().optional(),
|
|
7160
7213
|
os_version: z2.string().optional(),
|
|
7161
7214
|
device_model: z2.string().optional(),
|
|
7162
7215
|
timezone: z2.string().optional(),
|
|
7163
7216
|
locale: z2.string().optional(),
|
|
7217
|
+
carrier: z2.string().optional(),
|
|
7218
|
+
screen_width: z2.number().optional(),
|
|
7219
|
+
screen_height: z2.number().optional(),
|
|
7220
|
+
screen_density: z2.number().optional(),
|
|
7164
7221
|
attribution: z2.record(z2.string(), z2.unknown()).optional(),
|
|
7165
7222
|
ids: z2.record(z2.string(), z2.unknown()).optional()
|
|
7166
7223
|
});
|
|
@@ -7173,12 +7230,21 @@ var init_eventEnvelopeV2 = __esm({
|
|
|
7173
7230
|
session_id: ["session_id", "sessionId"],
|
|
7174
7231
|
device_id: ["device_id", "deviceId"],
|
|
7175
7232
|
app_version: ["app_version", "appVersion"],
|
|
7233
|
+
// F2.2 — alias só snake_case canônico: campos vêm do context provider, não
|
|
7234
|
+
// de properties de evento. Evita promover (e deletar) chaves do payload do
|
|
7235
|
+
// $app_installed que o server lê (screenWidth etc.).
|
|
7236
|
+
app_build: ["app_build"],
|
|
7237
|
+
bundle_id: ["bundle_id"],
|
|
7176
7238
|
sdk_version: ["sdk_version", "sdkVersion"],
|
|
7177
7239
|
platform: ["platform"],
|
|
7178
7240
|
os_version: ["os_version", "osVersion", "systemVersion"],
|
|
7179
7241
|
device_model: ["device_model", "deviceModel", "model"],
|
|
7180
7242
|
timezone: ["timezone", "timeZone"],
|
|
7181
7243
|
locale: ["locale"],
|
|
7244
|
+
carrier: ["carrier_ctx"],
|
|
7245
|
+
screen_width: ["screen_width"],
|
|
7246
|
+
screen_height: ["screen_height"],
|
|
7247
|
+
screen_density: ["screen_density"],
|
|
7182
7248
|
attribution: ["attribution"],
|
|
7183
7249
|
ids: ["ids"]
|
|
7184
7250
|
};
|
|
@@ -7305,8 +7371,8 @@ var init_EventBatcher = __esm({
|
|
|
7305
7371
|
for (const event of drained) {
|
|
7306
7372
|
try {
|
|
7307
7373
|
await this.postBatch([event], `event_critical:${event.eventName}`, "critical");
|
|
7308
|
-
} catch {
|
|
7309
|
-
|
|
7374
|
+
} catch (err) {
|
|
7375
|
+
console.error("[Paywallo:CRITICAL] critical event post failed", { eventName: event.eventName, error: err instanceof Error ? err.message : String(err) });
|
|
7310
7376
|
}
|
|
7311
7377
|
}
|
|
7312
7378
|
}
|
|
@@ -7319,8 +7385,8 @@ var init_EventBatcher = __esm({
|
|
|
7319
7385
|
}
|
|
7320
7386
|
try {
|
|
7321
7387
|
await this.postBatch(batch, `event_batch:${batch.length}`);
|
|
7322
|
-
} catch {
|
|
7323
|
-
|
|
7388
|
+
} catch (err) {
|
|
7389
|
+
console.error("[Paywallo:NORMAL] batch post failed \u2014 relying on OfflineQueue", { batchSize: batch.length, error: err instanceof Error ? err.message : String(err) });
|
|
7324
7390
|
}
|
|
7325
7391
|
}
|
|
7326
7392
|
async postBatch(events, label, priority = "normal") {
|
|
@@ -7335,6 +7401,7 @@ var init_EventBatcher = __esm({
|
|
|
7335
7401
|
const parsed = v2EnvelopeSchema.safeParse(envelope);
|
|
7336
7402
|
if (!parsed.success) {
|
|
7337
7403
|
if (this.debug) console.log("[Paywallo EVENTS] V2 envelope schema validation failed:", parsed.error.issues);
|
|
7404
|
+
console.error("[Paywallo:CRITICAL] V2 envelope schema validation failed", { issues: parsed.error.issues, eventCount: events.length, firstEventName: events[0]?.eventName, context: providerContext });
|
|
7338
7405
|
throw parsed.error;
|
|
7339
7406
|
}
|
|
7340
7407
|
await this.post(V2_BATCH_ENDPOINT, parsed.data, label, priority);
|
|
@@ -7917,7 +7984,8 @@ function setupNotifications(apiClient, config, environment, eventPipeline) {
|
|
|
7917
7984
|
httpClient: apiClient.getHttpClient(),
|
|
7918
7985
|
secureStorage: new SecureStorage(config.debug),
|
|
7919
7986
|
getDeviceId: () => identityManager.getDeviceId(),
|
|
7920
|
-
getDistinctId: () => identityManager.getDistinctId()
|
|
7987
|
+
getDistinctId: () => identityManager.getDistinctId(),
|
|
7988
|
+
environment: environment === "Sandbox" ? "sandbox" : "production"
|
|
7921
7989
|
});
|
|
7922
7990
|
notificationsManager.setupHandlers({ eventBatcher: eventPipeline });
|
|
7923
7991
|
notificationsManager.initialize({
|
|
@@ -8001,7 +8069,38 @@ var init_PaywalloState = __esm({
|
|
|
8001
8069
|
}
|
|
8002
8070
|
});
|
|
8003
8071
|
|
|
8072
|
+
// src/utils/detectEnvironment.ts
|
|
8073
|
+
import { NativeModules as NativeModules8 } from "react-native";
|
|
8074
|
+
async function detectEnvironment() {
|
|
8075
|
+
if (cached !== null) return cached;
|
|
8076
|
+
if (typeof globalThis.__DEV__ !== "undefined" && globalThis.__DEV__) {
|
|
8077
|
+
cached = "sandbox";
|
|
8078
|
+
return cached;
|
|
8079
|
+
}
|
|
8080
|
+
if (!nativeModule) {
|
|
8081
|
+
cached = "production";
|
|
8082
|
+
return cached;
|
|
8083
|
+
}
|
|
8084
|
+
try {
|
|
8085
|
+
const result = await nativeModule.detect();
|
|
8086
|
+
cached = result === "sandbox" ? "sandbox" : "production";
|
|
8087
|
+
return cached;
|
|
8088
|
+
} catch {
|
|
8089
|
+
cached = "production";
|
|
8090
|
+
return cached;
|
|
8091
|
+
}
|
|
8092
|
+
}
|
|
8093
|
+
var nativeModule, cached;
|
|
8094
|
+
var init_detectEnvironment = __esm({
|
|
8095
|
+
"src/utils/detectEnvironment.ts"() {
|
|
8096
|
+
"use strict";
|
|
8097
|
+
nativeModule = NativeModules8.PaywalloEnv ?? null;
|
|
8098
|
+
cached = null;
|
|
8099
|
+
}
|
|
8100
|
+
});
|
|
8101
|
+
|
|
8004
8102
|
// src/core/PaywalloInitializer.ts
|
|
8103
|
+
import { Dimensions as Dimensions4, PixelRatio as PixelRatio2 } from "react-native";
|
|
8005
8104
|
async function initWithRetry(state, config) {
|
|
8006
8105
|
while (state.initAttempts <= MAX_INIT_RETRIES) {
|
|
8007
8106
|
try {
|
|
@@ -8080,7 +8179,13 @@ async function resolveSessionFlags(state, keys, apiClient, distinctId) {
|
|
|
8080
8179
|
}
|
|
8081
8180
|
}
|
|
8082
8181
|
async function doInit(state, config) {
|
|
8083
|
-
|
|
8182
|
+
let environment;
|
|
8183
|
+
if (config.environment) {
|
|
8184
|
+
environment = config.environment;
|
|
8185
|
+
} else {
|
|
8186
|
+
const detected = await detectEnvironment();
|
|
8187
|
+
environment = detected === "sandbox" ? "Sandbox" : "Production";
|
|
8188
|
+
}
|
|
8084
8189
|
const offlineQueueEnabled = config.offlineQueueEnabled !== false;
|
|
8085
8190
|
await Promise.all([
|
|
8086
8191
|
networkMonitor.initialize({ debug: config.debug }),
|
|
@@ -8168,15 +8273,31 @@ async function doInit(state, config) {
|
|
|
8168
8273
|
timezone = opts.timeZone || void 0;
|
|
8169
8274
|
} catch {
|
|
8170
8275
|
}
|
|
8276
|
+
let screenWidth;
|
|
8277
|
+
let screenHeight;
|
|
8278
|
+
let screenDensity;
|
|
8279
|
+
try {
|
|
8280
|
+
const screen = Dimensions4.get("screen");
|
|
8281
|
+
screenWidth = Math.round(screen.width) || void 0;
|
|
8282
|
+
screenHeight = Math.round(screen.height) || void 0;
|
|
8283
|
+
screenDensity = PixelRatio2.get() || void 0;
|
|
8284
|
+
} catch {
|
|
8285
|
+
}
|
|
8171
8286
|
return {
|
|
8172
8287
|
distinct_id: identityManager.getDistinctId() || void 0,
|
|
8173
8288
|
device_id: identityManager.getDeviceId() ?? void 0,
|
|
8174
8289
|
session_id: sessionManager.getSessionId() ?? void 0,
|
|
8175
8290
|
app_version: device?.appVersion && device.appVersion !== "0.0.0" ? device.appVersion : void 0,
|
|
8291
|
+
app_build: device?.buildNumber && device.buildNumber !== "0" ? device.buildNumber : void 0,
|
|
8292
|
+
bundle_id: device?.bundleId || void 0,
|
|
8176
8293
|
os_version: device?.systemVersion && device.systemVersion !== "0.0.0" ? device.systemVersion : void 0,
|
|
8177
8294
|
device_model: device?.modelId || device?.model || void 0,
|
|
8178
8295
|
timezone,
|
|
8179
8296
|
locale,
|
|
8297
|
+
carrier: device?.carrier || void 0,
|
|
8298
|
+
screen_width: screenWidth,
|
|
8299
|
+
screen_height: screenHeight,
|
|
8300
|
+
screen_density: screenDensity,
|
|
8180
8301
|
...attribution && Object.keys(attribution).length > 0 && { attribution },
|
|
8181
8302
|
...ids && Object.keys(ids).length > 0 && { ids }
|
|
8182
8303
|
};
|
|
@@ -8248,6 +8369,7 @@ var init_PaywalloInitializer = __esm({
|
|
|
8248
8369
|
init_PaywalloState();
|
|
8249
8370
|
init_queue();
|
|
8250
8371
|
init_NativeStorage();
|
|
8372
|
+
init_detectEnvironment();
|
|
8251
8373
|
}
|
|
8252
8374
|
});
|
|
8253
8375
|
|
|
@@ -8705,8 +8827,8 @@ var init_OfferingService = __esm({
|
|
|
8705
8827
|
this.config = config;
|
|
8706
8828
|
}
|
|
8707
8829
|
async getOfferings(ids) {
|
|
8708
|
-
const
|
|
8709
|
-
if (
|
|
8830
|
+
const cached2 = this.getMemCache();
|
|
8831
|
+
if (cached2 && !cached2.isStale) return this.filterByIds(cached2.data, ids);
|
|
8710
8832
|
if (!this.cache) {
|
|
8711
8833
|
try {
|
|
8712
8834
|
const stored = await secureStorage.get(OFFERINGS_CACHE_KEY);
|
|
@@ -9245,9 +9367,10 @@ function useSubscription() {
|
|
|
9245
9367
|
|
|
9246
9368
|
// src/PaywalloProvider.tsx
|
|
9247
9369
|
import { useCallback as useCallback19, useEffect as useEffect12, useLayoutEffect, useMemo as useMemo2, useRef as useRef10, useState as useState16 } from "react";
|
|
9248
|
-
import { Animated as Animated3, Dimensions as
|
|
9370
|
+
import { Animated as Animated3, Dimensions as Dimensions5, Easing as Easing2, StyleSheet as StyleSheet3 } from "react-native";
|
|
9249
9371
|
init_PaywalloClient();
|
|
9250
9372
|
init_SecureStorage();
|
|
9373
|
+
init_NativeStorage();
|
|
9251
9374
|
init_campaign();
|
|
9252
9375
|
init_paywall();
|
|
9253
9376
|
init_paywall();
|
|
@@ -9279,12 +9402,13 @@ async function detectOsVersion() {
|
|
|
9279
9402
|
}
|
|
9280
9403
|
|
|
9281
9404
|
// src/hooks/useAppAutoEvents.ts
|
|
9282
|
-
var FIRST_SEEN_KEY = "@paywallo:
|
|
9405
|
+
var FIRST_SEEN_KEY = "@paywallo:firstSeen_v226";
|
|
9283
9406
|
var DEBOUNCE_MS = 1e3;
|
|
9284
9407
|
function useAppAutoEvents(config) {
|
|
9285
9408
|
const { isInitialized, getAppVersion: getAppVersion2, getSessionId, emitLifecycle, storageGet, storageSet, debug } = config;
|
|
9286
9409
|
const didRunRef = useRef7(false);
|
|
9287
9410
|
useEffect11(() => {
|
|
9411
|
+
if (debug) console.log("[Paywallo EVENTS] useEffect fired", { isInitialized, didRunRefCurrent: didRunRef.current });
|
|
9288
9412
|
if (!isInitialized || didRunRef.current) return;
|
|
9289
9413
|
const timer = setTimeout(() => {
|
|
9290
9414
|
if (didRunRef.current) return;
|
|
@@ -9294,17 +9418,23 @@ function useAppAutoEvents(config) {
|
|
|
9294
9418
|
const appVersion = getAppVersion2();
|
|
9295
9419
|
const deviceType = await detectPlatform3();
|
|
9296
9420
|
const osVersion = await detectOsVersion();
|
|
9421
|
+
if (debug) console.log("[Paywallo EVENTS] computed device context", { deviceType, osVersion, appVersion, sessionId, hasSessionId: !!sessionId });
|
|
9297
9422
|
try {
|
|
9423
|
+
if (debug) console.log("[Paywallo EVENTS] checking install \u2014 about to read FIRST_SEEN_KEY");
|
|
9298
9424
|
const firstSeen = await storageGet(FIRST_SEEN_KEY);
|
|
9299
9425
|
if (!firstSeen) {
|
|
9300
9426
|
await emitLifecycle({ type: "install", device_type: deviceType, os_version: osVersion, app_version: appVersion, ...sessionId ? { session_id: sessionId } : {} }, "critical");
|
|
9301
9427
|
await storageSet(FIRST_SEEN_KEY, (/* @__PURE__ */ new Date()).toISOString());
|
|
9428
|
+
if (debug) console.log("[Paywallo EVENTS] install event emitted (first time)");
|
|
9302
9429
|
if (debug) console.log("[Paywallo EVENTS] lifecycle install emitted");
|
|
9430
|
+
} else {
|
|
9431
|
+
if (debug) console.log("[Paywallo EVENTS] install skipped \u2014 firstSeen already exists", { firstSeen });
|
|
9303
9432
|
}
|
|
9304
9433
|
} catch (err) {
|
|
9305
9434
|
if (debug) console.log("[Paywallo EVENTS] lifecycle install check failed", err);
|
|
9306
9435
|
}
|
|
9307
9436
|
try {
|
|
9437
|
+
if (debug) console.log("[Paywallo EVENTS] emitting cold_start");
|
|
9308
9438
|
await emitLifecycle({ type: "cold_start", app_version: appVersion, device_type: deviceType, os_version: osVersion, ...sessionId ? { session_id: sessionId } : {} }, "normal");
|
|
9309
9439
|
if (debug) console.log("[Paywallo EVENTS] lifecycle cold_start emitted");
|
|
9310
9440
|
} catch (err) {
|
|
@@ -9619,9 +9749,9 @@ function subscriptionInfoToSub(s) {
|
|
|
9619
9749
|
}
|
|
9620
9750
|
async function resolveOfflineFromCache(distinctId) {
|
|
9621
9751
|
try {
|
|
9622
|
-
const
|
|
9623
|
-
if (!
|
|
9624
|
-
const sub =
|
|
9752
|
+
const cached2 = await subscriptionCache.get(distinctId);
|
|
9753
|
+
if (!cached2) return false;
|
|
9754
|
+
const sub = cached2.data.subscription;
|
|
9625
9755
|
return isSubscriptionStillActive(
|
|
9626
9756
|
sub ? { status: sub.status, expiresAt: sub.expiresAt ?? null } : null
|
|
9627
9757
|
);
|
|
@@ -9691,8 +9821,8 @@ function useSubscriptionSync() {
|
|
|
9691
9821
|
if (!apiClient || !distinctId) return false;
|
|
9692
9822
|
const storeKitResult = await checkStoreKitActive(PaywalloClient.getConfig()?.debug);
|
|
9693
9823
|
if (storeKitResult !== null) return storeKitResult;
|
|
9694
|
-
const
|
|
9695
|
-
if (
|
|
9824
|
+
const cached2 = cacheRef.current;
|
|
9825
|
+
if (cached2 && cached2.expiresAt > Date.now()) return isActiveCacheEntry(cached2);
|
|
9696
9826
|
const persistedResult = await checkPersistedCache(distinctId, (sub) => setCacheAndState(sub));
|
|
9697
9827
|
if (persistedResult !== null) return persistedResult;
|
|
9698
9828
|
try {
|
|
@@ -9709,8 +9839,8 @@ function useSubscriptionSync() {
|
|
|
9709
9839
|
const apiClient = PaywalloClient.getApiClient();
|
|
9710
9840
|
const distinctId = PaywalloClient.getDistinctId();
|
|
9711
9841
|
if (!apiClient || !distinctId) return null;
|
|
9712
|
-
const
|
|
9713
|
-
if (
|
|
9842
|
+
const cached2 = cacheRef.current;
|
|
9843
|
+
if (cached2 && cached2.expiresAt > Date.now()) return cached2.data;
|
|
9714
9844
|
try {
|
|
9715
9845
|
return await fetchAndCache();
|
|
9716
9846
|
} catch {
|
|
@@ -9726,6 +9856,196 @@ function useSubscriptionSync() {
|
|
|
9726
9856
|
return { subscription, hasActiveSubscription, getSubscription, invalidateCache };
|
|
9727
9857
|
}
|
|
9728
9858
|
|
|
9859
|
+
// src/domains/paywall/SuperwallAutoBridge.ts
|
|
9860
|
+
init_PaywalloClient();
|
|
9861
|
+
|
|
9862
|
+
// src/core/utils/eventId.ts
|
|
9863
|
+
function hashString(input) {
|
|
9864
|
+
let h1 = 3735928559;
|
|
9865
|
+
let h2 = 1103547991;
|
|
9866
|
+
for (let i = 0; i < input.length; i++) {
|
|
9867
|
+
const ch = input.charCodeAt(i);
|
|
9868
|
+
h1 = Math.imul(h1 ^ ch, 2654435769);
|
|
9869
|
+
h2 = Math.imul(h2 ^ ch, 1598716949);
|
|
9870
|
+
}
|
|
9871
|
+
h1 = Math.imul(h1 ^ h1 >>> 16, 73244475);
|
|
9872
|
+
h1 ^= Math.imul(h2 ^ h2 >>> 13, 351452291);
|
|
9873
|
+
h2 = Math.imul(h2 ^ h2 >>> 16, 73244475);
|
|
9874
|
+
h2 ^= Math.imul(h1 ^ h1 >>> 13, 351452291);
|
|
9875
|
+
const toHex = (n) => (n >>> 0).toString(16).padStart(8, "0");
|
|
9876
|
+
return toHex(h1) + toHex(h2);
|
|
9877
|
+
}
|
|
9878
|
+
function buildDeterministicEventId(parts) {
|
|
9879
|
+
const raw = hashString(parts.join("|"));
|
|
9880
|
+
const p1 = raw.slice(0, 8);
|
|
9881
|
+
const p2 = raw.slice(8, 12);
|
|
9882
|
+
const p3 = "4" + raw.slice(13, 16);
|
|
9883
|
+
const p4 = (parseInt(raw[16], 16) & 3 | 8).toString(16) + raw.slice(17, 20);
|
|
9884
|
+
const p5 = raw.padEnd(32, "0").slice(20, 32);
|
|
9885
|
+
return `${p1}-${p2}-${p3}-${p4}-${p5}`;
|
|
9886
|
+
}
|
|
9887
|
+
|
|
9888
|
+
// src/domains/paywall/SuperwallAutoBridge.ts
|
|
9889
|
+
var bridgeStarted = false;
|
|
9890
|
+
var unsubscribe = null;
|
|
9891
|
+
var debugEnabled = false;
|
|
9892
|
+
function log(msg, data) {
|
|
9893
|
+
if (!debugEnabled) return;
|
|
9894
|
+
if (data !== void 0) {
|
|
9895
|
+
console.log(`[Paywallo:SuperwallBridge] ${msg}`, data);
|
|
9896
|
+
} else {
|
|
9897
|
+
console.log(`[Paywallo:SuperwallBridge] ${msg}`);
|
|
9898
|
+
}
|
|
9899
|
+
}
|
|
9900
|
+
function minuteBucket(ts) {
|
|
9901
|
+
return String(Math.floor(ts / 6e4));
|
|
9902
|
+
}
|
|
9903
|
+
function buildEventId(type, identifier, ts) {
|
|
9904
|
+
return buildDeterministicEventId(["sw", type, identifier, minuteBucket(ts)]);
|
|
9905
|
+
}
|
|
9906
|
+
async function trackPaywallEvent(type, identifier, ts, extra) {
|
|
9907
|
+
const _eventId = buildEventId(type, identifier, ts);
|
|
9908
|
+
try {
|
|
9909
|
+
const cleanExtra = {};
|
|
9910
|
+
if (extra) {
|
|
9911
|
+
for (const [k, v] of Object.entries(extra)) if (v !== void 0) cleanExtra[k] = v;
|
|
9912
|
+
}
|
|
9913
|
+
await PaywalloClient.track("paywall", {
|
|
9914
|
+
priority: "critical",
|
|
9915
|
+
properties: {
|
|
9916
|
+
type,
|
|
9917
|
+
paywall_id: identifier,
|
|
9918
|
+
...cleanExtra
|
|
9919
|
+
}
|
|
9920
|
+
});
|
|
9921
|
+
} catch (err) {
|
|
9922
|
+
log("track error", { type, identifier, eventId: _eventId, err: String(err) });
|
|
9923
|
+
}
|
|
9924
|
+
}
|
|
9925
|
+
function mapDismissToCloseReason(resultType) {
|
|
9926
|
+
switch (resultType) {
|
|
9927
|
+
case "purchased":
|
|
9928
|
+
return "purchased";
|
|
9929
|
+
case "restored":
|
|
9930
|
+
return "purchased";
|
|
9931
|
+
// restore counts as a purchase outcome for funnel
|
|
9932
|
+
case "declined":
|
|
9933
|
+
return "dismissed";
|
|
9934
|
+
default:
|
|
9935
|
+
return void 0;
|
|
9936
|
+
}
|
|
9937
|
+
}
|
|
9938
|
+
function buildCallbacks() {
|
|
9939
|
+
return {
|
|
9940
|
+
onPaywallPresent: (info) => {
|
|
9941
|
+
const ts = Date.now();
|
|
9942
|
+
log("onPaywallPresent", { identifier: info.identifier });
|
|
9943
|
+
void trackPaywallEvent("viewed", info.identifier, ts, {
|
|
9944
|
+
placement: info.presentedByEventWithName,
|
|
9945
|
+
variant_id: info.experiment?.variant?.id,
|
|
9946
|
+
campaign_id: info.experiment?.id
|
|
9947
|
+
});
|
|
9948
|
+
},
|
|
9949
|
+
onPaywallDismiss: (info, result) => {
|
|
9950
|
+
const ts = Date.now();
|
|
9951
|
+
log("onPaywallDismiss", { identifier: info.identifier, result: result.type });
|
|
9952
|
+
void trackPaywallEvent("closed", info.identifier, ts, {
|
|
9953
|
+
placement: info.presentedByEventWithName,
|
|
9954
|
+
variant_id: info.experiment?.variant?.id,
|
|
9955
|
+
campaign_id: info.experiment?.id,
|
|
9956
|
+
close_reason: mapDismissToCloseReason(result.type),
|
|
9957
|
+
closed_at: new Date(ts).toISOString()
|
|
9958
|
+
});
|
|
9959
|
+
},
|
|
9960
|
+
onPurchase: (params) => {
|
|
9961
|
+
const ts = Date.now();
|
|
9962
|
+
const safe = params !== null && typeof params === "object" ? params : {};
|
|
9963
|
+
const productId = "productId" in safe && typeof safe.productId === "string" ? safe.productId : "unknown";
|
|
9964
|
+
const identifier = "paywallIdentifier" in safe && typeof safe.paywallIdentifier === "string" ? safe.paywallIdentifier : productId;
|
|
9965
|
+
log("onPurchase", { productId, identifier });
|
|
9966
|
+
void trackPaywallEvent("purchased", identifier, ts, { product_id: productId });
|
|
9967
|
+
},
|
|
9968
|
+
// Global Superwall event listener — used specifically for `transactionComplete`
|
|
9969
|
+
// which is the only event that exposes the full product (currency/price) +
|
|
9970
|
+
// transaction (storeTransactionId) shape needed to create a server-side
|
|
9971
|
+
// `transactions` row. Other events are skipped (paywallOpen/Dismiss already
|
|
9972
|
+
// handled above with their typed callbacks).
|
|
9973
|
+
onSuperwallEvent: (info) => {
|
|
9974
|
+
const ev = info?.event;
|
|
9975
|
+
if (!ev || ev.event !== "transactionComplete") return;
|
|
9976
|
+
const ts = Date.now();
|
|
9977
|
+
const product = ev.product;
|
|
9978
|
+
const transaction = ev.transaction;
|
|
9979
|
+
if (!product) {
|
|
9980
|
+
log("transactionComplete missing product \u2014 skipping transaction track");
|
|
9981
|
+
return;
|
|
9982
|
+
}
|
|
9983
|
+
const productId = product.productIdentifier ?? product.id ?? "unknown";
|
|
9984
|
+
const currency = product.currencyCode ?? "USD";
|
|
9985
|
+
const price = product.price ?? 0;
|
|
9986
|
+
const transactionId = transaction?.storeTransactionId ?? transaction?.originalTransactionIdentifier ?? `${productId}_${String(ts)}`;
|
|
9987
|
+
const isTrial = product.hasFreeTrial === true || (product.trialPeriodPrice ?? 0) > 0;
|
|
9988
|
+
const paywallIdentifier = ev.paywallInfo?.identifier;
|
|
9989
|
+
log("onSuperwallEvent: transactionComplete", { productId, currency, price, transactionId, isTrial });
|
|
9990
|
+
void (async () => {
|
|
9991
|
+
try {
|
|
9992
|
+
await PaywalloClient.track("transaction", {
|
|
9993
|
+
priority: "critical",
|
|
9994
|
+
properties: {
|
|
9995
|
+
type: isTrial ? "trial_started" : "completed",
|
|
9996
|
+
// Server's IngestTranslator looks for `transaction_id`/`product_id`
|
|
9997
|
+
// /`amount`/`currency`/`paywall_id` keys (not `tx_id`). PurchaseHandler
|
|
9998
|
+
// then resolves type=trial/new/renewal based on amount being 0 vs >0.
|
|
9999
|
+
transaction_id: transactionId,
|
|
10000
|
+
product_id: productId,
|
|
10001
|
+
amount: price,
|
|
10002
|
+
currency,
|
|
10003
|
+
...paywallIdentifier ? { paywall_id: paywallIdentifier } : {}
|
|
10004
|
+
}
|
|
10005
|
+
});
|
|
10006
|
+
} catch (err) {
|
|
10007
|
+
log("transactionComplete track error", { err: String(err) });
|
|
10008
|
+
}
|
|
10009
|
+
})();
|
|
10010
|
+
}
|
|
10011
|
+
};
|
|
10012
|
+
}
|
|
10013
|
+
function startSuperwallAutoBridge(debug = false) {
|
|
10014
|
+
debugEnabled = debug;
|
|
10015
|
+
if (bridgeStarted) {
|
|
10016
|
+
log("already started, skipping");
|
|
10017
|
+
return;
|
|
10018
|
+
}
|
|
10019
|
+
void detectAndStart();
|
|
10020
|
+
}
|
|
10021
|
+
async function detectAndStart() {
|
|
10022
|
+
let subscribeFn;
|
|
10023
|
+
try {
|
|
10024
|
+
const mod = await import("expo-superwall");
|
|
10025
|
+
if (!mod || typeof mod.subscribeToSuperwallEvents !== "function") {
|
|
10026
|
+
const internal = await import("expo-superwall/build/src/internal/superwallEventBridge");
|
|
10027
|
+
if (typeof internal.subscribeToSuperwallEvents !== "function") {
|
|
10028
|
+
log("expo-superwall subscribeToSuperwallEvents not found \u2014 bridge inactive");
|
|
10029
|
+
return;
|
|
10030
|
+
}
|
|
10031
|
+
subscribeFn = internal.subscribeToSuperwallEvents;
|
|
10032
|
+
} else {
|
|
10033
|
+
subscribeFn = mod.subscribeToSuperwallEvents;
|
|
10034
|
+
}
|
|
10035
|
+
} catch {
|
|
10036
|
+
log("expo-superwall not installed \u2014 bridge inactive");
|
|
10037
|
+
return;
|
|
10038
|
+
}
|
|
10039
|
+
try {
|
|
10040
|
+
const callbacks = buildCallbacks();
|
|
10041
|
+
unsubscribe = subscribeFn(void 0, () => callbacks);
|
|
10042
|
+
bridgeStarted = true;
|
|
10043
|
+
log("bridge started");
|
|
10044
|
+
} catch (err) {
|
|
10045
|
+
log("subscribe failed", { err: String(err) });
|
|
10046
|
+
}
|
|
10047
|
+
}
|
|
10048
|
+
|
|
9729
10049
|
// src/PaywalloProvider.tsx
|
|
9730
10050
|
init_localization();
|
|
9731
10051
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
@@ -9755,8 +10075,18 @@ function PaywalloProvider({ children, config }) {
|
|
|
9755
10075
|
for (const [k, v] of Object.entries(props)) if (v !== void 0) flat[k] = v;
|
|
9756
10076
|
return PaywalloClient.track("lifecycle", { properties: flat, priority });
|
|
9757
10077
|
},
|
|
9758
|
-
storageGet: (key) =>
|
|
9759
|
-
|
|
10078
|
+
storageGet: async (key) => {
|
|
10079
|
+
if (key === "@paywallo:firstSeen_v226") {
|
|
10080
|
+
return nativeStorage.get(key);
|
|
10081
|
+
}
|
|
10082
|
+
return secureStorageRef.current.get(key);
|
|
10083
|
+
},
|
|
10084
|
+
storageSet: async (key, value) => {
|
|
10085
|
+
if (key === "@paywallo:firstSeen_v226") {
|
|
10086
|
+
return nativeStorage.set(key, value);
|
|
10087
|
+
}
|
|
10088
|
+
return secureStorageRef.current.set(key, value);
|
|
10089
|
+
},
|
|
9760
10090
|
debug: config.debug
|
|
9761
10091
|
});
|
|
9762
10092
|
const triggerRepreload = useCallback19((placement) => {
|
|
@@ -9764,7 +10094,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
9764
10094
|
});
|
|
9765
10095
|
}, []);
|
|
9766
10096
|
const { showingPreloadedWebView, presentPreloadedWebView, resolvePreloadedPaywall, handlePreloadedWebViewReady: baseHandlePreloadedWebViewReady, handlePreloadedClose: baseHandlePreloadedClose, setShowingPreloadedWebView, presentedAtRef } = usePaywallPresenter(preloadedWebView, setPreloadedWebView);
|
|
9767
|
-
const SCREEN_HEIGHT = useMemo2(() =>
|
|
10097
|
+
const SCREEN_HEIGHT = useMemo2(() => Dimensions5.get("window").height, []);
|
|
9768
10098
|
const slideAnim = useRef10(new Animated3.Value(SCREEN_HEIGHT)).current;
|
|
9769
10099
|
const handlePreloadedWebViewReady = useCallback19(() => {
|
|
9770
10100
|
if (PaywalloClient.getConfig()?.debug) {
|
|
@@ -9803,6 +10133,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
9803
10133
|
PaywalloClient.init(configRef.current).then(async () => {
|
|
9804
10134
|
if (!mounted) return;
|
|
9805
10135
|
setDistinctId(PaywalloClient.getDistinctId());
|
|
10136
|
+
startSuperwallAutoBridge(configRef.current.debug);
|
|
9806
10137
|
setIsInitialized(true);
|
|
9807
10138
|
if (!autoPreloadTriggeredRef.current) {
|
|
9808
10139
|
autoPreloadTriggeredRef.current = true;
|