backend-manager 5.0.110 → 5.0.111
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
CHANGED
package/src/manager/index.js
CHANGED
|
@@ -138,6 +138,9 @@ Manager.prototype.init = function (exporter, options) {
|
|
|
138
138
|
(_objValue, srcValue) => isArray(srcValue) ? srcValue : undefined,
|
|
139
139
|
);
|
|
140
140
|
|
|
141
|
+
// Set PAYPAL_CLIENT_ID from config (clientId is public, not a secret — lives in config, not .env)
|
|
142
|
+
process.env.PAYPAL_CLIENT_ID = process.env.PAYPAL_CLIENT_ID || self.config?.payment?.processors?.paypal?.clientId || '';
|
|
143
|
+
|
|
141
144
|
// Resolve legacy paths
|
|
142
145
|
// TODO: Remove this in future versions (after we migrate to removing app.id from config)
|
|
143
146
|
self.config.app = self.config.app || {};
|
|
@@ -8,12 +8,41 @@ const EPOCH_ZERO_UNIX = powertools.timestamp(EPOCH_ZERO, { output: 'unix' });
|
|
|
8
8
|
const INTERVAL_TO_FREQUENCY = { YEAR: 'annually', MONTH: 'monthly', WEEK: 'weekly', DAY: 'daily' };
|
|
9
9
|
const FREQUENCY_TO_INTERVAL = { annually: 'YEAR', monthly: 'MONTH', weekly: 'WEEK', daily: 'DAY' };
|
|
10
10
|
|
|
11
|
-
// PayPal API base
|
|
12
|
-
const
|
|
11
|
+
// PayPal API base URLs
|
|
12
|
+
const LIVE_URL = 'https://api-m.paypal.com';
|
|
13
|
+
const SANDBOX_URL = 'https://api-m.sandbox.paypal.com';
|
|
13
14
|
|
|
14
|
-
// Cached access token
|
|
15
|
+
// Cached access token, expiry, and resolved base URL
|
|
15
16
|
let cachedToken = null;
|
|
16
17
|
let tokenExpiresAt = 0;
|
|
18
|
+
let resolvedBaseUrl = null;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Try to authenticate against a specific PayPal endpoint
|
|
22
|
+
* @param {string} auth - Base64-encoded client_id:secret
|
|
23
|
+
* @param {string} baseUrl - PayPal API base URL
|
|
24
|
+
* @returns {Promise<object|null>} Token data or null if auth failed
|
|
25
|
+
*/
|
|
26
|
+
async function tryAuth(auth, baseUrl) {
|
|
27
|
+
try {
|
|
28
|
+
const response = await fetch(`${baseUrl}/v1/oauth2/token`, {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: {
|
|
31
|
+
'Authorization': `Basic ${auth}`,
|
|
32
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
33
|
+
},
|
|
34
|
+
body: 'grant_type=client_credentials',
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (!response.ok) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return await response.json();
|
|
42
|
+
} catch (e) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
17
46
|
|
|
18
47
|
/**
|
|
19
48
|
* PayPal shared library
|
|
@@ -22,7 +51,7 @@ let tokenExpiresAt = 0;
|
|
|
22
51
|
const PayPal = {
|
|
23
52
|
/**
|
|
24
53
|
* Initialize or return a PayPal access token
|
|
25
|
-
*
|
|
54
|
+
* Tries both live and sandbox endpoints in parallel on first auth
|
|
26
55
|
* @returns {Promise<string>} Access token
|
|
27
56
|
*/
|
|
28
57
|
async init() {
|
|
@@ -40,22 +69,39 @@ const PayPal = {
|
|
|
40
69
|
|
|
41
70
|
const auth = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
|
|
42
71
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
72
|
+
// First auth — try both endpoints in parallel to detect environment
|
|
73
|
+
if (!resolvedBaseUrl) {
|
|
74
|
+
const [liveResult, sandboxResult] = await Promise.all([
|
|
75
|
+
tryAuth(auth, LIVE_URL),
|
|
76
|
+
tryAuth(auth, SANDBOX_URL),
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
if (liveResult) {
|
|
80
|
+
resolvedBaseUrl = LIVE_URL;
|
|
81
|
+
cachedToken = liveResult.access_token;
|
|
82
|
+
tokenExpiresAt = Date.now() + (liveResult.expires_in * 1000);
|
|
83
|
+
return cachedToken;
|
|
84
|
+
}
|
|
51
85
|
|
|
52
|
-
|
|
53
|
-
|
|
86
|
+
if (sandboxResult) {
|
|
87
|
+
resolvedBaseUrl = SANDBOX_URL;
|
|
88
|
+
cachedToken = sandboxResult.access_token;
|
|
89
|
+
tokenExpiresAt = Date.now() + (sandboxResult.expires_in * 1000);
|
|
90
|
+
return cachedToken;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
throw new Error('PayPal auth failed on both live and sandbox — check your client ID and secret');
|
|
54
94
|
}
|
|
55
95
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
96
|
+
// Subsequent auths — use the resolved endpoint
|
|
97
|
+
const result = await tryAuth(auth, resolvedBaseUrl);
|
|
98
|
+
|
|
99
|
+
if (!result) {
|
|
100
|
+
throw new Error(`PayPal auth failed (${resolvedBaseUrl})`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
cachedToken = result.access_token;
|
|
104
|
+
tokenExpiresAt = Date.now() + (result.expires_in * 1000);
|
|
59
105
|
|
|
60
106
|
return cachedToken;
|
|
61
107
|
},
|
|
@@ -69,7 +115,7 @@ const PayPal = {
|
|
|
69
115
|
async request(endpoint, options = {}) {
|
|
70
116
|
const token = await this.init();
|
|
71
117
|
|
|
72
|
-
const response = await fetch(`${
|
|
118
|
+
const response = await fetch(`${resolvedBaseUrl}${endpoint}`, {
|
|
73
119
|
...options,
|
|
74
120
|
headers: {
|
|
75
121
|
'Authorization': `Bearer ${token}`,
|