@revenuecat/purchases-js 0.0.4 β†’ 0.0.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/README.md CHANGED
@@ -1,6 +1,221 @@
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 use the `.waitForEntitlement` method.
199
+
200
+ ```tsx
201
+ const appUserId = "the unique id of the user in your systems";
202
+ const entitlementId = "the entitlementId you set up in RC";
203
+
204
+ const purchases = new Purchases("your RC_PUBLISHABLE_API_KEY");
205
+ const numberOfAttempts = 10;
206
+
207
+ purchases
208
+ .waitForEntitlement(appUserId, entitlementId, numberOfAttempts)
209
+ .then((isEntitled) => {
210
+ if (isEntitled == true) {
211
+ console.log(`User ${appUserID} is entitled to ${entitlementId}`);
212
+ } else {
213
+ console.log(
214
+ `User ${appUserID} is not entitled to ${entitlementId}, even after ${numberOfAttempts} attempts`,
215
+ );
216
+ }
217
+ });
218
+ ```
4
219
 
5
220
  # Development
6
221
 
@@ -15,10 +230,11 @@ npm install
15
230
  npm run build:dev
16
231
  ```
17
232
 
18
- Then in your local project you can do:
233
+ To avoid publishing the package you can set it up as a local dependency.
234
+ In your testing project install the library as.
19
235
 
20
236
  ```bash
21
- npm i ../path/to/rcbilling-js
237
+ npm i /path/to/rcbilling-js
22
238
  ```
23
239
 
24
240
  ## Running tests
@@ -0,0 +1,62 @@
1
+ export declare type Offering = Offering_2;
2
+
3
+ declare interface Offering_2 {
4
+ id: string;
5
+ identifier: string;
6
+ displayName: string;
7
+ packages: Package_2[];
8
+ }
9
+
10
+ export declare type OfferingsPage = OfferingsPage_2;
11
+
12
+ declare interface OfferingsPage_2 {
13
+ offerings: Offering_2[];
14
+ priceByPackageId: {
15
+ [packageId: string]: number;
16
+ };
17
+ }
18
+
19
+ export declare type Package = Package_2;
20
+
21
+ declare interface Package_2 {
22
+ id: string;
23
+ identifier: string;
24
+ displayName: string;
25
+ rcBillingProduct: Product | null;
26
+ }
27
+
28
+ declare interface Price {
29
+ amount: number;
30
+ currency: string;
31
+ }
32
+
33
+ declare interface Product {
34
+ id: string;
35
+ displayName: string;
36
+ identifier: string;
37
+ currentPrice: Price | null;
38
+ normalPeriodDuration: string | null;
39
+ }
40
+
41
+ export declare class Purchases {
42
+ _API_KEY: string | null;
43
+ _APP_USER_ID: string | null;
44
+ private static readonly _RC_ENDPOINT;
45
+ private static readonly _BASE_PATH;
46
+ constructor(apiKey: string);
47
+ private toOfferingsPage;
48
+ listOfferings(): Promise<OfferingsPage>;
49
+ isEntitledTo(appUserId: string, entitlementIdentifier: string): Promise<boolean>;
50
+ waitForEntitlement(appUserId: string, entitlementIdentifier: string, maxAttempts?: number): Promise<boolean>;
51
+ subscribe(appUserId: string, productId: string, email: string, environment?: "sandbox" | "production"): Promise<SubscribeResponse>;
52
+ getPackage(packageIdentifier: string): Promise<Package | null>;
53
+ }
54
+
55
+ declare interface SubscribeResponse {
56
+ nextAction: string;
57
+ data: {
58
+ clientSecret?: string;
59
+ };
60
+ }
61
+
62
+ export { }
@@ -0,0 +1,156 @@
1
+ var U = Object.defineProperty;
2
+ var L = (E, T, _) => T in E ? U(E, T, { enumerable: !0, configurable: !0, writable: !0, value: _ }) : E[T] = _;
3
+ var A = (E, T, _) => (L(E, typeof T != "symbol" ? T + "" : T, _), _);
4
+ const l = (E) => ({
5
+ amount: E.amount,
6
+ currency: E.currency
7
+ }), p = (E) => ({
8
+ id: E.id,
9
+ identifier: E.identifier,
10
+ displayName: E.display_name,
11
+ currentPrice: E.current_price ? l(E.current_price) : null,
12
+ normalPeriodDuration: E.normal_period_duration
13
+ }), f = (E) => ({
14
+ id: E.id,
15
+ identifier: E.identifier,
16
+ displayName: E.display_name,
17
+ rcBillingProduct: E.rc_billing_product ? p(E.rc_billing_product) : null
18
+ }), M = (E) => ({
19
+ id: E.id,
20
+ identifier: E.identifier,
21
+ displayName: E.display_name,
22
+ packages: E.packages.map(f)
23
+ }), F = (E) => {
24
+ var T;
25
+ return {
26
+ nextAction: E.next_action,
27
+ data: {
28
+ clientSecret: ((T = E.data) == null ? void 0 : T.client_secret) ?? void 0
29
+ }
30
+ };
31
+ };
32
+ var i;
33
+ (function(E) {
34
+ E[E.CONTINUE = 100] = "CONTINUE", E[E.SWITCHING_PROTOCOLS = 101] = "SWITCHING_PROTOCOLS", E[E.PROCESSING = 102] = "PROCESSING", E[E.EARLY_HINTS = 103] = "EARLY_HINTS", E[E.OK = 200] = "OK", E[E.CREATED = 201] = "CREATED", E[E.ACCEPTED = 202] = "ACCEPTED", E[E.NON_AUTHORITATIVE_INFORMATION = 203] = "NON_AUTHORITATIVE_INFORMATION", E[E.NO_CONTENT = 204] = "NO_CONTENT", E[E.RESET_CONTENT = 205] = "RESET_CONTENT", E[E.PARTIAL_CONTENT = 206] = "PARTIAL_CONTENT", E[E.MULTI_STATUS = 207] = "MULTI_STATUS", E[E.MULTIPLE_CHOICES = 300] = "MULTIPLE_CHOICES", E[E.MOVED_PERMANENTLY = 301] = "MOVED_PERMANENTLY", E[E.MOVED_TEMPORARILY = 302] = "MOVED_TEMPORARILY", E[E.SEE_OTHER = 303] = "SEE_OTHER", E[E.NOT_MODIFIED = 304] = "NOT_MODIFIED", E[E.USE_PROXY = 305] = "USE_PROXY", E[E.TEMPORARY_REDIRECT = 307] = "TEMPORARY_REDIRECT", E[E.PERMANENT_REDIRECT = 308] = "PERMANENT_REDIRECT", E[E.BAD_REQUEST = 400] = "BAD_REQUEST", E[E.UNAUTHORIZED = 401] = "UNAUTHORIZED", E[E.PAYMENT_REQUIRED = 402] = "PAYMENT_REQUIRED", E[E.FORBIDDEN = 403] = "FORBIDDEN", E[E.NOT_FOUND = 404] = "NOT_FOUND", E[E.METHOD_NOT_ALLOWED = 405] = "METHOD_NOT_ALLOWED", E[E.NOT_ACCEPTABLE = 406] = "NOT_ACCEPTABLE", E[E.PROXY_AUTHENTICATION_REQUIRED = 407] = "PROXY_AUTHENTICATION_REQUIRED", E[E.REQUEST_TIMEOUT = 408] = "REQUEST_TIMEOUT", E[E.CONFLICT = 409] = "CONFLICT", E[E.GONE = 410] = "GONE", E[E.LENGTH_REQUIRED = 411] = "LENGTH_REQUIRED", E[E.PRECONDITION_FAILED = 412] = "PRECONDITION_FAILED", E[E.REQUEST_TOO_LONG = 413] = "REQUEST_TOO_LONG", E[E.REQUEST_URI_TOO_LONG = 414] = "REQUEST_URI_TOO_LONG", E[E.UNSUPPORTED_MEDIA_TYPE = 415] = "UNSUPPORTED_MEDIA_TYPE", E[E.REQUESTED_RANGE_NOT_SATISFIABLE = 416] = "REQUESTED_RANGE_NOT_SATISFIABLE", E[E.EXPECTATION_FAILED = 417] = "EXPECTATION_FAILED", E[E.IM_A_TEAPOT = 418] = "IM_A_TEAPOT", E[E.INSUFFICIENT_SPACE_ON_RESOURCE = 419] = "INSUFFICIENT_SPACE_ON_RESOURCE", E[E.METHOD_FAILURE = 420] = "METHOD_FAILURE", E[E.MISDIRECTED_REQUEST = 421] = "MISDIRECTED_REQUEST", E[E.UNPROCESSABLE_ENTITY = 422] = "UNPROCESSABLE_ENTITY", E[E.LOCKED = 423] = "LOCKED", E[E.FAILED_DEPENDENCY = 424] = "FAILED_DEPENDENCY", E[E.UPGRADE_REQUIRED = 426] = "UPGRADE_REQUIRED", E[E.PRECONDITION_REQUIRED = 428] = "PRECONDITION_REQUIRED", E[E.TOO_MANY_REQUESTS = 429] = "TOO_MANY_REQUESTS", E[E.REQUEST_HEADER_FIELDS_TOO_LARGE = 431] = "REQUEST_HEADER_FIELDS_TOO_LARGE", E[E.UNAVAILABLE_FOR_LEGAL_REASONS = 451] = "UNAVAILABLE_FOR_LEGAL_REASONS", E[E.INTERNAL_SERVER_ERROR = 500] = "INTERNAL_SERVER_ERROR", E[E.NOT_IMPLEMENTED = 501] = "NOT_IMPLEMENTED", E[E.BAD_GATEWAY = 502] = "BAD_GATEWAY", E[E.SERVICE_UNAVAILABLE = 503] = "SERVICE_UNAVAILABLE", E[E.GATEWAY_TIMEOUT = 504] = "GATEWAY_TIMEOUT", E[E.HTTP_VERSION_NOT_SUPPORTED = 505] = "HTTP_VERSION_NOT_SUPPORTED", E[E.INSUFFICIENT_STORAGE = 507] = "INSUFFICIENT_STORAGE", E[E.NETWORK_AUTHENTICATION_REQUIRED = 511] = "NETWORK_AUTHENTICATION_REQUIRED";
35
+ })(i || (i = {}));
36
+ class c extends Error {
37
+ constructor(T, _) {
38
+ super(_), this.statusCode = T;
39
+ }
40
+ }
41
+ class Y extends c {
42
+ constructor() {
43
+ super(i.INTERNAL_SERVER_ERROR, "An unknown error occurred.");
44
+ }
45
+ }
46
+ class H extends c {
47
+ }
48
+ class Q extends c {
49
+ }
50
+ class g extends c {
51
+ }
52
+ class h extends c {
53
+ }
54
+ const r = class r {
55
+ constructor(T) {
56
+ A(this, "_API_KEY", null);
57
+ A(this, "_APP_USER_ID", null);
58
+ A(this, "toOfferingsPage", (T) => ({
59
+ offerings: T.offerings.map(M),
60
+ priceByPackageId: T.prices_by_package_id
61
+ }));
62
+ this._API_KEY = T, r._RC_ENDPOINT === void 0 && console.error(
63
+ "Project was build without some of the environment variables set"
64
+ );
65
+ }
66
+ async listOfferings() {
67
+ const _ = await (await fetch(
68
+ `${r._RC_ENDPOINT}/${r._BASE_PATH}/offerings`,
69
+ {
70
+ headers: {
71
+ Authorization: `Bearer ${this._API_KEY}`,
72
+ "Content-Type": "application/json",
73
+ Accept: "application/json"
74
+ }
75
+ }
76
+ )).json();
77
+ return this.toOfferingsPage(_);
78
+ }
79
+ async isEntitledTo(T, _) {
80
+ const R = await fetch(
81
+ `${r._RC_ENDPOINT}/${r._BASE_PATH}/entitlements/${T}`,
82
+ {
83
+ headers: {
84
+ Authorization: `Bearer ${this._API_KEY}`,
85
+ "Content-Type": "application/json",
86
+ Accept: "application/json"
87
+ }
88
+ }
89
+ );
90
+ return R.status === 404 ? !1 : (await R.json()).entitlements.map(
91
+ (I) => I.lookup_key
92
+ ).includes(_);
93
+ }
94
+ waitForEntitlement(T, _, R = 10) {
95
+ return new Promise((O, n) => {
96
+ const I = (D = 1) => this.isEntitledTo(T, _).then((P) => {
97
+ if (D > R)
98
+ return O(!1);
99
+ if (P)
100
+ return O(!0);
101
+ setTimeout(
102
+ () => I(D + 1),
103
+ 1e3
104
+ );
105
+ }).catch(n);
106
+ I();
107
+ });
108
+ }
109
+ async subscribe(T, _, R, N = "production") {
110
+ const O = N === "sandbox", n = await fetch(
111
+ `${r._RC_ENDPOINT}/${r._BASE_PATH}/subscribe`,
112
+ {
113
+ method: "POST",
114
+ headers: {
115
+ Authorization: `Bearer ${this._API_KEY}`,
116
+ "Content-Type": "application/json",
117
+ Accept: "application/json"
118
+ },
119
+ body: JSON.stringify({
120
+ app_user_id: T,
121
+ product_id: _,
122
+ is_sandbox: O,
123
+ email: R
124
+ })
125
+ }
126
+ );
127
+ if (n.status === i.BAD_REQUEST)
128
+ throw new H(n.status);
129
+ if (n.status === i.TOO_MANY_REQUESTS)
130
+ throw new h(n.status);
131
+ if (n.status === i.CONFLICT)
132
+ throw new Q(n.status);
133
+ if (n.status === i.INTERNAL_SERVER_ERROR)
134
+ throw new g(n.status);
135
+ if (n.status === i.OK || n.status === i.CREATED) {
136
+ const I = await n.json();
137
+ return F(I);
138
+ }
139
+ throw new Y();
140
+ }
141
+ async getPackage(T) {
142
+ const _ = await this.listOfferings(), R = [];
143
+ _.offerings.forEach(
144
+ (O) => R.push(...O.packages)
145
+ );
146
+ const N = R.filter(
147
+ (O) => O.identifier === T
148
+ );
149
+ return N.length === 0 ? null : N[0];
150
+ }
151
+ };
152
+ A(r, "_RC_ENDPOINT", "https://api.revenuecat.com"), A(r, "_BASE_PATH", "rcbilling/v1");
153
+ let e = r;
154
+ export {
155
+ e as Purchases
156
+ };
@@ -0,0 +1 @@
1
+ (function(r,n){typeof exports=="object"&&typeof module<"u"?n(exports):typeof define=="function"&&define.amd?define(["exports"],n):(r=typeof globalThis<"u"?globalThis:r||self,n(r.Purchases={}))})(this,function(r){"use strict";var H=Object.defineProperty;var Q=(r,n,A)=>n in r?H(r,n,{enumerable:!0,configurable:!0,writable:!0,value:A}):r[n]=A;var D=(r,n,A)=>(Q(r,typeof n!="symbol"?n+"":n,A),A);const n=E=>({amount:E.amount,currency:E.currency}),A=E=>({id:E.id,identifier:E.identifier,displayName:E.display_name,currentPrice:E.current_price?n(E.current_price):null,normalPeriodDuration:E.normal_period_duration}),L=E=>({id:E.id,identifier:E.identifier,displayName:E.display_name,rcBillingProduct:E.rc_billing_product?A(E.rc_billing_product):null}),p=E=>({id:E.id,identifier:E.identifier,displayName:E.display_name,packages:E.packages.map(L)}),f=E=>{var T;return{nextAction:E.next_action,data:{clientSecret:((T=E.data)==null?void 0:T.client_secret)??void 0}}};var O;(function(E){E[E.CONTINUE=100]="CONTINUE",E[E.SWITCHING_PROTOCOLS=101]="SWITCHING_PROTOCOLS",E[E.PROCESSING=102]="PROCESSING",E[E.EARLY_HINTS=103]="EARLY_HINTS",E[E.OK=200]="OK",E[E.CREATED=201]="CREATED",E[E.ACCEPTED=202]="ACCEPTED",E[E.NON_AUTHORITATIVE_INFORMATION=203]="NON_AUTHORITATIVE_INFORMATION",E[E.NO_CONTENT=204]="NO_CONTENT",E[E.RESET_CONTENT=205]="RESET_CONTENT",E[E.PARTIAL_CONTENT=206]="PARTIAL_CONTENT",E[E.MULTI_STATUS=207]="MULTI_STATUS",E[E.MULTIPLE_CHOICES=300]="MULTIPLE_CHOICES",E[E.MOVED_PERMANENTLY=301]="MOVED_PERMANENTLY",E[E.MOVED_TEMPORARILY=302]="MOVED_TEMPORARILY",E[E.SEE_OTHER=303]="SEE_OTHER",E[E.NOT_MODIFIED=304]="NOT_MODIFIED",E[E.USE_PROXY=305]="USE_PROXY",E[E.TEMPORARY_REDIRECT=307]="TEMPORARY_REDIRECT",E[E.PERMANENT_REDIRECT=308]="PERMANENT_REDIRECT",E[E.BAD_REQUEST=400]="BAD_REQUEST",E[E.UNAUTHORIZED=401]="UNAUTHORIZED",E[E.PAYMENT_REQUIRED=402]="PAYMENT_REQUIRED",E[E.FORBIDDEN=403]="FORBIDDEN",E[E.NOT_FOUND=404]="NOT_FOUND",E[E.METHOD_NOT_ALLOWED=405]="METHOD_NOT_ALLOWED",E[E.NOT_ACCEPTABLE=406]="NOT_ACCEPTABLE",E[E.PROXY_AUTHENTICATION_REQUIRED=407]="PROXY_AUTHENTICATION_REQUIRED",E[E.REQUEST_TIMEOUT=408]="REQUEST_TIMEOUT",E[E.CONFLICT=409]="CONFLICT",E[E.GONE=410]="GONE",E[E.LENGTH_REQUIRED=411]="LENGTH_REQUIRED",E[E.PRECONDITION_FAILED=412]="PRECONDITION_FAILED",E[E.REQUEST_TOO_LONG=413]="REQUEST_TOO_LONG",E[E.REQUEST_URI_TOO_LONG=414]="REQUEST_URI_TOO_LONG",E[E.UNSUPPORTED_MEDIA_TYPE=415]="UNSUPPORTED_MEDIA_TYPE",E[E.REQUESTED_RANGE_NOT_SATISFIABLE=416]="REQUESTED_RANGE_NOT_SATISFIABLE",E[E.EXPECTATION_FAILED=417]="EXPECTATION_FAILED",E[E.IM_A_TEAPOT=418]="IM_A_TEAPOT",E[E.INSUFFICIENT_SPACE_ON_RESOURCE=419]="INSUFFICIENT_SPACE_ON_RESOURCE",E[E.METHOD_FAILURE=420]="METHOD_FAILURE",E[E.MISDIRECTED_REQUEST=421]="MISDIRECTED_REQUEST",E[E.UNPROCESSABLE_ENTITY=422]="UNPROCESSABLE_ENTITY",E[E.LOCKED=423]="LOCKED",E[E.FAILED_DEPENDENCY=424]="FAILED_DEPENDENCY",E[E.UPGRADE_REQUIRED=426]="UPGRADE_REQUIRED",E[E.PRECONDITION_REQUIRED=428]="PRECONDITION_REQUIRED",E[E.TOO_MANY_REQUESTS=429]="TOO_MANY_REQUESTS",E[E.REQUEST_HEADER_FIELDS_TOO_LARGE=431]="REQUEST_HEADER_FIELDS_TOO_LARGE",E[E.UNAVAILABLE_FOR_LEGAL_REASONS=451]="UNAVAILABLE_FOR_LEGAL_REASONS",E[E.INTERNAL_SERVER_ERROR=500]="INTERNAL_SERVER_ERROR",E[E.NOT_IMPLEMENTED=501]="NOT_IMPLEMENTED",E[E.BAD_GATEWAY=502]="BAD_GATEWAY",E[E.SERVICE_UNAVAILABLE=503]="SERVICE_UNAVAILABLE",E[E.GATEWAY_TIMEOUT=504]="GATEWAY_TIMEOUT",E[E.HTTP_VERSION_NOT_SUPPORTED=505]="HTTP_VERSION_NOT_SUPPORTED",E[E.INSUFFICIENT_STORAGE=507]="INSUFFICIENT_STORAGE",E[E.NETWORK_AUTHENTICATION_REQUIRED=511]="NETWORK_AUTHENTICATION_REQUIRED"})(O||(O={}));class P extends Error{constructor(T,R){super(R),this.statusCode=T}}class M extends P{constructor(){super(O.INTERNAL_SERVER_ERROR,"An unknown error occurred.")}}class F extends P{}class h extends P{}class Y extends P{}class g extends P{}const i=class i{constructor(T){D(this,"_API_KEY",null);D(this,"_APP_USER_ID",null);D(this,"toOfferingsPage",T=>({offerings:T.offerings.map(p),priceByPackageId:T.prices_by_package_id}));this._API_KEY=T,i._RC_ENDPOINT===void 0&&console.error("Project was build without some of the environment variables set")}async listOfferings(){const R=await(await fetch(`${i._RC_ENDPOINT}/${i._BASE_PATH}/offerings`,{headers:{Authorization:`Bearer ${this._API_KEY}`,"Content-Type":"application/json",Accept:"application/json"}})).json();return this.toOfferingsPage(R)}async isEntitledTo(T,R){const N=await fetch(`${i._RC_ENDPOINT}/${i._BASE_PATH}/entitlements/${T}`,{headers:{Authorization:`Bearer ${this._API_KEY}`,"Content-Type":"application/json",Accept:"application/json"}});return N.status===404?!1:(await N.json()).entitlements.map(c=>c.lookup_key).includes(R)}waitForEntitlement(T,R,N=10){return new Promise((I,_)=>{const c=(l=1)=>this.isEntitledTo(T,R).then(m=>{if(l>N)return I(!1);if(m)return I(!0);setTimeout(()=>c(l+1),1e3)}).catch(_);c()})}async subscribe(T,R,N,e="production"){const I=e==="sandbox",_=await fetch(`${i._RC_ENDPOINT}/${i._BASE_PATH}/subscribe`,{method:"POST",headers:{Authorization:`Bearer ${this._API_KEY}`,"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({app_user_id:T,product_id:R,is_sandbox:I,email:N})});if(_.status===O.BAD_REQUEST)throw new F(_.status);if(_.status===O.TOO_MANY_REQUESTS)throw new g(_.status);if(_.status===O.CONFLICT)throw new h(_.status);if(_.status===O.INTERNAL_SERVER_ERROR)throw new Y(_.status);if(_.status===O.OK||_.status===O.CREATED){const c=await _.json();return f(c)}throw new M}async getPackage(T){const R=await this.listOfferings(),N=[];R.offerings.forEach(I=>N.push(...I.packages));const e=N.filter(I=>I.identifier===T);return e.length===0?null:e[0]}};D(i,"_RC_ENDPOINT","https://api.revenuecat.com"),D(i,"_BASE_PATH","rcbilling/v1");let U=i;r.Purchases=U,Object.defineProperty(r,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,10 +1,19 @@
1
1
  {
2
2
  "name": "@revenuecat/purchases-js",
3
3
  "private": false,
4
- "version": "0.0.4",
4
+ "version": "0.0.6",
5
5
  "type": "module",
6
- "types": "dist/main.d.ts",
7
- "main": "dist/purchases-js.js",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "main": "./dist/Purchases.umd.js",
10
+ "module": "./dist/Purchases.es.js",
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/Purchases.es.js",
14
+ "require": "./dist/Purchases.umd.js"
15
+ }
16
+ },
8
17
  "license": "MIT",
9
18
  "scripts": {
10
19
  "dev": "vite",
@@ -33,5 +42,8 @@
33
42
  "vite": "^4.4.5",
34
43
  "vite-plugin-dts": "^3.6.3",
35
44
  "vitest": "^0.34.6"
45
+ },
46
+ "dependencies": {
47
+ "http-status-codes": "^2.3.0"
36
48
  }
37
49
  }
package/.eslintrc.cjs DELETED
@@ -1,30 +0,0 @@
1
- module.exports = {
2
- plugins: ["prettier"],
3
- env: {
4
- browser: true,
5
- es2021: true,
6
- },
7
- extends: [
8
- "plugin:@typescript-eslint/recommended",
9
- "plugin:prettier/recommended",
10
- ],
11
- overrides: [
12
- {
13
- env: {
14
- node: true,
15
- },
16
- files: [".eslintrc.{js,cjs}"],
17
- parserOptions: {
18
- sourceType: "script",
19
- },
20
- },
21
- ],
22
- parserOptions: {
23
- ecmaVersion: "latest",
24
- sourceType: "module",
25
- },
26
- rules: {
27
- "prettier/prettier": "error",
28
- },
29
- ignorePatterns: ["vite.config.js", "vitest.config.js", "dist/"],
30
- };
package/.prettierignore DELETED
@@ -1,2 +0,0 @@
1
- package-lock.json
2
- node_modules/
package/.prettierrc DELETED
@@ -1,6 +0,0 @@
1
- {
2
- "trailingComma": "all",
3
- "tabWidth": 2,
4
- "semi": true,
5
- "singleQuote": false
6
- }
package/CHANGELOG DELETED
@@ -1,27 +0,0 @@
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
- # 0.0.3
6
-
7
- - Add prettier by @francocorreasosa in #13
8
- - Bug: fix some types by @alfondotnet in #14
9
-
10
- # 0.0.2
11
-
12
- - Fix publishing to NPM by @alfondotnet in # 10
13
- - BIL-40: Add subscribe method by @francocorreasosa in #11
14
- - Only build ES modules by @alfondotnet in #12
15
-
16
- # 0.0.1
17
-
18
- Initial release πŸ±πŸš€
19
-
20
- - Add Vite by @alfondotnet in #1
21
- - add README by @alfondotnet in #2
22
- - Fon/add entrypoint by @alfondotnet in #3
23
- - Simplify existing methods + MSW by @alfondotnet in #5
24
- - Added the listOfferings method by @nicfix in #4
25
- - Migrated to the new price naming by @nicfix in #6
26
- - BIL-15: isEntitledTo method! by @nicfix in #7
27
- - Rename / Clean up package prior to publishing to NPM by @alfondotnet in #9
@@ -1,34 +0,0 @@
1
- import { ServerResponse } from "./types";
2
- export interface Price {
3
- amount: number;
4
- currency: string;
5
- }
6
- export interface Product {
7
- id: string;
8
- displayName: string;
9
- identifier: string;
10
- currentPrice: Price | null;
11
- normalPeriodDuration: string | null;
12
- }
13
- export interface Package {
14
- id: string;
15
- identifier: string;
16
- displayName: string;
17
- rcBillingProduct: Product | null;
18
- }
19
- export interface Offering {
20
- id: string;
21
- identifier: string;
22
- displayName: string;
23
- packages: Package[];
24
- }
25
- export interface OfferingsPage {
26
- offerings: Offering[];
27
- priceByPackageId: {
28
- [packageId: string]: number;
29
- };
30
- }
31
- export declare const toPrice: (data: ServerResponse) => Price;
32
- export declare const toProduct: (data: ServerResponse) => Product;
33
- export declare const toPackage: (data: ServerResponse) => Package;
34
- export declare const toOffering: (data: ServerResponse) => Offering;
@@ -1,8 +0,0 @@
1
- import { ServerResponse } from "./types";
2
- export interface SubscribeResponse {
3
- nextAction: string;
4
- data: {
5
- clientSecret?: string;
6
- };
7
- }
8
- export declare const toSubscribeResponse: (raw: ServerResponse) => SubscribeResponse;
@@ -1 +0,0 @@
1
- export type ServerResponse = any;
package/dist/main.d.ts DELETED
@@ -1,16 +0,0 @@
1
- import { Offering as InnerOffering, OfferingsPage as InnerOfferingsPage, Package as InnerPackage } from "./entities/offerings";
2
- import { SubscribeResponse } from "./entities/subscribe-response";
3
- export type OfferingsPage = InnerOfferingsPage;
4
- export type Offering = InnerOffering;
5
- export type Package = InnerPackage;
6
- export declare class Purchases {
7
- _API_KEY: string | null;
8
- _APP_USER_ID: string | null;
9
- private static readonly _RC_ENDPOINT;
10
- private static readonly _BASE_PATH;
11
- constructor(apiKey: string);
12
- private toOfferingsPage;
13
- listOfferings(): Promise<OfferingsPage>;
14
- isEntitledTo(appUserId: string, entitlementIdentifier: string): Promise<boolean>;
15
- subscribe(appUserId: string, productId: string, environment?: "sandbox" | "production"): Promise<SubscribeResponse>;
16
- }
@@ -1,117 +0,0 @@
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) => {
6
- try {
7
- a(n.next(r));
8
- } catch (u) {
9
- c(u);
10
- }
11
- }, p = (r) => {
12
- try {
13
- a(n.throw(r));
14
- } catch (u) {
15
- c(u);
16
- }
17
- }, a = (r) => r.done ? o(r.value) : Promise.resolve(r.value).then(_, p);
18
- a((n = n.apply(e, t)).next());
19
- });
20
- const m = (e) => ({
21
- amount: e.amount,
22
- currency: e.currency
23
- }), A = (e) => ({
24
- id: e.id,
25
- identifier: e.identifier,
26
- displayName: e.display_name,
27
- currentPrice: e.current_price ? m(e.current_price) : null,
28
- normalPeriodDuration: e.normal_period_duration
29
- }), g = (e) => ({
30
- id: e.id,
31
- identifier: e.identifier,
32
- displayName: e.display_name,
33
- rcBillingProduct: e.rc_billing_product ? A(e.rc_billing_product) : null
34
- }), y = (e) => ({
35
- id: e.id,
36
- identifier: e.identifier,
37
- displayName: e.display_name,
38
- packages: e.packages.map(g)
39
- }), b = (e) => {
40
- var t, n;
41
- return {
42
- nextAction: e.next_action,
43
- data: {
44
- clientSecret: (n = (t = e.data) == null ? void 0 : t.client_secret) != null ? n : void 0
45
- }
46
- };
47
- }, i = class i {
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),
53
- priceByPackageId: t.prices_by_package_id
54
- }));
55
- this._API_KEY = t, i._RC_ENDPOINT === void 0 && console.error(
56
- "Project was build without some of the environment variables set"
57
- );
58
- }
59
- listOfferings() {
60
- return l(this, null, function* () {
61
- const n = yield (yield fetch(
62
- `${i._RC_ENDPOINT}/${i._BASE_PATH}/offerings`,
63
- {
64
- headers: {
65
- Authorization: `Bearer ${this._API_KEY}`,
66
- "Content-Type": "application/json",
67
- Accept: "application/json"
68
- }
69
- }
70
- )).json();
71
- return this.toOfferingsPage(n);
72
- });
73
- }
74
- isEntitledTo(t, n) {
75
- return l(this, null, function* () {
76
- const o = yield fetch(
77
- `${i._RC_ENDPOINT}/${i._BASE_PATH}/entitlements/${t}`,
78
- {
79
- headers: {
80
- Authorization: `Bearer ${this._API_KEY}`,
81
- "Content-Type": "application/json",
82
- Accept: "application/json"
83
- }
84
- }
85
- );
86
- return o.status === 404 ? !1 : (yield o.json()).entitlements.map(
87
- (a) => a.lookup_key
88
- ).includes(n);
89
- });
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`,
95
- {
96
- method: "POST",
97
- headers: {
98
- Authorization: `Bearer ${this._API_KEY}`,
99
- "Content-Type": "application/json",
100
- Accept: "application/json"
101
- },
102
- body: JSON.stringify({
103
- app_user_id: t,
104
- product_id: n,
105
- is_sandbox: c
106
- })
107
- }
108
- )).json();
109
- return b(p);
110
- });
111
- }
112
- };
113
- s(i, "_RC_ENDPOINT", "https://api.revenuecat.com"), s(i, "_BASE_PATH", "rcbilling/v1");
114
- let d = i;
115
- export {
116
- d as Purchases
117
- };
package/global.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export {}; // eslint-disable-line
2
-
3
- declare global {}
Binary file
package/test.html DELETED
@@ -1,38 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>RCBilling Example</title>
7
- <script src="./dist/rcbilling-js.iife.js"></script>
8
- <style>
9
- /* Some basic styling for our Stripe form */
10
- #payment-form {
11
- width: 300px;
12
- margin: 50px auto;
13
- padding: 20px;
14
- border: 1px solid #ddd;
15
- border-radius: 5px;
16
- }
17
- </style>
18
- </head>
19
- <body>
20
- <div id="payment-form"></div>
21
-
22
- <script>
23
- document.addEventListener("DOMContentLoaded", function () {
24
- var billing = new RCBilling(
25
- "web_tFpmIVwEGKNprbMOyiRRzZAbzIHX",
26
- "test_rcbilling",
27
- );
28
-
29
- setTimeout(() => {
30
- billing.renderForm(
31
- document.getElementById("payment-form"),
32
- "monthly.product_1234",
33
- );
34
- }, 3000);
35
- });
36
- </script>
37
- </body>
38
- </html>
package/tsconfig.json DELETED
@@ -1,23 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "types": ["vite/client"],
5
- "useDefineForClassFields": true,
6
- "module": "ESNext",
7
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
8
- // /* Bundler mode */
9
- "moduleResolution": "node",
10
- "resolveJsonModule": true,
11
- "isolatedModules": true,
12
- "noEmit": true,
13
-
14
- /* Linting */
15
- "strict": true,
16
- "noUnusedLocals": true,
17
- "noUnusedParameters": true,
18
- "noFallthroughCasesInSwitch": true,
19
- "baseUrl": "."
20
- },
21
- "include": ["./src/**/*.ts", "global.d.ts"],
22
- "exclude": ["node_modules", "*.test.ts"]
23
- }