@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.
Files changed (82) hide show
  1. package/LinaPaySdk.podspec +20 -0
  2. package/README.md +522 -0
  3. package/android/build.gradle +77 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/src/main/AndroidManifest.xml +2 -0
  6. package/android/src/main/java/com/linapaysdk/LinaPaySdkModule.kt +18 -0
  7. package/android/src/main/java/com/linapaysdk/LinaPaySdkPackage.kt +17 -0
  8. package/ios/LinaPaySdk.h +5 -0
  9. package/ios/LinaPaySdk.mm +16 -0
  10. package/lib/module/config/environment.js +61 -0
  11. package/lib/module/config/environment.js.map +1 -0
  12. package/lib/module/index.js +142 -0
  13. package/lib/module/index.js.map +1 -0
  14. package/lib/module/package.json +1 -0
  15. package/lib/module/services/auth.service.js +73 -0
  16. package/lib/module/services/auth.service.js.map +1 -0
  17. package/lib/module/services/consent.service.js +49 -0
  18. package/lib/module/services/consent.service.js.map +1 -0
  19. package/lib/module/services/participants.service.js +71 -0
  20. package/lib/module/services/participants.service.js.map +1 -0
  21. package/lib/module/services/payment.service.js +39 -0
  22. package/lib/module/services/payment.service.js.map +1 -0
  23. package/lib/module/types/auth.types.js +2 -0
  24. package/lib/module/types/auth.types.js.map +1 -0
  25. package/lib/module/types/consent.types.js +2 -0
  26. package/lib/module/types/consent.types.js.map +1 -0
  27. package/lib/module/types/index.js +2 -0
  28. package/lib/module/types/index.js.map +1 -0
  29. package/lib/module/types/participants.types.js +2 -0
  30. package/lib/module/types/participants.types.js.map +1 -0
  31. package/lib/module/types/payment.types.js +2 -0
  32. package/lib/module/types/payment.types.js.map +1 -0
  33. package/lib/module/utils/consent.utils.js +168 -0
  34. package/lib/module/utils/consent.utils.js.map +1 -0
  35. package/lib/module/utils/http.utils.js +58 -0
  36. package/lib/module/utils/http.utils.js.map +1 -0
  37. package/lib/module/utils/payment.utils.js +27 -0
  38. package/lib/module/utils/payment.utils.js.map +1 -0
  39. package/lib/typescript/package.json +1 -0
  40. package/lib/typescript/src/config/environment.d.ts +38 -0
  41. package/lib/typescript/src/config/environment.d.ts.map +1 -0
  42. package/lib/typescript/src/index.d.ts +108 -0
  43. package/lib/typescript/src/index.d.ts.map +1 -0
  44. package/lib/typescript/src/services/auth.service.d.ts +13 -0
  45. package/lib/typescript/src/services/auth.service.d.ts.map +1 -0
  46. package/lib/typescript/src/services/consent.service.d.ts +9 -0
  47. package/lib/typescript/src/services/consent.service.d.ts.map +1 -0
  48. package/lib/typescript/src/services/participants.service.d.ts +9 -0
  49. package/lib/typescript/src/services/participants.service.d.ts.map +1 -0
  50. package/lib/typescript/src/services/payment.service.d.ts +9 -0
  51. package/lib/typescript/src/services/payment.service.d.ts.map +1 -0
  52. package/lib/typescript/src/types/auth.types.d.ts +23 -0
  53. package/lib/typescript/src/types/auth.types.d.ts.map +1 -0
  54. package/lib/typescript/src/types/consent.types.d.ts +129 -0
  55. package/lib/typescript/src/types/consent.types.d.ts.map +1 -0
  56. package/lib/typescript/src/types/index.d.ts +9 -0
  57. package/lib/typescript/src/types/index.d.ts.map +1 -0
  58. package/lib/typescript/src/types/participants.types.d.ts +50 -0
  59. package/lib/typescript/src/types/participants.types.d.ts.map +1 -0
  60. package/lib/typescript/src/types/payment.types.d.ts +107 -0
  61. package/lib/typescript/src/types/payment.types.d.ts.map +1 -0
  62. package/lib/typescript/src/utils/consent.utils.d.ts +10 -0
  63. package/lib/typescript/src/utils/consent.utils.d.ts.map +1 -0
  64. package/lib/typescript/src/utils/http.utils.d.ts +21 -0
  65. package/lib/typescript/src/utils/http.utils.d.ts.map +1 -0
  66. package/lib/typescript/src/utils/payment.utils.d.ts +10 -0
  67. package/lib/typescript/src/utils/payment.utils.d.ts.map +1 -0
  68. package/package.json +169 -0
  69. package/src/config/environment.ts +58 -0
  70. package/src/index.tsx +178 -0
  71. package/src/services/auth.service.ts +88 -0
  72. package/src/services/consent.service.ts +63 -0
  73. package/src/services/participants.service.ts +89 -0
  74. package/src/services/payment.service.ts +49 -0
  75. package/src/types/auth.types.ts +24 -0
  76. package/src/types/consent.types.ts +152 -0
  77. package/src/types/index.ts +34 -0
  78. package/src/types/participants.types.ts +53 -0
  79. package/src/types/payment.types.ts +141 -0
  80. package/src/utils/consent.utils.ts +225 -0
  81. package/src/utils/http.utils.ts +80 -0
  82. 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
+