@umituz/react-native-subscription 2.27.141 → 2.27.142
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/package.json +1 -1
- package/src/domains/paywall/components/PaywallContainer.tsx +9 -65
- package/src/domains/paywall/hooks/useTrialEligibilityCheck.ts +65 -0
- package/src/domains/wallet/domain/errors/WalletError.ts +17 -141
- package/src/domains/wallet/domain/errors/WalletError.types.ts +30 -0
- package/src/domains/wallet/domain/errors/WalletErrorClasses.ts +82 -0
- package/src/domains/wallet/domain/errors/WalletErrorFactory.ts +24 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-subscription",
|
|
3
|
-
"version": "2.27.
|
|
3
|
+
"version": "2.27.142",
|
|
4
4
|
"description": "Complete subscription management with RevenueCat, paywall UI, and credits system for React Native apps",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -1,19 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
* PaywallContainer Component
|
|
3
|
-
* Uses centralized pending purchase state - no local auth handling
|
|
4
|
-
* Apple Guideline 3.1.2 compliant trial display
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import React, { useMemo, useEffect } from "react";
|
|
1
|
+
import React, { useMemo } from "react";
|
|
8
2
|
import { usePaywallVisibility } from "../../subscription/presentation/usePaywallVisibility";
|
|
9
3
|
import { useSubscriptionPackages } from "../../subscription/infrastructure/hooks/useSubscriptionPackages";
|
|
10
4
|
import { useRevenueCatTrialEligibility } from "../../subscription/infrastructure/hooks/useRevenueCatTrialEligibility";
|
|
11
5
|
import { createCreditAmountsFromPackages } from "../../../utils/creditMapper";
|
|
12
6
|
import { PaywallModal } from "./PaywallModal";
|
|
13
|
-
import type { TrialEligibilityInfo } from "./PaywallModal.types";
|
|
14
|
-
|
|
15
7
|
import { usePaywallActions } from "../hooks/usePaywallActions";
|
|
16
8
|
import { useAuthAwarePurchase } from "../../subscription/presentation/useAuthAwarePurchase";
|
|
9
|
+
import { useTrialEligibilityCheck } from "../hooks/useTrialEligibilityCheck";
|
|
17
10
|
import type { PaywallContainerProps } from "./PaywallContainer.types";
|
|
18
11
|
|
|
19
12
|
export const PaywallContainer: React.FC<PaywallContainerProps> = (props) => {
|
|
@@ -59,62 +52,13 @@ export const PaywallContainer: React.FC<PaywallContainerProps> = (props) => {
|
|
|
59
52
|
onClose: handleClose,
|
|
60
53
|
});
|
|
61
54
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (isLoading) return; // Wait for packages to fully load
|
|
70
|
-
|
|
71
|
-
// Get current package identifiers
|
|
72
|
-
const currentPackageIds = packages.map((pkg) => pkg.product.identifier);
|
|
73
|
-
const sortedIds = [...currentPackageIds].sort().join(",");
|
|
74
|
-
|
|
75
|
-
// Skip if we've already checked these exact packages
|
|
76
|
-
if (checkedPackagesRef.current.join(",") === sortedIds) {
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Update ref
|
|
81
|
-
checkedPackagesRef.current = currentPackageIds;
|
|
82
|
-
|
|
83
|
-
// Get all actual product IDs from packages
|
|
84
|
-
const allProductIds = packages.map((pkg) => pkg.product.identifier);
|
|
85
|
-
|
|
86
|
-
// If eligibleProductIds are provided, filter to matching packages (partial match)
|
|
87
|
-
// e.g., "yearly" matches "futureus.yearly"
|
|
88
|
-
let productIdsToCheck: string[];
|
|
89
|
-
if (trialConfig.eligibleProductIds?.length) {
|
|
90
|
-
productIdsToCheck = allProductIds.filter((actualId) =>
|
|
91
|
-
trialConfig.eligibleProductIds?.some((configId) =>
|
|
92
|
-
actualId.toLowerCase().includes(configId.toLowerCase())
|
|
93
|
-
)
|
|
94
|
-
);
|
|
95
|
-
} else {
|
|
96
|
-
productIdsToCheck = allProductIds;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (productIdsToCheck.length > 0) {
|
|
100
|
-
checkEligibility(productIdsToCheck);
|
|
101
|
-
}
|
|
102
|
-
}, [packages, isLoading, checkEligibility, trialConfig?.enabled, trialConfig?.eligibleProductIds]);
|
|
103
|
-
|
|
104
|
-
// Convert eligibility map to format expected by PaywallModal
|
|
105
|
-
// Only process if trial is enabled
|
|
106
|
-
const trialEligibility = useMemo((): Record<string, TrialEligibilityInfo> => {
|
|
107
|
-
if (!trialConfig?.enabled) return {};
|
|
108
|
-
|
|
109
|
-
const result: Record<string, TrialEligibilityInfo> = {};
|
|
110
|
-
for (const [productId, info] of Object.entries(eligibilityMap)) {
|
|
111
|
-
result[productId] = {
|
|
112
|
-
eligible: info.eligible,
|
|
113
|
-
durationDays: trialConfig.durationDays ?? info.trialDurationDays ?? 7,
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
return result;
|
|
117
|
-
}, [eligibilityMap, trialConfig?.enabled, trialConfig?.durationDays]);
|
|
55
|
+
const trialEligibility = useTrialEligibilityCheck({
|
|
56
|
+
packages,
|
|
57
|
+
isLoading,
|
|
58
|
+
eligibilityMap,
|
|
59
|
+
checkEligibility,
|
|
60
|
+
trialConfig,
|
|
61
|
+
});
|
|
118
62
|
|
|
119
63
|
// Compute credit amounts from packageAllocations if not provided directly
|
|
120
64
|
const creditAmounts = useMemo(() => {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { useEffect, useRef, useMemo } from "react";
|
|
2
|
+
import type { PurchasesPackage } from "react-native-purchases";
|
|
3
|
+
import type { TrialEligibilityInfo } from "../components/PaywallModal.types";
|
|
4
|
+
import type { PaywallContainerProps } from "../components/PaywallContainer.types";
|
|
5
|
+
|
|
6
|
+
interface UseTrialEligibilityCheckParams {
|
|
7
|
+
packages: PurchasesPackage[];
|
|
8
|
+
isLoading: boolean;
|
|
9
|
+
eligibilityMap: Record<string, { eligible: boolean; trialDurationDays?: number }>;
|
|
10
|
+
checkEligibility: (productIds: string[]) => void;
|
|
11
|
+
trialConfig: PaywallContainerProps["trialConfig"];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const useTrialEligibilityCheck = ({
|
|
15
|
+
packages,
|
|
16
|
+
isLoading,
|
|
17
|
+
eligibilityMap,
|
|
18
|
+
checkEligibility,
|
|
19
|
+
trialConfig,
|
|
20
|
+
}: UseTrialEligibilityCheckParams) => {
|
|
21
|
+
const checkedPackagesRef = useRef<string[]>([]);
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (!trialConfig?.enabled || packages.length === 0 || isLoading) return;
|
|
25
|
+
|
|
26
|
+
const currentPackageIds = packages.map((pkg) => pkg.product.identifier);
|
|
27
|
+
const sortedIds = [...currentPackageIds].sort().join(",");
|
|
28
|
+
|
|
29
|
+
if (checkedPackagesRef.current.join(",") === sortedIds) return;
|
|
30
|
+
|
|
31
|
+
checkedPackagesRef.current = currentPackageIds;
|
|
32
|
+
|
|
33
|
+
const allProductIds = packages.map((pkg) => pkg.product.identifier);
|
|
34
|
+
|
|
35
|
+
let productIdsToCheck: string[];
|
|
36
|
+
if (trialConfig.eligibleProductIds?.length) {
|
|
37
|
+
productIdsToCheck = allProductIds.filter((actualId) =>
|
|
38
|
+
trialConfig.eligibleProductIds?.some((configId) =>
|
|
39
|
+
actualId.toLowerCase().includes(configId.toLowerCase())
|
|
40
|
+
)
|
|
41
|
+
);
|
|
42
|
+
} else {
|
|
43
|
+
productIdsToCheck = allProductIds;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (productIdsToCheck.length > 0) {
|
|
47
|
+
checkEligibility(productIdsToCheck);
|
|
48
|
+
}
|
|
49
|
+
}, [packages, isLoading, checkEligibility, trialConfig?.enabled, trialConfig?.eligibleProductIds]);
|
|
50
|
+
|
|
51
|
+
const trialEligibility = useMemo((): Record<string, TrialEligibilityInfo> => {
|
|
52
|
+
if (!trialConfig?.enabled) return {};
|
|
53
|
+
|
|
54
|
+
const result: Record<string, TrialEligibilityInfo> = {};
|
|
55
|
+
for (const [productId, info] of Object.entries(eligibilityMap)) {
|
|
56
|
+
result[productId] = {
|
|
57
|
+
eligible: info.eligible,
|
|
58
|
+
durationDays: trialConfig.durationDays ?? info.trialDurationDays ?? 7,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}, [eligibilityMap, trialConfig?.enabled, trialConfig?.durationDays]);
|
|
63
|
+
|
|
64
|
+
return trialEligibility;
|
|
65
|
+
};
|
|
@@ -1,141 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
abstract readonly userMessage: string;
|
|
19
|
-
abstract readonly category: WalletErrorCategory;
|
|
20
|
-
|
|
21
|
-
constructor(
|
|
22
|
-
message: string,
|
|
23
|
-
public readonly cause?: Error
|
|
24
|
-
) {
|
|
25
|
-
super(message);
|
|
26
|
-
this.name = this.constructor.name;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
toJSON() {
|
|
30
|
-
return {
|
|
31
|
-
name: this.name,
|
|
32
|
-
code: this.code,
|
|
33
|
-
userMessage: this.userMessage,
|
|
34
|
-
category: this.category,
|
|
35
|
-
message: this.message,
|
|
36
|
-
cause: this.cause?.message,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export class PaymentValidationError extends WalletError {
|
|
42
|
-
readonly code = "PAYMENT_VALIDATION_ERROR";
|
|
43
|
-
readonly category = "PAYMENT" as const;
|
|
44
|
-
readonly userMessage = WALLET_ERROR_MESSAGES.PAYMENT_VALIDATION_FAILED;
|
|
45
|
-
|
|
46
|
-
constructor(message: string, cause?: Error) {
|
|
47
|
-
super(message, cause);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export class PaymentProviderError extends WalletError {
|
|
52
|
-
readonly code = "PAYMENT_PROVIDER_ERROR";
|
|
53
|
-
readonly category = "PAYMENT" as const;
|
|
54
|
-
readonly userMessage = WALLET_ERROR_MESSAGES.PAYMENT_PROVIDER_ERROR;
|
|
55
|
-
|
|
56
|
-
constructor(message: string, cause?: Error) {
|
|
57
|
-
super(message, cause);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export class DuplicatePaymentError extends WalletError {
|
|
62
|
-
readonly code = "DUPLICATE_PAYMENT";
|
|
63
|
-
readonly category = "PAYMENT" as const;
|
|
64
|
-
readonly userMessage = WALLET_ERROR_MESSAGES.DUPLICATE_PAYMENT;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export class UserValidationError extends WalletError {
|
|
68
|
-
readonly code = "USER_VALIDATION_ERROR";
|
|
69
|
-
readonly category = "VALIDATION" as const;
|
|
70
|
-
readonly userMessage = WALLET_ERROR_MESSAGES.USER_VALIDATION_FAILED;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export class PackageValidationError extends WalletError {
|
|
74
|
-
readonly code = "PACKAGE_VALIDATION_ERROR";
|
|
75
|
-
readonly category = "VALIDATION" as const;
|
|
76
|
-
readonly userMessage = WALLET_ERROR_MESSAGES.PACKAGE_VALIDATION_FAILED;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export class ReceiptValidationError extends WalletError {
|
|
80
|
-
readonly code = "RECEIPT_VALIDATION_ERROR";
|
|
81
|
-
readonly category = "VALIDATION" as const;
|
|
82
|
-
readonly userMessage = WALLET_ERROR_MESSAGES.RECEIPT_VALIDATION_FAILED;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export class TransactionError extends WalletError {
|
|
86
|
-
readonly code = "TRANSACTION_ERROR";
|
|
87
|
-
readonly category = "INFRASTRUCTURE" as const;
|
|
88
|
-
readonly userMessage = WALLET_ERROR_MESSAGES.TRANSACTION_FAILED;
|
|
89
|
-
|
|
90
|
-
constructor(message: string, cause?: Error) {
|
|
91
|
-
super(message, cause);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export class NetworkError extends WalletError {
|
|
96
|
-
readonly code = "NETWORK_ERROR";
|
|
97
|
-
readonly category = "INFRASTRUCTURE" as const;
|
|
98
|
-
readonly userMessage = WALLET_ERROR_MESSAGES.NETWORK_ERROR;
|
|
99
|
-
|
|
100
|
-
constructor(message: string, cause?: Error) {
|
|
101
|
-
super(message, cause);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export class CreditLimitError extends WalletError {
|
|
106
|
-
readonly code = "CREDIT_LIMIT_ERROR";
|
|
107
|
-
readonly category = "BUSINESS" as const;
|
|
108
|
-
readonly userMessage = WALLET_ERROR_MESSAGES.CREDIT_LIMIT_EXCEEDED;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export class RefundError extends WalletError {
|
|
112
|
-
readonly code = "REFUND_ERROR";
|
|
113
|
-
readonly category = "BUSINESS" as const;
|
|
114
|
-
readonly userMessage = WALLET_ERROR_MESSAGES.REFUND_FAILED;
|
|
115
|
-
|
|
116
|
-
constructor(message: string, cause?: Error) {
|
|
117
|
-
super(message, cause);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export function handleWalletError(error: unknown): WalletError {
|
|
122
|
-
if (error instanceof WalletError) {
|
|
123
|
-
return error;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (error instanceof Error) {
|
|
127
|
-
const message = error.message.toLowerCase();
|
|
128
|
-
|
|
129
|
-
if (message.includes("network") || message.includes("timeout")) {
|
|
130
|
-
return new NetworkError(error.message, error);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (message.includes("permission") || message.includes("unauthorized")) {
|
|
134
|
-
return new UserValidationError("Authentication failed");
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return new TransactionError(error.message, error);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return new TransactionError("Unexpected error occurred");
|
|
141
|
-
}
|
|
1
|
+
export type { WalletErrorCategory } from "./WalletError.types";
|
|
2
|
+
export { WalletError } from "./WalletError.types";
|
|
3
|
+
|
|
4
|
+
export {
|
|
5
|
+
PaymentValidationError,
|
|
6
|
+
PaymentProviderError,
|
|
7
|
+
DuplicatePaymentError,
|
|
8
|
+
UserValidationError,
|
|
9
|
+
PackageValidationError,
|
|
10
|
+
ReceiptValidationError,
|
|
11
|
+
TransactionError,
|
|
12
|
+
NetworkError,
|
|
13
|
+
CreditLimitError,
|
|
14
|
+
RefundError,
|
|
15
|
+
} from "./WalletErrorClasses";
|
|
16
|
+
|
|
17
|
+
export { handleWalletError } from "./WalletErrorFactory";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type WalletErrorCategory =
|
|
2
|
+
| "PAYMENT"
|
|
3
|
+
| "VALIDATION"
|
|
4
|
+
| "INFRASTRUCTURE"
|
|
5
|
+
| "BUSINESS";
|
|
6
|
+
|
|
7
|
+
export abstract class WalletError extends Error {
|
|
8
|
+
abstract readonly code: string;
|
|
9
|
+
abstract readonly userMessage: string;
|
|
10
|
+
abstract readonly category: WalletErrorCategory;
|
|
11
|
+
|
|
12
|
+
constructor(
|
|
13
|
+
message: string,
|
|
14
|
+
public readonly cause?: Error
|
|
15
|
+
) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = this.constructor.name;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
toJSON() {
|
|
21
|
+
return {
|
|
22
|
+
name: this.name,
|
|
23
|
+
code: this.code,
|
|
24
|
+
userMessage: this.userMessage,
|
|
25
|
+
category: this.category,
|
|
26
|
+
message: this.message,
|
|
27
|
+
cause: this.cause?.message,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { WalletError } from "./WalletError.types";
|
|
2
|
+
import { WALLET_ERROR_MESSAGES } from "./WalletErrorMessages";
|
|
3
|
+
|
|
4
|
+
export class PaymentValidationError extends WalletError {
|
|
5
|
+
readonly code = "PAYMENT_VALIDATION_ERROR";
|
|
6
|
+
readonly category = "PAYMENT" as const;
|
|
7
|
+
readonly userMessage = WALLET_ERROR_MESSAGES.PAYMENT_VALIDATION_FAILED;
|
|
8
|
+
|
|
9
|
+
constructor(message: string, cause?: Error) {
|
|
10
|
+
super(message, cause);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class PaymentProviderError extends WalletError {
|
|
15
|
+
readonly code = "PAYMENT_PROVIDER_ERROR";
|
|
16
|
+
readonly category = "PAYMENT" as const;
|
|
17
|
+
readonly userMessage = WALLET_ERROR_MESSAGES.PAYMENT_PROVIDER_ERROR;
|
|
18
|
+
|
|
19
|
+
constructor(message: string, cause?: Error) {
|
|
20
|
+
super(message, cause);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class DuplicatePaymentError extends WalletError {
|
|
25
|
+
readonly code = "DUPLICATE_PAYMENT";
|
|
26
|
+
readonly category = "PAYMENT" as const;
|
|
27
|
+
readonly userMessage = WALLET_ERROR_MESSAGES.DUPLICATE_PAYMENT;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class UserValidationError extends WalletError {
|
|
31
|
+
readonly code = "USER_VALIDATION_ERROR";
|
|
32
|
+
readonly category = "VALIDATION" as const;
|
|
33
|
+
readonly userMessage = WALLET_ERROR_MESSAGES.USER_VALIDATION_FAILED;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class PackageValidationError extends WalletError {
|
|
37
|
+
readonly code = "PACKAGE_VALIDATION_ERROR";
|
|
38
|
+
readonly category = "VALIDATION" as const;
|
|
39
|
+
readonly userMessage = WALLET_ERROR_MESSAGES.PACKAGE_VALIDATION_FAILED;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class ReceiptValidationError extends WalletError {
|
|
43
|
+
readonly code = "RECEIPT_VALIDATION_ERROR";
|
|
44
|
+
readonly category = "VALIDATION" as const;
|
|
45
|
+
readonly userMessage = WALLET_ERROR_MESSAGES.RECEIPT_VALIDATION_FAILED;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export class TransactionError extends WalletError {
|
|
49
|
+
readonly code = "TRANSACTION_ERROR";
|
|
50
|
+
readonly category = "INFRASTRUCTURE" as const;
|
|
51
|
+
readonly userMessage = WALLET_ERROR_MESSAGES.TRANSACTION_FAILED;
|
|
52
|
+
|
|
53
|
+
constructor(message: string, cause?: Error) {
|
|
54
|
+
super(message, cause);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export class NetworkError extends WalletError {
|
|
59
|
+
readonly code = "NETWORK_ERROR";
|
|
60
|
+
readonly category = "INFRASTRUCTURE" as const;
|
|
61
|
+
readonly userMessage = WALLET_ERROR_MESSAGES.NETWORK_ERROR;
|
|
62
|
+
|
|
63
|
+
constructor(message: string, cause?: Error) {
|
|
64
|
+
super(message, cause);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export class CreditLimitError extends WalletError {
|
|
69
|
+
readonly code = "CREDIT_LIMIT_ERROR";
|
|
70
|
+
readonly category = "BUSINESS" as const;
|
|
71
|
+
readonly userMessage = WALLET_ERROR_MESSAGES.CREDIT_LIMIT_EXCEEDED;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export class RefundError extends WalletError {
|
|
75
|
+
readonly code = "REFUND_ERROR";
|
|
76
|
+
readonly category = "BUSINESS" as const;
|
|
77
|
+
readonly userMessage = WALLET_ERROR_MESSAGES.REFUND_FAILED;
|
|
78
|
+
|
|
79
|
+
constructor(message: string, cause?: Error) {
|
|
80
|
+
super(message, cause);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { WalletError } from "./WalletError.types";
|
|
2
|
+
import { NetworkError, UserValidationError, TransactionError } from "./WalletErrorClasses";
|
|
3
|
+
|
|
4
|
+
export const handleWalletError = (error: unknown): WalletError => {
|
|
5
|
+
if (error instanceof WalletError) {
|
|
6
|
+
return error;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if (error instanceof Error) {
|
|
10
|
+
const message = error.message.toLowerCase();
|
|
11
|
+
|
|
12
|
+
if (message.includes("network") || message.includes("timeout")) {
|
|
13
|
+
return new NetworkError(error.message, error);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (message.includes("permission") || message.includes("unauthorized")) {
|
|
17
|
+
return new UserValidationError("Authentication failed");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return new TransactionError(error.message, error);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return new TransactionError("Unexpected error occurred");
|
|
24
|
+
};
|