Files
WRNexusJS/packages/payment/src/plugin.ts
T
Clintchiz 98e0813061
Quality / quality (ubuntu-latest) (push) Failing after 9m55s
Quality / quality (windows-latest) (push) Canceled after 0s
feat: add gateway-neutral payment package
2026-08-23 21:05:27 +05:30

54 lines
3.4 KiB
TypeScript

import { basename, dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { definePlugin, type PluginContext } from "@wrnexus/plugin";
const root = dirname(dirname(fileURLToPath(import.meta.url)));
const extension = basename(dirname(fileURLToPath(import.meta.url))) === "dist" ? ".js" : ".ts";
const webhookEntry = join(dirname(fileURLToPath(import.meta.url)), `runtime-webhook${extension}`);
const migration = `-- +up
CREATE TABLE IF NOT EXISTS wrn_payment_intent (id TEXT PRIMARY KEY, subject TEXT NOT NULL, gateway TEXT NOT NULL, gateway_ref TEXT NOT NULL, amount BIGINT NOT NULL, currency TEXT NOT NULL, idempotency_key TEXT NOT NULL UNIQUE, created_at BIGINT NOT NULL, checkout_url TEXT, client_json TEXT NOT NULL, metadata_json TEXT NOT NULL);
CREATE INDEX IF NOT EXISTS wrn_payment_intent_subject ON wrn_payment_intent(subject, created_at);
CREATE TABLE IF NOT EXISTS wrn_payment_event (id TEXT PRIMARY KEY, intent_id TEXT NOT NULL, type TEXT NOT NULL, status TEXT NOT NULL, created_at BIGINT NOT NULL, payload_json TEXT, FOREIGN KEY(intent_id) REFERENCES wrn_payment_intent(id));
CREATE INDEX IF NOT EXISTS wrn_payment_event_intent ON wrn_payment_event(intent_id, created_at, id);
CREATE TABLE IF NOT EXISTS wrn_payment_refund (id TEXT PRIMARY KEY, intent_id TEXT NOT NULL, gateway_ref TEXT NOT NULL, amount BIGINT NOT NULL, currency TEXT NOT NULL, reason TEXT NOT NULL, idempotency_key TEXT NOT NULL UNIQUE, status TEXT NOT NULL, created_at BIGINT NOT NULL, FOREIGN KEY(intent_id) REFERENCES wrn_payment_intent(id));
CREATE TABLE IF NOT EXISTS wrn_payment_method (id TEXT PRIMARY KEY, subject TEXT NOT NULL, gateway TEXT NOT NULL, gateway_ref TEXT NOT NULL, brand TEXT, last4 TEXT, expires TEXT, is_default INTEGER NOT NULL DEFAULT 0, created_at BIGINT NOT NULL);
CREATE TABLE IF NOT EXISTS wrn_payment_customer (subject TEXT NOT NULL, gateway TEXT NOT NULL, gateway_ref TEXT NOT NULL, created_at BIGINT NOT NULL, PRIMARY KEY(subject,gateway));
-- +down
DROP TABLE IF EXISTS wrn_payment_customer;
DROP TABLE IF EXISTS wrn_payment_method;
DROP TABLE IF EXISTS wrn_payment_refund;
DROP TABLE IF EXISTS wrn_payment_event;
DROP TABLE IF EXISTS wrn_payment_intent;`;
export function paymentPlugin() {
const key = "@wrnexus/payment:enabled";
return definePlugin({
name: "@wrnexus/payment",
version: "0.8.0",
componentDirs: [join(root, "components")],
routeEntries(context) {
return context.metadata.get(key)
? [{ kind: "api" as const, path: "/api/payments/webhook/:gateway", entry: webhookEntry }]
: [];
},
configure(config, context) {
const value = config.payment as
{ default?: string; gateways?: Record<string, unknown>; sandbox?: boolean } | undefined;
context.metadata.set(key, Boolean(value));
if (!value) return;
if (!value.default) throw new Error("WRN-PAYMENT-CONFIG: payment.default is required");
if (!value.gateways?.[value.default] && value.default !== "sandbox")
throw new Error(
`WRN-PAYMENT-CONFIG: default gateway '${value.default}' has no configuration`,
);
if (process.env.NODE_ENV === "production" && value.sandbox)
throw new Error("WRN-PAYMENT-CONFIG: sandbox cannot be enabled in production");
},
migrations(context: PluginContext) {
return context.metadata.get(key) ? [{ id: "wrnexus-payment-001", source: migration }] : [];
},
documentation: [join(root, "README.md")],
});
}
export default paymentPlugin;