import db from "../db.server"; import { planCodeFromSubscription } from "./plans"; type GraphQL = (query: string, options?: { variables?: Record }) => Promise; export interface AdminLike { graphql: GraphQL } export async function gql(admin: AdminLike, query: string, variables?: Record): Promise { const res = await admin.graphql(query, variables ? { variables } : undefined); const json = (await res.json()) as { data?: T; errors?: unknown }; if (json.errors) throw new Error(`GraphQL error: ${JSON.stringify(json.errors)}`); return json.data as T; } const SHOP_QUERY = `#graphql query BundleOffersShop { shop { currencyCode ianaTimezone currencyFormats { moneyFormat } } currentAppInstallation { id activeSubscriptions { name status test } } }`; /** Creates/refreshes the Shop row from the Admin API (currency, timezone, plan). */ export async function syncShop(admin: AdminLike, domain: string) { const data = await gql(admin, SHOP_QUERY); const subs = (data.currentAppInstallation?.activeSubscriptions || []) as { name: string; status: string }[]; const active = subs.find((s) => s.status === "ACTIVE"); const planCode = planCodeFromSubscription(active?.name); const values = { currency: data.shop.currencyCode, timezone: data.shop.ianaTimezone || "UTC", moneyFormat: data.shop.currencyFormats?.moneyFormat || "${{amount}}", appInstallationId: data.currentAppInstallation?.id, planCode, uninstalledAt: null, }; return db.shop.upsert({ where: { domain }, create: { domain, ...values }, update: values }); } export async function getShop(domain: string) { return db.shop.findUnique({ where: { domain } }); } /** Shop row for an admin request; syncs from Shopify the first time (or when forced). */ export async function ensureShop(admin: AdminLike, domain: string, force = false) { const shop = await getShop(domain); if (shop && !force && shop.appInstallationId && !shop.uninstalledAt) return shop; return syncShop(admin, domain); }