react-native-iap 15.3.5 → 15.3.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/lib/module/index.js +37 -59
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/error.js +98 -15
- package/lib/module/utils/error.js.map +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/utils/error.d.ts +1 -1
- package/lib/typescript/src/utils/error.d.ts.map +1 -1
- package/openiap-versions.json +1 -1
- package/package.json +1 -1
- package/src/index.ts +122 -59
- package/src/utils/error.ts +127 -14
package/src/utils/error.ts
CHANGED
|
@@ -16,12 +16,125 @@ export interface IapError {
|
|
|
16
16
|
[key: string]: any; // Allow additional platform-specific fields
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
const parseJsonPayload = (
|
|
20
|
+
payload: string,
|
|
21
|
+
fallbackMessage: string,
|
|
22
|
+
): IapError | null => {
|
|
23
|
+
const trimmed = payload.trim();
|
|
24
|
+
const candidates = [trimmed];
|
|
25
|
+
|
|
26
|
+
if (trimmed.includes('\\"')) {
|
|
27
|
+
candidates.push(trimmed.replace(/\\"/g, '"'));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
for (const candidate of candidates) {
|
|
31
|
+
try {
|
|
32
|
+
const parsed = JSON.parse(candidate);
|
|
33
|
+
if (typeof parsed === 'object' && parsed !== null) {
|
|
34
|
+
const parsedError = parsed as Partial<IapError>;
|
|
35
|
+
return {
|
|
36
|
+
code: parsedError.code || ErrorCode.Unknown,
|
|
37
|
+
message: parsedError.message || fallbackMessage,
|
|
38
|
+
...parsedError,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
} catch {
|
|
42
|
+
// Try the next candidate.
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return null;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const extractBalancedJsonObject = (
|
|
50
|
+
value: string,
|
|
51
|
+
startIndex: number,
|
|
52
|
+
): string | null => {
|
|
53
|
+
for (let index = startIndex; index < value.length; index += 1) {
|
|
54
|
+
if (value[index] !== '}') {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const candidate = value.substring(startIndex, index + 1);
|
|
59
|
+
if (parseJsonPayload(candidate, value)) {
|
|
60
|
+
return candidate;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return null;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const parseNSErrorJsonPayload = (rawString: string): IapError | null => {
|
|
68
|
+
const payloads: string[] = [];
|
|
69
|
+
const quotedPayloadMatch = /Code=-?\d+\s+"/.exec(rawString);
|
|
70
|
+
|
|
71
|
+
if (quotedPayloadMatch?.index !== undefined) {
|
|
72
|
+
const contentStart =
|
|
73
|
+
quotedPayloadMatch.index + quotedPayloadMatch[0].length;
|
|
74
|
+
const userInfoIndex = rawString.indexOf('UserInfo=', contentStart);
|
|
75
|
+
const contentEnd =
|
|
76
|
+
userInfoIndex > contentStart
|
|
77
|
+
? rawString.lastIndexOf('"', userInfoIndex)
|
|
78
|
+
: rawString.lastIndexOf('"');
|
|
79
|
+
|
|
80
|
+
if (contentEnd > contentStart) {
|
|
81
|
+
payloads.push(rawString.substring(contentStart, contentEnd));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const localizedDescription = 'NSLocalizedDescription=';
|
|
86
|
+
const descriptionIndex = rawString.indexOf(localizedDescription);
|
|
87
|
+
|
|
88
|
+
if (descriptionIndex >= 0) {
|
|
89
|
+
let valueStart = descriptionIndex + localizedDescription.length;
|
|
90
|
+
while (/\s/.test(rawString[valueStart] ?? '')) {
|
|
91
|
+
valueStart += 1;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const firstBraceIndex = rawString.indexOf('{', valueStart);
|
|
95
|
+
if (firstBraceIndex >= 0 && firstBraceIndex <= valueStart + 2) {
|
|
96
|
+
const payload = extractBalancedJsonObject(rawString, firstBraceIndex);
|
|
97
|
+
if (payload) {
|
|
98
|
+
payloads.push(payload);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
for (const payload of payloads) {
|
|
104
|
+
const parsed = parseJsonPayload(payload, rawString);
|
|
105
|
+
if (parsed?.code && parsed.code !== ErrorCode.Unknown) {
|
|
106
|
+
return parsed;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return null;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const parseStructuredError = (error: Error): IapError | null => {
|
|
114
|
+
const errorWithCode = error as Error & {code?: unknown} & Record<
|
|
115
|
+
string,
|
|
116
|
+
unknown
|
|
117
|
+
>;
|
|
118
|
+
|
|
119
|
+
if (typeof errorWithCode.code === 'string' && errorWithCode.code.length > 0) {
|
|
120
|
+
const {code, message, ...extraFields} = errorWithCode;
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
...extraFields,
|
|
124
|
+
code,
|
|
125
|
+
message: typeof message === 'string' ? message : error.message,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return null;
|
|
130
|
+
};
|
|
131
|
+
|
|
19
132
|
/**
|
|
20
133
|
* Parses error string from native modules into a structured error object
|
|
21
134
|
*
|
|
22
135
|
* Native modules return errors in different formats:
|
|
23
136
|
* - Android: JSON string like '{"code":"E_USER_CANCELLED","message":"User cancelled the purchase","responseCode":1}'
|
|
24
|
-
* - iOS: JSON string or plain message
|
|
137
|
+
* - iOS: JSON string, Nitro NSError string with embedded JSON, or plain message
|
|
25
138
|
* - Legacy: "CODE: message" format
|
|
26
139
|
*
|
|
27
140
|
* @param errorString - The error string from native module
|
|
@@ -32,6 +145,11 @@ export function parseErrorStringToJsonObj(
|
|
|
32
145
|
): IapError {
|
|
33
146
|
// Handle Error objects
|
|
34
147
|
if (errorString instanceof Error) {
|
|
148
|
+
const structuredError = parseStructuredError(errorString);
|
|
149
|
+
if (structuredError) {
|
|
150
|
+
return structuredError;
|
|
151
|
+
}
|
|
152
|
+
|
|
35
153
|
errorString = errorString.message;
|
|
36
154
|
}
|
|
37
155
|
|
|
@@ -43,19 +161,14 @@ export function parseErrorStringToJsonObj(
|
|
|
43
161
|
};
|
|
44
162
|
}
|
|
45
163
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
...parsed,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
} catch {
|
|
58
|
-
// Not JSON, continue with other formats
|
|
164
|
+
const jsonPayload = parseJsonPayload(errorString, errorString);
|
|
165
|
+
if (jsonPayload) {
|
|
166
|
+
return jsonPayload;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const nsErrorPayload = parseNSErrorJsonPayload(errorString);
|
|
170
|
+
if (nsErrorPayload) {
|
|
171
|
+
return nsErrorPayload;
|
|
59
172
|
}
|
|
60
173
|
|
|
61
174
|
// Try to parse "CODE: message" format
|