mirror of
https://github.com/xtr-dev/payload-billing.git
synced 2025-12-10 10:53:23 +00:00
Use Symbol.for() instead of Symbol() for plugin singleton storage to ensure
plugin state persists across different module loading contexts (admin panel,
API routes, server components).
This fixes the "Billing plugin not initialized" error that occurred when
calling payload.create() from Next.js API routes, server components, or
server actions.
Changes:
- Plugin singleton now uses Symbol.for('@xtr-dev/payload-billing')
- Provider singletons (stripe, mollie, test) use global symbols
- Enhanced error message with troubleshooting guidance
Fixes #1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
57 lines
1.8 KiB
TypeScript
57 lines
1.8 KiB
TypeScript
import { createInvoicesCollection, createPaymentsCollection, createRefundsCollection } from '../collections/index'
|
|
import type { BillingPluginConfig } from './config'
|
|
import type { Config, Payload } from 'payload'
|
|
import { createSingleton } from './singleton'
|
|
import type { PaymentProvider } from '../providers/index'
|
|
|
|
const singleton = createSingleton(Symbol.for('@xtr-dev/payload-billing'))
|
|
|
|
type BillingPlugin = {
|
|
config: BillingPluginConfig
|
|
providerConfig: {
|
|
[key: string]: PaymentProvider
|
|
}
|
|
}
|
|
|
|
export const useBillingPlugin = (payload: Payload) => singleton.get(payload) as BillingPlugin | undefined
|
|
|
|
export const billingPlugin = (pluginConfig: BillingPluginConfig = {}) => (config: Config): Config => {
|
|
if (pluginConfig.disabled) {
|
|
return config
|
|
}
|
|
|
|
config.collections = [
|
|
...(config.collections || []),
|
|
createPaymentsCollection(pluginConfig),
|
|
createInvoicesCollection(pluginConfig),
|
|
createRefundsCollection(pluginConfig),
|
|
];
|
|
|
|
(pluginConfig.providers || [])
|
|
.filter(provider => provider?.onConfig)
|
|
.forEach(provider => provider?.onConfig!(config, pluginConfig))
|
|
|
|
const incomingOnInit = config.onInit
|
|
config.onInit = async (payload) => {
|
|
if (incomingOnInit) {
|
|
await incomingOnInit(payload)
|
|
}
|
|
singleton.set(payload, {
|
|
config: pluginConfig,
|
|
providerConfig: (pluginConfig.providers || []).filter(Boolean).reduce(
|
|
(record, provider) => {
|
|
record[provider!.key] = provider as PaymentProvider
|
|
return record
|
|
},
|
|
{} as Record<string, PaymentProvider>
|
|
)
|
|
} satisfies BillingPlugin)
|
|
await Promise.all((pluginConfig.providers || [])
|
|
.filter(provider => provider?.onInit)
|
|
.map(provider => provider?.onInit!(payload)))
|
|
}
|
|
|
|
return config
|
|
}
|
|
export default billingPlugin
|