feat(payment, payment-stripe): Add Stripe module provider (#6311)
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
dist
|
||||
node_modules
|
||||
.DS_store
|
||||
yarn.lock
|
||||
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
globals: {
|
||||
"ts-jest": {
|
||||
tsconfig: "tsconfig.spec.json",
|
||||
isolatedModules: false,
|
||||
},
|
||||
},
|
||||
transform: {
|
||||
"^.+\\.[jt]s?$": "ts-jest",
|
||||
},
|
||||
testEnvironment: `node`,
|
||||
moduleFileExtensions: [`js`, `jsx`, `ts`, `tsx`, `json`],
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "@medusajs/payment-stripe",
|
||||
"version": "0.0.1",
|
||||
"description": "Stripe payment provider for Medusa",
|
||||
"main": "dist/index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/medusajs/medusa",
|
||||
"directory": "packages/payment-stripe"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"author": "Medusa",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"prepublishOnly": "cross-env NODE_ENV=production tsc --build",
|
||||
"test": "jest --passWithNoTests src",
|
||||
"build": "rimraf dist && tsc -p ./tsconfig.json",
|
||||
"watch": "tsc --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@medusajs/medusa": "^1.19.1",
|
||||
"@types/stripe": "^8.0.417",
|
||||
"awilix": "^8.0.1",
|
||||
"cross-env": "^5.2.1",
|
||||
"jest": "^25.5.4",
|
||||
"rimraf": "^5.0.1",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@medusajs/medusa": "^1.12.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@medusajs/utils": "^1.11.3",
|
||||
"body-parser": "^1.19.0",
|
||||
"express": "^4.17.1",
|
||||
"stripe": "latest"
|
||||
},
|
||||
"gitHead": "81a7ff73d012fda722f6e9ef0bd9ba0232d37808",
|
||||
"keywords": [
|
||||
"medusa-plugin",
|
||||
"medusa-plugin-payment"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,382 @@
|
||||
import { EOL } from "os"
|
||||
|
||||
import Stripe from "stripe"
|
||||
|
||||
import {
|
||||
MedusaContainer,
|
||||
PaymentSessionStatus,
|
||||
PaymentProviderContext,
|
||||
PaymentProviderError,
|
||||
PaymentProviderSessionResponse,
|
||||
ProviderWebhookPayload,
|
||||
WebhookActionResult,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
PaymentActions,
|
||||
AbstractPaymentProvider,
|
||||
isPaymentProviderError,
|
||||
MedusaError,
|
||||
} from "@medusajs/utils"
|
||||
import { isDefined } from "medusa-core-utils"
|
||||
|
||||
import {
|
||||
ErrorCodes,
|
||||
ErrorIntentStatus,
|
||||
PaymentIntentOptions,
|
||||
StripeCredentials,
|
||||
StripeOptions,
|
||||
} from "../types"
|
||||
|
||||
abstract class StripeBase extends AbstractPaymentProvider<StripeCredentials> {
|
||||
protected readonly options_: StripeOptions
|
||||
protected stripe_: Stripe
|
||||
protected container_: MedusaContainer
|
||||
|
||||
protected constructor(container: MedusaContainer, options: StripeOptions) {
|
||||
// @ts-ignore
|
||||
super(...arguments)
|
||||
|
||||
this.container_ = container
|
||||
this.options_ = options
|
||||
|
||||
this.stripe_ = this.init()
|
||||
}
|
||||
|
||||
protected init() {
|
||||
this.validateOptions(this.config)
|
||||
|
||||
return new Stripe(this.config.apiKey)
|
||||
}
|
||||
|
||||
abstract get paymentIntentOptions(): PaymentIntentOptions
|
||||
|
||||
private validateOptions(options: StripeCredentials): void {
|
||||
if (!isDefined(options.apiKey)) {
|
||||
throw new Error("Required option `apiKey` is missing in Stripe plugin")
|
||||
}
|
||||
}
|
||||
|
||||
get options(): StripeOptions {
|
||||
return this.options_
|
||||
}
|
||||
|
||||
getPaymentIntentOptions(): PaymentIntentOptions {
|
||||
const options: PaymentIntentOptions = {}
|
||||
|
||||
if (this?.paymentIntentOptions?.capture_method) {
|
||||
options.capture_method = this.paymentIntentOptions.capture_method
|
||||
}
|
||||
|
||||
if (this?.paymentIntentOptions?.setup_future_usage) {
|
||||
options.setup_future_usage = this.paymentIntentOptions.setup_future_usage
|
||||
}
|
||||
|
||||
if (this?.paymentIntentOptions?.payment_method_types) {
|
||||
options.payment_method_types =
|
||||
this.paymentIntentOptions.payment_method_types
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
async getPaymentStatus(
|
||||
paymentSessionData: Record<string, unknown>
|
||||
): Promise<PaymentSessionStatus> {
|
||||
const id = paymentSessionData.id as string
|
||||
const paymentIntent = await this.stripe_.paymentIntents.retrieve(id)
|
||||
|
||||
switch (paymentIntent.status) {
|
||||
case "requires_payment_method":
|
||||
case "requires_confirmation":
|
||||
case "processing":
|
||||
return PaymentSessionStatus.PENDING
|
||||
case "requires_action":
|
||||
return PaymentSessionStatus.REQUIRES_MORE
|
||||
case "canceled":
|
||||
return PaymentSessionStatus.CANCELED
|
||||
case "requires_capture":
|
||||
case "succeeded":
|
||||
return PaymentSessionStatus.AUTHORIZED
|
||||
default:
|
||||
return PaymentSessionStatus.PENDING
|
||||
}
|
||||
}
|
||||
|
||||
async initiatePayment(
|
||||
context: PaymentProviderContext
|
||||
): Promise<PaymentProviderError | PaymentProviderSessionResponse> {
|
||||
const intentRequestData = this.getPaymentIntentOptions()
|
||||
const {
|
||||
email,
|
||||
context: cart_context,
|
||||
currency_code,
|
||||
amount,
|
||||
resource_id,
|
||||
customer,
|
||||
} = context
|
||||
|
||||
const description = (cart_context.payment_description ??
|
||||
this.options_?.payment_description) as string
|
||||
|
||||
const intentRequest: Stripe.PaymentIntentCreateParams = {
|
||||
description,
|
||||
amount: Math.round(amount),
|
||||
currency: currency_code,
|
||||
metadata: { resource_id },
|
||||
capture_method: this.options_.capture ? "automatic" : "manual",
|
||||
...intentRequestData,
|
||||
}
|
||||
|
||||
if (this.options_?.automatic_payment_methods) {
|
||||
intentRequest.automatic_payment_methods = { enabled: true }
|
||||
}
|
||||
|
||||
if (customer?.metadata?.stripe_id) {
|
||||
intentRequest.customer = customer.metadata.stripe_id as string
|
||||
} else {
|
||||
let stripeCustomer
|
||||
try {
|
||||
stripeCustomer = await this.stripe_.customers.create({
|
||||
email,
|
||||
})
|
||||
} catch (e) {
|
||||
return this.buildError(
|
||||
"An error occurred in initiatePayment when creating a Stripe customer",
|
||||
e
|
||||
)
|
||||
}
|
||||
|
||||
intentRequest.customer = stripeCustomer.id
|
||||
}
|
||||
|
||||
let session_data
|
||||
try {
|
||||
session_data = (await this.stripe_.paymentIntents.create(
|
||||
intentRequest
|
||||
)) as unknown as Record<string, unknown>
|
||||
} catch (e) {
|
||||
return this.buildError(
|
||||
"An error occurred in InitiatePayment during the creation of the stripe payment intent",
|
||||
e
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
data: session_data,
|
||||
// TODO: REVISIT
|
||||
// update_requests: customer?.metadata?.stripe_id
|
||||
// ? undefined
|
||||
// : {
|
||||
// customer_metadata: {
|
||||
// stripe_id: intentRequest.customer,
|
||||
// },
|
||||
// },
|
||||
}
|
||||
}
|
||||
|
||||
async authorizePayment(
|
||||
paymentSessionData: Record<string, unknown>,
|
||||
context: Record<string, unknown>
|
||||
): Promise<
|
||||
| PaymentProviderError
|
||||
| {
|
||||
status: PaymentSessionStatus
|
||||
data: PaymentProviderSessionResponse["data"]
|
||||
}
|
||||
> {
|
||||
const status = await this.getPaymentStatus(paymentSessionData)
|
||||
return { data: paymentSessionData, status }
|
||||
}
|
||||
|
||||
async cancelPayment(
|
||||
paymentSessionData: Record<string, unknown>
|
||||
): Promise<PaymentProviderError | PaymentProviderSessionResponse["data"]> {
|
||||
try {
|
||||
const id = paymentSessionData.id as string
|
||||
return (await this.stripe_.paymentIntents.cancel(
|
||||
id
|
||||
)) as unknown as PaymentProviderSessionResponse["data"]
|
||||
} catch (error) {
|
||||
if (error.payment_intent?.status === ErrorIntentStatus.CANCELED) {
|
||||
return error.payment_intent
|
||||
}
|
||||
|
||||
return this.buildError("An error occurred in cancelPayment", error)
|
||||
}
|
||||
}
|
||||
|
||||
async capturePayment(
|
||||
paymentSessionData: Record<string, unknown>
|
||||
): Promise<PaymentProviderError | PaymentProviderSessionResponse["data"]> {
|
||||
const id = paymentSessionData.id as string
|
||||
try {
|
||||
const intent = await this.stripe_.paymentIntents.capture(id)
|
||||
return intent as unknown as PaymentProviderSessionResponse["data"]
|
||||
} catch (error) {
|
||||
if (error.code === ErrorCodes.PAYMENT_INTENT_UNEXPECTED_STATE) {
|
||||
if (error.payment_intent?.status === ErrorIntentStatus.SUCCEEDED) {
|
||||
return error.payment_intent
|
||||
}
|
||||
}
|
||||
|
||||
return this.buildError("An error occurred in capturePayment", error)
|
||||
}
|
||||
}
|
||||
|
||||
async deletePayment(
|
||||
paymentSessionData: Record<string, unknown>
|
||||
): Promise<PaymentProviderError | PaymentProviderSessionResponse["data"]> {
|
||||
return await this.cancelPayment(paymentSessionData)
|
||||
}
|
||||
|
||||
async refundPayment(
|
||||
paymentSessionData: Record<string, unknown>,
|
||||
refundAmount: number
|
||||
): Promise<PaymentProviderError | PaymentProviderSessionResponse["data"]> {
|
||||
const id = paymentSessionData.id as string
|
||||
|
||||
try {
|
||||
await this.stripe_.refunds.create({
|
||||
amount: Math.round(refundAmount),
|
||||
payment_intent: id as string,
|
||||
})
|
||||
} catch (e) {
|
||||
return this.buildError("An error occurred in refundPayment", e)
|
||||
}
|
||||
|
||||
return paymentSessionData
|
||||
}
|
||||
|
||||
async retrievePayment(
|
||||
paymentSessionData: Record<string, unknown>
|
||||
): Promise<PaymentProviderError | PaymentProviderSessionResponse["data"]> {
|
||||
try {
|
||||
const id = paymentSessionData.id as string
|
||||
const intent = await this.stripe_.paymentIntents.retrieve(id)
|
||||
return intent as unknown as PaymentProviderSessionResponse["data"]
|
||||
} catch (e) {
|
||||
return this.buildError("An error occurred in retrievePayment", e)
|
||||
}
|
||||
}
|
||||
|
||||
async updatePayment(
|
||||
context: PaymentProviderContext
|
||||
): Promise<PaymentProviderError | PaymentProviderSessionResponse> {
|
||||
const { amount, customer, payment_session_data } = context
|
||||
const stripeId = customer?.metadata?.stripe_id
|
||||
|
||||
if (stripeId !== payment_session_data.customer) {
|
||||
const result = await this.initiatePayment(context)
|
||||
if (isPaymentProviderError(result)) {
|
||||
return this.buildError(
|
||||
"An error occurred in updatePayment during the initiate of the new payment for the new customer",
|
||||
result
|
||||
)
|
||||
}
|
||||
|
||||
return result
|
||||
} else {
|
||||
if (amount && payment_session_data.amount === Math.round(amount)) {
|
||||
return { data: payment_session_data }
|
||||
}
|
||||
|
||||
try {
|
||||
const id = payment_session_data.id as string
|
||||
const sessionData = (await this.stripe_.paymentIntents.update(id, {
|
||||
amount: Math.round(amount),
|
||||
})) as unknown as PaymentProviderSessionResponse["data"]
|
||||
|
||||
return { data: sessionData }
|
||||
} catch (e) {
|
||||
return this.buildError("An error occurred in updatePayment", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async updatePaymentData(sessionId: string, data: Record<string, unknown>) {
|
||||
try {
|
||||
// Prevent from updating the amount from here as it should go through
|
||||
// the updatePayment method to perform the correct logic
|
||||
if (data.amount) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Cannot update amount, use updatePayment instead"
|
||||
)
|
||||
}
|
||||
|
||||
return (await this.stripe_.paymentIntents.update(sessionId, {
|
||||
...data,
|
||||
})) as unknown as PaymentProviderSessionResponse["data"]
|
||||
} catch (e) {
|
||||
return this.buildError("An error occurred in updatePaymentData", e)
|
||||
}
|
||||
}
|
||||
|
||||
async getWebhookActionAndData(
|
||||
webhookData: ProviderWebhookPayload["payload"]
|
||||
): Promise<WebhookActionResult> {
|
||||
const event = this.constructWebhookEvent(webhookData)
|
||||
const intent = event.data.object as Stripe.PaymentIntent
|
||||
|
||||
switch (event.type) {
|
||||
case "payment_intent.amount_capturable_updated":
|
||||
return {
|
||||
action: PaymentActions.AUTHORIZED,
|
||||
data: {
|
||||
resource_id: intent.metadata.resource_id,
|
||||
amount: intent.amount_capturable, // NOTE: revisit when implementing multicapture
|
||||
},
|
||||
}
|
||||
case "payment_intent.succeeded":
|
||||
return {
|
||||
action: PaymentActions.SUCCESSFUL,
|
||||
data: {
|
||||
resource_id: intent.metadata.resource_id,
|
||||
amount: intent.amount_received,
|
||||
},
|
||||
}
|
||||
case "payment_intent.payment_failed":
|
||||
return {
|
||||
action: PaymentActions.FAILED,
|
||||
data: {
|
||||
resource_id: intent.metadata.resource_id,
|
||||
amount: intent.amount,
|
||||
},
|
||||
}
|
||||
default:
|
||||
return { action: PaymentActions.NOT_SUPPORTED }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs Stripe Webhook event
|
||||
* @param {object} data - the data of the webhook request: req.body
|
||||
* ensures integrity of the webhook event
|
||||
* @return {object} Stripe Webhook event
|
||||
*/
|
||||
constructWebhookEvent(data: ProviderWebhookPayload["payload"]): Stripe.Event {
|
||||
const signature = data.headers["stripe-signature"] as string
|
||||
|
||||
return this.stripe_.webhooks.constructEvent(
|
||||
data.rawData as string | Buffer,
|
||||
signature,
|
||||
this.config.webhookSecret
|
||||
)
|
||||
}
|
||||
protected buildError(
|
||||
message: string,
|
||||
error: Stripe.StripeRawError | PaymentProviderError | Error
|
||||
): PaymentProviderError {
|
||||
return {
|
||||
error: message,
|
||||
code: "code" in error ? error.code : "unknown",
|
||||
detail: isPaymentProviderError(error)
|
||||
? `${error.error}${EOL}${error.detail ?? ""}`
|
||||
: "detail" in error
|
||||
? error.detail
|
||||
: error.message ?? "",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default StripeBase
|
||||
@@ -0,0 +1,24 @@
|
||||
import { ModuleProviderExports } from "@medusajs/types"
|
||||
import {
|
||||
StripeBancontactService,
|
||||
StripeBlikService,
|
||||
StripeGiropayService,
|
||||
StripeIdealService,
|
||||
StripeProviderService,
|
||||
StripePrzelewy24Service,
|
||||
} from "./services"
|
||||
|
||||
const services = [
|
||||
StripeBancontactService,
|
||||
StripeBlikService,
|
||||
StripeGiropayService,
|
||||
StripeIdealService,
|
||||
StripeProviderService,
|
||||
StripePrzelewy24Service,
|
||||
]
|
||||
|
||||
const providerExport: ModuleProviderExports = {
|
||||
services,
|
||||
}
|
||||
|
||||
export default providerExport
|
||||
@@ -0,0 +1,7 @@
|
||||
export { default as StripeBancontactService } from "./stripe-bancontact"
|
||||
export { default as StripeBlikService } from "./stripe-blik"
|
||||
export { default as StripeGiropayService } from "./stripe-giropay"
|
||||
export { default as StripeIdealService } from "./stripe-ideal"
|
||||
export { default as StripeProviderService } from "./stripe-provider"
|
||||
export { default as StripePrzelewy24Service } from "./stripe-przelewy24"
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import StripeBase from "../core/stripe-base"
|
||||
import { PaymentIntentOptions, PaymentProviderKeys } from "../types"
|
||||
|
||||
class BancontactProviderService extends StripeBase {
|
||||
static PROVIDER = PaymentProviderKeys.BAN_CONTACT
|
||||
|
||||
constructor(_, options) {
|
||||
super(_, options)
|
||||
}
|
||||
|
||||
get paymentIntentOptions(): PaymentIntentOptions {
|
||||
return {
|
||||
payment_method_types: ["bancontact"],
|
||||
capture_method: "automatic",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default BancontactProviderService
|
||||
@@ -0,0 +1,19 @@
|
||||
import StripeBase from "../core/stripe-base"
|
||||
import { PaymentIntentOptions, PaymentProviderKeys } from "../types"
|
||||
|
||||
class BlikProviderService extends StripeBase {
|
||||
static PROVIDER = PaymentProviderKeys.BLIK
|
||||
|
||||
constructor(_, options) {
|
||||
super(_, options)
|
||||
}
|
||||
|
||||
get paymentIntentOptions(): PaymentIntentOptions {
|
||||
return {
|
||||
payment_method_types: ["blik"],
|
||||
capture_method: "automatic",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default BlikProviderService
|
||||
@@ -0,0 +1,19 @@
|
||||
import StripeBase from "../core/stripe-base"
|
||||
import { PaymentIntentOptions, PaymentProviderKeys } from "../types"
|
||||
|
||||
class GiropayProviderService extends StripeBase {
|
||||
static PROVIDER = PaymentProviderKeys.GIROPAY
|
||||
|
||||
constructor(_, options) {
|
||||
super(_, options)
|
||||
}
|
||||
|
||||
get paymentIntentOptions(): PaymentIntentOptions {
|
||||
return {
|
||||
payment_method_types: ["giropay"],
|
||||
capture_method: "automatic",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default GiropayProviderService
|
||||
@@ -0,0 +1,19 @@
|
||||
import StripeBase from "../core/stripe-base"
|
||||
import { PaymentIntentOptions, PaymentProviderKeys } from "../types"
|
||||
|
||||
class IdealProviderService extends StripeBase {
|
||||
static PROVIDER = PaymentProviderKeys.IDEAL
|
||||
|
||||
constructor(_, options) {
|
||||
super(_, options)
|
||||
}
|
||||
|
||||
get paymentIntentOptions(): PaymentIntentOptions {
|
||||
return {
|
||||
payment_method_types: ["ideal"],
|
||||
capture_method: "automatic",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default IdealProviderService
|
||||
@@ -0,0 +1,16 @@
|
||||
import StripeBase from "../core/stripe-base"
|
||||
import { PaymentIntentOptions, PaymentProviderKeys } from "../types"
|
||||
|
||||
class StripeProviderService extends StripeBase {
|
||||
static PROVIDER = PaymentProviderKeys.STRIPE
|
||||
|
||||
constructor(_, options) {
|
||||
super(_, options)
|
||||
}
|
||||
|
||||
get paymentIntentOptions(): PaymentIntentOptions {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
export default StripeProviderService
|
||||
@@ -0,0 +1,19 @@
|
||||
import StripeBase from "../core/stripe-base"
|
||||
import { PaymentIntentOptions, PaymentProviderKeys } from "../types"
|
||||
|
||||
class Przelewy24ProviderService extends StripeBase {
|
||||
static PROVIDER = PaymentProviderKeys.PRZELEWY_24
|
||||
|
||||
constructor(_, options) {
|
||||
super(_, options)
|
||||
}
|
||||
|
||||
get paymentIntentOptions(): PaymentIntentOptions {
|
||||
return {
|
||||
payment_method_types: ["p24"],
|
||||
capture_method: "automatic",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Przelewy24ProviderService
|
||||
@@ -0,0 +1,44 @@
|
||||
export interface StripeCredentials {
|
||||
apiKey: string
|
||||
webhookSecret: string
|
||||
}
|
||||
|
||||
export interface StripeOptions {
|
||||
credentials: Record<string, StripeCredentials>
|
||||
/**
|
||||
* Use this flag to capture payment immediately (default is false)
|
||||
*/
|
||||
capture?: boolean
|
||||
/**
|
||||
* set `automatic_payment_methods` to `{ enabled: true }`
|
||||
*/
|
||||
automatic_payment_methods?: boolean
|
||||
/**
|
||||
* Set a default description on the intent if the context does not provide one
|
||||
*/
|
||||
payment_description?: string
|
||||
}
|
||||
|
||||
export interface PaymentIntentOptions {
|
||||
capture_method?: "automatic" | "manual"
|
||||
setup_future_usage?: "on_session" | "off_session"
|
||||
payment_method_types?: string[]
|
||||
}
|
||||
|
||||
export const ErrorCodes = {
|
||||
PAYMENT_INTENT_UNEXPECTED_STATE: "payment_intent_unexpected_state",
|
||||
}
|
||||
|
||||
export const ErrorIntentStatus = {
|
||||
SUCCEEDED: "succeeded",
|
||||
CANCELED: "canceled",
|
||||
}
|
||||
|
||||
export const PaymentProviderKeys = {
|
||||
STRIPE: "stripe",
|
||||
BAN_CONTACT: "stripe-bancontact",
|
||||
BLIK: "stripe-blik",
|
||||
GIROPAY: "stripe-giropay",
|
||||
IDEAL: "stripe-ideal",
|
||||
PRZELEWY_24: "stripe-przelewy24",
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"es5",
|
||||
"es6",
|
||||
"es2019"
|
||||
],
|
||||
"target": "es5",
|
||||
"jsx": "react-jsx" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */,
|
||||
"outDir": "./dist",
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"noImplicitReturns": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"noImplicitThis": true,
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"downlevelIteration": true, // to use ES5 specific tooling
|
||||
"inlineSourceMap": true /* Emit a single file with source maps instead of having a separate file. */
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": [
|
||||
"dist",
|
||||
"build",
|
||||
"src/**/__tests__",
|
||||
"src/**/__mocks__",
|
||||
"src/**/__fixtures__",
|
||||
"node_modules",
|
||||
".eslintrc.js"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user