@revenuecat/purchases-js 0.0.4 β†’ 0.0.5

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 CHANGED
@@ -1,7 +1,3 @@
1
- # 0.0.4
2
-
3
- - Fix bug in 0.0.3 that didn't include the dist/ folder in the NPM package
4
-
5
1
  # 0.0.3
6
2
 
7
3
  - Add prettier by @francocorreasosa in #13
package/README.md CHANGED
@@ -1,6 +1,202 @@
1
- # RCBilling JS
1
+ <h3 align="center">😻 In-App Subscriptions Made Easy 😻</h3>
2
+ <h4 align="center">πŸ•ΈοΈ For the web πŸ•ΈοΈ</h4>
2
3
 
3
- JS SDK for RC Billing.
4
+ RevenueCat is a powerful, reliable, and free to use in-app purchase server with cross-platform support.
5
+ This repository includes all you need to manage your subscriptions on your website or web app using RevenueCat.
6
+
7
+ Sign up to [get started for free](https://app.revenuecat.com/signup).
8
+
9
+ # Prerequisites
10
+
11
+ Login @ [app.revenuecat.com](https://app.revenuecat.com)
12
+
13
+ - Create a Project (if you haven't already)
14
+
15
+ ### ======> Only while testing <======
16
+
17
+ - Add the private project id (a.k.a. app_id) to the following feature flags
18
+ - RCBILLING
19
+ - GENERATE_V2_SUBSCRIPTION_MODELS_FOR_RCBILLING
20
+ - GENERATE_V2_SUBSCRIPTION_MODELS
21
+
22
+ ### ======> Only while testing <======
23
+
24
+ - Add a new RCBilling app
25
+ - Get the `RC_PUBLISHABLE_API_KEY` (you will need it soon)
26
+ - Connect your Stripe account (More payment gateways are coming soon)
27
+ - Create some products for the RCBilling App
28
+ - Create an offering and add packages with RCBilling products
29
+ - Create the entitlements you need in your app and link them to the RCBilling products
30
+
31
+ # Installation
32
+
33
+ ### ======> Only during testing <======
34
+
35
+ - Get a token to download the sdk from our private npm registry
36
+ - Set the environment variable `NODE_AUTH_TOKEN`
37
+
38
+ ```bash
39
+ export NODE_AUTH_TOKEN="the token you got from the npm registry"
40
+ ```
41
+
42
+ ### ======> Only during testing <======
43
+
44
+ - Add the library to your project's dependencies
45
+
46
+ ```
47
+ npm add --save @revenuecat/purchases-js
48
+ ```
49
+
50
+ # Usage
51
+
52
+ ## Download the current Offerings
53
+
54
+ By downloading the current Offerings you can easily build a Paywall page using the embedded Packages and their
55
+ associated `rcBillingProduct` and price.
56
+
57
+ ```typescript
58
+ const purchases = new Purchases("your RC_PUBLISHABLE_API_KEY");
59
+
60
+ purchases.listOfferings().then((offeringsPage) => {
61
+ offeringsPage.offerings.forEach((offering) => {
62
+ console.log(offering);
63
+ });
64
+ });
65
+ ```
66
+
67
+ This should print the current offerings you have set up in your RC Account.
68
+
69
+ Please check out [this file](https://github.com/RevenueCat/purchases-js/blob/main/src/entities/offerings.ts) for the
70
+ Offering's data structure
71
+
72
+ ## Check User Entitlements
73
+
74
+ You can check the entitlements granted to your users throughout all the platforms, now
75
+ also on your website!
76
+
77
+ ```typescript
78
+ const appUserId = "the unique id of the user in your systems";
79
+ const entitlementId = "the entitlementId you set up in RC";
80
+
81
+ const purchases = new Purchases("your RC_PUBLISHABLE_API_KEY");
82
+
83
+ purchases.isEntitledTo(appUserId, entitlementId).then((isEntitled) => {
84
+ if (isEntitled == true) {
85
+ console.log(`User ${appUserID} is entitled to ${entitlementId}`);
86
+ } else {
87
+ console.log(`User ${appUserID} is not entitled to ${entitlementId}`);
88
+ }
89
+ });
90
+ ```
91
+
92
+ As example, you can build a cool React component with it:
93
+
94
+ ```tsx
95
+ const WithEntitlement = ({ appUserId, entitlementId, children }) => {
96
+ const [isEntitled, setIsEntitled] = useState<boolean | null>(null);
97
+
98
+ useEffect(() => {
99
+ const purchases = new Purchases("your RC_PUBLISHABLE_API_KEY");
100
+ purchases.isEntitledTo(appUserId, entitlementId).then((isEntitled) => {
101
+ setIsEntitled(isEntitled);
102
+ });
103
+ }, [appUserId, entitlementId]);
104
+
105
+ if (isEntitled === null) {
106
+ return <>"loading..."</>;
107
+ }
108
+
109
+ if (isEntitled === true) {
110
+ return <>{children}</>;
111
+ }
112
+
113
+ return <>You are not entitled!</>;
114
+ };
115
+ ```
116
+
117
+ And then use it in your app:
118
+
119
+ ```tsx
120
+ const App = () => (
121
+ <>
122
+ <WithEntitlement appUserId={"user12345"} entitlementId={"functionality5"}>
123
+ <Functionality5 />
124
+ </WithEntitlement>
125
+ </>
126
+ );
127
+ ```
128
+
129
+ ## Subscribe a User to an entitlement and allow payment with Stripe
130
+
131
+ RCBilling allows you to use your payment gateway for payments.
132
+ In this example we will show Stripe, more will be supported soon!
133
+
134
+ ### Context
135
+
136
+ You built your paywall, and your user just clicked on the offer they want to subscribe to.
137
+
138
+ ### 1. Call the .subscribe method to initialise the process
139
+
140
+ ```tsx
141
+ const purchases = new Purchases("your RC_PUBLISHABLE_API_KEY");
142
+ // You can retrieve this from the offerings you downloaded, as example:
143
+ // offeringsPage.offerings[0].packages[0].rcBillingProduct.identifier
144
+ const rcBillingProductIndentifier =
145
+ "the Product Identifier the user wants to buy";
146
+ const appUserId =
147
+ "the unique id of the user that wants to subscribe to your product";
148
+
149
+ purchase.subscribe(appUserId, rcBillingProductIndentifier).then((response) => {
150
+ if (response.nextAction === "collect_payment_info") {
151
+ // Use the clientSecret to show the StripeElements payment components
152
+ showStripeElements({
153
+ setupIntentClientSecret: response.data.clientSecret,
154
+ });
155
+ } else {
156
+ // No need to collect payment info, just wait for the entitlement to be granted
157
+ }
158
+ });
159
+ ```
160
+
161
+ ### 2. [If nextAction === 'collect_payment_info'] Show the Stripe Elements to collect payment
162
+
163
+ ```tsx
164
+ // Set up stripe as shown in their docs
165
+ const stripePromise = loadStripe(
166
+ import.meta.env.VITE_RC_STRIPE_PK_KEY as string,
167
+ { stripeAccount: import.meta.env.VITE_RC_STRIPE_ACCOUNT_ID as string },
168
+ );
169
+
170
+ // Use the clientSecret obtained in the step 1. Call the .subscribe method to initialise the process
171
+ const PaymentForm = ({ clientSecret }) => {
172
+ const handleSubmit = async (e: SyntheticEvent) => {
173
+ e.preventDefault();
174
+ stripe
175
+ .confirmSetup({
176
+ elements,
177
+ clientSecret,
178
+ confirmParams: {
179
+ return_url: `${window.location.origin}/success`,
180
+ },
181
+ redirect: "if_required",
182
+ })
183
+ .then((response) => {
184
+ // All is done you can now wait for the entitlement to be granted.
185
+ });
186
+ };
187
+
188
+ return (
189
+ <form id="payment-form" onSubmit={handleSubmit}>
190
+ <PaymentElement id="payment-element" options={paymentElementOptions} />
191
+ </form>
192
+ );
193
+ };
194
+ ```
195
+
196
+ ### 3. Wait for the entitlement to be granted
197
+
198
+ You can now loop and use the `.isEntitledTo` while Stripe communicates with our servers to grant the entitlement.
199
+ As soon as the entitlement is given, your user's payment went through!
4
200
 
5
201
  # Development
6
202
 
@@ -15,10 +211,11 @@ npm install
15
211
  npm run build:dev
16
212
  ```
17
213
 
18
- Then in your local project you can do:
214
+ To avoid publishing the package you can set it up as a local dependency.
215
+ In your testing project install the library as.
19
216
 
20
217
  ```bash
21
- npm i ../path/to/rcbilling-js
218
+ npm i /path/to/rcbilling-js
22
219
  ```
23
220
 
24
221
  ## Running tests
package/dist/main.d.ts CHANGED
@@ -12,5 +12,7 @@ export declare class Purchases {
12
12
  private toOfferingsPage;
13
13
  listOfferings(): Promise<OfferingsPage>;
14
14
  isEntitledTo(appUserId: string, entitlementIdentifier: string): Promise<boolean>;
15
+ waitForEntitlement(appUserId: string, entitlementIdentifier: string, maxAttempts?: number): Promise<boolean>;
15
16
  subscribe(appUserId: string, productId: string, environment?: "sandbox" | "production"): Promise<SubscribeResponse>;
17
+ getPackage(packageIdentifier: string): Promise<Package | null>;
16
18
  }
@@ -1,42 +1,42 @@
1
- var f = Object.defineProperty;
2
- var P = (e, t, n) => t in e ? f(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
3
- var s = (e, t, n) => (P(e, typeof t != "symbol" ? t + "" : t, n), n);
4
- var l = (e, t, n) => new Promise((o, c) => {
5
- var _ = (r) => {
1
+ var d = Object.defineProperty;
2
+ var g = (e, t, n) => t in e ? d(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
3
+ var l = (e, t, n) => (g(e, typeof t != "symbol" ? t + "" : t, n), n);
4
+ var _ = (e, t, n) => new Promise((i, c) => {
5
+ var s = (o) => {
6
6
  try {
7
- a(n.next(r));
7
+ a(n.next(o));
8
8
  } catch (u) {
9
9
  c(u);
10
10
  }
11
- }, p = (r) => {
11
+ }, p = (o) => {
12
12
  try {
13
- a(n.throw(r));
13
+ a(n.throw(o));
14
14
  } catch (u) {
15
15
  c(u);
16
16
  }
17
- }, a = (r) => r.done ? o(r.value) : Promise.resolve(r.value).then(_, p);
17
+ }, a = (o) => o.done ? i(o.value) : Promise.resolve(o.value).then(s, p);
18
18
  a((n = n.apply(e, t)).next());
19
19
  });
20
- const m = (e) => ({
20
+ const P = (e) => ({
21
21
  amount: e.amount,
22
22
  currency: e.currency
23
- }), A = (e) => ({
23
+ }), m = (e) => ({
24
24
  id: e.id,
25
25
  identifier: e.identifier,
26
26
  displayName: e.display_name,
27
- currentPrice: e.current_price ? m(e.current_price) : null,
27
+ currentPrice: e.current_price ? P(e.current_price) : null,
28
28
  normalPeriodDuration: e.normal_period_duration
29
- }), g = (e) => ({
29
+ }), A = (e) => ({
30
30
  id: e.id,
31
31
  identifier: e.identifier,
32
32
  displayName: e.display_name,
33
- rcBillingProduct: e.rc_billing_product ? A(e.rc_billing_product) : null
34
- }), y = (e) => ({
33
+ rcBillingProduct: e.rc_billing_product ? m(e.rc_billing_product) : null
34
+ }), h = (e) => ({
35
35
  id: e.id,
36
36
  identifier: e.identifier,
37
37
  displayName: e.display_name,
38
- packages: e.packages.map(g)
39
- }), b = (e) => {
38
+ packages: e.packages.map(A)
39
+ }), y = (e) => {
40
40
  var t, n;
41
41
  return {
42
42
  nextAction: e.next_action,
@@ -44,22 +44,22 @@ const m = (e) => ({
44
44
  clientSecret: (n = (t = e.data) == null ? void 0 : t.client_secret) != null ? n : void 0
45
45
  }
46
46
  };
47
- }, i = class i {
47
+ }, r = class r {
48
48
  constructor(t) {
49
- s(this, "_API_KEY", null);
50
- s(this, "_APP_USER_ID", null);
51
- s(this, "toOfferingsPage", (t) => ({
52
- offerings: t.offerings.map(y),
49
+ l(this, "_API_KEY", null);
50
+ l(this, "_APP_USER_ID", null);
51
+ l(this, "toOfferingsPage", (t) => ({
52
+ offerings: t.offerings.map(h),
53
53
  priceByPackageId: t.prices_by_package_id
54
54
  }));
55
- this._API_KEY = t, i._RC_ENDPOINT === void 0 && console.error(
55
+ this._API_KEY = t, r._RC_ENDPOINT === void 0 && console.error(
56
56
  "Project was build without some of the environment variables set"
57
57
  );
58
58
  }
59
59
  listOfferings() {
60
- return l(this, null, function* () {
60
+ return _(this, null, function* () {
61
61
  const n = yield (yield fetch(
62
- `${i._RC_ENDPOINT}/${i._BASE_PATH}/offerings`,
62
+ `${r._RC_ENDPOINT}/${r._BASE_PATH}/offerings`,
63
63
  {
64
64
  headers: {
65
65
  Authorization: `Bearer ${this._API_KEY}`,
@@ -72,9 +72,9 @@ const m = (e) => ({
72
72
  });
73
73
  }
74
74
  isEntitledTo(t, n) {
75
- return l(this, null, function* () {
76
- const o = yield fetch(
77
- `${i._RC_ENDPOINT}/${i._BASE_PATH}/entitlements/${t}`,
75
+ return _(this, null, function* () {
76
+ const i = yield fetch(
77
+ `${r._RC_ENDPOINT}/${r._BASE_PATH}/entitlements/${t}`,
78
78
  {
79
79
  headers: {
80
80
  Authorization: `Bearer ${this._API_KEY}`,
@@ -83,15 +83,30 @@ const m = (e) => ({
83
83
  }
84
84
  }
85
85
  );
86
- return o.status === 404 ? !1 : (yield o.json()).entitlements.map(
86
+ return i.status === 404 ? !1 : (yield i.json()).entitlements.map(
87
87
  (a) => a.lookup_key
88
88
  ).includes(n);
89
89
  });
90
90
  }
91
- subscribe(t, n, o = "production") {
92
- return l(this, null, function* () {
93
- const c = o === "sandbox", p = yield (yield fetch(
94
- `${i._RC_ENDPOINT}/${i._BASE_PATH}/subscribe`,
91
+ waitForEntitlement(t, n, i = 10) {
92
+ return new Promise((s, p) => {
93
+ const a = (o = 1) => this.isEntitledTo(t, n).then((u) => {
94
+ if (o > i)
95
+ return s(!1);
96
+ if (u)
97
+ return s(!0);
98
+ setTimeout(
99
+ () => a(o + 1),
100
+ 1e3
101
+ );
102
+ }).catch(p);
103
+ a();
104
+ });
105
+ }
106
+ subscribe(t, n, i = "production") {
107
+ return _(this, null, function* () {
108
+ const c = i === "sandbox", p = yield (yield fetch(
109
+ `${r._RC_ENDPOINT}/${r._BASE_PATH}/subscribe`,
95
110
  {
96
111
  method: "POST",
97
112
  headers: {
@@ -106,12 +121,24 @@ const m = (e) => ({
106
121
  })
107
122
  }
108
123
  )).json();
109
- return b(p);
124
+ return y(p);
125
+ });
126
+ }
127
+ getPackage(t) {
128
+ return _(this, null, function* () {
129
+ const n = yield this.listOfferings(), i = [];
130
+ n.offerings.forEach(
131
+ (s) => i.push(...s.packages)
132
+ );
133
+ const c = i.filter(
134
+ (s) => s.identifier === t
135
+ );
136
+ return c.length === 0 ? null : c[0];
110
137
  });
111
138
  }
112
139
  };
113
- s(i, "_RC_ENDPOINT", "https://api.revenuecat.com"), s(i, "_BASE_PATH", "rcbilling/v1");
114
- let d = i;
140
+ l(r, "_RC_ENDPOINT", "https://api.revenuecat.com"), l(r, "_BASE_PATH", "rcbilling/v1");
141
+ let f = r;
115
142
  export {
116
- d as Purchases
143
+ f as Purchases
117
144
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@revenuecat/purchases-js",
3
3
  "private": false,
4
- "version": "0.0.4",
4
+ "version": "0.0.5",
5
5
  "type": "module",
6
6
  "types": "dist/main.d.ts",
7
7
  "main": "dist/purchases-js.js",
Binary file