Files
0pt/lib/subscriptions-store.ts
T
adminandClaude Opus 4.8 f4fa1c0a5e feat(portal+admin): shared shell, customer portal (dashboard nav, subscriptions, settings) + admin portal (order queue w/ status actions, source registry) + admin/subscriptions APIs
PortalShell (sidebar + session bar via /api/auth/me + logout). Customer: /portal nav, /portal/subscriptions (create feed), /portal/settings (dev-login + DPA). Admin: /admin (metrics + order queue with inline status advance), /admin/sources. APIs: /api/admin/metrics, /api/subscriptions. tsc 0, build green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 21:29:27 +02:00

37 lines
1.3 KiB
TypeScript

import { getSql } from "@/lib/db";
export interface Subscription {
sub_id: string;
order_id: string;
cadence: string;
webhook_url: string | null;
status: string;
next_run_at: string | null;
created_at: string;
}
const mem = new Map<string, Subscription>();
export async function createSubscription(order_id: string, cadence: string, webhook_url: string | null): Promise<Subscription> {
const sql = getSql();
if (sql) {
const [row] = await sql<Subscription[]>`
INSERT INTO subscriptions (order_id, cadence, webhook_url, status)
VALUES (${order_id}, ${cadence}, ${webhook_url}, 'active')
RETURNING sub_id, order_id, cadence, webhook_url, status, next_run_at, now() AS created_at`;
return row;
}
const id = globalThis.crypto?.randomUUID?.() ?? `sub-${Math.floor(Math.random() * 1e9)}`;
const sub: Subscription = { sub_id: id, order_id, cadence, webhook_url, status: "active", next_run_at: null, created_at: new Date().toISOString() };
mem.set(id, sub);
return sub;
}
export async function listSubscriptions(): Promise<Subscription[]> {
const sql = getSql();
if (sql) {
return sql<Subscription[]>`SELECT sub_id, order_id, cadence, webhook_url, status, next_run_at, created_at FROM subscriptions ORDER BY created_at DESC LIMIT 100`;
}
return [...mem.values()];
}