Files
Keysat 238689ddcc Persist payment-webhook dedup; declare BTCPay required; scope CORS
Replace the in-memory dedup Sets in the BTCPay and Zaprite webhook
handlers (and the BTCPay rescan path) with a persistent JSON-backed
store (server/webhook-dedup.js). The in-memory sets were cleared on
restart, so a duplicate webhook delivery straddling a relay restart
could double-credit (BTCPay) or double-extend a subscription (Zaprite).
The store atomically writes /data/processed-webhooks.json, namespaces
keys per rail (storeId|invoiceId vs zaprite:orderId), and prunes
entries older than 180 days (safely beyond any retry window).

Also:
- BTCPay is a required running dependency (operator decision). Config
  was already optional:false/kind:'running'; corrected the contradictory
  "optional" comment in the manifest to match.
- Scope cors() to /relay/* only — off /admin/* and the same-origin
  dashboard, which don't need permissive CORS.
- Add money-path unit tests (commitCredit/refundCredit/applyTierPromotion)
  and webhook-dedup tests (incl. the survives-a-restart guarantee).
- Fix two AGENTS.md auth-doc drifts; refresh Current state.

Version 0.2.125 -> 0.2.126.
2026-06-15 18:15:00 -05:00

54 lines
1.8 KiB
TypeScript

import { setupManifest } from '@start9labs/start-sdk'
import { alertInstall, long, short } from './i18n'
export const manifest = setupManifest({
id: 'recap-relay',
title: 'Recap Relay',
license: 'Proprietary',
packageRepo: 'https://ten31.xyz',
upstreamRepo: 'https://ten31.xyz',
marketingUrl: 'https://ten31.xyz',
donationUrl: null,
docsUrls: [],
description: { short, long },
volumes: ['main'],
images: {
main: {
source: {
dockerBuild: {
workdir: '.',
dockerfile: './Dockerfile',
},
},
arch: ['x86_64', 'aarch64'],
},
},
alerts: {
install: alertInstall,
update: null,
uninstall: null,
restore: null,
start: null,
stop: null,
},
// BTCPay Server is a REQUIRED running dependency (optional: false
// here, kind: 'running' in dependencies.ts). It's the only payment
// rail through which the operator actually gets paid, so the relay
// shouldn't run without it. The dependency also wires up the internal
// docker hostname (btcpayserver.startos:23000) the relay-to-BTCPay API
// calls rely on, and lets the dashboard's "Connect BTCPay" flow
// auto-discover the URL via sdk.serviceInterface.getAll(). (Gemini is
// internet-fronted and the Parakeet/Gemma backends are at
// user-configured LAN URLs, so neither is a StartOS dependency.)
dependencies: {
btcpayserver: {
description: {
en_US:
'Required for relay credit top-ups via Lightning. The relay-to-BTCPay API calls use the internal Start9 docker hostname (btcpayserver.startos:23000), which is only wired up when BTCPay is declared as a required running dependency. Without this dependency the one-click BTCPay setup flow fails with "fetch failed".',
},
optional: false,
s9pk: null,
},
},
})