@easypayment/medusa-paypal 0.6.2 → 0.6.4

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 (68) hide show
  1. package/.medusa/server/src/admin/index.js +12 -15
  2. package/.medusa/server/src/admin/index.mjs +12 -15
  3. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.d.ts.map +1 -1
  4. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.js.map +1 -1
  5. package/.medusa/server/src/api/store/paypal/capture-order/route.d.ts.map +1 -1
  6. package/.medusa/server/src/api/store/paypal/capture-order/route.js +1 -11
  7. package/.medusa/server/src/api/store/paypal/capture-order/route.js.map +1 -1
  8. package/.medusa/server/src/api/store/paypal/create-order/route.d.ts.map +1 -1
  9. package/.medusa/server/src/api/store/paypal/create-order/route.js +0 -9
  10. package/.medusa/server/src/api/store/paypal/create-order/route.js.map +1 -1
  11. package/.medusa/server/src/api/store/paypal/webhook/route.d.ts.map +1 -1
  12. package/.medusa/server/src/api/store/paypal/webhook/route.js +162 -115
  13. package/.medusa/server/src/api/store/paypal/webhook/route.js.map +1 -1
  14. package/.medusa/server/src/api/store/paypal-complete/route.d.ts.map +1 -1
  15. package/.medusa/server/src/api/store/paypal-complete/route.js +0 -6
  16. package/.medusa/server/src/api/store/paypal-complete/route.js.map +1 -1
  17. package/.medusa/server/src/jobs/paypal-webhook-retry.d.ts.map +1 -1
  18. package/.medusa/server/src/jobs/paypal-webhook-retry.js +97 -43
  19. package/.medusa/server/src/jobs/paypal-webhook-retry.js.map +1 -1
  20. package/.medusa/server/src/modules/paypal/migrations/20270201000000_add_webhook_dead_letter.d.ts +6 -0
  21. package/.medusa/server/src/modules/paypal/migrations/20270201000000_add_webhook_dead_letter.d.ts.map +1 -0
  22. package/.medusa/server/src/modules/paypal/migrations/20270201000000_add_webhook_dead_letter.js +20 -0
  23. package/.medusa/server/src/modules/paypal/migrations/20270201000000_add_webhook_dead_letter.js.map +1 -0
  24. package/.medusa/server/src/modules/paypal/payment-provider/service.d.ts.map +1 -1
  25. package/.medusa/server/src/modules/paypal/payment-provider/service.js +0 -42
  26. package/.medusa/server/src/modules/paypal/payment-provider/service.js.map +1 -1
  27. package/.medusa/server/src/modules/paypal/service.d.ts +0 -8
  28. package/.medusa/server/src/modules/paypal/service.d.ts.map +1 -1
  29. package/.medusa/server/src/modules/paypal/service.js +6 -114
  30. package/.medusa/server/src/modules/paypal/service.js.map +1 -1
  31. package/.medusa/server/src/modules/paypal/types/config.d.ts +0 -2
  32. package/.medusa/server/src/modules/paypal/types/config.d.ts.map +1 -1
  33. package/.medusa/server/src/modules/paypal/types/config.js +0 -9
  34. package/.medusa/server/src/modules/paypal/types/config.js.map +1 -1
  35. package/.medusa/server/src/modules/paypal/webhook-processor.d.ts +21 -17
  36. package/.medusa/server/src/modules/paypal/webhook-processor.d.ts.map +1 -1
  37. package/.medusa/server/src/modules/paypal/webhook-processor.js +195 -99
  38. package/.medusa/server/src/modules/paypal/webhook-processor.js.map +1 -1
  39. package/README.md +156 -159
  40. package/package.json +1 -1
  41. package/src/admin/routes/settings/paypal/_components/Tabs.tsx +48 -52
  42. package/src/admin/routes/settings/paypal/paypal-settings/page.tsx +0 -23
  43. package/src/api/store/payment-collections/[id]/payment-sessions/route.ts +56 -65
  44. package/src/api/store/paypal/capture-order/route.ts +266 -276
  45. package/src/api/store/paypal/create-order/route.ts +0 -9
  46. package/src/api/store/paypal/webhook/route.ts +325 -246
  47. package/src/api/store/paypal-complete/route.ts +69 -75
  48. package/src/jobs/paypal-webhook-retry.ts +149 -85
  49. package/src/modules/paypal/migrations/20270201000000_add_webhook_dead_letter.ts +17 -0
  50. package/src/modules/paypal/payment-provider/service.ts +1079 -1121
  51. package/src/modules/paypal/service.ts +6 -127
  52. package/src/modules/paypal/types/config.ts +33 -47
  53. package/src/modules/paypal/webhook-processor.ts +377 -215
  54. package/.medusa/server/src/api/admin/paypal/rotate-credentials/route.d.ts +0 -3
  55. package/.medusa/server/src/api/admin/paypal/rotate-credentials/route.d.ts.map +0 -1
  56. package/.medusa/server/src/api/admin/paypal/rotate-credentials/route.js +0 -9
  57. package/.medusa/server/src/api/admin/paypal/rotate-credentials/route.js.map +0 -1
  58. package/.medusa/server/src/jobs/paypal-reconcile.d.ts +0 -7
  59. package/.medusa/server/src/jobs/paypal-reconcile.d.ts.map +0 -1
  60. package/.medusa/server/src/jobs/paypal-reconcile.js +0 -109
  61. package/.medusa/server/src/jobs/paypal-reconcile.js.map +0 -1
  62. package/.medusa/server/src/modules/paypal/utils/crypto.d.ts +0 -4
  63. package/.medusa/server/src/modules/paypal/utils/crypto.d.ts.map +0 -1
  64. package/.medusa/server/src/modules/paypal/utils/crypto.js +0 -47
  65. package/.medusa/server/src/modules/paypal/utils/crypto.js.map +0 -1
  66. package/src/api/admin/paypal/rotate-credentials/route.ts +0 -8
  67. package/src/jobs/paypal-reconcile.ts +0 -113
  68. package/src/modules/paypal/utils/crypto.ts +0 -51
@@ -4,7 +4,6 @@ import PayPalMetric from "./models/paypal_metric"
4
4
  import PayPalSettings from "./models/paypal_settings"
5
5
  import PayPalWebhookEvent from "./models/paypal_webhook_event"
6
6
  import { getPayPalConfig } from "./types/config"
7
- import { decryptSecret, encryptSecret, isEncryptedSecret } from "./utils/crypto"
8
7
  import { normalizeCurrencyCode } from "./utils/currencies"
9
8
 
10
9
  type Environment = "sandbox" | "live"
@@ -99,59 +98,6 @@ class PayPalModuleService extends MedusaService({
99
98
  return (this.cfg.alertWebhookUrls || []).map((url) => url.trim()).filter(Boolean)
100
99
  }
101
100
 
102
- private getEncryptionKey() {
103
- return (this.cfg.credentialsEncryptionKey || "").trim()
104
- }
105
-
106
- private getDecryptionKeys() {
107
- const current = this.getEncryptionKey()
108
- const previous = this.cfg.credentialsEncryptionKeyPrevious || []
109
- const keys = [current, ...previous].map((key) => (key || "").trim()).filter(Boolean)
110
- return Array.from(new Set(keys))
111
- }
112
-
113
- private decryptSecretWithKeys(secret: string, keys: string[]) {
114
- let lastError: unknown
115
- for (const key of keys) {
116
- try {
117
- return decryptSecret(secret, key)
118
- } catch (err) {
119
- lastError = err
120
- }
121
- }
122
- if (lastError) {
123
- throw lastError
124
- }
125
- return secret
126
- }
127
-
128
- private maybeEncryptSecret(secret: string) {
129
- const key = this.getEncryptionKey()
130
- if (!key) {
131
- return secret
132
- }
133
- return encryptSecret(secret, key)
134
- }
135
-
136
- private maybeDecryptSecret(secret?: string | null) {
137
- if (!secret) {
138
- return ""
139
- }
140
- const keys = this.getDecryptionKeys()
141
- if (keys.length === 0) {
142
- if (isEncryptedSecret(secret)) {
143
- throw new Error(
144
- "PayPal client secret is encrypted. Set PAYPAL_CREDENTIALS_ENCRYPTION_KEY to decrypt."
145
- )
146
- }
147
- return secret
148
- }
149
- if (!isEncryptedSecret(secret)) {
150
- return secret
151
- }
152
- return this.decryptSecretWithKeys(secret, keys)
153
- }
154
-
155
101
  private async getPartnerMerchantId(env: Environment) {
156
102
  const { onboarding } = await this.ensureSettingsDefaults()
157
103
  return env === "live" ? onboarding.partner_merchant_id_live : onboarding.partner_merchant_id_sandbox
@@ -619,7 +565,6 @@ class PayPalModuleService extends MedusaService({
619
565
  }
620
566
  }
621
567
 
622
- // ✅ If PayPal returned an error object, surface it clearly.
623
568
  // Typical error shape: { name, message, debug_id, details: [...], links: [...] }
624
569
  if (json?.name && json?.message && (json?.debug_id || json?.details || json?.links)) {
625
570
  const debug = json.debug_id ? ` debug_id=${json.debug_id}` : ""
@@ -871,7 +816,6 @@ class PayPalModuleService extends MedusaService({
871
816
  const currentEnv = await this.getCurrentEnvironment()
872
817
  const env = (input.environment || currentEnv) as Environment
873
818
 
874
- const encryptedSecret = this.maybeEncryptSecret(input.clientSecret)
875
819
  const existingCreds = row ? this.getEnvCreds(row, env) : {}
876
820
  const nextSellerMerchantId =
877
821
  (input.sellerMerchantId || "").trim() || existingCreds.sellerMerchantId || row?.seller_merchant_id || null
@@ -881,8 +825,8 @@ class PayPalModuleService extends MedusaService({
881
825
  const nextCreds = {
882
826
  client_id: input.clientId,
883
827
  clientId: input.clientId,
884
- client_secret: encryptedSecret,
885
- clientSecret: encryptedSecret,
828
+ client_secret: input.clientSecret,
829
+ clientSecret: input.clientSecret,
886
830
  merchantId: nextSellerMerchantId,
887
831
  merchant_id: nextSellerMerchantId,
888
832
  payer_id: nextSellerMerchantId,
@@ -897,7 +841,7 @@ class PayPalModuleService extends MedusaService({
897
841
  environment: env,
898
842
  status: "connected",
899
843
  seller_client_id: input.clientId,
900
- seller_client_secret: encryptedSecret,
844
+ seller_client_secret: input.clientSecret,
901
845
  seller_merchant_id: nextSellerMerchantId,
902
846
  seller_email: nextSellerEmail,
903
847
  app_access_token: null,
@@ -928,7 +872,7 @@ class PayPalModuleService extends MedusaService({
928
872
  id: row.id,
929
873
  status: "connected",
930
874
  seller_client_id: input.clientId,
931
- seller_client_secret: encryptedSecret,
875
+ seller_client_secret: input.clientSecret,
932
876
  seller_merchant_id: nextSellerMerchantId,
933
877
  seller_email: nextSellerEmail,
934
878
  app_access_token: null,
@@ -1111,62 +1055,6 @@ class PayPalModuleService extends MedusaService({
1111
1055
  )}`
1112
1056
  }
1113
1057
 
1114
- async rotateCredentialEncryptionKey() {
1115
- const currentKey = this.getEncryptionKey()
1116
- if (!currentKey) {
1117
- throw new Error("PAYPAL_CREDENTIALS_ENCRYPTION_KEY must be set to rotate credentials.")
1118
- }
1119
-
1120
- const row = await this.getCurrentRow()
1121
- if (!row) {
1122
- return { rotated: 0 }
1123
- }
1124
-
1125
- const meta = (row.metadata || {}) as any
1126
- const credentials = { ...(meta.credentials || {}) }
1127
- let rotated = 0
1128
-
1129
- for (const [env, envCreds] of Object.entries(credentials)) {
1130
- if (!envCreds || typeof envCreds !== "object") continue
1131
- const clientSecret = (envCreds as any).client_secret
1132
- if (!clientSecret) continue
1133
-
1134
- const decrypted = this.maybeDecryptSecret(clientSecret)
1135
- const reEncrypted = this.maybeEncryptSecret(decrypted)
1136
- if (reEncrypted !== clientSecret) {
1137
- credentials[env] = {
1138
- ...(envCreds as any),
1139
- client_secret: reEncrypted,
1140
- }
1141
- rotated += 1
1142
- }
1143
- }
1144
-
1145
- if (rotated === 0) {
1146
- return { rotated: 0 }
1147
- }
1148
-
1149
- await this.updatePayPalConnections({
1150
- id: row.id,
1151
- metadata: {
1152
- ...(row.metadata || {}),
1153
- credentials,
1154
- },
1155
- seller_client_secret: credentials?.[row.environment as Environment]?.client_secret || null,
1156
- })
1157
-
1158
- const updated = await this.getCurrentRow()
1159
- if (updated) {
1160
- await this.syncRowFieldsFromMetadata(updated, (updated.environment as Environment) || "live")
1161
- }
1162
-
1163
- await this.recordAuditEvent("credentials_rotated", {
1164
- environments: Object.keys(credentials),
1165
- })
1166
-
1167
- return { rotated }
1168
- }
1169
-
1170
1058
  async getStatus(envOverride?: Environment) {
1171
1059
  const row = await this.getCurrentRow()
1172
1060
  const env = envOverride ?? (await this.getCurrentEnvironment())
@@ -1179,14 +1067,6 @@ class PayPalModuleService extends MedusaService({
1179
1067
  const hasCreds = !!(c.clientId && c.clientSecret)
1180
1068
  let sellerEmail: string | null = c.sellerEmail || row.seller_email || null
1181
1069
  let sellerMerchantId: string | null = c.sellerMerchantId || row.seller_merchant_id || null
1182
- let decryptedSecret: string | null = null
1183
- if (c.clientSecret) {
1184
- try {
1185
- decryptedSecret = this.maybeDecryptSecret(c.clientSecret)
1186
- } catch (e: any) {
1187
- console.warn("[PayPal] Unable to decrypt seller client secret for status sync:", e?.message || e)
1188
- }
1189
- }
1190
1070
 
1191
1071
  if (!sellerEmail && hasCreds) {
1192
1072
  try {
@@ -1194,7 +1074,7 @@ class PayPalModuleService extends MedusaService({
1194
1074
  if (hydrated.sellerEmail || hydrated.sellerMerchantId) {
1195
1075
  await this.saveSellerCredentials({
1196
1076
  clientId: c.clientId!,
1197
- clientSecret: decryptedSecret || c.clientSecret!,
1077
+ clientSecret: c.clientSecret!,
1198
1078
  sellerMerchantId: hydrated.sellerMerchantId || sellerMerchantId,
1199
1079
  sellerEmail: hydrated.sellerEmail || sellerEmail,
1200
1080
  environment: env,
@@ -1410,7 +1290,7 @@ class PayPalModuleService extends MedusaService({
1410
1290
  }
1411
1291
 
1412
1292
  const c = this.getEnvCreds(row, env)
1413
- const clientSecret = this.maybeDecryptSecret(c.clientSecret)
1293
+ const clientSecret = c.clientSecret || ""
1414
1294
 
1415
1295
  if (!c.clientId || !clientSecret) {
1416
1296
  throw new Error(
@@ -1563,7 +1443,6 @@ class PayPalModuleService extends MedusaService({
1563
1443
  metadata: metadata ?? {},
1564
1444
  created_at: new Date().toISOString(),
1565
1445
  }
1566
- console.info("[PayPal] payment_event", payload)
1567
1446
  return await this.recordAuditEvent(`payment_${eventType}`, metadata)
1568
1447
  }
1569
1448
 
@@ -1,47 +1,33 @@
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
+ alertWebhookUrls?: string[]
10
+ }
11
+
12
+ const STATIC_CFG: PayPalModuleConfig = {
13
+ partnerServiceUrl: "https://mbjtechnolabs.com/ppcp-seller-onboarding/seller-onboarding.php",
14
+ partnerJsUrl: "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js",
15
+ backendUrl: "http://localhost:9000",
16
+ sellerNonce: "a1233wtergfsdt4365tzrshgfbaewa36AGa1233wtergfsdt4365tzrshgfbaewa36AG",
17
+ bnCode: "",
18
+ partnerMerchantIdSandbox: "K6QLN2LPGQRHL",
19
+ partnerMerchantIdLive: "GT5R877JNBPLL",
20
+ alertWebhookUrls: [],
21
+ }
22
+
23
+ export function getPayPalConfig(): PayPalModuleConfig {
24
+ return {
25
+ ...STATIC_CFG,
26
+ backendUrl: process.env.MEDUSA_BACKEND_URL || STATIC_CFG.backendUrl,
27
+ alertWebhookUrls:
28
+ (process.env.PAYPAL_ALERT_WEBHOOK_URLS || "")
29
+ .split(",")
30
+ .map((url) => url.trim())
31
+ .filter(Boolean) || STATIC_CFG.alertWebhookUrls,
32
+ }
33
+ }