@lina-openx/react-native-lina-pay-sdk 1.0.0
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/LinaPaySdk.podspec +20 -0
- package/README.md +522 -0
- package/android/build.gradle +77 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/linapaysdk/LinaPaySdkModule.kt +18 -0
- package/android/src/main/java/com/linapaysdk/LinaPaySdkPackage.kt +17 -0
- package/ios/LinaPaySdk.h +5 -0
- package/ios/LinaPaySdk.mm +16 -0
- package/lib/module/config/environment.js +61 -0
- package/lib/module/config/environment.js.map +1 -0
- package/lib/module/index.js +142 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/services/auth.service.js +73 -0
- package/lib/module/services/auth.service.js.map +1 -0
- package/lib/module/services/consent.service.js +49 -0
- package/lib/module/services/consent.service.js.map +1 -0
- package/lib/module/services/participants.service.js +71 -0
- package/lib/module/services/participants.service.js.map +1 -0
- package/lib/module/services/payment.service.js +39 -0
- package/lib/module/services/payment.service.js.map +1 -0
- package/lib/module/types/auth.types.js +2 -0
- package/lib/module/types/auth.types.js.map +1 -0
- package/lib/module/types/consent.types.js +2 -0
- package/lib/module/types/consent.types.js.map +1 -0
- package/lib/module/types/index.js +2 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/module/types/participants.types.js +2 -0
- package/lib/module/types/participants.types.js.map +1 -0
- package/lib/module/types/payment.types.js +2 -0
- package/lib/module/types/payment.types.js.map +1 -0
- package/lib/module/utils/consent.utils.js +168 -0
- package/lib/module/utils/consent.utils.js.map +1 -0
- package/lib/module/utils/http.utils.js +58 -0
- package/lib/module/utils/http.utils.js.map +1 -0
- package/lib/module/utils/payment.utils.js +27 -0
- package/lib/module/utils/payment.utils.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/config/environment.d.ts +38 -0
- package/lib/typescript/src/config/environment.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +108 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/services/auth.service.d.ts +13 -0
- package/lib/typescript/src/services/auth.service.d.ts.map +1 -0
- package/lib/typescript/src/services/consent.service.d.ts +9 -0
- package/lib/typescript/src/services/consent.service.d.ts.map +1 -0
- package/lib/typescript/src/services/participants.service.d.ts +9 -0
- package/lib/typescript/src/services/participants.service.d.ts.map +1 -0
- package/lib/typescript/src/services/payment.service.d.ts +9 -0
- package/lib/typescript/src/services/payment.service.d.ts.map +1 -0
- package/lib/typescript/src/types/auth.types.d.ts +23 -0
- package/lib/typescript/src/types/auth.types.d.ts.map +1 -0
- package/lib/typescript/src/types/consent.types.d.ts +129 -0
- package/lib/typescript/src/types/consent.types.d.ts.map +1 -0
- package/lib/typescript/src/types/index.d.ts +9 -0
- package/lib/typescript/src/types/index.d.ts.map +1 -0
- package/lib/typescript/src/types/participants.types.d.ts +50 -0
- package/lib/typescript/src/types/participants.types.d.ts.map +1 -0
- package/lib/typescript/src/types/payment.types.d.ts +107 -0
- package/lib/typescript/src/types/payment.types.d.ts.map +1 -0
- package/lib/typescript/src/utils/consent.utils.d.ts +10 -0
- package/lib/typescript/src/utils/consent.utils.d.ts.map +1 -0
- package/lib/typescript/src/utils/http.utils.d.ts +21 -0
- package/lib/typescript/src/utils/http.utils.d.ts.map +1 -0
- package/lib/typescript/src/utils/payment.utils.d.ts +10 -0
- package/lib/typescript/src/utils/payment.utils.d.ts.map +1 -0
- package/package.json +169 -0
- package/src/config/environment.ts +58 -0
- package/src/index.tsx +178 -0
- package/src/services/auth.service.ts +88 -0
- package/src/services/consent.service.ts +63 -0
- package/src/services/participants.service.ts +89 -0
- package/src/services/payment.service.ts +49 -0
- package/src/types/auth.types.ts +24 -0
- package/src/types/consent.types.ts +152 -0
- package/src/types/index.ts +34 -0
- package/src/types/participants.types.ts +53 -0
- package/src/types/payment.types.ts +141 -0
- package/src/utils/consent.utils.ts +225 -0
- package/src/utils/http.utils.ts +80 -0
- package/src/utils/payment.utils.ts +32 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consent utilities for payload validation
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { LinaPayError } from './http.utils';
|
|
6
|
+
import type { CreateConsentRequest } from '../types/consent.types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Validate CPF/CNPJ format (basic validation)
|
|
10
|
+
*/
|
|
11
|
+
function validateCpfCnpj(cpfCnpj: string, fieldName: string): void {
|
|
12
|
+
// Remove non-numeric characters
|
|
13
|
+
const cleaned = cpfCnpj.replace(/\D/g, '');
|
|
14
|
+
|
|
15
|
+
// CPF must have 11 digits, CNPJ must have 14 digits
|
|
16
|
+
if (cleaned.length !== 11 && cleaned.length !== 14) {
|
|
17
|
+
throw new LinaPayError(
|
|
18
|
+
`${fieldName} must be a valid CPF (11 digits) or CNPJ (14 digits)`
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Validate URL format
|
|
25
|
+
*/
|
|
26
|
+
function validateUrl(url: string, fieldName: string): void {
|
|
27
|
+
if (!url || url.trim() === '') {
|
|
28
|
+
throw new LinaPayError(`${fieldName} is required and cannot be empty`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const urlObj = new URL(url);
|
|
33
|
+
if (!urlObj.protocol.startsWith('http')) {
|
|
34
|
+
throw new Error('Invalid protocol');
|
|
35
|
+
}
|
|
36
|
+
} catch {
|
|
37
|
+
throw new LinaPayError(
|
|
38
|
+
`${fieldName} must be a valid URL starting with http:// or https://`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Validate positive number
|
|
45
|
+
*/
|
|
46
|
+
function validatePositiveNumber(
|
|
47
|
+
value: number,
|
|
48
|
+
fieldName: string
|
|
49
|
+
): void {
|
|
50
|
+
if (typeof value !== 'number' || isNaN(value)) {
|
|
51
|
+
throw new LinaPayError(`${fieldName} must be a valid number`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (value <= 0) {
|
|
55
|
+
throw new LinaPayError(`${fieldName} must be greater than zero`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Validate date format (YYYY-MM-DD)
|
|
61
|
+
*/
|
|
62
|
+
function validateDateFormat(date: string, fieldName: string): void {
|
|
63
|
+
const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
|
|
64
|
+
if (!dateRegex.test(date)) {
|
|
65
|
+
throw new LinaPayError(
|
|
66
|
+
`${fieldName} must be in format YYYY-MM-DD (e.g., 2024-09-01)`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Check if date is valid
|
|
71
|
+
const dateObj = new Date(date);
|
|
72
|
+
if (isNaN(dateObj.getTime())) {
|
|
73
|
+
throw new LinaPayError(`${fieldName} is not a valid date`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Validate required string field
|
|
79
|
+
*/
|
|
80
|
+
function validateRequiredString(
|
|
81
|
+
value: string | undefined,
|
|
82
|
+
fieldName: string
|
|
83
|
+
): void {
|
|
84
|
+
if (!value || value.trim() === '') {
|
|
85
|
+
throw new LinaPayError(`${fieldName} is required and cannot be empty`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Validate consent payload before sending to API
|
|
91
|
+
* Throws LinaPayError if validation fails
|
|
92
|
+
*/
|
|
93
|
+
export function validateConsentPayload(
|
|
94
|
+
payload: CreateConsentRequest
|
|
95
|
+
): void {
|
|
96
|
+
// Validate main required fields
|
|
97
|
+
validateRequiredString(payload.organisationId, 'organisationId');
|
|
98
|
+
validateRequiredString(
|
|
99
|
+
payload.authorisationServerId,
|
|
100
|
+
'authorisationServerId'
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
if (!payload.payment) {
|
|
104
|
+
throw new LinaPayError('payment is required');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Validate payment required fields
|
|
108
|
+
validateUrl(payload.payment.redirectUri, 'payment.redirectUri');
|
|
109
|
+
validatePositiveNumber(payload.payment.value, 'payment.value');
|
|
110
|
+
|
|
111
|
+
if (!payload.payment.creditor) {
|
|
112
|
+
throw new LinaPayError('payment.creditor is required');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Validate creditor required fields
|
|
116
|
+
const creditor = payload.payment.creditor;
|
|
117
|
+
validateRequiredString(creditor.name, 'payment.creditor.name');
|
|
118
|
+
validateRequiredString(creditor.personType, 'payment.creditor.personType');
|
|
119
|
+
validateCpfCnpj(creditor.cpfCnpj, 'payment.creditor.cpfCnpj');
|
|
120
|
+
validateRequiredString(
|
|
121
|
+
creditor.accountNumber,
|
|
122
|
+
'payment.creditor.accountNumber'
|
|
123
|
+
);
|
|
124
|
+
validateRequiredString(
|
|
125
|
+
creditor.accountIssuer,
|
|
126
|
+
'payment.creditor.accountIssuer'
|
|
127
|
+
);
|
|
128
|
+
validateRequiredString(
|
|
129
|
+
creditor.accountPixKey,
|
|
130
|
+
'payment.creditor.accountPixKey'
|
|
131
|
+
);
|
|
132
|
+
validateRequiredString(creditor.accountIspb, 'payment.creditor.accountIspb');
|
|
133
|
+
validateRequiredString(creditor.accountType, 'payment.creditor.accountType');
|
|
134
|
+
|
|
135
|
+
// Validate optional CPF/CNPJ in payment
|
|
136
|
+
if (payload.payment.cpfCnpj) {
|
|
137
|
+
validateCpfCnpj(payload.payment.cpfCnpj, 'payment.cpfCnpj');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Validate schedule if present
|
|
141
|
+
if (payload.payment.schedule) {
|
|
142
|
+
validateSchedule(payload.payment.schedule);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Validate redirectUri if present at root level
|
|
146
|
+
if (payload.redirectUri) {
|
|
147
|
+
validateUrl(payload.redirectUri, 'redirectUri');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Validate schedule structure
|
|
153
|
+
*/
|
|
154
|
+
function validateSchedule(schedule: any): void {
|
|
155
|
+
const scheduleTypes = ['single', 'daily', 'weekly', 'monthly', 'custom'];
|
|
156
|
+
const providedTypes = scheduleTypes.filter((type) => schedule[type]);
|
|
157
|
+
|
|
158
|
+
if (providedTypes.length === 0) {
|
|
159
|
+
throw new LinaPayError(
|
|
160
|
+
'At least one schedule type must be provided (single, daily, weekly, monthly, or custom)'
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Validate single schedule
|
|
165
|
+
if (schedule.single) {
|
|
166
|
+
validateDateFormat(schedule.single.date, 'schedule.single.date');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Validate daily schedule
|
|
170
|
+
if (schedule.daily) {
|
|
171
|
+
validateDateFormat(schedule.daily.startDate, 'schedule.daily.startDate');
|
|
172
|
+
validatePositiveNumber(schedule.daily.quantity, 'schedule.daily.quantity');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Validate weekly schedule
|
|
176
|
+
if (schedule.weekly) {
|
|
177
|
+
validateRequiredString(
|
|
178
|
+
schedule.weekly.dayOfWeek,
|
|
179
|
+
'schedule.weekly.dayOfWeek'
|
|
180
|
+
);
|
|
181
|
+
validateDateFormat(schedule.weekly.startDate, 'schedule.weekly.startDate');
|
|
182
|
+
validatePositiveNumber(
|
|
183
|
+
schedule.weekly.quantity,
|
|
184
|
+
'schedule.weekly.quantity'
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Validate monthly schedule
|
|
189
|
+
if (schedule.monthly) {
|
|
190
|
+
if (
|
|
191
|
+
typeof schedule.monthly.dayOfMonth !== 'number' ||
|
|
192
|
+
schedule.monthly.dayOfMonth < 1 ||
|
|
193
|
+
schedule.monthly.dayOfMonth > 31
|
|
194
|
+
) {
|
|
195
|
+
throw new LinaPayError(
|
|
196
|
+
'schedule.monthly.dayOfMonth must be a number between 1 and 31'
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
validateDateFormat(
|
|
200
|
+
schedule.monthly.startDate,
|
|
201
|
+
'schedule.monthly.startDate'
|
|
202
|
+
);
|
|
203
|
+
validatePositiveNumber(
|
|
204
|
+
schedule.monthly.quantity,
|
|
205
|
+
'schedule.monthly.quantity'
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Validate custom schedule
|
|
210
|
+
if (schedule.custom) {
|
|
211
|
+
if (
|
|
212
|
+
!Array.isArray(schedule.custom.dates) ||
|
|
213
|
+
schedule.custom.dates.length === 0
|
|
214
|
+
) {
|
|
215
|
+
throw new LinaPayError(
|
|
216
|
+
'schedule.custom.dates must be a non-empty array'
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
schedule.custom.dates.forEach((date: string, index: number) => {
|
|
221
|
+
validateDateFormat(date, `schedule.custom.dates[${index}]`);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP utilities for error handling and request management
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export class LinaPayError extends Error {
|
|
6
|
+
constructor(
|
|
7
|
+
message: string,
|
|
8
|
+
public statusCode?: number,
|
|
9
|
+
public originalError?: unknown
|
|
10
|
+
) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'LinaPayError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Handle HTTP response errors
|
|
18
|
+
*/
|
|
19
|
+
export async function handleHttpError(response: Response): Promise<never> {
|
|
20
|
+
let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const errorBody = await response.json();
|
|
24
|
+
if (
|
|
25
|
+
errorBody &&
|
|
26
|
+
typeof errorBody === 'object' &&
|
|
27
|
+
'error_description' in errorBody
|
|
28
|
+
) {
|
|
29
|
+
errorMessage = String(errorBody.error_description);
|
|
30
|
+
} else if (
|
|
31
|
+
errorBody &&
|
|
32
|
+
typeof errorBody === 'object' &&
|
|
33
|
+
'message' in errorBody
|
|
34
|
+
) {
|
|
35
|
+
errorMessage = String(errorBody.message);
|
|
36
|
+
} else if (
|
|
37
|
+
errorBody &&
|
|
38
|
+
typeof errorBody === 'object' &&
|
|
39
|
+
'error' in errorBody
|
|
40
|
+
) {
|
|
41
|
+
errorMessage = String(errorBody.error);
|
|
42
|
+
}
|
|
43
|
+
} catch {
|
|
44
|
+
// If response is not JSON, use default message
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
throw new LinaPayError(errorMessage, response.status);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Validate credentials before making requests
|
|
52
|
+
*/
|
|
53
|
+
export function validateCredentials(
|
|
54
|
+
subtenantId: string,
|
|
55
|
+
subtenantSecret: string
|
|
56
|
+
): void {
|
|
57
|
+
if (!subtenantId || subtenantId.trim() === '') {
|
|
58
|
+
throw new LinaPayError('subtenantId is required and cannot be empty');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!subtenantSecret || subtenantSecret.trim() === '') {
|
|
62
|
+
throw new LinaPayError('subtenantSecret is required and cannot be empty');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Handle network errors
|
|
68
|
+
*/
|
|
69
|
+
export function handleNetworkError(error: unknown): never {
|
|
70
|
+
if (error instanceof LinaPayError) {
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const message =
|
|
75
|
+
error instanceof Error
|
|
76
|
+
? `Network error: ${error.message}`
|
|
77
|
+
: 'Unknown network error occurred';
|
|
78
|
+
|
|
79
|
+
throw new LinaPayError(message, undefined, error);
|
|
80
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Payment utilities for payload validation
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { LinaPayError } from './http.utils';
|
|
6
|
+
import type { CreatePaymentRequest } from '../types/payment.types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Validate required string field
|
|
10
|
+
*/
|
|
11
|
+
function validateRequiredString(
|
|
12
|
+
value: string | undefined,
|
|
13
|
+
fieldName: string
|
|
14
|
+
): void {
|
|
15
|
+
if (!value || value.trim() === '') {
|
|
16
|
+
throw new LinaPayError(`${fieldName} is required and cannot be empty`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Validate payment payload before sending to API
|
|
22
|
+
* Throws LinaPayError if validation fails
|
|
23
|
+
*/
|
|
24
|
+
export function validatePaymentPayload(
|
|
25
|
+
payload: CreatePaymentRequest
|
|
26
|
+
): void {
|
|
27
|
+
validateRequiredString(payload.state, 'state');
|
|
28
|
+
validateRequiredString(payload.code, 'code');
|
|
29
|
+
validateRequiredString(payload.idToken, 'idToken');
|
|
30
|
+
validateRequiredString(payload.tenantId, 'tenantId');
|
|
31
|
+
}
|
|
32
|
+
|