react-native-fpay 0.4.5 → 0.4.7

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.
@@ -8,6 +8,8 @@ import axios from 'axios';
8
8
  import { getFPStore } from "../../store/FPStore.js";
9
9
  const DEFAULT_BASE_URL = 'https://kenisha-happiest-nan.ngrok-free.dev/sdk/v1/fpip/';
10
10
  let _client = null;
11
+ let _isRefreshing = false;
12
+ let _retryQueue = [];
11
13
  export function initClient(apiKey, options = {}) {
12
14
  _client = axios.create({
13
15
  baseURL: options.baseUrl ?? DEFAULT_BASE_URL,
@@ -26,12 +28,67 @@ export function initClient(apiKey, options = {}) {
26
28
  // store each time so it's always current after login
27
29
  _client.interceptors.request.use(config => {
28
30
  const accessToken = getFPStore().accessToken;
31
+ console.log('[FPay HTTP] Token on request:', accessToken ? 'present' : 'NULL');
29
32
  if (accessToken) {
30
33
  config.headers.Authorization = `Bearer ${accessToken}`;
31
34
  }
32
35
  return config;
33
36
  });
34
- _client.interceptors.response.use(r => r, err => {
37
+ _client.interceptors.response.use(r => r, async err => {
38
+ const originalRequest = err.config;
39
+
40
+ // Handle 401 — token expired
41
+ if (err.response?.status === 401 && !originalRequest._retry) {
42
+ originalRequest._retry = true; // prevent infinite loop
43
+
44
+ if (_isRefreshing) {
45
+ // Another request already refreshing — queue this one
46
+ return new Promise(resolve => {
47
+ _retryQueue.push(newToken => {
48
+ originalRequest.headers.Authorization = `Bearer ${newToken}`;
49
+ resolve(_client.request(originalRequest));
50
+ });
51
+ });
52
+ }
53
+ _isRefreshing = true;
54
+ try {
55
+ console.log('[FPay HTTP] Token expired — re-authenticating...');
56
+
57
+ // Clear expired token first
58
+ getFPStore().clearAccessToken();
59
+
60
+ // Re-authenticate with the stored API key
61
+ const apiKey = originalRequest.headers['x-api-key'];
62
+ const response = await _client.post('/auth', {
63
+ api_key: apiKey
64
+ });
65
+ if (response.data?.status && response.data?.payload?.access_token) {
66
+ const newToken = response.data.payload.access_token;
67
+ const expiresIn = response.data.payload.expires_in;
68
+
69
+ // Save new token to store
70
+ getFPStore().setAccessToken(newToken, expiresIn);
71
+ console.log('[FPay HTTP] Re-authenticated successfully.');
72
+
73
+ // Retry queued requests with new token
74
+ _retryQueue.forEach(cb => cb(newToken));
75
+ _retryQueue = [];
76
+
77
+ // Retry original request with new token
78
+ originalRequest.headers.Authorization = `Bearer ${newToken}`;
79
+ return _client.request(originalRequest);
80
+ }
81
+ } catch (refreshErr) {
82
+ console.error('[FPay HTTP] Re-authentication failed:', refreshErr);
83
+ _retryQueue = [];
84
+ getFPStore().clearAccessToken();
85
+ getFPStore().setAuthenticated(false, 'Session expired. Please restart the app.');
86
+ } finally {
87
+ _isRefreshing = false;
88
+ }
89
+ }
90
+
91
+ // All other errors — normalize and reject
35
92
  const e = {
36
93
  code: 'UNKNOWN',
37
94
  message: 'An error occurred'
@@ -44,10 +101,6 @@ export function initClient(apiKey, options = {}) {
44
101
  e.code = d.code ?? `HTTP_${err.response.status}`;
45
102
  e.message = d.message ?? err.message;
46
103
  e.statusCode = err.response.status;
47
- if (err.response.status === 401) {
48
- e.code = 'INVALID_API_KEY';
49
- e.message = 'Invalid API key.';
50
- }
51
104
  }
52
105
  return Promise.reject(e);
53
106
  });
@@ -1 +1 @@
1
- {"version":3,"names":["axios","getFPStore","DEFAULT_BASE_URL","_client","initClient","apiKey","options","create","baseURL","baseUrl","timeout","headers","environment","interceptors","request","use","config","accessToken","Authorization","response","r","err","e","code","message","d","data","status","statusCode","Promise","reject","http","Error"],"sourceRoot":"../../../../src","sources":["core/api/client.ts"],"mappings":";;AAAA;AACA;AACA;;AAEA,OAAOA,KAAK,MAA8B,OAAO;AAEjD,SAASC,UAAU,QAAQ,wBAAqB;AAEhD,MAAMC,gBAAgB,GACpB,0DAA0D;AAE5D,IAAIC,OAA6B,GAAG,IAAI;AAExC,OAAO,SAASC,UAAUA,CACxBC,MAAc,EACdC,OAAmD,GAAG,CAAC,CAAC,EAClD;EACNH,OAAO,GAAGH,KAAK,CAACO,MAAM,CAAC;IACrBC,OAAO,EAAEF,OAAO,CAACG,OAAO,IAAIP,gBAAgB;IAC5CQ,OAAO,EAAE,KAAK;IACdC,OAAO,EAAE;MACP,cAAc,EAAE,kBAAkB;MAClC,WAAW,EAAEN,MAAM;MACnB,cAAc,EAAE,OAAO;MACvB,OAAO,EAAE,8BAA8B;MACvC,eAAe,EAAE,OAAO;MACxB,OAAO,EAAEC,OAAO,CAACM,WAAW,IAAI;IAClC;EACF,CAAC,CAAC;;EAEF;EACA;EACAT,OAAO,CAACU,YAAY,CAACC,OAAO,CAACC,GAAG,CAAEC,MAAM,IAAK;IAC3C,MAAMC,WAAW,GAAGhB,UAAU,CAAC,CAAC,CAACgB,WAAW;IAC5C,IAAIA,WAAW,EAAE;MACfD,MAAM,CAACL,OAAO,CAACO,aAAa,GAAG,UAAUD,WAAW,EAAE;IACxD;IACA,OAAOD,MAAM;EACf,CAAC,CAAC;EAEFb,OAAO,CAACU,YAAY,CAACM,QAAQ,CAACJ,GAAG,CAC9BK,CAAC,IAAKA,CAAC,EACPC,GAAG,IAAK;IACP,MAAMC,CAAU,GAAG;MAAEC,IAAI,EAAE,SAAS;MAAEC,OAAO,EAAE;IAAoB,CAAC;IACpE,IAAI,CAACH,GAAG,CAACF,QAAQ,EAAE;MACjBG,CAAC,CAACC,IAAI,GAAG,eAAe;MACxBD,CAAC,CAACE,OAAO,GAAG,uCAAuC;IACrD,CAAC,MAAM;MACL,MAAMC,CAAC,GAAGJ,GAAG,CAACF,QAAQ,CAACO,IAAI,IAAI,CAAC,CAAC;MACjCJ,CAAC,CAACC,IAAI,GAAGE,CAAC,CAACF,IAAI,IAAI,QAAQF,GAAG,CAACF,QAAQ,CAACQ,MAAM,EAAE;MAChDL,CAAC,CAACE,OAAO,GAAGC,CAAC,CAACD,OAAO,IAAIH,GAAG,CAACG,OAAO;MACpCF,CAAC,CAACM,UAAU,GAAGP,GAAG,CAACF,QAAQ,CAACQ,MAAM;MAClC,IAAIN,GAAG,CAACF,QAAQ,CAACQ,MAAM,KAAK,GAAG,EAAE;QAC/BL,CAAC,CAACC,IAAI,GAAG,iBAAiB;QAC1BD,CAAC,CAACE,OAAO,GAAG,kBAAkB;MAChC;IACF;IACA,OAAOK,OAAO,CAACC,MAAM,CAACR,CAAC,CAAC;EAC1B,CACF,CAAC;AACH;AAEA,OAAO,SAASS,IAAIA,CAAA,EAAkB;EACpC,IAAI,CAAC5B,OAAO,EACV,MAAM,IAAI6B,KAAK,CACb,oEACF,CAAC;EACH,OAAO7B,OAAO;AAChB","ignoreList":[]}
1
+ {"version":3,"names":["axios","getFPStore","DEFAULT_BASE_URL","_client","_isRefreshing","_retryQueue","initClient","apiKey","options","create","baseURL","baseUrl","timeout","headers","environment","interceptors","request","use","config","accessToken","console","log","Authorization","response","r","err","originalRequest","status","_retry","Promise","resolve","push","newToken","clearAccessToken","post","api_key","data","payload","access_token","expiresIn","expires_in","setAccessToken","forEach","cb","refreshErr","error","setAuthenticated","e","code","message","d","statusCode","reject","http","Error"],"sourceRoot":"../../../../src","sources":["core/api/client.ts"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../../src/core/api/client.ts"],"names":[],"mappings":"AAIA,OAAc,EAAE,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AASlD,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACvD,IAAI,CA4CN;AAED,wBAAgB,IAAI,IAAI,aAAa,CAMpC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../../src/core/api/client.ts"],"names":[],"mappings":"AAIA,OAAc,EAAE,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAWlD,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACvD,IAAI,CAgGN;AAED,wBAAgB,IAAI,IAAI,aAAa,CAMpC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-fpay",
3
- "version": "0.4.5",
3
+ "version": "0.4.7",
4
4
  "description": "Fountain Pay react-native sdk library",
5
5
  "main": "./lib/module/index.js",
6
6
  "module": "./lib/module/index.js",
@@ -10,6 +10,8 @@ const DEFAULT_BASE_URL =
10
10
  'https://kenisha-happiest-nan.ngrok-free.dev/sdk/v1/fpip/';
11
11
 
12
12
  let _client: AxiosInstance | null = null;
13
+ let _isRefreshing = false;
14
+ let _retryQueue: Array<(token: string) => void> = [];
13
15
 
14
16
  export function initClient(
15
17
  apiKey: string,
@@ -32,6 +34,7 @@ export function initClient(
32
34
  // store each time so it's always current after login
33
35
  _client.interceptors.request.use((config) => {
34
36
  const accessToken = getFPStore().accessToken;
37
+ console.log('[FPay HTTP] Token on request:', accessToken ? 'present' : 'NULL');
35
38
  if (accessToken) {
36
39
  config.headers.Authorization = `Bearer ${accessToken}`;
37
40
  }
@@ -40,7 +43,62 @@ export function initClient(
40
43
 
41
44
  _client.interceptors.response.use(
42
45
  (r) => r,
43
- (err) => {
46
+ async (err) => {
47
+ const originalRequest = err.config;
48
+
49
+ // Handle 401 — token expired
50
+ if (err.response?.status === 401 && !originalRequest._retry) {
51
+ originalRequest._retry = true; // prevent infinite loop
52
+
53
+ if (_isRefreshing) {
54
+ // Another request already refreshing — queue this one
55
+ return new Promise((resolve) => {
56
+ _retryQueue.push((newToken: string) => {
57
+ originalRequest.headers.Authorization = `Bearer ${newToken}`;
58
+ resolve(_client!.request(originalRequest));
59
+ });
60
+ });
61
+ }
62
+
63
+ _isRefreshing = true;
64
+
65
+ try {
66
+ console.log('[FPay HTTP] Token expired — re-authenticating...');
67
+
68
+ // Clear expired token first
69
+ getFPStore().clearAccessToken();
70
+
71
+ // Re-authenticate with the stored API key
72
+ const apiKey = originalRequest.headers['x-api-key'];
73
+ const response = await _client!.post('/auth', { api_key: apiKey });
74
+
75
+ if (response.data?.status && response.data?.payload?.access_token) {
76
+ const newToken = response.data.payload.access_token;
77
+ const expiresIn = response.data.payload.expires_in;
78
+
79
+ // Save new token to store
80
+ getFPStore().setAccessToken(newToken, expiresIn);
81
+ console.log('[FPay HTTP] Re-authenticated successfully.');
82
+
83
+ // Retry queued requests with new token
84
+ _retryQueue.forEach(cb => cb(newToken));
85
+ _retryQueue = [];
86
+
87
+ // Retry original request with new token
88
+ originalRequest.headers.Authorization = `Bearer ${newToken}`;
89
+ return _client!.request(originalRequest);
90
+ }
91
+ } catch (refreshErr) {
92
+ console.error('[FPay HTTP] Re-authentication failed:', refreshErr);
93
+ _retryQueue = [];
94
+ getFPStore().clearAccessToken();
95
+ getFPStore().setAuthenticated(false, 'Session expired. Please restart the app.');
96
+ } finally {
97
+ _isRefreshing = false;
98
+ }
99
+ }
100
+
101
+ // All other errors — normalize and reject
44
102
  const e: FPError = { code: 'UNKNOWN', message: 'An error occurred' };
45
103
  if (!err.response) {
46
104
  e.code = 'NETWORK_ERROR';
@@ -50,10 +108,6 @@ export function initClient(
50
108
  e.code = d.code ?? `HTTP_${err.response.status}`;
51
109
  e.message = d.message ?? err.message;
52
110
  e.statusCode = err.response.status;
53
- if (err.response.status === 401) {
54
- e.code = 'INVALID_API_KEY';
55
- e.message = 'Invalid API key.';
56
- }
57
111
  }
58
112
  return Promise.reject(e);
59
113
  }