158 lines
5.3 KiB
TypeScript
158 lines
5.3 KiB
TypeScript
// Switch the active payment provider WITHOUT re-running Connect.
|
|
// Use case: operator has both BTCPay and Zaprite configured (i.e.,
|
|
// they ran Connect on both at some point) and wants to flip which
|
|
// one currently handles purchases.
|
|
//
|
|
// One unified "Switch active payment provider" action with a
|
|
// dropdown — replaces the two earlier "Activate BTCPay" / "Activate
|
|
// Zaprite" actions, which were confusing because they appeared
|
|
// alongside Connect/Disconnect/Status and operators couldn't tell
|
|
// at a glance which one was currently active.
|
|
//
|
|
// If the chosen provider isn't yet configured, the daemon returns
|
|
// 400 with a "Run Connect first" message; we surface that to the
|
|
// operator unchanged.
|
|
|
|
import { sdk } from '../sdk'
|
|
import { store } from '../fileModels/store'
|
|
import { adminCall, LICENSING_URL } from '../utils'
|
|
|
|
const { InputSpec, Value } = sdk
|
|
|
|
const switchInput = InputSpec.of({
|
|
provider: Value.select({
|
|
name: 'Active provider',
|
|
description:
|
|
'Which connected payment provider should handle new purchases. ' +
|
|
'The other provider stays configured (no need to re-run Connect ' +
|
|
'if you switch back). Existing license keys are unaffected.',
|
|
default: 'btcpay',
|
|
values: {
|
|
btcpay: 'BTCPay',
|
|
zaprite: 'Zaprite',
|
|
},
|
|
}),
|
|
})
|
|
|
|
async function activate(provider: 'btcpay' | 'zaprite') {
|
|
const storeData = await store.read().once()
|
|
if (!storeData) throw new Error('Store not initialized — restart the service.')
|
|
const resp = await adminCall(
|
|
LICENSING_URL,
|
|
storeData.admin_api_key,
|
|
'/v1/admin/payment-provider/activate',
|
|
{
|
|
method: 'POST',
|
|
body: JSON.stringify({ provider }),
|
|
},
|
|
)
|
|
if (!resp.ok) {
|
|
throw new Error(`Activate failed: HTTP ${resp.status} — ${await resp.text()}`)
|
|
}
|
|
const body = (await resp.json()) as { ok: true; active: string }
|
|
return body
|
|
}
|
|
|
|
/** Unified switch — replaces the two single-purpose Activate actions. */
|
|
export const switchPaymentProvider = sdk.Action.withInput(
|
|
'switch-payment-provider',
|
|
async () => ({
|
|
name: 'Switch active payment provider',
|
|
description:
|
|
'Flip which connected payment provider handles new purchases ' +
|
|
'(BTCPay vs Zaprite). Use only when both are already configured. ' +
|
|
"Existing license keys aren't affected by the swap.",
|
|
warning: null,
|
|
allowedStatuses: 'only-running',
|
|
group: 'Payment provider',
|
|
visibility: 'enabled',
|
|
}),
|
|
switchInput,
|
|
async ({ effects: _effects }) => {
|
|
// Pre-fill from current active provider so the operator can
|
|
// see what's set and only need to click if they want to change.
|
|
const storeData = await store.read().once()
|
|
if (!storeData) return { provider: 'btcpay' as const }
|
|
try {
|
|
const resp = await adminCall(
|
|
LICENSING_URL,
|
|
storeData.admin_api_key,
|
|
'/v1/admin/payment-provider/status',
|
|
{ method: 'GET' },
|
|
)
|
|
if (resp.ok) {
|
|
const body = (await resp.json()) as { active?: string }
|
|
if (body.active === 'zaprite') return { provider: 'zaprite' as const }
|
|
}
|
|
} catch {
|
|
// Status read failure shouldn't block the action.
|
|
}
|
|
return { provider: 'btcpay' as const }
|
|
},
|
|
async ({ effects: _effects, input }) => {
|
|
const body = await activate(input.provider)
|
|
const other = input.provider === 'btcpay' ? 'Zaprite' : 'BTCPay'
|
|
const label = input.provider === 'btcpay' ? 'BTCPay' : 'Zaprite'
|
|
return {
|
|
version: '1',
|
|
title: `${label} is now the active provider`,
|
|
message:
|
|
`Active payment provider is now ${body.active}. New purchases ` +
|
|
`route through ${label}. ${other} remains configured but ` +
|
|
`inactive until you switch again or disconnect it.`,
|
|
result: null,
|
|
}
|
|
},
|
|
)
|
|
|
|
// Legacy single-purpose actions retained as deprecated shims so any
|
|
// operator scripts/links pointing at the old action ids still work
|
|
// after upgrade. The unified switchPaymentProvider above is the
|
|
// recommended path. Operators see only the new action in the StartOS
|
|
// UI (these aren't registered in actions/index.ts after this change).
|
|
export const activateBtcpay = sdk.Action.withoutInput(
|
|
'activate-btcpay',
|
|
async () => ({
|
|
name: 'Activate BTCPay (legacy)',
|
|
description:
|
|
'Deprecated — use "Switch active payment provider" instead. ' +
|
|
'Kept for backward compatibility with old scripts.',
|
|
warning: null,
|
|
allowedStatuses: 'only-running',
|
|
group: 'Payment provider',
|
|
visibility: 'hidden',
|
|
}),
|
|
async () => {
|
|
const body = await activate('btcpay')
|
|
return {
|
|
version: '1',
|
|
title: 'BTCPay is now the active provider',
|
|
message: `Active payment provider is now ${body.active}.`,
|
|
result: null,
|
|
}
|
|
},
|
|
)
|
|
|
|
export const activateZaprite = sdk.Action.withoutInput(
|
|
'activate-zaprite',
|
|
async () => ({
|
|
name: 'Activate Zaprite (legacy)',
|
|
description:
|
|
'Deprecated — use "Switch active payment provider" instead. ' +
|
|
'Kept for backward compatibility with old scripts.',
|
|
warning: null,
|
|
allowedStatuses: 'only-running',
|
|
group: 'Payment provider',
|
|
visibility: 'hidden',
|
|
}),
|
|
async () => {
|
|
const body = await activate('zaprite')
|
|
return {
|
|
version: '1',
|
|
title: 'Zaprite is now the active provider',
|
|
message: `Active payment provider is now ${body.active}.`,
|
|
result: null,
|
|
}
|
|
},
|
|
)
|