mobilyflow-react-native-sdk 0.0.1

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.
Files changed (46) hide show
  1. package/LICENSE +20 -0
  2. package/MobilyflowReactNativeSdk.podspec +52 -0
  3. package/README.md +33 -0
  4. package/android/build.gradle +114 -0
  5. package/android/generated/java/com/mobilyflowreactnativesdk/NativeMobilyflowReactNativeSdkSpec.java +89 -0
  6. package/android/generated/jni/CMakeLists.txt +36 -0
  7. package/android/generated/jni/RNMobilyflowReactNativeSdkSpec-generated.cpp +104 -0
  8. package/android/generated/jni/RNMobilyflowReactNativeSdkSpec.h +31 -0
  9. package/android/generated/jni/react/renderer/components/RNMobilyflowReactNativeSdkSpec/RNMobilyflowReactNativeSdkSpecJSI-generated.cpp +124 -0
  10. package/android/generated/jni/react/renderer/components/RNMobilyflowReactNativeSdkSpec/RNMobilyflowReactNativeSdkSpecJSI.h +287 -0
  11. package/android/gradle.properties +5 -0
  12. package/android/src/main/AndroidManifest.xml +3 -0
  13. package/android/src/main/AndroidManifestNew.xml +2 -0
  14. package/android/src/main/java/com/mobilyflowreactnativesdk/MobilyflowReactNativeSdkModule.kt +183 -0
  15. package/android/src/main/java/com/mobilyflowreactnativesdk/MobilyflowReactNativeSdkPackage.kt +32 -0
  16. package/android/src/main/java/com/mobilyflowreactnativesdk/ParserUtils.kt +149 -0
  17. package/ios/MobilyflowReactNativeSdk.h +7 -0
  18. package/ios/MobilyflowReactNativeSdk.mm +204 -0
  19. package/ios/Utils/ParserMobilyPurchaseSDKOptions.h +21 -0
  20. package/ios/Utils/ParserMobilyPurchaseSDKOptions.mm +25 -0
  21. package/ios/Utils/Utils.h +18 -0
  22. package/ios/Utils/Utils.m +22 -0
  23. package/ios/generated/RNMobilyflowReactNativeSdkSpec/RNMobilyflowReactNativeSdkSpec-generated.mm +134 -0
  24. package/ios/generated/RNMobilyflowReactNativeSdkSpec/RNMobilyflowReactNativeSdkSpec.h +161 -0
  25. package/ios/generated/RNMobilyflowReactNativeSdkSpecJSI-generated.cpp +124 -0
  26. package/ios/generated/RNMobilyflowReactNativeSdkSpecJSI.h +287 -0
  27. package/package.json +183 -0
  28. package/react-native.config.js +12 -0
  29. package/src/NativeMobilyflowReactNativeSdk.ts +46 -0
  30. package/src/entities/mobily-customer-entitlement.ts +37 -0
  31. package/src/entities/mobily-one-time-product.ts +11 -0
  32. package/src/entities/mobily-product.ts +34 -0
  33. package/src/entities/mobily-subscription-group.ts +20 -0
  34. package/src/entities/mobily-subscription-offer.ts +16 -0
  35. package/src/entities/mobily-subscription-product.ts +14 -0
  36. package/src/enums/mobily-environment.ts +5 -0
  37. package/src/enums/period-unit.ts +5 -0
  38. package/src/enums/platform.ts +4 -0
  39. package/src/enums/product-status.ts +5 -0
  40. package/src/enums/product-type.ts +4 -0
  41. package/src/enums/webhook-status.ts +5 -0
  42. package/src/errors/mobily-error.ts +18 -0
  43. package/src/errors/mobily-purchase-error.ts +30 -0
  44. package/src/errors/mobily-transfer-ownership-error.ts +20 -0
  45. package/src/index.tsx +153 -0
  46. package/src/utils/object-transformer.ts +60 -0
@@ -0,0 +1,37 @@
1
+ import { ProductType } from '../enums/product-type';
2
+ import { MobilyProduct } from './mobily-product';
3
+ import { Platform } from '../enums/platform';
4
+ import { objectTransformer } from '../utils/object-transformer';
5
+
6
+ export class ItemEntitlement {
7
+ quantity: number;
8
+ }
9
+
10
+ export class SubscriptionEntitlement {
11
+ startDate: Date;
12
+ expirationDate: Date;
13
+ autoRenewEnable: boolean;
14
+ platform: Platform;
15
+ isManagedByThisStoreAccount: boolean;
16
+
17
+ static parseFromAPI(obj: SubscriptionEntitlement) {
18
+ return objectTransformer(obj, { dates: ['startDate', 'expirationDate'] });
19
+ }
20
+ }
21
+
22
+ export class MobilyCustomerEntitlement {
23
+ type: ProductType;
24
+ product: MobilyProduct;
25
+ platformOriginalTransactionId: string;
26
+ item?: ItemEntitlement;
27
+ subscription?: SubscriptionEntitlement;
28
+
29
+ static parseFromAPI(obj: MobilyCustomerEntitlement) {
30
+ return objectTransformer(obj, {
31
+ mapping: {
32
+ product: MobilyProduct.parseFromAPI,
33
+ subscription: SubscriptionEntitlement.parseFromAPI,
34
+ },
35
+ });
36
+ }
37
+ }
@@ -0,0 +1,11 @@
1
+ import type { ProductStatus } from '../enums/product-status';
2
+
3
+ export class MobilyOneTimeProduct {
4
+ price: number;
5
+ currencyCode: string;
6
+ priceFormatted: string;
7
+ isConsumable: boolean;
8
+ isNonRenewableSub: boolean;
9
+ isMultiQuantity: boolean;
10
+ status: ProductStatus;
11
+ }
@@ -0,0 +1,34 @@
1
+ import { ProductType } from '../enums/product-type';
2
+ import type { ProductStatus } from '../enums/product-status';
3
+ import type { MobilyOneTimeProduct } from './mobily-one-time-product';
4
+ import type { MobilySubscriptionProduct } from './mobily-subscription-product';
5
+ import { objectTransformer } from '../utils/object-transformer';
6
+
7
+ export class MobilyProduct {
8
+ id: string;
9
+ createdAt: Date;
10
+ updatedAt: Date;
11
+ deletedAt?: Date;
12
+
13
+ identifier: string;
14
+ appId: string;
15
+
16
+ name: string;
17
+ description: string;
18
+ ios_sku: string;
19
+ android_sku: string;
20
+
21
+ type: ProductType;
22
+ extras: any;
23
+
24
+ status: ProductStatus;
25
+
26
+ oneTimeProduct?: MobilyOneTimeProduct;
27
+ subscriptionProduct?: MobilySubscriptionProduct;
28
+
29
+ static parseFromAPI(obj: MobilyProduct) {
30
+ return objectTransformer(obj, {
31
+ dates: ['createdAt', 'updatedAt', 'deletedAt'],
32
+ });
33
+ }
34
+ }
@@ -0,0 +1,20 @@
1
+ import { MobilyProduct } from './mobily-product';
2
+ import { objectTransformer } from '../utils/object-transformer';
3
+
4
+ export class MobilySubscriptionGroup {
5
+ id: string;
6
+ identifier: string;
7
+ name: string;
8
+ description: string;
9
+ ios_groupId: string;
10
+ extras: any;
11
+ products: MobilyProduct[];
12
+
13
+ static parseFromAPI(obj: MobilySubscriptionGroup) {
14
+ return objectTransformer(obj, {
15
+ mapping: {
16
+ products: MobilyProduct.parseFromAPI,
17
+ },
18
+ });
19
+ }
20
+ }
@@ -0,0 +1,16 @@
1
+ import type { ProductStatus } from '../enums/product-status';
2
+ import type { PeriodUnit } from '../enums/period-unit';
3
+
4
+ export class MobilySubscriptionOffer {
5
+ id: string;
6
+ name: string;
7
+ price: number;
8
+ currencyCode: string;
9
+ priceFormatted: string;
10
+ isFreeTrial: boolean;
11
+ periodCount: number;
12
+ periodUnit: PeriodUnit;
13
+ ios_offerId: string;
14
+ extras: any;
15
+ status: ProductStatus;
16
+ }
@@ -0,0 +1,14 @@
1
+ import type { ProductStatus } from '../enums/product-status';
2
+ import { MobilySubscriptionOffer } from './mobily-subscription-offer';
3
+ import { MobilySubscriptionGroup } from './mobily-subscription-group';
4
+
5
+ export class MobilySubscriptionProduct {
6
+ baseOffer: MobilySubscriptionOffer;
7
+ freeTrial: MobilySubscriptionOffer;
8
+ promotionalOffers: MobilySubscriptionOffer[];
9
+ status: ProductStatus;
10
+
11
+ groupLevel: number;
12
+ subscriptionGroupId: string;
13
+ subscriptionGroup: MobilySubscriptionGroup;
14
+ }
@@ -0,0 +1,5 @@
1
+ export enum MobilyEnvironment {
2
+ DEVELOPMENT = 0,
3
+ STAGING = 1,
4
+ PRODUCTION = 2,
5
+ }
@@ -0,0 +1,5 @@
1
+ export enum PeriodUnit {
2
+ WEEK = 0,
3
+ MONTH = 1,
4
+ YEAR = 2,
5
+ }
@@ -0,0 +1,4 @@
1
+ export enum Platform {
2
+ IOS = 0,
3
+ ANDROID = 1,
4
+ }
@@ -0,0 +1,5 @@
1
+ export enum ProductStatus {
2
+ INVALID = 0,
3
+ unavailable = 1,
4
+ available = 2,
5
+ }
@@ -0,0 +1,4 @@
1
+ export enum ProductType {
2
+ ONE_TIME = 'one_time',
3
+ SUBSCRIPTION = 'subscription',
4
+ }
@@ -0,0 +1,5 @@
1
+ export enum WebhookStatus {
2
+ PENDING = 0,
3
+ ERROR = 1,
4
+ SUCCESS = 2,
5
+ }
@@ -0,0 +1,18 @@
1
+ export class MobilyError extends Error {
2
+ constructor(
3
+ public readonly type: MobilyError.Type,
4
+ public readonly message: string,
5
+ public readonly nativeStack?: any
6
+ ) {
7
+ super(message);
8
+ }
9
+ }
10
+
11
+ export namespace MobilyError {
12
+ export enum Type {
13
+ STORE_UNAVAILABLE,
14
+ SERVER_UNAVAILABLE,
15
+ NO_CUSTOMER_LOGGED,
16
+ UNKNOWN_ERROR,
17
+ }
18
+ }
@@ -0,0 +1,30 @@
1
+ export class MobilyPurchaseError extends Error {
2
+ constructor(
3
+ public readonly type: MobilyPurchaseError.Type,
4
+ public readonly message: string,
5
+ public readonly nativeStack?: any
6
+ ) {
7
+ super(message);
8
+ }
9
+ }
10
+
11
+ export namespace MobilyPurchaseError {
12
+ export enum Type {
13
+ PURCHASE_ALREADY_PENDING,
14
+
15
+ PRODUCT_UNAVAILABLE,
16
+ NETWORK_UNAVAILABLE,
17
+
18
+ WEBHOOK_NOT_PRECESSED,
19
+ WEBHOOK_FAILED,
20
+
21
+ ALREADY_PURCHASED,
22
+ NOT_MANAGED_BY_THIS_STORE_ACCOUNT,
23
+ STORE_ACCOUNT_ALREADY_HAVE_PURCHASE,
24
+ RENEW_ALREADY_ON_THIS_PLAN,
25
+
26
+ USER_CANCELED,
27
+ FAILED,
28
+ PENDING,
29
+ }
30
+ }
@@ -0,0 +1,20 @@
1
+ export class MobilyTransferOwnershipError extends Error {
2
+ constructor(
3
+ public readonly type: MobilyTransferOwnershipError.Type,
4
+ public readonly message: string,
5
+ public readonly nativeStack?: any
6
+ ) {
7
+ super(message);
8
+ }
9
+ }
10
+
11
+ export namespace MobilyTransferOwnershipError {
12
+ export enum Type {
13
+ NOTHING_TO_TRANSFER,
14
+ TRANSFER_TO_SAME_CUSTOMER,
15
+ ALREADY_PENDING,
16
+
17
+ WEBHOOK_NOT_PROCESSED,
18
+ WEBHOOK_FAILED,
19
+ }
20
+ }
package/src/index.tsx ADDED
@@ -0,0 +1,153 @@
1
+ import MobilyflowReactNativeSdk, { type MobilyPurchaseSDKOptions } from './NativeMobilyflowReactNativeSdk';
2
+ import { MobilyProduct } from './entities/mobily-product';
3
+ import type { WebhookStatus } from './enums/webhook-status';
4
+ import type { MobilySubscriptionOffer } from './entities/mobily-subscription-offer';
5
+ import { MobilySubscriptionGroup } from './entities/mobily-subscription-group';
6
+ import { MobilyCustomerEntitlement } from './entities/mobily-customer-entitlement';
7
+ import { Platform as RNPlatform } from 'react-native';
8
+ import { MobilyError } from './errors/mobily-error';
9
+ import { MobilyPurchaseError } from './errors/mobily-purchase-error';
10
+ import { MobilyTransferOwnershipError } from './errors/mobily-transfer-ownership-error';
11
+
12
+ export type PurchaseOptions = {
13
+ offer?: MobilySubscriptionOffer;
14
+ quantity?: number;
15
+ };
16
+
17
+ export class MobilyPurchaseSDK {
18
+ private _uuid: string;
19
+
20
+ constructor(appId: string, apiKey: string, environment: number, options?: MobilyPurchaseSDKOptions) {
21
+ this._uuid = MobilyflowReactNativeSdk.instantiate(appId, apiKey, environment, options ?? {});
22
+ }
23
+
24
+ private throwError(error: any) {
25
+ if (RNPlatform.OS === 'android') {
26
+ switch (error.name) {
27
+ case 'com.mobilyflow.mobilypurchasesdk.Exceptions.MobilyException':
28
+ return new MobilyError(parseInt(error.code, 10), error.message, error.nativeStackAndroid);
29
+ case 'com.mobilyflow.mobilypurchasesdk.Exceptions.MobilyPurchaseException':
30
+ return new MobilyPurchaseError(parseInt(error.code, 10), error.message, error.nativeStackAndroid);
31
+ case 'com.mobilyflow.mobilypurchasesdk.Exceptions.MobilyTransferOwnershipException':
32
+ return new MobilyTransferOwnershipError(parseInt(error.code, 10), error.message, error.nativeStackAndroid);
33
+ }
34
+ } else {
35
+ switch (error.domain) {
36
+ case 'MobilyflowSDK.MobilyError':
37
+ return new MobilyError(parseInt(error.code, 10), error.message, error.nativeStackIOS);
38
+ case 'MobilyflowSDK.MobilyPurchaseError':
39
+ return new MobilyPurchaseError(parseInt(error.code, 10), error.message, error.nativeStackIOS);
40
+ case 'MobilyflowSDK.MobilyTransferOwnershipError':
41
+ return new MobilyTransferOwnershipError(parseInt(error.code, 10), error.message, error.nativeStackIOS);
42
+ }
43
+ }
44
+
45
+ return error;
46
+ }
47
+
48
+ close() {
49
+ try {
50
+ MobilyflowReactNativeSdk.close(this._uuid);
51
+ } catch (error: any) {
52
+ throw this.throwError(error);
53
+ }
54
+ }
55
+
56
+ async login(externalId: string) {
57
+ try {
58
+ await MobilyflowReactNativeSdk.login(this._uuid, externalId);
59
+ } catch (error: any) {
60
+ throw this.throwError(error);
61
+ }
62
+ }
63
+
64
+ async getProducts(identifiers?: string[]) {
65
+ try {
66
+ const products = await MobilyflowReactNativeSdk.getProducts(this._uuid, identifiers);
67
+ return products.map(MobilyProduct.parseFromAPI);
68
+ } catch (error: any) {
69
+ throw this.throwError(error);
70
+ }
71
+ }
72
+
73
+ async getSubscriptionGroups(identifiers?: string[]) {
74
+ try {
75
+ const groups = await MobilyflowReactNativeSdk.getSubscriptionGroups(this._uuid, identifiers);
76
+ return groups.map(MobilySubscriptionGroup.parseFromAPI);
77
+ } catch (error: any) {
78
+ throw this.throwError(error);
79
+ }
80
+ }
81
+
82
+ async getEntitlementForSubscription(subscriptionGroupId: string) {
83
+ try {
84
+ const entitlement = await MobilyflowReactNativeSdk.getEntitlementForSubscription(this._uuid, subscriptionGroupId);
85
+ return MobilyCustomerEntitlement.parseFromAPI(entitlement);
86
+ } catch (error: any) {
87
+ throw this.throwError(error);
88
+ }
89
+ }
90
+
91
+ async getEntitlement(productId: string) {
92
+ try {
93
+ const entitlement = await MobilyflowReactNativeSdk.getEntitlement(this._uuid, productId);
94
+ return MobilyCustomerEntitlement.parseFromAPI(entitlement);
95
+ } catch (error: any) {
96
+ throw this.throwError(error);
97
+ }
98
+ }
99
+
100
+ async getEntitlements(productIds: string[]) {
101
+ try {
102
+ const entitlements = await MobilyflowReactNativeSdk.getEntitlements(this._uuid, productIds);
103
+ return entitlements.map(MobilyCustomerEntitlement.parseFromAPI);
104
+ } catch (error: any) {
105
+ throw this.throwError(error);
106
+ }
107
+ }
108
+
109
+ async requestTransferOwnership() {
110
+ try {
111
+ return await MobilyflowReactNativeSdk.requestTransferOwnership(this._uuid);
112
+ } catch (error: any) {
113
+ throw this.throwError(error);
114
+ }
115
+ }
116
+
117
+ async openManageSubscription() {
118
+ try {
119
+ return await MobilyflowReactNativeSdk.openManageSubscription(this._uuid);
120
+ } catch (error: any) {
121
+ throw this.throwError(error);
122
+ }
123
+ }
124
+
125
+ // openRefundDialog(transactionId: string): Promise<void>;
126
+
127
+ async purchaseProduct(product: MobilyProduct, options?: PurchaseOptions): Promise<WebhookStatus> {
128
+ try {
129
+ return await MobilyflowReactNativeSdk.purchaseProduct(this._uuid, product.id, {
130
+ offerId: options?.offer?.id || null,
131
+ quantity: options?.quantity || null,
132
+ });
133
+ } catch (error: any) {
134
+ throw this.throwError(error);
135
+ }
136
+ }
137
+
138
+ sendDiagnotic() {
139
+ try {
140
+ return MobilyflowReactNativeSdk.sendDiagnotic(this._uuid);
141
+ } catch (error: any) {
142
+ throw this.throwError(error);
143
+ }
144
+ }
145
+
146
+ async getStoreCountry() {
147
+ try {
148
+ return await MobilyflowReactNativeSdk.getStoreCountry(this._uuid);
149
+ } catch (error: any) {
150
+ throw this.throwError(error);
151
+ }
152
+ }
153
+ }
@@ -0,0 +1,60 @@
1
+ export type ObjectTransformer = {
2
+ dates?: string[];
3
+ mapping?: {
4
+ [key in string]: (obj: any) => any;
5
+ };
6
+ };
7
+
8
+ /**
9
+ * Transform object following the transformer.
10
+ * Note: The function is safe, take care of the real type of each field and perform null checks.
11
+ *
12
+ * ```
13
+ * // Example:
14
+ * objectTransformer(
15
+ * {
16
+ * date_start: '2023-04-12',
17
+ * date_end: '2023-04-13',
18
+ * user_array: [
19
+ * { name: 'Greg', created_date: '2023-05-12' },
20
+ * { name: 'Antoine', created_date: '2023-06-12' },
21
+ * ],
22
+ * single_user: { name: 'Greg', created_date: '2023-05-12' },
23
+ * },
24
+ * {
25
+ * dates: ['date_start', 'date_end'],
26
+ * mapping: {
27
+ * user_array: parseUser,
28
+ * single_user: parseUser,
29
+ * },
30
+ * },
31
+ * );
32
+ * // Return an object with parsed dates & mapped user.
33
+ * ```
34
+ * @param obj
35
+ * @param tranformer
36
+ */
37
+ export const objectTransformer = <T extends any>(obj: T, tranformer: ObjectTransformer) => {
38
+ const anyObj = obj as any;
39
+
40
+ if (tranformer.dates) {
41
+ for (const date of tranformer.dates) {
42
+ if (anyObj[date] && (typeof anyObj[date] === 'string' || typeof anyObj[date] === 'number')) {
43
+ anyObj[date] = new Date(anyObj[date]);
44
+ }
45
+ }
46
+ }
47
+
48
+ if (tranformer.mapping) {
49
+ for (const mapKey of Object.keys(tranformer.mapping)) {
50
+ if (anyObj[mapKey]) {
51
+ if (Array.isArray(anyObj[mapKey])) {
52
+ anyObj[mapKey] = anyObj[mapKey].map(tranformer.mapping[mapKey]);
53
+ } else {
54
+ anyObj[mapKey] = tranformer.mapping[mapKey](anyObj[mapKey]);
55
+ }
56
+ }
57
+ }
58
+ }
59
+ return anyObj as T;
60
+ };