Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(medusa-payment-stripe): Add delay to Stripe webhook #5838

Merged
merged 13 commits into from
Jan 5, 2024
Merged
6 changes: 6 additions & 0 deletions .changeset/metal-pans-beg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@medusajs/medusa": patch
"medusa-payment-stripe": patch
---

feat(medusa-payment-stripe): Add delay to Stripe webhook
2 changes: 1 addition & 1 deletion packages/medusa-payment-stripe/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@
"medusa-react": "^9.0.0"
},
"dependencies": {
"@medusajs/utils": "workspace:^",
"body-parser": "^1.19.0",
"express": "^4.17.1",
"medusa-core-utils": "^1.2.0",
"stripe": "^11.10.0"
},
"gitHead": "81a7ff73d012fda722f6e9ef0bd9ba0232d37808",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
import { getStripePayments } from "../../../../../controllers/get-payments"

export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
const payments = await getStripePayments(req)
res.json({ payments })
}
18 changes: 0 additions & 18 deletions packages/medusa-payment-stripe/src/api/hooks/index.ts

This file was deleted.

25 changes: 0 additions & 25 deletions packages/medusa-payment-stripe/src/api/hooks/stripe.ts

This file was deleted.

35 changes: 0 additions & 35 deletions packages/medusa-payment-stripe/src/api/index.ts

This file was deleted.

11 changes: 11 additions & 0 deletions packages/medusa-payment-stripe/src/api/middlewares.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { MiddlewaresConfig } from "@medusajs/medusa"
import { raw } from "body-parser"

export const config: MiddlewaresConfig = {
routes: [
{
matcher: "/stripe/hooks",
middlewares: [raw({ type: "application/json" })],
},
],
}
30 changes: 30 additions & 0 deletions packages/medusa-payment-stripe/src/api/stripe/hooks/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
import { constructWebhook } from "../../utils/utils"

const WEBHOOK_DELAY = process.env.STRIPE_WEBHOOK_DELAY ?? 2000
const WEBHOOK_RETRIES = process.env.STRIPE_WEBHOOK_RETRIES ?? 3

export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
let event
olivermrbl marked this conversation as resolved.
Show resolved Hide resolved

try {
event = constructWebhook({
signature: req.headers["stripe-signature"],
body: req.body,
container: req.scope,
})

const eventBus = req.scope.resolve("eventBusService")

// we delay the processing of the event to avoid a conflict caused by a race condition
await eventBus.emit("medusa.stripe_payment_intent", event, {
delay: WEBHOOK_DELAY,
attempts: WEBHOOK_RETRIES,
})
} catch (err) {
res.status(400).send(`Webhook Error: ${err.message}`)
return
}

res.sendStatus(200)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { PostgresError } from "@medusajs/medusa"
import Stripe from "stripe"
import { EOL } from "os"
import Stripe from "stripe"

import { buildError, handlePaymentHook, isPaymentCollection } from "../utils"
import { container } from "../__fixtures__/container"
import {
existingCartId,
Expand All @@ -14,6 +13,7 @@ import {
paymentId,
paymentIntentId,
} from "../__fixtures__/data"
import { buildError, handlePaymentHook, isPaymentCollection } from "../utils"

describe("Utils", () => {
afterEach(() => {
Expand Down Expand Up @@ -334,7 +334,7 @@ describe("Utils", () => {
const paymentIntent = {
id: paymentIntentId,
metadata: { cart_id: nonExistingCartId },
last_payment_error: { message: "error message" },
last_payment_error: { message: "error message" } as any,
}

await handlePaymentHook({ event, container, paymentIntent })
Expand Down
14 changes: 5 additions & 9 deletions packages/medusa-payment-stripe/src/api/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import {
IdempotencyKeyService,
PostgresError,
} from "@medusajs/medusa"
import { MedusaError } from "@medusajs/utils"
import { AwilixContainer } from "awilix"
import { MedusaError } from "medusa-core-utils"
import { EOL } from "os"
import Stripe from "stripe"

Expand Down Expand Up @@ -51,19 +51,15 @@ export async function handlePaymentHook({
container,
paymentIntent,
}: {
event: { type: string; id: string }
event: Partial<Stripe.Event>
container: AwilixContainer
paymentIntent: {
id: string
metadata: { cart_id?: string; resource_id?: string }
last_payment_error?: { message: string }
}
paymentIntent: Partial<Stripe.PaymentIntent>
}): Promise<{ statusCode: number }> {
const logger = container.resolve("logger")

const cartId =
paymentIntent.metadata.cart_id ?? paymentIntent.metadata.resource_id // Backward compatibility
const resourceId = paymentIntent.metadata.resource_id
paymentIntent.metadata?.cart_id ?? paymentIntent.metadata?.resource_id // Backward compatibility
const resourceId = paymentIntent.metadata?.resource_id

switch (event.type) {
case "payment_intent.succeeded":
Expand Down
2 changes: 1 addition & 1 deletion packages/medusa-payment-stripe/src/core/stripe-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
PaymentProcessorSessionResponse,
PaymentSessionStatus,
} from "@medusajs/medusa"
import { MedusaError } from "@medusajs/utils"
import { EOL } from "os"
import Stripe from "stripe"
import {
Expand All @@ -14,7 +15,6 @@ import {
PaymentIntentOptions,
StripeOptions,
} from "../types"
import { MedusaError } from "@medusajs/utils"

abstract class StripeBase extends AbstractPaymentProcessor {
static identifier = ""
Expand Down
6 changes: 3 additions & 3 deletions packages/medusa-payment-stripe/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export * from "./types"
export * from "./core/stripe-base"
export * from "./services/stripe-blik"
export * from "./services/stripe-bancontact"
export * from "./services/stripe-blik"
export * from "./services/stripe-giropay"
export * from "./services/stripe-ideal"
export * from "./services/stripe-przelewy24"
export * from "./services/stripe-provider"
export * from "./services/stripe-przelewy24"
export * from "./types"
24 changes: 24 additions & 0 deletions packages/medusa-payment-stripe/src/subscribers/stripe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { type SubscriberArgs, type SubscriberConfig } from "@medusajs/medusa"
import Stripe from "stripe"
import { handlePaymentHook } from "../api/utils/utils"

export default async function stripeHandler({
data,
container,
}: SubscriberArgs<Stripe.Event>) {
const event = data
const paymentIntent = event.data.object as Stripe.PaymentIntent

await handlePaymentHook({
event,
container,
paymentIntent,
})
}

export const config: SubscriberConfig = {
event: "medusa.stripe_payment_intent",
context: {
subscriberId: "medusa.stripe_payment_intent",
},
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { IsEmail, IsNotEmpty } from "class-validator"
import jwt from "jsonwebtoken"
import { EntityManager } from "typeorm"
import { defaultRelations } from "."
import AuthService from "../../../../services/auth"
import CustomerService from "../../../../services/customer"
import { validator } from "../../../../utils/validator"
import { defaultRelations } from "."

/**
* @oas [post] /store/auth
Expand Down
4 changes: 2 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8050,7 +8050,7 @@ __metadata:
languageName: unknown
linkType: soft

"@medusajs/utils@^1.10.0, @medusajs/utils@^1.10.5, @medusajs/utils@^1.11.1, @medusajs/utils@^1.9.2, @medusajs/utils@^1.9.4, @medusajs/utils@workspace:packages/utils":
"@medusajs/utils@^1.10.0, @medusajs/utils@^1.10.5, @medusajs/utils@^1.11.1, @medusajs/utils@^1.9.2, @medusajs/utils@^1.9.4, @medusajs/utils@workspace:^, @medusajs/utils@workspace:packages/utils":
version: 0.0.0-use.local
resolution: "@medusajs/utils@workspace:packages/utils"
dependencies:
Expand Down Expand Up @@ -35878,14 +35878,14 @@ __metadata:
dependencies:
"@medusajs/admin": ^7.1.7
"@medusajs/medusa": ^1.17.4
"@medusajs/utils": "workspace:^"
"@tanstack/react-table": ^8.7.9
"@types/stripe": ^8.0.417
awilix: ^8.0.1
body-parser: ^1.19.0
cross-env: ^5.2.1
express: ^4.17.1
jest: ^25.5.4
medusa-core-utils: ^1.2.0
medusa-react: ^9.0.11
rimraf: ^5.0.1
stripe: ^11.10.0
Expand Down