@easypayment/medusa-paypal 0.4.7 → 0.4.8

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 (70) hide show
  1. package/.medusa/server/src/admin/index.js +7 -7
  2. package/.medusa/server/src/admin/index.mjs +7 -7
  3. package/.medusa/server/src/api/store/paypal/create-order/route.d.ts.map +1 -1
  4. package/.medusa/server/src/api/store/paypal/create-order/route.js +62 -139
  5. package/.medusa/server/src/api/store/paypal/create-order/route.js.map +1 -1
  6. package/.medusa/server/src/modules/paypal/migrations/20260115120000_create_paypal_connection.js +22 -22
  7. package/.medusa/server/src/modules/paypal/migrations/20260123090000_create_paypal_settings.js +11 -11
  8. package/.medusa/server/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.js +18 -18
  9. package/.medusa/server/src/modules/paypal/migrations/20260401090000_create_paypal_metric.js +16 -16
  10. package/.medusa/server/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.js +20 -20
  11. package/.medusa/server/src/modules/paypal/migrations/20261101090000_remove_paypal_reconciliation_status.js +14 -14
  12. package/.medusa/server/src/modules/paypal/migrations/20261201090000_remove_paypal_audit_log.js +15 -15
  13. package/README.md +142 -142
  14. package/package.json +75 -75
  15. package/src/admin/index.ts +7 -7
  16. package/src/admin/routes/settings/paypal/_components/Tabs.tsx +52 -52
  17. package/src/admin/routes/settings/paypal/_components/Toast.tsx +51 -51
  18. package/src/admin/routes/settings/paypal/additional-settings/page.tsx +200 -200
  19. package/src/admin/routes/settings/paypal/advanced-card-payments/page.tsx +183 -183
  20. package/src/admin/routes/settings/paypal/apple-pay/page.tsx +5 -5
  21. package/src/admin/routes/settings/paypal/connection/page.tsx +754 -754
  22. package/src/admin/routes/settings/paypal/google-pay/page.tsx +5 -5
  23. package/src/admin/routes/settings/paypal/pay-later-messaging/page.tsx +5 -5
  24. package/src/admin/routes/settings/paypal/paypal-settings/page.tsx +376 -376
  25. package/src/api/admin/payment-collections/[id]/payment-sessions/route.ts +24 -24
  26. package/src/api/admin/paypal/disconnect/route.ts +8 -8
  27. package/src/api/admin/paypal/environment/route.ts +25 -25
  28. package/src/api/admin/paypal/onboard-complete/route.ts +44 -44
  29. package/src/api/admin/paypal/onboarding-link/route.ts +45 -45
  30. package/src/api/admin/paypal/onboarding-status/route.ts +18 -18
  31. package/src/api/admin/paypal/rotate-credentials/route.ts +8 -8
  32. package/src/api/admin/paypal/save-credentials/route.ts +14 -14
  33. package/src/api/admin/paypal/settings/route.ts +14 -14
  34. package/src/api/admin/paypal/status/route.ts +12 -12
  35. package/src/api/store/payment-collections/[id]/payment-sessions/route.ts +65 -65
  36. package/src/api/store/paypal/capture-order/route.ts +276 -276
  37. package/src/api/store/paypal/config/route.ts +102 -102
  38. package/src/api/store/paypal/create-order/route.ts +77 -176
  39. package/src/api/store/paypal/settings/route.ts +19 -19
  40. package/src/api/store/paypal/webhook/route.ts +246 -246
  41. package/src/api/store/paypal-complete/route.ts +75 -75
  42. package/src/jobs/paypal-reconcile.ts +112 -112
  43. package/src/jobs/paypal-webhook-retry.ts +85 -85
  44. package/src/modules/paypal/clients/paypal-seller.client.ts +59 -59
  45. package/src/modules/paypal/index.ts +8 -8
  46. package/src/modules/paypal/migrations/20260115120000_create_paypal_connection.ts +33 -33
  47. package/src/modules/paypal/migrations/20260123090000_create_paypal_settings.ts +22 -22
  48. package/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.ts +29 -29
  49. package/src/modules/paypal/migrations/20260401090000_create_paypal_metric.ts +27 -27
  50. package/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.ts +31 -31
  51. package/src/modules/paypal/migrations/20261101090000_remove_paypal_reconciliation_status.ts +25 -25
  52. package/src/modules/paypal/migrations/20261201090000_remove_paypal_audit_log.ts +26 -26
  53. package/src/modules/paypal/migrations/20270101090000_set_paypal_environment_default_live.ts +11 -11
  54. package/src/modules/paypal/models/paypal_connection.ts +21 -21
  55. package/src/modules/paypal/models/paypal_metric.ts +9 -9
  56. package/src/modules/paypal/models/paypal_settings.ts +8 -8
  57. package/src/modules/paypal/models/paypal_webhook_event.ts +19 -19
  58. package/src/modules/paypal/payment-provider/README.md +22 -22
  59. package/src/modules/paypal/payment-provider/card-service.ts +760 -760
  60. package/src/modules/paypal/payment-provider/index.ts +19 -19
  61. package/src/modules/paypal/payment-provider/service.ts +1121 -1121
  62. package/src/modules/paypal/payment-provider/webhook-utils.ts +88 -88
  63. package/src/modules/paypal/service.ts +1247 -1247
  64. package/src/modules/paypal/types/config.ts +47 -47
  65. package/src/modules/paypal/utils/amounts.ts +41 -41
  66. package/src/modules/paypal/utils/crypto.ts +51 -51
  67. package/src/modules/paypal/utils/currencies.ts +84 -84
  68. package/src/modules/paypal/utils/paypal-auth.ts +32 -32
  69. package/src/modules/paypal/utils/provider-ids.ts +15 -15
  70. package/src/modules/paypal/webhook-processor.ts +215 -215
@@ -1,47 +1,47 @@
1
- export type PayPalModuleConfig = {
2
- partnerServiceUrl: string
3
- partnerJsUrl: string
4
- backendUrl: string
5
- sellerNonce: string
6
- bnCode?: string
7
- partnerMerchantIdSandbox: string
8
- partnerMerchantIdLive: string
9
- credentialsEncryptionKey?: string
10
- credentialsEncryptionKeyPrevious?: string[]
11
- alertWebhookUrls?: string[]
12
- }
13
-
14
- const STATIC_CFG: PayPalModuleConfig = {
15
- partnerServiceUrl: "https://mbjtechnolabs.com/ppcp-seller-onboarding/seller-onboarding.php",
16
- partnerJsUrl: "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js",
17
- backendUrl: "http://localhost:9000",
18
- sellerNonce: "a1233wtergfsdt4365tzrshgfbaewa36AGa1233wtergfsdt4365tzrshgfbaewa36AG",
19
- bnCode: "",
20
- partnerMerchantIdSandbox: "K6QLN2LPGQRHL",
21
- partnerMerchantIdLive: "GT5R877JNBPLL",
22
- credentialsEncryptionKey: "",
23
- credentialsEncryptionKeyPrevious: [],
24
- alertWebhookUrls: [],
25
- }
26
-
27
- export function getPayPalConfig(): PayPalModuleConfig {
28
- const previousKeys = (process.env.PAYPAL_CREDENTIALS_ENCRYPTION_KEY_PREVIOUS || "")
29
- .split(",")
30
- .map((key) => key.trim())
31
- .filter(Boolean)
32
-
33
- return {
34
- ...STATIC_CFG,
35
- backendUrl: process.env.MEDUSA_BACKEND_URL || STATIC_CFG.backendUrl,
36
- credentialsEncryptionKey:
37
- process.env.PAYPAL_CREDENTIALS_ENCRYPTION_KEY ||
38
- STATIC_CFG.credentialsEncryptionKey,
39
- credentialsEncryptionKeyPrevious:
40
- previousKeys.length > 0 ? previousKeys : STATIC_CFG.credentialsEncryptionKeyPrevious,
41
- alertWebhookUrls:
42
- (process.env.PAYPAL_ALERT_WEBHOOK_URLS || "")
43
- .split(",")
44
- .map((url) => url.trim())
45
- .filter(Boolean) || STATIC_CFG.alertWebhookUrls,
46
- }
47
- }
1
+ export type PayPalModuleConfig = {
2
+ partnerServiceUrl: string
3
+ partnerJsUrl: string
4
+ backendUrl: string
5
+ sellerNonce: string
6
+ bnCode?: string
7
+ partnerMerchantIdSandbox: string
8
+ partnerMerchantIdLive: string
9
+ credentialsEncryptionKey?: string
10
+ credentialsEncryptionKeyPrevious?: string[]
11
+ alertWebhookUrls?: string[]
12
+ }
13
+
14
+ const STATIC_CFG: PayPalModuleConfig = {
15
+ partnerServiceUrl: "https://mbjtechnolabs.com/ppcp-seller-onboarding/seller-onboarding.php",
16
+ partnerJsUrl: "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js",
17
+ backendUrl: "http://localhost:9000",
18
+ sellerNonce: "a1233wtergfsdt4365tzrshgfbaewa36AGa1233wtergfsdt4365tzrshgfbaewa36AG",
19
+ bnCode: "",
20
+ partnerMerchantIdSandbox: "K6QLN2LPGQRHL",
21
+ partnerMerchantIdLive: "GT5R877JNBPLL",
22
+ credentialsEncryptionKey: "",
23
+ credentialsEncryptionKeyPrevious: [],
24
+ alertWebhookUrls: [],
25
+ }
26
+
27
+ export function getPayPalConfig(): PayPalModuleConfig {
28
+ const previousKeys = (process.env.PAYPAL_CREDENTIALS_ENCRYPTION_KEY_PREVIOUS || "")
29
+ .split(",")
30
+ .map((key) => key.trim())
31
+ .filter(Boolean)
32
+
33
+ return {
34
+ ...STATIC_CFG,
35
+ backendUrl: process.env.MEDUSA_BACKEND_URL || STATIC_CFG.backendUrl,
36
+ credentialsEncryptionKey:
37
+ process.env.PAYPAL_CREDENTIALS_ENCRYPTION_KEY ||
38
+ STATIC_CFG.credentialsEncryptionKey,
39
+ credentialsEncryptionKeyPrevious:
40
+ previousKeys.length > 0 ? previousKeys : STATIC_CFG.credentialsEncryptionKeyPrevious,
41
+ alertWebhookUrls:
42
+ (process.env.PAYPAL_ALERT_WEBHOOK_URLS || "")
43
+ .split(",")
44
+ .map((url) => url.trim())
45
+ .filter(Boolean) || STATIC_CFG.alertWebhookUrls,
46
+ }
47
+ }
@@ -1,41 +1,41 @@
1
- const ZERO_DECIMAL_CURRENCIES = new Set([
2
- "BIF",
3
- "CLP",
4
- "DJF",
5
- "GNF",
6
- "JPY",
7
- "KMF",
8
- "KRW",
9
- "MGA",
10
- "PYG",
11
- "RWF",
12
- "UGX",
13
- "VND",
14
- "VUV",
15
- "XAF",
16
- "XOF",
17
- "XPF",
18
- ])
19
-
20
- const THREE_DECIMAL_CURRENCIES = new Set(["BHD", "JOD", "KWD", "OMR", "TND"])
21
-
22
- export function getCurrencyExponent(currencyCode: string) {
23
- const code = currencyCode.toUpperCase()
24
- if (ZERO_DECIMAL_CURRENCIES.has(code)) {
25
- return 0
26
- }
27
- if (THREE_DECIMAL_CURRENCIES.has(code)) {
28
- return 3
29
- }
30
- return 2
31
- }
32
-
33
- export function formatAmountForPayPal(
34
- minorAmount: number,
35
- currencyCode: string
36
- ) {
37
- const exponent = getCurrencyExponent(currencyCode)
38
- const factor = 10 ** exponent
39
- const majorAmount = Number(minorAmount || 0) / factor
40
- return majorAmount.toFixed(exponent)
41
- }
1
+ const ZERO_DECIMAL_CURRENCIES = new Set([
2
+ "BIF",
3
+ "CLP",
4
+ "DJF",
5
+ "GNF",
6
+ "JPY",
7
+ "KMF",
8
+ "KRW",
9
+ "MGA",
10
+ "PYG",
11
+ "RWF",
12
+ "UGX",
13
+ "VND",
14
+ "VUV",
15
+ "XAF",
16
+ "XOF",
17
+ "XPF",
18
+ ])
19
+
20
+ const THREE_DECIMAL_CURRENCIES = new Set(["BHD", "JOD", "KWD", "OMR", "TND"])
21
+
22
+ export function getCurrencyExponent(currencyCode: string) {
23
+ const code = currencyCode.toUpperCase()
24
+ if (ZERO_DECIMAL_CURRENCIES.has(code)) {
25
+ return 0
26
+ }
27
+ if (THREE_DECIMAL_CURRENCIES.has(code)) {
28
+ return 3
29
+ }
30
+ return 2
31
+ }
32
+
33
+ export function formatAmountForPayPal(
34
+ minorAmount: number,
35
+ currencyCode: string
36
+ ) {
37
+ const exponent = getCurrencyExponent(currencyCode)
38
+ const factor = 10 ** exponent
39
+ const majorAmount = Number(minorAmount || 0) / factor
40
+ return majorAmount.toFixed(exponent)
41
+ }
@@ -1,51 +1,51 @@
1
- import { createCipheriv, createDecipheriv, createHash, randomBytes } from "crypto"
2
-
3
- const ENCRYPTED_PREFIX = "enc:"
4
- const ALGORITHM = "aes-256-gcm"
5
- const IV_LENGTH = 12
6
-
7
- function deriveKey(secret: string) {
8
- return createHash("sha256").update(secret).digest()
9
- }
10
-
11
- export function isEncryptedSecret(value?: string | null) {
12
- return typeof value === "string" && value.startsWith(ENCRYPTED_PREFIX)
13
- }
14
-
15
- export function encryptSecret(value: string, secret: string) {
16
- if (!value || isEncryptedSecret(value)) {
17
- return value
18
- }
19
-
20
- const iv = randomBytes(IV_LENGTH)
21
- const cipher = createCipheriv(ALGORITHM, deriveKey(secret), iv)
22
- const encrypted = Buffer.concat([cipher.update(value, "utf8"), cipher.final()])
23
- const tag = cipher.getAuthTag()
24
-
25
- return [
26
- ENCRYPTED_PREFIX.slice(0, -1),
27
- iv.toString("base64"),
28
- tag.toString("base64"),
29
- encrypted.toString("base64"),
30
- ].join(":")
31
- }
32
-
33
- export function decryptSecret(value: string, secret: string) {
34
- if (!isEncryptedSecret(value)) {
35
- return value
36
- }
37
-
38
- const [, ivBase64, tagBase64, payloadBase64] = value.split(":")
39
- if (!ivBase64 || !tagBase64 || !payloadBase64) {
40
- throw new Error("Invalid encrypted PayPal secret format.")
41
- }
42
-
43
- const iv = Buffer.from(ivBase64, "base64")
44
- const tag = Buffer.from(tagBase64, "base64")
45
- const payload = Buffer.from(payloadBase64, "base64")
46
- const decipher = createDecipheriv(ALGORITHM, deriveKey(secret), iv)
47
- decipher.setAuthTag(tag)
48
- const decrypted = Buffer.concat([decipher.update(payload), decipher.final()])
49
-
50
- return decrypted.toString("utf8")
51
- }
1
+ import { createCipheriv, createDecipheriv, createHash, randomBytes } from "crypto"
2
+
3
+ const ENCRYPTED_PREFIX = "enc:"
4
+ const ALGORITHM = "aes-256-gcm"
5
+ const IV_LENGTH = 12
6
+
7
+ function deriveKey(secret: string) {
8
+ return createHash("sha256").update(secret).digest()
9
+ }
10
+
11
+ export function isEncryptedSecret(value?: string | null) {
12
+ return typeof value === "string" && value.startsWith(ENCRYPTED_PREFIX)
13
+ }
14
+
15
+ export function encryptSecret(value: string, secret: string) {
16
+ if (!value || isEncryptedSecret(value)) {
17
+ return value
18
+ }
19
+
20
+ const iv = randomBytes(IV_LENGTH)
21
+ const cipher = createCipheriv(ALGORITHM, deriveKey(secret), iv)
22
+ const encrypted = Buffer.concat([cipher.update(value, "utf8"), cipher.final()])
23
+ const tag = cipher.getAuthTag()
24
+
25
+ return [
26
+ ENCRYPTED_PREFIX.slice(0, -1),
27
+ iv.toString("base64"),
28
+ tag.toString("base64"),
29
+ encrypted.toString("base64"),
30
+ ].join(":")
31
+ }
32
+
33
+ export function decryptSecret(value: string, secret: string) {
34
+ if (!isEncryptedSecret(value)) {
35
+ return value
36
+ }
37
+
38
+ const [, ivBase64, tagBase64, payloadBase64] = value.split(":")
39
+ if (!ivBase64 || !tagBase64 || !payloadBase64) {
40
+ throw new Error("Invalid encrypted PayPal secret format.")
41
+ }
42
+
43
+ const iv = Buffer.from(ivBase64, "base64")
44
+ const tag = Buffer.from(tagBase64, "base64")
45
+ const payload = Buffer.from(payloadBase64, "base64")
46
+ const decipher = createDecipheriv(ALGORITHM, deriveKey(secret), iv)
47
+ decipher.setAuthTag(tag)
48
+ const decrypted = Buffer.concat([decipher.update(payload), decipher.final()])
49
+
50
+ return decrypted.toString("utf8")
51
+ }
@@ -1,84 +1,84 @@
1
- const PAYPAL_SUPPORTED_CURRENCIES = new Set([
2
- "AUD",
3
- "BRL",
4
- "CAD",
5
- "CHF",
6
- "CZK",
7
- "DKK",
8
- "EUR",
9
- "GBP",
10
- "HKD",
11
- "HUF",
12
- "ILS",
13
- "JPY",
14
- "MXN",
15
- "MYR",
16
- "NOK",
17
- "NZD",
18
- "PHP",
19
- "PLN",
20
- "SEK",
21
- "SGD",
22
- "THB",
23
- "TWD",
24
- "USD",
25
- ])
26
-
27
- type CurrencyCheck = {
28
- currency: string
29
- overrideCurrency?: string
30
- supported: boolean
31
- errors: string[]
32
- }
33
-
34
- export function normalizeCurrencyCode(code?: string, fallback = "EUR") {
35
- const trimmed = String(code || "").trim()
36
- return (trimmed || fallback).toUpperCase()
37
- }
38
-
39
- export function isPayPalCurrencySupported(currencyCode: string) {
40
- return PAYPAL_SUPPORTED_CURRENCIES.has(normalizeCurrencyCode(currencyCode))
41
- }
42
-
43
- export function getPayPalCurrencyCompatibility(input: {
44
- currencyCode?: string
45
- paypalCurrencyOverride?: string
46
- }): CurrencyCheck {
47
- const currency = normalizeCurrencyCode(input.currencyCode)
48
- const overrideCurrency = input.paypalCurrencyOverride
49
- ? normalizeCurrencyCode(input.paypalCurrencyOverride)
50
- : undefined
51
- const errors: string[] = []
52
-
53
- if (!isPayPalCurrencySupported(currency)) {
54
- errors.push(`PayPal does not support currency "${currency}".`)
55
- }
56
-
57
- if (overrideCurrency && overrideCurrency !== currency) {
58
- errors.push(
59
- `PayPal is configured for "${overrideCurrency}", but the store cart uses "${currency}".`
60
- )
61
- }
62
-
63
- return {
64
- currency,
65
- overrideCurrency,
66
- supported: errors.length === 0,
67
- errors,
68
- }
69
- }
70
-
71
- export function assertPayPalCurrencySupported(input: {
72
- currencyCode?: string
73
- paypalCurrencyOverride?: string
74
- }) {
75
- const result = getPayPalCurrencyCompatibility(input)
76
- if (!result.supported) {
77
- throw new Error(result.errors.join(" "))
78
- }
79
- return result
80
- }
81
-
82
- export function getPayPalSupportedCurrencies() {
83
- return Array.from(PAYPAL_SUPPORTED_CURRENCIES.values())
84
- }
1
+ const PAYPAL_SUPPORTED_CURRENCIES = new Set([
2
+ "AUD",
3
+ "BRL",
4
+ "CAD",
5
+ "CHF",
6
+ "CZK",
7
+ "DKK",
8
+ "EUR",
9
+ "GBP",
10
+ "HKD",
11
+ "HUF",
12
+ "ILS",
13
+ "JPY",
14
+ "MXN",
15
+ "MYR",
16
+ "NOK",
17
+ "NZD",
18
+ "PHP",
19
+ "PLN",
20
+ "SEK",
21
+ "SGD",
22
+ "THB",
23
+ "TWD",
24
+ "USD",
25
+ ])
26
+
27
+ type CurrencyCheck = {
28
+ currency: string
29
+ overrideCurrency?: string
30
+ supported: boolean
31
+ errors: string[]
32
+ }
33
+
34
+ export function normalizeCurrencyCode(code?: string, fallback = "EUR") {
35
+ const trimmed = String(code || "").trim()
36
+ return (trimmed || fallback).toUpperCase()
37
+ }
38
+
39
+ export function isPayPalCurrencySupported(currencyCode: string) {
40
+ return PAYPAL_SUPPORTED_CURRENCIES.has(normalizeCurrencyCode(currencyCode))
41
+ }
42
+
43
+ export function getPayPalCurrencyCompatibility(input: {
44
+ currencyCode?: string
45
+ paypalCurrencyOverride?: string
46
+ }): CurrencyCheck {
47
+ const currency = normalizeCurrencyCode(input.currencyCode)
48
+ const overrideCurrency = input.paypalCurrencyOverride
49
+ ? normalizeCurrencyCode(input.paypalCurrencyOverride)
50
+ : undefined
51
+ const errors: string[] = []
52
+
53
+ if (!isPayPalCurrencySupported(currency)) {
54
+ errors.push(`PayPal does not support currency "${currency}".`)
55
+ }
56
+
57
+ if (overrideCurrency && overrideCurrency !== currency) {
58
+ errors.push(
59
+ `PayPal is configured for "${overrideCurrency}", but the store cart uses "${currency}".`
60
+ )
61
+ }
62
+
63
+ return {
64
+ currency,
65
+ overrideCurrency,
66
+ supported: errors.length === 0,
67
+ errors,
68
+ }
69
+ }
70
+
71
+ export function assertPayPalCurrencySupported(input: {
72
+ currencyCode?: string
73
+ paypalCurrencyOverride?: string
74
+ }) {
75
+ const result = getPayPalCurrencyCompatibility(input)
76
+ if (!result.supported) {
77
+ throw new Error(result.errors.join(" "))
78
+ }
79
+ return result
80
+ }
81
+
82
+ export function getPayPalSupportedCurrencies() {
83
+ return Array.from(PAYPAL_SUPPORTED_CURRENCIES.values())
84
+ }
@@ -1,32 +1,32 @@
1
- /**
2
- * Shared PayPal API authentication helpers.
3
- * Import these instead of copying into each route.
4
- */
5
- export function getPayPalApiBase(environment: string): string {
6
- return environment === "live"
7
- ? "https://api-m.paypal.com"
8
- : "https://api-m.sandbox.paypal.com"
9
- }
10
-
11
- export async function getPayPalAccessToken(opts: {
12
- environment: string
13
- client_id: string
14
- client_secret: string
15
- }): Promise<{ accessToken: string; base: string }> {
16
- const base = getPayPalApiBase(opts.environment)
17
- const auth = Buffer.from(`${opts.client_id}:${opts.client_secret}`).toString("base64")
18
- const resp = await fetch(`${base}/v1/oauth2/token`, {
19
- method: "POST",
20
- headers: {
21
- Authorization: `Basic ${auth}`,
22
- "Content-Type": "application/x-www-form-urlencoded",
23
- },
24
- body: "grant_type=client_credentials",
25
- })
26
- const text = await resp.text()
27
- if (!resp.ok) {
28
- throw new Error(`PayPal token error (${resp.status}): ${text}`)
29
- }
30
- const json = JSON.parse(text)
31
- return { accessToken: String(json.access_token), base }
32
- }
1
+ /**
2
+ * Shared PayPal API authentication helpers.
3
+ * Import these instead of copying into each route.
4
+ */
5
+ export function getPayPalApiBase(environment: string): string {
6
+ return environment === "live"
7
+ ? "https://api-m.paypal.com"
8
+ : "https://api-m.sandbox.paypal.com"
9
+ }
10
+
11
+ export async function getPayPalAccessToken(opts: {
12
+ environment: string
13
+ client_id: string
14
+ client_secret: string
15
+ }): Promise<{ accessToken: string; base: string }> {
16
+ const base = getPayPalApiBase(opts.environment)
17
+ const auth = Buffer.from(`${opts.client_id}:${opts.client_secret}`).toString("base64")
18
+ const resp = await fetch(`${base}/v1/oauth2/token`, {
19
+ method: "POST",
20
+ headers: {
21
+ Authorization: `Basic ${auth}`,
22
+ "Content-Type": "application/x-www-form-urlencoded",
23
+ },
24
+ body: "grant_type=client_credentials",
25
+ })
26
+ const text = await resp.text()
27
+ if (!resp.ok) {
28
+ throw new Error(`PayPal token error (${resp.status}): ${text}`)
29
+ }
30
+ const json = JSON.parse(text)
31
+ return { accessToken: String(json.access_token), base }
32
+ }
@@ -1,15 +1,15 @@
1
- export const PAYPAL_WALLET_PROVIDER_ID = "pp_paypal_paypal" as const
2
- export const PAYPAL_CARD_PROVIDER_ID = "pp_paypal_card_paypal_card" as const
3
-
4
- export const PAYPAL_PROVIDER_IDS = [
5
- PAYPAL_WALLET_PROVIDER_ID,
6
- PAYPAL_CARD_PROVIDER_ID,
7
- ] as const
8
-
9
- export const isPayPalProviderId = (providerId?: string | null) => {
10
- if (!providerId) return false
11
-
12
- return PAYPAL_PROVIDER_IDS.includes(
13
- providerId as (typeof PAYPAL_PROVIDER_IDS)[number]
14
- )
15
- }
1
+ export const PAYPAL_WALLET_PROVIDER_ID = "pp_paypal_paypal" as const
2
+ export const PAYPAL_CARD_PROVIDER_ID = "pp_paypal_card_paypal_card" as const
3
+
4
+ export const PAYPAL_PROVIDER_IDS = [
5
+ PAYPAL_WALLET_PROVIDER_ID,
6
+ PAYPAL_CARD_PROVIDER_ID,
7
+ ] as const
8
+
9
+ export const isPayPalProviderId = (providerId?: string | null) => {
10
+ if (!providerId) return false
11
+
12
+ return PAYPAL_PROVIDER_IDS.includes(
13
+ providerId as (typeof PAYPAL_PROVIDER_IDS)[number]
14
+ )
15
+ }