@mysuperwall/react-native 1.1.0 → 1.2.0
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/CHANGELOG.md +6 -0
- package/README.md +16 -0
- package/lib/MySuperwall.d.ts +3 -0
- package/lib/MySuperwall.js +13 -1
- package/lib/services/manifestService.d.ts +1 -0
- package/lib/services/manifestService.js +2 -2
- package/package.json +2 -2
- package/src/MySuperwall.ts +13 -1
- package/src/services/manifestService.ts +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.0 - 2026-10-15
|
|
4
|
+
|
|
5
|
+
- Add setProductData for real localized billing prices and currency.
|
|
6
|
+
- Scope rendered HTML caches by the exact price payload, rejecting late responses from previous price contexts.
|
|
7
|
+
- Keep existing billing and store purchase flows owned by the host application.
|
|
8
|
+
|
|
3
9
|
## 1.1.0
|
|
4
10
|
|
|
5
11
|
- Add compiled JavaScript and TypeScript declarations to npm packages.
|
package/README.md
CHANGED
|
@@ -156,3 +156,19 @@ Programmatic dismissal through the hook clears the modal without starting recove
|
|
|
156
156
|
Manifest and offline event storage are isolated by app/server scope. Unscoped legacy
|
|
157
157
|
caches are ignored; source updates need one successful manifest sync before offline use.
|
|
158
158
|
No store billing is replaced by this SDK.
|
|
159
|
+
|
|
160
|
+
## Localized store prices (1.2.0+)
|
|
161
|
+
|
|
162
|
+
This SDK does not query StoreKit, Google Play Billing or RevenueCat products itself.
|
|
163
|
+
Initialize the existing billing provider and fetch its products first. Build a map
|
|
164
|
+
keyed by the exact store product ID. Each value must contain `displayPrice`,
|
|
165
|
+
`priceString` and `currencyCode` from the store. Supply `subscriptionPeriod` and
|
|
166
|
+
store-derived `pricePerDayText`, `pricePerWeekText`, `pricePerMonthText`,
|
|
167
|
+
`pricePerYearText` where the template uses them. Never convert a USD catalog price
|
|
168
|
+
using device locale or exchange rates. Storefront determines the currency.
|
|
169
|
+
|
|
170
|
+
Call `setProductData` after SDK initialization and before presenting. Await its
|
|
171
|
+
completion (Promise on React Native, callback on native platforms) and refresh it
|
|
172
|
+
when store product prices change. Missing live product data is not proof that
|
|
173
|
+
catalog/default prices are localized. Wait for successful manifest loading on a
|
|
174
|
+
first installation. Existing displayed paywalls are not silently replaced.
|
package/lib/MySuperwall.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export declare class MySuperwall {
|
|
|
23
23
|
country: string;
|
|
24
24
|
appVersion?: string;
|
|
25
25
|
private premium;
|
|
26
|
+
private productData;
|
|
26
27
|
private epoch;
|
|
27
28
|
private presentationSequence;
|
|
28
29
|
private followUps;
|
|
@@ -42,6 +43,8 @@ export declare class MySuperwall {
|
|
|
42
43
|
private resetFlow;
|
|
43
44
|
private manifestOptions;
|
|
44
45
|
setLocale(locale: string): Promise<void>;
|
|
46
|
+
/** Supply localized prices from StoreKit, Play Billing or RevenueCat before presenting. */
|
|
47
|
+
setProductData(products: Record<string, unknown>): Promise<void>;
|
|
45
48
|
setCountry(country: string): void;
|
|
46
49
|
setAppVersion(version: string): void;
|
|
47
50
|
setSubscriptionStatus(premium: boolean): void;
|
package/lib/MySuperwall.js
CHANGED
|
@@ -13,6 +13,7 @@ class MySuperwall {
|
|
|
13
13
|
this.locale = 'en';
|
|
14
14
|
this.country = '';
|
|
15
15
|
this.premium = false;
|
|
16
|
+
this.productData = {};
|
|
16
17
|
this.epoch = 0;
|
|
17
18
|
this.presentationSequence = 0;
|
|
18
19
|
this.followUps = new followUpService_1.FollowUpService();
|
|
@@ -35,6 +36,7 @@ class MySuperwall {
|
|
|
35
36
|
inst.resetFlow();
|
|
36
37
|
inst.userAttributes = {};
|
|
37
38
|
inst.premium = false;
|
|
39
|
+
inst.productData = {};
|
|
38
40
|
inst.appKey = options.appKey;
|
|
39
41
|
inst.baseUrl = options.baseUrl
|
|
40
42
|
? options.baseUrl.endsWith('/')
|
|
@@ -78,7 +80,7 @@ class MySuperwall {
|
|
|
78
80
|
}
|
|
79
81
|
resetFlow() { this.epoch++; this.followUps.reset(); this.activeFlow = undefined; }
|
|
80
82
|
manifestOptions() {
|
|
81
|
-
return { baseUrl: this.baseUrl, appKey: this.appKey, bundleId: this.bundleId, platform: this.platform, lang: this.locale };
|
|
83
|
+
return { baseUrl: this.baseUrl, appKey: this.appKey, bundleId: this.bundleId, platform: this.platform, lang: this.locale, substitutionData: this.productData };
|
|
82
84
|
}
|
|
83
85
|
async setLocale(locale) {
|
|
84
86
|
const normalized = locale.trim().replace(/_/g, '-').toLowerCase();
|
|
@@ -92,6 +94,16 @@ class MySuperwall {
|
|
|
92
94
|
if (epoch === this.epoch)
|
|
93
95
|
await this.manifestService.syncInBackground(this.manifestOptions());
|
|
94
96
|
}
|
|
97
|
+
/** Supply localized prices from StoreKit, Play Billing or RevenueCat before presenting. */
|
|
98
|
+
async setProductData(products) {
|
|
99
|
+
const captured = JSON.parse(JSON.stringify(products));
|
|
100
|
+
if (JSON.stringify(captured) === JSON.stringify(this.productData))
|
|
101
|
+
return;
|
|
102
|
+
this.productData = captured;
|
|
103
|
+
const options = this.manifestOptions();
|
|
104
|
+
this.manifestService.configure(options); // Drops old price HTML and rejects stale responses.
|
|
105
|
+
await this.manifestService.syncInBackground(options);
|
|
106
|
+
}
|
|
95
107
|
setCountry(country) { this.country = country.trim().toUpperCase(); }
|
|
96
108
|
setAppVersion(version) { this.appVersion = version; }
|
|
97
109
|
setSubscriptionStatus(premium) { this.premium = premium; }
|
|
@@ -14,7 +14,7 @@ class ManifestService {
|
|
|
14
14
|
}
|
|
15
15
|
static scopeKey(options) {
|
|
16
16
|
return JSON.stringify([options.baseUrl.replace(/\/+$/, '') + '/', options.appKey || '',
|
|
17
|
-
options.bundleId || '', options.platform || 'ios', options.lang || 'en']);
|
|
17
|
+
options.bundleId || '', options.platform || 'ios', options.lang || 'en', JSON.stringify(options.substitutionData || {})]);
|
|
18
18
|
}
|
|
19
19
|
configure(options) {
|
|
20
20
|
const scope = ManifestService.scopeKey(options);
|
|
@@ -59,7 +59,7 @@ class ManifestService {
|
|
|
59
59
|
const response = await fetch(options.baseUrl.replace(/\/+$/, '') + '/paywall/manifest', {
|
|
60
60
|
method: 'POST', headers, body: JSON.stringify({ platform: options.platform || 'ios',
|
|
61
61
|
appKey: options.appKey, bundleId: options.platform === 'android' ? undefined : options.bundleId,
|
|
62
|
-
packageName: options.platform === 'android' ? options.bundleId : undefined, lang: options.lang || 'en', hash: this.manifest?.hash })
|
|
62
|
+
packageName: options.platform === 'android' ? options.bundleId : undefined, lang: options.lang || 'en', hash: this.manifest?.hash, substitutionData: options.substitutionData || {} })
|
|
63
63
|
});
|
|
64
64
|
if (scope !== this.scope || generation !== this.generation)
|
|
65
65
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mysuperwall/react-native",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "React Native SDK for MySuperWall paywalls, targeting and offline rule evaluation",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"homepage": "https://mysuperwall.com",
|
|
46
46
|
"repository": {
|
|
47
47
|
"type": "git",
|
|
48
|
-
"url": "https://github.com/Unevenn/mysuperwall_react_native.git"
|
|
48
|
+
"url": "git+https://github.com/Unevenn/mysuperwall_react_native.git"
|
|
49
49
|
},
|
|
50
50
|
"publishConfig": {
|
|
51
51
|
"access": "public"
|
package/src/MySuperwall.ts
CHANGED
|
@@ -28,6 +28,7 @@ export class MySuperwall {
|
|
|
28
28
|
public country: string = '';
|
|
29
29
|
public appVersion?: string;
|
|
30
30
|
private premium = false;
|
|
31
|
+
private productData: Record<string, unknown> = {};
|
|
31
32
|
private epoch = 0;
|
|
32
33
|
private presentationSequence = 0;
|
|
33
34
|
private followUps = new FollowUpService();
|
|
@@ -61,6 +62,7 @@ export class MySuperwall {
|
|
|
61
62
|
inst.resetFlow();
|
|
62
63
|
inst.userAttributes = {};
|
|
63
64
|
inst.premium = false;
|
|
65
|
+
inst.productData = {};
|
|
64
66
|
inst.appKey = options.appKey;
|
|
65
67
|
inst.baseUrl = options.baseUrl
|
|
66
68
|
? options.baseUrl.endsWith('/')
|
|
@@ -102,7 +104,7 @@ export class MySuperwall {
|
|
|
102
104
|
|
|
103
105
|
private resetFlow(): void { this.epoch++; this.followUps.reset(); this.activeFlow = undefined; }
|
|
104
106
|
private manifestOptions() {
|
|
105
|
-
return { baseUrl: this.baseUrl, appKey: this.appKey, bundleId: this.bundleId, platform: this.platform, lang: this.locale };
|
|
107
|
+
return { baseUrl: this.baseUrl, appKey: this.appKey, bundleId: this.bundleId, platform: this.platform, lang: this.locale, substitutionData: this.productData };
|
|
106
108
|
}
|
|
107
109
|
public async setLocale(locale: string): Promise<void> {
|
|
108
110
|
const normalized = locale.trim().replace(/_/g, '-').toLowerCase();
|
|
@@ -113,6 +115,16 @@ export class MySuperwall {
|
|
|
113
115
|
await this.manifestService.loadFromDisk();
|
|
114
116
|
if (epoch === this.epoch) await this.manifestService.syncInBackground(this.manifestOptions());
|
|
115
117
|
}
|
|
118
|
+
/** Supply localized prices from StoreKit, Play Billing or RevenueCat before presenting. */
|
|
119
|
+
public async setProductData(products: Record<string, unknown>): Promise<void> {
|
|
120
|
+
const captured = JSON.parse(JSON.stringify(products)) as Record<string, unknown>;
|
|
121
|
+
if (JSON.stringify(captured) === JSON.stringify(this.productData)) return;
|
|
122
|
+
this.productData = captured;
|
|
123
|
+
const options = this.manifestOptions();
|
|
124
|
+
this.manifestService.configure(options); // Drops old price HTML and rejects stale responses.
|
|
125
|
+
await this.manifestService.syncInBackground(options);
|
|
126
|
+
}
|
|
127
|
+
|
|
116
128
|
public setCountry(country: string): void { this.country = country.trim().toUpperCase(); }
|
|
117
129
|
public setAppVersion(version: string): void { this.appVersion = version; }
|
|
118
130
|
public setSubscriptionStatus(premium: boolean): void { this.premium = premium; }
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PaywallManifest } from '../models/manifest';
|
|
2
2
|
|
|
3
3
|
export interface ManifestScope {
|
|
4
|
-
baseUrl: string; appKey?: string; bundleId?: string; platform?: string; lang?: string;
|
|
4
|
+
baseUrl: string; appKey?: string; bundleId?: string; platform?: string; lang?: string; substitutionData?: Record<string, unknown>;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export class ManifestService {
|
|
@@ -15,7 +15,7 @@ export class ManifestService {
|
|
|
15
15
|
}
|
|
16
16
|
static scopeKey(options: ManifestScope): string {
|
|
17
17
|
return JSON.stringify([options.baseUrl.replace(/\/+$/, '') + '/', options.appKey || '',
|
|
18
|
-
options.bundleId || '', options.platform || 'ios', options.lang || 'en']);
|
|
18
|
+
options.bundleId || '', options.platform || 'ios', options.lang || 'en', JSON.stringify(options.substitutionData || {})]);
|
|
19
19
|
}
|
|
20
20
|
configure(options: ManifestScope): void {
|
|
21
21
|
const scope = ManifestService.scopeKey(options);
|
|
@@ -48,7 +48,7 @@ export class ManifestService {
|
|
|
48
48
|
const response = await fetch(options.baseUrl.replace(/\/+$/, '') + '/paywall/manifest', {
|
|
49
49
|
method: 'POST', headers, body: JSON.stringify({ platform: options.platform || 'ios',
|
|
50
50
|
appKey: options.appKey, bundleId: options.platform === 'android' ? undefined : options.bundleId,
|
|
51
|
-
packageName: options.platform === 'android' ? options.bundleId : undefined, lang: options.lang || 'en', hash: this.manifest?.hash })
|
|
51
|
+
packageName: options.platform === 'android' ? options.bundleId : undefined, lang: options.lang || 'en', hash: this.manifest?.hash, substitutionData: options.substitutionData || {} })
|
|
52
52
|
});
|
|
53
53
|
if (scope !== this.scope || generation !== this.generation) return null;
|
|
54
54
|
if (response.status === 304) return this.manifest;
|