feat(payment): expose secure APIs and themed pages

This commit is contained in:
Clintchiz committed 2026-08-28 09:59:07 +05:30
1 parent dd8d6ecc3b
commit 2d77f5457c
15 files changed
+654 -13

No files matched your search

+42 -5
View File
@@ -1,11 +1,25 @@
import { basename, dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { definePlugin, type PluginContext } from "@wrnexus/plugin";
import type { PaymentConfig } from "./config.ts";
import { configurePaymentFromConfig, validatePaymentConfig, type PaymentConfig } from "./config.ts";
import { configurePaymentApi } from "./http.ts";
import { databasePaymentStore } from "./database.ts";
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 apiEntry = join(dirname(fileURLToPath(import.meta.url)), `runtime-api${extension}`);
const apiRoutes = [
"/api/payments/providers",
"/api/payments/intents",
"/api/payments/intents/[id]",
"/api/payments/intents/[id]/sync",
"/api/payments/intents/[id]/capture",
"/api/payments/intents/[id]/cancel",
"/api/payments/intents/[id]/refund",
"/api/payments/methods",
"/api/payments/reconcile",
];
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);
@@ -32,17 +46,40 @@ export function paymentPlugin() {
const key = "@wrnexus/payment:enabled";
return definePlugin({
name: "@wrnexus/payment",
version: "0.8.1",
version: "0.8.5",
componentDirs: [join(root, "components")],
styleSources: [
{
id: "payment-components",
entry: join(root, "components", "payment.css"),
source: join(root, "components"),
order: "normal",
},
],
routeEntries(context) {
return context.metadata.get(key)
? [{ kind: "api" as const, path: "/api/payments/webhook/:gateway", entry: webhookEntry }]
: [];
if (!context.metadata.get(key)) return [];
const apiEnabled = context.metadata.get("@wrnexus/payment:api") !== false;
return [
{ kind: "api" as const, path: "/api/payments/webhook/:gateway", entry: webhookEntry },
...(apiEnabled
? apiRoutes.map((path) => ({ kind: "api" as const, path, entry: apiEntry }))
: []),
];
},
configure(config, context) {
const value = config.payment as PaymentConfig | undefined;
context.metadata.set(key, Boolean(value));
if (!value) return;
const api = value.api === false ? { enabled: false } : (value.api ?? {});
context.metadata.set(
"@wrnexus/payment:api",
Boolean(value.gateways) && api.enabled !== false,
);
configurePaymentApi(api);
if (value.gateways) {
validatePaymentConfig(value);
configurePaymentFromConfig(value, value.store ?? databasePaymentStore());
}
if (!value.default) throw new Error("WRN-PAYMENT-CONFIG: payment.default is required");
const legacySandbox = value.default === "sandbox" && !value.gateways;
if (!value.gateways?.[value.default] && !legacySandbox)