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(plugin-stripe): update plugin stripe for v3 #6019

Merged
merged 12 commits into from May 2, 2024
8 changes: 3 additions & 5 deletions packages/plugin-stripe/src/admin.ts
@@ -1,10 +1,10 @@
import type { Config } from 'payload/config'

import type { SanitizedStripeConfig, StripeConfig } from './types'
import type { SanitizedStripeConfig, StripeConfig } from './types.js'

import { getFields } from './fields/getFields'
import { getFields } from './fields/getFields.js'

const stripePlugin =
export const stripePlugin =
(incomingStripeConfig: StripeConfig) =>
(config: Config): Config => {
const { collections } = config
Expand Down Expand Up @@ -42,5 +42,3 @@ const stripePlugin =
}),
}
}

export default stripePlugin
17 changes: 8 additions & 9 deletions packages/plugin-stripe/src/fields/getFields.ts
@@ -1,8 +1,8 @@
import type { CollectionConfig, Field } from 'payload/types'

import type { SanitizedStripeConfig } from '../types'
import type { SanitizedStripeConfig } from '../types.js'

import { LinkToDoc } from '../ui/LinkToDoc'
import { LinkToDoc } from '../ui/LinkToDoc.js'

interface Args {
collection: CollectionConfig
Expand Down Expand Up @@ -39,13 +39,12 @@ export const getFields = ({ collection, stripeConfig, syncConfig }: Args): Field
type: 'ui',
admin: {
components: {
Field: (args) =>
LinkToDoc({
...args,
isTestKey: stripeConfig.isTestKey,
nameOfIDField: 'stripeID',
stripeResourceType: syncConfig.stripeResourceType,
}),
Field: LinkToDoc,
},
custom: {
isTestKey: stripeConfig.isTestKey,
nameOfIDField: 'stripeID',
stripeResourceType: syncConfig.stripeResourceType,
},
position: 'sidebar',
},
Expand Down
21 changes: 14 additions & 7 deletions packages/plugin-stripe/src/hooks/createNewInStripe.ts
Expand Up @@ -3,11 +3,13 @@ import type { CollectionBeforeValidateHook, CollectionConfig } from 'payload/typ
import { APIError } from 'payload/errors'
import Stripe from 'stripe'

import type { StripeConfig } from '../types'
import type { StripeConfig } from '../types.js'

import { deepen } from '../utilities/deepen'
import { deepen } from '../utilities/deepen.js'

const stripeSecretKey = process.env.STRIPE_SECRET_KEY
// api version can only be the latest, stripe recommends ts ignoring it
// @ts-expect-error
const stripe = new Stripe(stripeSecretKey || '', { apiVersion: '2022-08-01' })

type HookArgsWithCustomCollection = Omit<
Expand Down Expand Up @@ -52,12 +54,15 @@ export const createNewInStripe: CollectionBeforeValidateHookWithArgs = async (ar

if (syncConfig) {
// combine all fields of this object and match their respective values within the document
let syncedFields = syncConfig.fields.reduce((acc, field) => {
const { fieldPath, stripeProperty } = field
let syncedFields = syncConfig.fields.reduce(
(acc, field) => {
const { fieldPath, stripeProperty } = field

acc[stripeProperty] = dataRef[fieldPath]
return acc
}, {} as Record<string, any>)
acc[stripeProperty] = dataRef[fieldPath]
return acc
},
{} as Record<string, any>,
)

syncedFields = deepen(syncedFields)

Expand All @@ -72,6 +77,7 @@ export const createNewInStripe: CollectionBeforeValidateHookWithArgs = async (ar
try {
// NOTE: Typed as "any" because the "create" method is not standard across all Stripe resources
const stripeResource = await stripe?.[syncConfig.stripeResourceType]?.create(
// @ts-expect-error
syncedFields,
)

Expand Down Expand Up @@ -105,6 +111,7 @@ export const createNewInStripe: CollectionBeforeValidateHookWithArgs = async (ar

// NOTE: Typed as "any" because the "create" method is not standard across all Stripe resources
const stripeResource = await stripe?.[syncConfig.stripeResourceType]?.create(
// @ts-expect-error
syncedFields,
)

Expand Down
4 changes: 3 additions & 1 deletion packages/plugin-stripe/src/hooks/deleteFromStripe.ts
Expand Up @@ -3,9 +3,11 @@ import type { CollectionAfterDeleteHook, CollectionConfig } from 'payload/types'
import { APIError } from 'payload/errors'
import Stripe from 'stripe'

import type { StripeConfig } from '../types'
import type { StripeConfig } from '../types.js'

const stripeSecretKey = process.env.STRIPE_SECRET_KEY
// api version can only be the latest, stripe recommends ts ignoring it
// @ts-expect-error
const stripe = new Stripe(stripeSecretKey || '', { apiVersion: '2022-08-01' })

type HookArgsWithCustomCollection = Omit<Parameters<CollectionAfterDeleteHook>[0], 'collection'> & {
Expand Down
21 changes: 13 additions & 8 deletions packages/plugin-stripe/src/hooks/syncExistingWithStripe.ts
Expand Up @@ -3,11 +3,13 @@ import type { CollectionBeforeChangeHook, CollectionConfig } from 'payload/types
import { APIError } from 'payload/errors'
import Stripe from 'stripe'

import type { StripeConfig } from '../types'
import type { StripeConfig } from '../types.js'

import { deepen } from '../utilities/deepen'
import { deepen } from '../utilities/deepen.js'

const stripeSecretKey = process.env.STRIPE_SECRET_KEY
// api version can only be the latest, stripe recommends ts ignoring it
// @ts-expect-error
const stripe = new Stripe(stripeSecretKey || '', { apiVersion: '2022-08-01' })

type HookArgsWithCustomCollection = Omit<
Expand Down Expand Up @@ -39,12 +41,15 @@ export const syncExistingWithStripe: CollectionBeforeChangeHookWithArgs = async
if (syncConfig) {
if (operation === 'update') {
// combine all fields of this object and match their respective values within the document
let syncedFields = syncConfig.fields.reduce((acc, field) => {
const { fieldPath, stripeProperty } = field

acc[stripeProperty] = data[fieldPath]
return acc
}, {} as Record<string, any>)
let syncedFields = syncConfig.fields.reduce(
(acc, field) => {
const { fieldPath, stripeProperty } = field

acc[stripeProperty] = data[fieldPath]
return acc
},
{} as Record<string, any>,
)

syncedFields = deepen(syncedFields)

Expand Down
7 changes: 4 additions & 3 deletions packages/plugin-stripe/src/index.ts
Expand Up @@ -9,7 +9,10 @@ import { syncExistingWithStripe } from './hooks/syncExistingWithStripe.js'
import { stripeREST } from './routes/rest.js'
import { stripeWebhooks } from './routes/webhooks.js'

const stripePlugin =
export { LinkToDoc } from './ui/LinkToDoc.js'
export { stripeProxy } from './utilities/stripeProxy.js'

export const stripePlugin =
(incomingStripeConfig: StripeConfig) =>
(config: Config): Config => {
const { collections } = config
Expand Down Expand Up @@ -112,5 +115,3 @@ const stripePlugin =
endpoints,
}
}

export default stripePlugin
9 changes: 0 additions & 9 deletions packages/plugin-stripe/src/mocks/mockFile.js

This file was deleted.

9 changes: 4 additions & 5 deletions packages/plugin-stripe/src/routes/webhooks.ts
Expand Up @@ -19,24 +19,23 @@ export const stripeWebhooks = async (args: {

if (stripeWebhooksEndpointSecret) {
const stripe = new Stripe(stripeSecretKey, {
// api version can only be the latest, stripe recommends ts ignoring it
// @ts-expect-error
apiVersion: '2022-08-01',
appInfo: {
name: 'Stripe Payload Plugin',
url: 'https://payloadcms.com',
},
})

const body = await req.text()
const stripeSignature = req.headers.get('stripe-signature')

if (stripeSignature) {
let event: Stripe.Event | undefined

try {
event = stripe.webhooks.constructEvent(
await req.text(),
stripeSignature,
stripeWebhooksEndpointSecret,
)
event = stripe.webhooks.constructEvent(body, stripeSignature, stripeWebhooksEndpointSecret)
} catch (err: unknown) {
const msg: string = err instanceof Error ? err.message : JSON.stringify(err)
req.payload.logger.error(`Error constructing Stripe event: ${msg}`)
Expand Down
14 changes: 6 additions & 8 deletions packages/plugin-stripe/src/ui/LinkToDoc.tsx
@@ -1,17 +1,15 @@
'use client'
import type { CustomComponent } from 'payload/config'
import type { UIField } from 'payload/types'

import { useFieldProps } from '@payloadcms/ui/forms/FieldPropsProvider'
// import CopyToClipboard from 'payload/dist/admin/components/elements/CopyToClipboard'
import { useFormFields } from '@payloadcms/ui/forms/Form'
import React from 'react'

export const LinkToDoc: React.FC<
UIField & {
isTestKey: boolean
nameOfIDField: string
stripeResourceType: string
}
> = (props) => {
const { isTestKey, nameOfIDField, stripeResourceType } = props
export const LinkToDoc: CustomComponent<UIField> = () => {
const { custom } = useFieldProps()
const { isTestKey, nameOfIDField, stripeResourceType } = custom

const field = useFormFields(([fields]) => fields[nameOfIDField])
const { value: stripeID } = field || {}
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin-stripe/src/utilities/stripeProxy.ts
@@ -1,7 +1,7 @@
import lodashGet from 'lodash.get'
import Stripe from 'stripe'

import type { StripeProxy } from '../types'
import type { StripeProxy } from '../types.js'

export const stripeProxy: StripeProxy = async ({ stripeArgs, stripeMethod, stripeSecretKey }) => {
const stripe = new Stripe(stripeSecretKey, {
Expand Down
17 changes: 10 additions & 7 deletions packages/plugin-stripe/src/webhooks/handleCreatedOrUpdated.ts
@@ -1,8 +1,8 @@
import { v4 as uuid } from 'uuid'

import type { SanitizedStripeConfig, StripeWebhookHandler } from '../types'
import type { SanitizedStripeConfig, StripeWebhookHandler } from '../types.js'

import { deepen } from '../utilities/deepen'
import { deepen } from '../utilities/deepen.js'

type HandleCreatedOrUpdated = (
args: Parameters<StripeWebhookHandler>[0] & {
Expand Down Expand Up @@ -62,12 +62,15 @@ export const handleCreatedOrUpdated: HandleCreatedOrUpdated = async (args) => {
const foundDoc = payloadQuery.docs[0] as any

// combine all properties of the Stripe doc and match their respective fields within the document
let syncedData = syncConfig.fields.reduce((acc, field) => {
const { fieldPath, stripeProperty } = field
let syncedData = syncConfig.fields.reduce(
(acc, field) => {
const { fieldPath, stripeProperty } = field

acc[fieldPath] = stripeDoc[stripeProperty]
return acc
}, {} as Record<string, any>)
acc[fieldPath] = stripeDoc[stripeProperty]
return acc
},
{} as Record<string, any>,
)

syncedData = deepen({
...syncedData,
Expand Down
3 changes: 2 additions & 1 deletion packages/plugin-stripe/src/webhooks/handleDeleted.ts
@@ -1,4 +1,4 @@
import type { SanitizedStripeConfig, StripeWebhookHandler } from '../types'
import type { SanitizedStripeConfig, StripeWebhookHandler } from '../types.js'

type HandleDeleted = (
args: Parameters<StripeWebhookHandler>[0] & {
Expand Down Expand Up @@ -58,6 +58,7 @@ export const handleDeleted: HandleDeleted = async (args) => {
if (logs) payload.logger.info(`- Deleting Payload document with ID: '${foundDoc.id}'...`)

try {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
payload.delete({
id: foundDoc.id,
collection: collectionSlug,
Expand Down
9 changes: 6 additions & 3 deletions packages/plugin-stripe/src/webhooks/index.ts
@@ -1,7 +1,7 @@
import type { StripeWebhookHandler } from '../types'
import type { StripeWebhookHandler } from '../types.js'

import { handleCreatedOrUpdated } from './handleCreatedOrUpdated'
import { handleDeleted } from './handleDeleted'
import { handleCreatedOrUpdated } from './handleCreatedOrUpdated.js'
import { handleDeleted } from './handleDeleted.js'

export const handleWebhooks: StripeWebhookHandler = async (args) => {
const { event, payload, stripeConfig } = args
Expand All @@ -21,6 +21,7 @@ export const handleWebhooks: StripeWebhookHandler = async (args) => {
if (syncConfig) {
switch (method) {
case 'created': {
// eslint-disable-next-line @typescript-eslint/await-thenable
paulpopus marked this conversation as resolved.
Show resolved Hide resolved
await handleCreatedOrUpdated({
...args,
resourceType,
Expand All @@ -30,6 +31,7 @@ export const handleWebhooks: StripeWebhookHandler = async (args) => {
break
}
case 'updated': {
// eslint-disable-next-line @typescript-eslint/await-thenable
await handleCreatedOrUpdated({
...args,
resourceType,
Expand All @@ -39,6 +41,7 @@ export const handleWebhooks: StripeWebhookHandler = async (args) => {
break
}
case 'deleted': {
// eslint-disable-next-line @typescript-eslint/await-thenable
await handleDeleted({
...args,
resourceType,
Expand Down
2 changes: 1 addition & 1 deletion scripts/release.ts
Expand Up @@ -49,7 +49,7 @@ const packageWhitelist = [
'plugin-redirects',
'plugin-search',
'plugin-seo',
// 'plugin-stripe',
'plugin-stripe',
paulpopus marked this conversation as resolved.
Show resolved Hide resolved
// 'plugin-sentry',
]

Expand Down
16 changes: 8 additions & 8 deletions test/plugin-stripe/collections/Customers.ts
@@ -1,6 +1,7 @@
import type { CollectionConfig } from 'payload/types'

import { LinkToDoc } from '../../../packages/plugin-stripe/src/ui/LinkToDoc.js'
import { LinkToDoc } from '@payloadcms/plugin-stripe'

import { customersSlug } from '../shared.js'

export const Customers: CollectionConfig = {
Expand Down Expand Up @@ -31,13 +32,12 @@ export const Customers: CollectionConfig = {
type: 'ui',
admin: {
components: {
Field: (args) =>
LinkToDoc({
...args,
isTestKey: process.env.PAYLOAD_PUBLIC_IS_STRIPE_TEST_KEY === 'true',
nameOfIDField: `${args.path}.stripeSubscriptionID`,
stripeResourceType: 'subscriptions',
}),
Field: LinkToDoc,
},
custom: {
isTestKey: process.env.PAYLOAD_PUBLIC_IS_STRIPE_TEST_KEY === 'true',
nameOfIDField: `stripeSubscriptionID`,
stripeResourceType: 'subscriptions',
},
},
label: 'Link',
Expand Down
2 changes: 1 addition & 1 deletion test/plugin-stripe/config.ts
@@ -1,4 +1,4 @@
import stripePlugin from '@payloadcms/plugin-stripe'
import { stripePlugin } from '@payloadcms/plugin-stripe'
paulpopus marked this conversation as resolved.
Show resolved Hide resolved

import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
import { devUser } from '../credentials.js'
Expand Down