feat(payment, payment-stripe): Add Stripe module provider (#6311)

This commit is contained in:
Oli Juhl authored and GitHub committed 2024-02-26 19:48:15 +01:00
1 parent ac829fc67f
commit ce39b9b66e
49 files changed
+1256 -119

No files matched your search

@@ -0,0 +1,9 @@
import { MiddlewareRoute } from "../../types/middlewares"
export const hooksRoutesMiddlewares: MiddlewareRoute[] = [
{
method: ["POST"],
bodyParser: { preserveRawBody: true },
matcher: "/hooks/payment/:provider",
},
]
@@ -0,0 +1,32 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { PaymentWebhookEvents } from "@medusajs/utils"
import { PaymentModuleOptions } from "@medusajs/types"
import { MedusaRequest, MedusaResponse } from "../../../../types/routing"
export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
try {
const { provider } = req.params
const options: PaymentModuleOptions =
req.scope.resolve(ModuleRegistrationName.PAYMENT).options || {}
const event = {
provider,
payload: { data: req.body, rawData: req.rawBody, headers: req.headers },
}
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(PaymentWebhookEvents.WebhookReceived, event, {
delay: options.webhook_delay || 5000,
attempts: options.webhook_retries || 3,
})
} catch (err) {
res.status(400).send(`Webhook Error: ${err.message}`)
return
}
res.sendStatus(200)
}
@@ -12,6 +12,7 @@ import { authRoutesMiddlewares } from "./auth/middlewares"
import { storeCartRoutesMiddlewares } from "./store/carts/middlewares"
import { storeCustomerRoutesMiddlewares } from "./store/customers/middlewares"
import { storeRegionRoutesMiddlewares } from "./store/regions/middlewares"
import { hooksRoutesMiddlewares } from "./hooks/middlewares"
export const config: MiddlewaresConfig = {
routes: [
@@ -29,5 +30,6 @@ export const config: MiddlewaresConfig = {
...adminUserRoutesMiddlewares,
...adminInviteRoutesMiddlewares,
...adminApiKeyRoutesMiddlewares,
...hooksRoutesMiddlewares,
],
}
+1 -2
View File
@@ -33,8 +33,6 @@ export default async ({
next()
})
app.use(bodyParser.json())
if (featureFlagRouter?.isFeatureEnabled(FeatureFlagUtils.MedusaV2Flag.key)) {
// TODO: Figure out why this is causing issues with test when placed inside ./api.ts
// Adding this here temporarily
@@ -52,6 +50,7 @@ export default async ({
throw Error("An error occurred while registering Medusa Core API Routes")
}
} else {
app.use(bodyParser.json())
app.use("/", routes(container, configModule.projectConfig))
}
@@ -22,7 +22,9 @@ import {
RouteConfig,
RouteDescriptor,
RouteVerb,
ParserConfigArgs,
} from "./types"
import { MedusaRequest, MedusaResponse } from "../../../types/routing"
const log = ({
activityId,
@@ -150,9 +152,18 @@ function findMatch(
* Returns an array of body parser middlewares that are applied on routes
* out-of-the-box.
*/
function getBodyParserMiddleware(sizeLimit?: string | number | undefined) {
function getBodyParserMiddleware(args?: ParserConfigArgs) {
const sizeLimit = args?.sizeLimit
const preserveRawBody = args?.preserveRawBody
return [
json({ limit: sizeLimit }),
json({
limit: sizeLimit,
verify: preserveRawBody
? (req: MedusaRequest, res: MedusaResponse, buf: Buffer) => {
req.rawBody = buf
}
: undefined,
}),
text({ limit: sizeLimit }),
urlencoded({ limit: sizeLimit, extended: true }),
]
@@ -556,7 +567,7 @@ export class RoutesLoader {
this.router[method.toLowerCase()](
path,
...getBodyParserMiddleware(sizeLimit)
...getBodyParserMiddleware(mostSpecificConfig?.bodyParser)
)
return
@@ -55,11 +55,12 @@ export type MedusaErrorHandlerFunction = (
next: MedusaNextFunction
) => Promise<void> | void
type ParserConfig =
| false
| {
sizeLimit?: string | number | undefined
}
export type ParserConfigArgs = {
sizeLimit?: string | number | undefined
preserveRawBody?: boolean
}
type ParserConfig = false | ParserConfigArgs
export type MiddlewareRoute = {
method?: MiddlewareVerb | MiddlewareVerb[]
@@ -0,0 +1,50 @@
import { PaymentWebhookEvents } from "@medusajs/utils"
import {
IEventBusService,
IPaymentModuleService,
ProviderWebhookPayload,
Subscriber,
} from "@medusajs/types"
import { EventBusService } from "../services"
type SerializedBuffer = {
data: ArrayBuffer
type: "Buffer"
}
type InjectedDependencies = {
paymentModuleService: IPaymentModuleService
eventBusService: EventBusService
}
class PaymentWebhookSubscriber {
private readonly eventBusService_: IEventBusService
private readonly paymentModuleService_: IPaymentModuleService
constructor({ eventBusService, paymentModuleService }: InjectedDependencies) {
this.eventBusService_ = eventBusService
this.paymentModuleService_ = paymentModuleService
this.eventBusService_.subscribe(
PaymentWebhookEvents.WebhookReceived,
this.processEvent as Subscriber
)
}
/**
* TODO: consider moving this to a workflow
*/
processEvent = async (data: ProviderWebhookPayload): Promise<void> => {
if (
(data.payload.rawData as unknown as SerializedBuffer).type === "Buffer"
) {
data.payload.rawData = Buffer.from(
(data.payload.rawData as unknown as SerializedBuffer).data
)
}
await this.paymentModuleService_.processEvent(data)
}
}
export default PaymentWebhookSubscriber
+1
View File
@@ -7,6 +7,7 @@ export interface MedusaRequest extends Request {
user?: (User | Customer) & { customer_id?: string; userId?: string }
scope: MedusaContainer
session?: any
rawBody?: any
requestId?: string
auth_user?: { id: string; app_metadata: Record<string, any>; scope: string }
}