@coursebuilder/analytics 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/database.ts"],"sourcesContent":["import {\n\tand,\n\tcount,\n\tdesc,\n\teq,\n\tgt,\n\tgte,\n\tinArray,\n\tlte,\n\tsql,\n\tsum,\n} from 'drizzle-orm'\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type AnalyticsTimeRange = '24h' | '7d' | '30d' | '90d' | 'all'\n\nexport interface AttributionTrailEvent {\n\ttype: 'click' | 'signup' | 'progress' | 'purchase'\n\ttimestamp: Date\n\tdetail: Record<string, any>\n}\n\nexport interface AttributionTrail {\n\tuser: {\n\t\tid: string\n\t\temail: string | null\n\t\tname: string | null\n\t\tcreatedAt: Date\n\t} | null\n\tevents: AttributionTrailEvent[]\n\tpurchases: {\n\t\tid: string\n\t\ttotalAmount: number\n\t\tproductName: string\n\t\tcreatedAt: Date\n\t\tcountry: string | null\n\t\tutmSource: string | null\n\t\tutmMedium: string | null\n\t\tutmCampaign: string | null\n\t}[]\n}\n\n// ─── Schema type ─────────────────────────────────────────────────────────────\n\nexport interface DatabaseAnalyticsSchema {\n\tpurchases: any\n\tproducts: any\n\tusers: any\n\tcoupon: any\n\tresourceProgress: any\n\tshortlink: any\n\tshortlinkAttribution: any\n\tshortlinkClick: any\n}\n\n// ─── Factory ─────────────────────────────────────────────────────────────────\n\n/**\n * Creates a database analytics provider that wraps all analytics query\n * functions with an injected drizzle db instance and schema tables.\n *\n * @param db - Drizzle database instance\n * @param schema - Object containing the required table references\n */\nexport function createDatabaseProvider(\n\tdb: any,\n\tschema: DatabaseAnalyticsSchema,\n) {\n\tconst {\n\t\tpurchases,\n\t\tproducts,\n\t\tusers,\n\t\tcoupon,\n\t\tresourceProgress,\n\t\tshortlink,\n\t\tshortlinkAttribution,\n\t\tshortlinkClick,\n\t} = schema\n\n\t// ─── Internal helpers ───────────────────────────────────────────────────\n\n\tconst PAID_STATUSES = ['Valid', 'Restricted'] as const\n\n\tfunction paidPurchase() {\n\t\treturn inArray(purchases.status, [...PAID_STATUSES])\n\t}\n\n\tfunction rangeToDate(range: AnalyticsTimeRange): Date | null {\n\t\tif (range === 'all') return null\n\t\tconst now = new Date()\n\t\tconst hours: Record<string, number> = {\n\t\t\t'24h': 24,\n\t\t\t'7d': 7 * 24,\n\t\t\t'30d': 30 * 24,\n\t\t\t'90d': 90 * 24,\n\t\t}\n\t\treturn new Date(now.getTime() - (hours[range] ?? 30 * 24) * 60 * 60 * 1000)\n\t}\n\n\t// ─── Revenue ───────────────────────────────────────────────────────────\n\n\tasync function getRevenueSummary(range: AnalyticsTimeRange = '30d') {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions = [paidPurchase()]\n\t\tif (since) conditions.push(gte(purchases.createdAt, since))\n\n\t\tconst [totals] = await db\n\t\t\t.select({\n\t\t\t\ttotalRevenue: sum(purchases.totalAmount),\n\t\t\t\tpurchaseCount: count(),\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions))\n\n\t\treturn {\n\t\t\ttotalRevenue: Number(totals?.totalRevenue ?? 0),\n\t\t\tpurchaseCount: totals?.purchaseCount ?? 0,\n\t\t\tavgOrderValue:\n\t\t\t\ttotals?.purchaseCount && totals.purchaseCount > 0\n\t\t\t\t\t? Number(totals.totalRevenue ?? 0) / totals.purchaseCount\n\t\t\t\t\t: 0,\n\t\t}\n\t}\n\n\tasync function getRevenueByDay(range: AnalyticsTimeRange = '30d') {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions = [paidPurchase()]\n\t\tif (since) conditions.push(gte(purchases.createdAt, since))\n\n\t\tconst rows = await db\n\t\t\t.select({\n\t\t\t\tdate: sql<string>`DATE(${purchases.createdAt})`.as('date'),\n\t\t\t\trevenue: sum(purchases.totalAmount),\n\t\t\t\tcount: count(),\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions))\n\t\t\t.groupBy(sql`DATE(${purchases.createdAt})`)\n\t\t\t.orderBy(sql`DATE(${purchases.createdAt})`)\n\n\t\treturn rows.map((r: any) => ({\n\t\t\tdate: r.date,\n\t\t\trevenue: Number(r.revenue ?? 0),\n\t\t\tcount: r.count,\n\t\t}))\n\t}\n\n\t/**\n\t * Revenue by day for the previous period of equal length.\n\t * E.g., if range = '30d', returns the 30 days before those 30 days.\n\t * Returns data with a `dayOffset` (0 = start of period) for overlay\n\t * alignment.\n\t */\n\tasync function getPreviousPeriodRevenueByDay(\n\t\trange: AnalyticsTimeRange = '30d',\n\t) {\n\t\tif (range === 'all') return []\n\n\t\tconst hours: Record<string, number> = {\n\t\t\t'24h': 24,\n\t\t\t'7d': 7 * 24,\n\t\t\t'30d': 30 * 24,\n\t\t\t'90d': 90 * 24,\n\t\t}\n\t\tconst periodMs = (hours[range] ?? 30 * 24) * 60 * 60 * 1000\n\t\tconst now = new Date()\n\t\tconst periodStart = new Date(now.getTime() - periodMs)\n\t\tconst prevStart = new Date(periodStart.getTime() - periodMs)\n\n\t\tconst rows = await db\n\t\t\t.select({\n\t\t\t\tdate: sql<string>`DATE(${purchases.createdAt})`.as('date'),\n\t\t\t\trevenue: sum(purchases.totalAmount),\n\t\t\t\tcount: count(),\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\tpaidPurchase(),\n\t\t\t\t\tgte(purchases.createdAt, prevStart),\n\t\t\t\t\tlte(purchases.createdAt, periodStart),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.groupBy(sql`DATE(${purchases.createdAt})`)\n\t\t\t.orderBy(sql`DATE(${purchases.createdAt})`)\n\n\t\treturn rows.map((r: any) => ({\n\t\t\tdate: r.date,\n\t\t\trevenue: Number(r.revenue ?? 0),\n\t\t\tcount: r.count,\n\t\t}))\n\t}\n\n\tasync function getRevenueByProduct(range: AnalyticsTimeRange = '30d') {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions = [paidPurchase()]\n\t\tif (since) conditions.push(gte(purchases.createdAt, since))\n\n\t\tconst rows = await db\n\t\t\t.select({\n\t\t\t\tproductId: purchases.productId,\n\t\t\t\tproductName: products.name,\n\t\t\t\trevenue: sum(purchases.totalAmount),\n\t\t\t\tcount: count(),\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.leftJoin(products, eq(purchases.productId, products.id))\n\t\t\t.where(and(...conditions))\n\t\t\t.groupBy(purchases.productId, products.name)\n\t\t\t.orderBy(desc(sum(purchases.totalAmount)))\n\n\t\treturn rows.map((r: any) => ({\n\t\t\tproductId: r.productId,\n\t\t\tproductName: r.productName ?? '(unknown)',\n\t\t\trevenue: Number(r.revenue ?? 0),\n\t\t\tcount: r.count,\n\t\t}))\n\t}\n\n\tasync function getRevenueByCountry(range: AnalyticsTimeRange = '30d') {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions = [paidPurchase()]\n\t\tif (since) conditions.push(gte(purchases.createdAt, since))\n\n\t\tconst rows = await db\n\t\t\t.select({\n\t\t\t\tcountry: purchases.country,\n\t\t\t\trevenue: sum(purchases.totalAmount),\n\t\t\t\tcount: count(),\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions))\n\t\t\t.groupBy(purchases.country)\n\t\t\t.orderBy(desc(sum(purchases.totalAmount)))\n\t\t\t.limit(20)\n\n\t\treturn rows.map((r: any) => ({\n\t\t\tcountry: r.country ?? '(unknown)',\n\t\t\trevenue: Number(r.revenue ?? 0),\n\t\t\tcount: r.count,\n\t\t}))\n\t}\n\n\tasync function getRecentPurchases(\n\t\tlimit: number = 20,\n\t\tfilter: 'all' | 'team' | 'individual' = 'all',\n\t\trange: AnalyticsTimeRange = 'all',\n\t) {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions = [paidPurchase()]\n\t\tif (since) conditions.push(gte(purchases.createdAt, since))\n\n\t\tif (filter === 'team') {\n\t\t\t// Multi-seat purchases: join coupon to filter seats > 1, sort by amount\n\t\t\tconditions.push(sql`${purchases.bulkCouponId} IS NOT NULL`)\n\n\t\t\tconst rows = await db\n\t\t\t\t.select({\n\t\t\t\t\tid: purchases.id,\n\t\t\t\t\tcreatedAt: purchases.createdAt,\n\t\t\t\t\ttotalAmount: purchases.totalAmount,\n\t\t\t\t\tproductName: products.name,\n\t\t\t\t\tproductId: purchases.productId,\n\t\t\t\t\tcountry: purchases.country,\n\t\t\t\t\tcouponId: purchases.couponId,\n\t\t\t\t\tuserId: purchases.userId,\n\t\t\t\t\tuserName: users.name,\n\t\t\t\t\tuserEmail: users.email,\n\t\t\t\t\torganizationId: purchases.organizationId,\n\t\t\t\t\tseats: coupon.maxUses,\n\t\t\t\t})\n\t\t\t\t.from(purchases)\n\t\t\t\t.leftJoin(products, eq(purchases.productId, products.id))\n\t\t\t\t.leftJoin(users, eq(purchases.userId, users.id))\n\t\t\t\t.leftJoin(coupon, eq(purchases.bulkCouponId, coupon.id))\n\t\t\t\t.where(and(...conditions, gt(coupon.maxUses, 1)))\n\t\t\t\t.orderBy(desc(purchases.totalAmount))\n\t\t\t\t.limit(limit)\n\n\t\t\treturn rows.map((r: any) => ({\n\t\t\t\tid: r.id,\n\t\t\t\tcreatedAt: r.createdAt,\n\t\t\t\ttotalAmount: Number(r.totalAmount),\n\t\t\t\tproductName: r.productName ?? '(unknown)',\n\t\t\t\tproductId: r.productId,\n\t\t\t\tcountry: r.country,\n\t\t\t\tcouponId: r.couponId,\n\t\t\t\tuserName: r.userName ?? null,\n\t\t\t\tuserEmail: r.userEmail ?? null,\n\t\t\t\tisTeam: true,\n\t\t\t\tseats: r.seats ?? null,\n\t\t\t}))\n\t\t}\n\n\t\tif (filter === 'individual') {\n\t\t\tconditions.push(sql`${purchases.bulkCouponId} IS NULL`)\n\t\t}\n\n\t\tconst rows = await db.query.purchases.findMany({\n\t\t\twhere: and(...conditions),\n\t\t\torderBy: [desc(purchases.totalAmount)],\n\t\t\tlimit,\n\t\t\twith: {\n\t\t\t\tproduct: true,\n\t\t\t\tuser: true,\n\t\t\t},\n\t\t})\n\n\t\treturn rows.map((r: any) => ({\n\t\t\tid: r.id,\n\t\t\tcreatedAt: r.createdAt,\n\t\t\ttotalAmount: Number(r.totalAmount),\n\t\t\tproductName: r.product?.name ?? '(unknown)',\n\t\t\tproductId: r.productId,\n\t\t\tcountry: r.country,\n\t\t\tcouponId: r.couponId,\n\t\t\tuserName: r.user?.name ?? null,\n\t\t\tuserEmail: r.user?.email ?? null,\n\t\t\tisTeam: r.organizationId != null,\n\t\t\tseats: null as number | null,\n\t\t}))\n\t}\n\n\t// ─── Attribution ────────────────────────────────────────────────────────\n\n\tasync function getAttributionSummary(range: AnalyticsTimeRange = '30d') {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions: any[] = []\n\t\tif (since) conditions.push(gte(shortlinkAttribution.createdAt, since))\n\n\t\tconst rows = await db\n\t\t\t.select({\n\t\t\t\ttype: shortlinkAttribution.type,\n\t\t\t\tcount: count(),\n\t\t\t})\n\t\t\t.from(shortlinkAttribution)\n\t\t\t.where(conditions.length > 0 ? and(...conditions) : undefined)\n\t\t\t.groupBy(shortlinkAttribution.type)\n\n\t\treturn rows.map((r: any) => ({\n\t\t\ttype: r.type,\n\t\t\tcount: r.count,\n\t\t}))\n\t}\n\n\tasync function getShortlinkPerformance(range: AnalyticsTimeRange = '30d') {\n\t\tconst since = rangeToDate(range)\n\t\tconst clickConditions: any[] = []\n\t\tif (since) clickConditions.push(gte(shortlinkClick.timestamp, since))\n\n\t\tconst rows = await db\n\t\t\t.select({\n\t\t\t\tshortlinkId: shortlinkClick.shortlinkId,\n\t\t\t\tslug: shortlink.slug,\n\t\t\t\turl: shortlink.url,\n\t\t\t\tclicks: count(),\n\t\t\t})\n\t\t\t.from(shortlinkClick)\n\t\t\t.innerJoin(shortlink, eq(shortlinkClick.shortlinkId, shortlink.id))\n\t\t\t.where(clickConditions.length > 0 ? and(...clickConditions) : undefined)\n\t\t\t.groupBy(shortlinkClick.shortlinkId, shortlink.slug, shortlink.url)\n\t\t\t.orderBy(desc(count()))\n\t\t\t.limit(20)\n\n\t\t// Get attribution counts per shortlink\n\t\tconst attrConditions: any[] = []\n\t\tif (since) attrConditions.push(gte(shortlinkAttribution.createdAt, since))\n\n\t\tconst attrRows = await db\n\t\t\t.select({\n\t\t\t\tshortlinkId: shortlinkAttribution.shortlinkId,\n\t\t\t\ttype: shortlinkAttribution.type,\n\t\t\t\tcount: count(),\n\t\t\t})\n\t\t\t.from(shortlinkAttribution)\n\t\t\t.where(attrConditions.length > 0 ? and(...attrConditions) : undefined)\n\t\t\t.groupBy(shortlinkAttribution.shortlinkId, shortlinkAttribution.type)\n\n\t\tconst attrMap = new Map<string, { signups: number; purchases: number }>()\n\t\tfor (const a of attrRows) {\n\t\t\tconst existing = attrMap.get(a.shortlinkId) ?? {\n\t\t\t\tsignups: 0,\n\t\t\t\tpurchases: 0,\n\t\t\t}\n\t\t\tif (a.type === 'signup') existing.signups = a.count\n\t\t\tif (a.type === 'purchase') existing.purchases = a.count\n\t\t\tattrMap.set(a.shortlinkId, existing)\n\t\t}\n\n\t\treturn rows.map((r: any) => {\n\t\t\tconst attr = attrMap.get(r.shortlinkId)\n\t\t\treturn {\n\t\t\t\tshortlinkId: r.shortlinkId,\n\t\t\t\tslug: r.slug,\n\t\t\t\turl: r.url,\n\t\t\t\tclicks: r.clicks,\n\t\t\t\tsignups: attr?.signups ?? 0,\n\t\t\t\tpurchases: attr?.purchases ?? 0,\n\t\t\t}\n\t\t})\n\t}\n\n\t// ─── Revenue Attribution ─────────────────────────────────────────────────\n\n\tasync function getRevenueBySource(range: AnalyticsTimeRange = '30d') {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions = [paidPurchase()]\n\t\tif (since) conditions.push(gte(purchases.createdAt, since))\n\n\t\tconst rows = await db\n\t\t\t.select({\n\t\t\t\tsource:\n\t\t\t\t\tsql<string>`JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.utmSource'))`.as(\n\t\t\t\t\t\t'source',\n\t\t\t\t\t),\n\t\t\t\tmedium:\n\t\t\t\t\tsql<string>`JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.utmMedium'))`.as(\n\t\t\t\t\t\t'medium',\n\t\t\t\t\t),\n\t\t\t\tcampaign:\n\t\t\t\t\tsql<string>`JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.utmCampaign'))`.as(\n\t\t\t\t\t\t'campaign',\n\t\t\t\t\t),\n\t\t\t\trevenue: sum(purchases.totalAmount),\n\t\t\t\tcount: count(),\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions))\n\t\t\t.groupBy(\n\t\t\t\tsql`JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.utmSource'))`,\n\t\t\t\tsql`JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.utmMedium'))`,\n\t\t\t\tsql`JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.utmCampaign'))`,\n\t\t\t)\n\t\t\t.orderBy(desc(sum(purchases.totalAmount)))\n\n\t\treturn rows.map((r: any) => ({\n\t\t\tsource: r.source ?? null,\n\t\t\tmedium: r.medium ?? null,\n\t\t\tcampaign: r.campaign ?? null,\n\t\t\trevenue: Number(r.revenue ?? 0),\n\t\t\tcount: r.count,\n\t\t}))\n\t}\n\n\tasync function getConversionFunnel(range: AnalyticsTimeRange = '30d') {\n\t\tconst since = rangeToDate(range)\n\n\t\tconst userConditions = since ? [gte(users.createdAt, since)] : []\n\t\tconst purchaseConditions = [paidPurchase()]\n\t\tif (since) purchaseConditions.push(gte(purchases.createdAt, since))\n\n\t\tconst [userCount] = await db\n\t\t\t.select({ total: count() })\n\t\t\t.from(users)\n\t\t\t.where(userConditions.length > 0 ? and(...userConditions) : undefined)\n\n\t\tconst [purchaseCount] = await db\n\t\t\t.select({ total: count() })\n\t\t\t.from(purchases)\n\t\t\t.where(and(...purchaseConditions))\n\n\t\tconst [attributedCount] = await db\n\t\t\t.select({ total: count() })\n\t\t\t.from(purchases)\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\t...purchaseConditions,\n\t\t\t\t\tsql`(\n JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.utmSource')) IS NOT NULL\n OR JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.gaClientId')) IS NOT NULL\n )`,\n\t\t\t\t),\n\t\t\t)\n\n\t\tconst totalSignups = userCount?.total ?? 0\n\t\tconst totalPurchases = purchaseCount?.total ?? 0\n\t\tconst attributedPurchases = attributedCount?.total ?? 0\n\n\t\treturn {\n\t\t\ttotalSignups,\n\t\t\ttotalPurchases,\n\t\t\tattributedPurchases,\n\t\t\tconversionRate: totalSignups > 0 ? totalPurchases / totalSignups : 0,\n\t\t\tattributionCoverage:\n\t\t\t\ttotalPurchases > 0 ? attributedPurchases / totalPurchases : 0,\n\t\t}\n\t}\n\n\tasync function getAttributedRevenueSummary(\n\t\trange: AnalyticsTimeRange = '30d',\n\t) {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions = [paidPurchase()]\n\t\tif (since) conditions.push(gte(purchases.createdAt, since))\n\n\t\tconst [totals] = await db\n\t\t\t.select({ total: sum(purchases.totalAmount), count: count() })\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions))\n\n\t\tconst [attributed] = await db\n\t\t\t.select({ total: sum(purchases.totalAmount) })\n\t\t\t.from(purchases)\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\t...conditions,\n\t\t\t\t\tsql`(\n JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.utmSource')) IS NOT NULL\n OR JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.gaClientId')) IS NOT NULL\n )`,\n\t\t\t\t),\n\t\t\t)\n\n\t\tconst totalRevenue = Number(totals?.total ?? 0)\n\t\tconst attributedRevenue = Number(attributed?.total ?? 0)\n\t\tconst unattributedRevenue = totalRevenue - attributedRevenue\n\t\tconst totalPurchases = totals?.count ?? 0\n\n\t\treturn {\n\t\t\ttotalRevenue,\n\t\t\tattributedRevenue,\n\t\t\tunattributedRevenue,\n\t\t\tattributionRate: totalRevenue > 0 ? attributedRevenue / totalRevenue : 0,\n\t\t\ttotalPurchases,\n\t\t}\n\t}\n\n\tasync function getContentPurchaseCorrelation(\n\t\trange: AnalyticsTimeRange = '30d',\n\t\tlimit: number = 20,\n\t) {\n\t\tconst since = rangeToDate(range)\n\t\tconst purchaseConditions = [paidPurchase()]\n\t\tif (since) purchaseConditions.push(gte(purchases.createdAt, since))\n\n\t\tconst purchaserRows = await db\n\t\t\t.selectDistinct({ userId: purchases.userId })\n\t\t\t.from(purchases)\n\t\t\t.where(and(...purchaseConditions))\n\n\t\tconst purchaserIds = purchaserRows\n\t\t\t.map((r: any) => r.userId)\n\t\t\t.filter((id: any): id is string => id !== null)\n\n\t\tif (purchaserIds.length === 0) return []\n\n\t\tconst rows = await db\n\t\t\t.select({\n\t\t\t\tresourceId: resourceProgress.resourceId,\n\t\t\t\tpurchaserCount: count(),\n\t\t\t})\n\t\t\t.from(resourceProgress)\n\t\t\t.where(\n\t\t\t\tsql`${resourceProgress.userId} IN (${sql.join(\n\t\t\t\t\tpurchaserIds.map((id: string) => sql`${id}`),\n\t\t\t\t\tsql`, `,\n\t\t\t\t)})`,\n\t\t\t)\n\t\t\t.groupBy(resourceProgress.resourceId)\n\t\t\t.orderBy(desc(count()))\n\t\t\t.limit(limit)\n\n\t\treturn rows.map((r: any) => ({\n\t\t\tresourceId: r.resourceId,\n\t\t\tpurchaserCount: r.purchaserCount,\n\t\t}))\n\t}\n\n\t// ─── Attribution Trail ───────────────────────────────────────────────────\n\n\t/**\n\t * Trace the full attribution journey for a user by email or purchaseId.\n\t * Walks: ShortlinkClick → ShortlinkAttribution (signup) →\n\t * ResourceProgress → Purchase\n\t */\n\tasync function traceAttribution(opts: {\n\t\temail?: string\n\t\tpurchaseId?: string\n\t}): Promise<AttributionTrail> {\n\t\tconst events: AttributionTrailEvent[] = []\n\n\t\t// Resolve user\n\t\tlet userId: string | null = null\n\t\tlet userEmail: string | null = opts.email ?? null\n\t\tlet userRecord: AttributionTrail['user'] = null\n\n\t\tif (opts.purchaseId) {\n\t\t\tconst [purchase] = await db\n\t\t\t\t.select({\n\t\t\t\t\tuserId: purchases.userId,\n\t\t\t\t\temail: users.email,\n\t\t\t\t})\n\t\t\t\t.from(purchases)\n\t\t\t\t.leftJoin(users, eq(purchases.userId, users.id))\n\t\t\t\t.where(eq(purchases.id, opts.purchaseId))\n\t\t\t\t.limit(1)\n\t\t\tuserId = purchase?.userId ?? null\n\t\t\tuserEmail = purchase?.email ?? userEmail\n\t\t}\n\n\t\tif (userEmail && !userId) {\n\t\t\tconst [u] = await db\n\t\t\t\t.select({ id: users.id })\n\t\t\t\t.from(users)\n\t\t\t\t.where(eq(users.email, userEmail))\n\t\t\t\t.limit(1)\n\t\t\tuserId = u?.id ?? null\n\t\t}\n\n\t\tif (userId) {\n\t\t\tconst [u] = await db\n\t\t\t\t.select({\n\t\t\t\t\tid: users.id,\n\t\t\t\t\temail: users.email,\n\t\t\t\t\tname: users.name,\n\t\t\t\t\tcreatedAt: users.createdAt,\n\t\t\t\t})\n\t\t\t\t.from(users)\n\t\t\t\t.where(eq(users.id, userId))\n\t\t\t\t.limit(1)\n\t\t\tuserRecord = u\n\t\t\t\t? {\n\t\t\t\t\t\tid: u.id,\n\t\t\t\t\t\temail: u.email,\n\t\t\t\t\t\tname: u.name ?? null,\n\t\t\t\t\t\tcreatedAt: u.createdAt!,\n\t\t\t\t\t}\n\t\t\t\t: null\n\t\t}\n\n\t\t// Find shortlink attributions for this user (by userId or email)\n\t\tconst attrConditions: any[] = []\n\t\tif (userId) attrConditions.push(eq(shortlinkAttribution.userId, userId))\n\t\tif (userEmail)\n\t\t\tattrConditions.push(eq(shortlinkAttribution.email, userEmail))\n\n\t\tif (attrConditions.length > 0) {\n\t\t\tconst attrs = await db\n\t\t\t\t.select({\n\t\t\t\t\ttype: shortlinkAttribution.type,\n\t\t\t\t\tcreatedAt: shortlinkAttribution.createdAt,\n\t\t\t\t\tmetadata: shortlinkAttribution.metadata,\n\t\t\t\t\tshortlinkId: shortlinkAttribution.shortlinkId,\n\t\t\t\t\tslug: shortlink.slug,\n\t\t\t\t\turl: shortlink.url,\n\t\t\t\t})\n\t\t\t\t.from(shortlinkAttribution)\n\t\t\t\t.leftJoin(shortlink, eq(shortlinkAttribution.shortlinkId, shortlink.id))\n\t\t\t\t.where(sql`(${sql.join(attrConditions, sql` OR `)})`)\n\t\t\t\t.orderBy(shortlinkAttribution.createdAt)\n\n\t\t\tfor (const attr of attrs) {\n\t\t\t\t// Find clicks on this shortlink before the attribution event\n\t\t\t\tconst clicks = await db\n\t\t\t\t\t.select({\n\t\t\t\t\t\ttimestamp: shortlinkClick.timestamp,\n\t\t\t\t\t\treferrer: shortlinkClick.referrer,\n\t\t\t\t\t\tcountry: shortlinkClick.country,\n\t\t\t\t\t\tdevice: shortlinkClick.device,\n\t\t\t\t\t})\n\t\t\t\t\t.from(shortlinkClick)\n\t\t\t\t\t.where(\n\t\t\t\t\t\tand(\n\t\t\t\t\t\t\teq(shortlinkClick.shortlinkId, attr.shortlinkId),\n\t\t\t\t\t\t\tlte(shortlinkClick.timestamp, attr.createdAt),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\t.orderBy(desc(shortlinkClick.timestamp))\n\t\t\t\t\t.limit(3) // last 3 clicks before attribution\n\n\t\t\t\tfor (const click of clicks) {\n\t\t\t\t\tevents.push({\n\t\t\t\t\t\ttype: 'click',\n\t\t\t\t\t\ttimestamp: click.timestamp,\n\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\tshortlink: `/s/${attr.slug}`,\n\t\t\t\t\t\t\tdestination: attr.url,\n\t\t\t\t\t\t\treferrer: click.referrer,\n\t\t\t\t\t\t\tcountry: click.country,\n\t\t\t\t\t\t\tdevice: click.device,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tevents.push({\n\t\t\t\t\ttype: attr.type === 'purchase' ? 'purchase' : 'signup',\n\t\t\t\t\ttimestamp: attr.createdAt,\n\t\t\t\t\tdetail: {\n\t\t\t\t\t\tshortlink: `/s/${attr.slug}`,\n\t\t\t\t\t\tmetadata: attr.metadata ? JSON.parse(attr.metadata) : null,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\t// Find resource progress for this user\n\t\tif (userId) {\n\t\t\tconst progress = await db\n\t\t\t\t.select({\n\t\t\t\t\tresourceId: resourceProgress.resourceId,\n\t\t\t\t\tcompletedAt: resourceProgress.completedAt,\n\t\t\t\t\tcreatedAt: resourceProgress.createdAt,\n\t\t\t\t})\n\t\t\t\t.from(resourceProgress)\n\t\t\t\t.where(eq(resourceProgress.userId, userId))\n\t\t\t\t.orderBy(resourceProgress.createdAt)\n\t\t\t\t.limit(20) // cap at 20 most recent\n\n\t\t\tfor (const p of progress) {\n\t\t\t\tevents.push({\n\t\t\t\t\ttype: 'progress',\n\t\t\t\t\ttimestamp: p.completedAt ?? p.createdAt,\n\t\t\t\t\tdetail: { resourceId: p.resourceId },\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\t// Find purchases\n\t\tconst purchaseConditions = [paidPurchase()]\n\t\tif (opts.purchaseId) {\n\t\t\tpurchaseConditions.push(eq(purchases.id, opts.purchaseId))\n\t\t} else if (userId) {\n\t\t\tpurchaseConditions.push(eq(purchases.userId, userId))\n\t\t} else {\n\t\t\t// No user found, return empty\n\t\t\treturn { user: userRecord, events: [], purchases: [] }\n\t\t}\n\n\t\tconst purchaseRows = await db\n\t\t\t.select({\n\t\t\t\tid: purchases.id,\n\t\t\t\ttotalAmount: purchases.totalAmount,\n\t\t\t\tproductName: products.name,\n\t\t\t\tcreatedAt: purchases.createdAt,\n\t\t\t\tcountry: purchases.country,\n\t\t\t\tfields: purchases.fields,\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.leftJoin(products, eq(purchases.productId, products.id))\n\t\t\t.where(and(...purchaseConditions))\n\t\t\t.orderBy(purchases.createdAt)\n\n\t\tconst purchaseResults = purchaseRows.map((p: any) => {\n\t\t\tconst fields = (p.fields as Record<string, any>) ?? {}\n\t\t\tevents.push({\n\t\t\t\ttype: 'purchase',\n\t\t\t\ttimestamp: p.createdAt,\n\t\t\t\tdetail: {\n\t\t\t\t\tpurchaseId: p.id,\n\t\t\t\t\tamount: Number(p.totalAmount),\n\t\t\t\t\tproduct: p.productName,\n\t\t\t\t},\n\t\t\t})\n\t\t\treturn {\n\t\t\t\tid: p.id,\n\t\t\t\ttotalAmount: Number(p.totalAmount),\n\t\t\t\tproductName: p.productName ?? 'Unknown',\n\t\t\t\tcreatedAt: p.createdAt,\n\t\t\t\tcountry: p.country,\n\t\t\t\tutmSource: fields.utmSource ?? null,\n\t\t\t\tutmMedium: fields.utmMedium ?? null,\n\t\t\t\tutmCampaign: fields.utmCampaign ?? null,\n\t\t\t}\n\t\t})\n\n\t\t// Sort all events by timestamp\n\t\tevents.sort(\n\t\t\t(a, b) =>\n\t\t\t\tnew Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(),\n\t\t)\n\n\t\treturn { user: userRecord, events, purchases: purchaseResults }\n\t}\n\n\treturn {\n\t\tgetRevenueSummary,\n\t\tgetRevenueByDay,\n\t\tgetPreviousPeriodRevenueByDay,\n\t\tgetRevenueByProduct,\n\t\tgetRevenueByCountry,\n\t\tgetRecentPurchases,\n\t\tgetAttributionSummary,\n\t\tgetShortlinkPerformance,\n\t\tgetRevenueBySource,\n\t\tgetConversionFunnel,\n\t\tgetAttributedRevenueSummary,\n\t\tgetContentPurchaseCorrelation,\n\t\ttraceAttribution,\n\t}\n}\n\nexport type DatabaseAnalyticsProvider = ReturnType<\n\ttypeof createDatabaseProvider\n>\n"],"mappings":"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","names":["and","count","desc","eq","gt","gte","inArray","lte","sql","sum","createDatabaseProvider","db","schema","purchases","products","users","coupon","resourceProgress","shortlink","shortlinkAttribution","shortlinkClick","PAID_STATUSES","paidPurchase","inArray","status","rangeToDate","range","now","Date","hours","getTime","getRevenueSummary","since","conditions","push","gte","createdAt","totals","select","totalRevenue","sum","totalAmount","purchaseCount","count","from","where","and","Number","avgOrderValue","getRevenueByDay","rows","date","sql","as","revenue","groupBy","orderBy","map","r","getPreviousPeriodRevenueByDay","periodMs","periodStart","prevStart","lte","getRevenueByProduct","productId","productName","name","leftJoin","eq","id","desc","getRevenueByCountry","country","limit","getRecentPurchases","filter","bulkCouponId","couponId","userId","userName","userEmail","email","organizationId","seats","maxUses","gt","isTeam","query","findMany","with","product","user","getAttributionSummary","type","length","undefined","getShortlinkPerformance","clickConditions","timestamp","shortlinkId","slug","url","clicks","innerJoin","attrConditions","attrRows","attrMap","Map","a","existing","get","signups","set","attr","getRevenueBySource","source","fields","medium","campaign","getConversionFunnel","userConditions","purchaseConditions","userCount","total","attributedCount","totalSignups","totalPurchases","attributedPurchases","conversionRate","attributionCoverage","getAttributedRevenueSummary","attributed","attributedRevenue","unattributedRevenue","attributionRate","getContentPurchaseCorrelation","purchaserRows","selectDistinct","purchaserIds","resourceId","purchaserCount","join","traceAttribution","opts","events","userRecord","purchaseId","purchase","u","attrs","metadata","referrer","device","click","detail","destination","JSON","parse","progress","completedAt","p","purchaseRows","purchaseResults","amount","utmSource","utmMedium","utmCampaign","sort","b"]}
1
+ {"version":3,"sources":["../../src/providers/database.ts","../../src/providers/attribution-recovery.ts"],"sourcesContent":["import {\n\tand,\n\tcount,\n\tdesc,\n\teq,\n\tgt,\n\tgte,\n\tinArray,\n\tlte,\n\tsql,\n\tsum,\n} from 'drizzle-orm'\n\nimport { SHORTLINK_RECOVERY_LANE } from './attribution-recovery'\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type AnalyticsTimeRange = '24h' | '7d' | '30d' | '90d' | 'all'\n\nexport interface AttributionTrailEvent {\n\ttype: 'click' | 'signup' | 'progress' | 'purchase'\n\ttimestamp: Date\n\tdetail: Record<string, any>\n}\n\nexport interface AttributionTrail {\n\tuser: {\n\t\tid: string\n\t\temail: string | null\n\t\tname: string | null\n\t\tcreatedAt: Date\n\t} | null\n\tevents: AttributionTrailEvent[]\n\tpurchases: {\n\t\tid: string\n\t\ttotalAmount: number\n\t\tproductName: string\n\t\tcreatedAt: Date\n\t\tcountry: string | null\n\t\tutmSource: string | null\n\t\tutmMedium: string | null\n\t\tutmCampaign: string | null\n\t}[]\n}\n\n// ─── Schema type ─────────────────────────────────────────────────────────────\n\nexport interface DatabaseAnalyticsSchema {\n\tpurchases: any\n\tproducts: any\n\tusers: any\n\tcoupon: any\n\tresourceProgress: any\n\tshortlink: any\n\tshortlinkAttribution: any\n\tshortlinkClick: any\n\tquestionResponse?: any\n\tcontactEvent?: any\n\tsideEffectIntent?: any\n}\n\n// ─── Factory ─────────────────────────────────────────────────────────────────\n\n/**\n * Creates a database analytics provider that wraps all analytics query\n * functions with an injected drizzle db instance and schema tables.\n *\n * @param db - Drizzle database instance\n * @param schema - Object containing the required table references\n */\nexport function createDatabaseProvider(\n\tdb: any,\n\tschema: DatabaseAnalyticsSchema,\n) {\n\tconst {\n\t\tpurchases,\n\t\tproducts,\n\t\tusers,\n\t\tcoupon,\n\t\tresourceProgress,\n\t\tshortlink,\n\t\tshortlinkAttribution,\n\t\tshortlinkClick,\n\t\tquestionResponse,\n\t\tcontactEvent,\n\t\tsideEffectIntent,\n\t} = schema\n\n\t// ─── Internal helpers ───────────────────────────────────────────────────\n\n\tconst PAID_STATUSES = ['Valid', 'Restricted'] as const\n\n\tfunction commerceRecord() {\n\t\treturn inArray(purchases.status, [...PAID_STATUSES])\n\t}\n\n\tfunction paidPurchase() {\n\t\treturn and(commerceRecord(), gt(purchases.totalAmount, 0))\n\t}\n\n\tfunction accessGrant() {\n\t\treturn and(commerceRecord(), sql`${purchases.totalAmount} = 0`)\n\t}\n\n\tfunction backfillFreeUpgrade() {\n\t\treturn and(\n\t\t\taccessGrant(),\n\t\t\tsql`JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.backfill')) = 'true'`,\n\t\t)\n\t}\n\n\tconst syntheticSignalSql = sql`(\n\t\tJSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.attribution.synthetic')) = 'true'\n\t\tOR JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.synthetic')) = 'true'\n\t\tOR JSON_SEARCH(JSON_EXTRACT(${purchases.fields}, '$.attribution.clickIds'), 'one', 'TEST_%') IS NOT NULL\n\t)`\n\n\tfunction syntheticPurchase() {\n\t\treturn and(commerceRecord(), syntheticSignalSql)\n\t}\n\n\tconst purchaseFieldAttributionSignalSql = sql`(\n\t\tJSON_EXTRACT(${purchases.fields}, '$.attribution') IS NOT NULL\n\t\tOR JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.utmSource')) IS NOT NULL\n\t\tOR JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.gaClientId')) IS NOT NULL\n\t)`\n\n\tconst exactShortlinkPurchaseAttributionSignalSql = sql`EXISTS (\n\t\tSELECT 1\n\t\tFROM ${shortlinkAttribution}\n\t\tWHERE ${shortlinkAttribution.type} = 'purchase'\n\t\t\tAND JSON_VALID(${shortlinkAttribution.metadata})\n\t\t\tAND JSON_UNQUOTE(JSON_EXTRACT(${shortlinkAttribution.metadata}, '$.purchaseId')) = ${purchases.id}\n\t)`\n\n\tconst shortlinkRecoveredAttributionSignalSql = sql`(\n\t\tNOT ${purchaseFieldAttributionSignalSql}\n\t\tAND ${exactShortlinkPurchaseAttributionSignalSql}\n\t)`\n\n\tconst attributionSignalSql = sql`(\n\t\t${purchaseFieldAttributionSignalSql}\n\t\tOR ${exactShortlinkPurchaseAttributionSignalSql}\n\t)`\n\n\tfunction rangeToDate(range: AnalyticsTimeRange): Date | null {\n\t\tif (range === 'all') return null\n\t\tconst now = new Date()\n\t\tconst hours: Record<string, number> = {\n\t\t\t'24h': 24,\n\t\t\t'7d': 7 * 24,\n\t\t\t'30d': 30 * 24,\n\t\t\t'90d': 90 * 24,\n\t\t}\n\t\treturn new Date(now.getTime() - (hours[range] ?? 30 * 24) * 60 * 60 * 1000)\n\t}\n\n\t// ─── Revenue ───────────────────────────────────────────────────────────\n\n\tasync function getRevenueSummary(range: AnalyticsTimeRange = '30d') {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions = [paidPurchase()]\n\t\tif (since) conditions.push(gte(purchases.createdAt, since))\n\n\t\tconst [totals] = await db\n\t\t\t.select({\n\t\t\t\ttotalRevenue: sum(purchases.totalAmount),\n\t\t\t\tpurchaseCount: count(),\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions))\n\n\t\treturn {\n\t\t\ttotalRevenue: Number(totals?.totalRevenue ?? 0),\n\t\t\tpurchaseCount: totals?.purchaseCount ?? 0,\n\t\t\tavgOrderValue:\n\t\t\t\ttotals?.purchaseCount && totals.purchaseCount > 0\n\t\t\t\t\t? Number(totals.totalRevenue ?? 0) / totals.purchaseCount\n\t\t\t\t\t: 0,\n\t\t}\n\t}\n\n\tasync function getRevenueByDay(range: AnalyticsTimeRange = '30d') {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions = [paidPurchase()]\n\t\tif (since) conditions.push(gte(purchases.createdAt, since))\n\n\t\tconst rows = await db\n\t\t\t.select({\n\t\t\t\tdate: sql<string>`DATE(${purchases.createdAt})`.as('date'),\n\t\t\t\trevenue: sum(purchases.totalAmount),\n\t\t\t\tcount: count(),\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions))\n\t\t\t.groupBy(sql`DATE(${purchases.createdAt})`)\n\t\t\t.orderBy(sql`DATE(${purchases.createdAt})`)\n\n\t\treturn rows.map((r: any) => ({\n\t\t\tdate: r.date,\n\t\t\trevenue: Number(r.revenue ?? 0),\n\t\t\tcount: r.count,\n\t\t}))\n\t}\n\n\t/**\n\t * Revenue by day for the previous period of equal length.\n\t * E.g., if range = '30d', returns the 30 days before those 30 days.\n\t * Returns data with a `dayOffset` (0 = start of period) for overlay\n\t * alignment.\n\t */\n\tasync function getPreviousPeriodRevenueByDay(\n\t\trange: AnalyticsTimeRange = '30d',\n\t) {\n\t\tif (range === 'all') return []\n\n\t\tconst hours: Record<string, number> = {\n\t\t\t'24h': 24,\n\t\t\t'7d': 7 * 24,\n\t\t\t'30d': 30 * 24,\n\t\t\t'90d': 90 * 24,\n\t\t}\n\t\tconst periodMs = (hours[range] ?? 30 * 24) * 60 * 60 * 1000\n\t\tconst now = new Date()\n\t\tconst periodStart = new Date(now.getTime() - periodMs)\n\t\tconst prevStart = new Date(periodStart.getTime() - periodMs)\n\n\t\tconst rows = await db\n\t\t\t.select({\n\t\t\t\tdate: sql<string>`DATE(${purchases.createdAt})`.as('date'),\n\t\t\t\trevenue: sum(purchases.totalAmount),\n\t\t\t\tcount: count(),\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\tpaidPurchase(),\n\t\t\t\t\tgte(purchases.createdAt, prevStart),\n\t\t\t\t\tlte(purchases.createdAt, periodStart),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.groupBy(sql`DATE(${purchases.createdAt})`)\n\t\t\t.orderBy(sql`DATE(${purchases.createdAt})`)\n\n\t\treturn rows.map((r: any) => ({\n\t\t\tdate: r.date,\n\t\t\trevenue: Number(r.revenue ?? 0),\n\t\t\tcount: r.count,\n\t\t}))\n\t}\n\n\tasync function getRevenueByProduct(range: AnalyticsTimeRange = '30d') {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions = [paidPurchase()]\n\t\tif (since) conditions.push(gte(purchases.createdAt, since))\n\n\t\tconst rows = await db\n\t\t\t.select({\n\t\t\t\tproductId: purchases.productId,\n\t\t\t\tproductName: products.name,\n\t\t\t\trevenue: sum(purchases.totalAmount),\n\t\t\t\tcount: count(),\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.leftJoin(products, eq(purchases.productId, products.id))\n\t\t\t.where(and(...conditions))\n\t\t\t.groupBy(purchases.productId, products.name)\n\t\t\t.orderBy(desc(sum(purchases.totalAmount)))\n\n\t\treturn rows.map((r: any) => ({\n\t\t\tproductId: r.productId,\n\t\t\tproductName: r.productName ?? '(unknown)',\n\t\t\trevenue: Number(r.revenue ?? 0),\n\t\t\tcount: r.count,\n\t\t}))\n\t}\n\n\tasync function getRevenueByCountry(range: AnalyticsTimeRange = '30d') {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions = [paidPurchase()]\n\t\tif (since) conditions.push(gte(purchases.createdAt, since))\n\n\t\tconst rows = await db\n\t\t\t.select({\n\t\t\t\tcountry: purchases.country,\n\t\t\t\trevenue: sum(purchases.totalAmount),\n\t\t\t\tcount: count(),\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions))\n\t\t\t.groupBy(purchases.country)\n\t\t\t.orderBy(desc(sum(purchases.totalAmount)))\n\t\t\t.limit(20)\n\n\t\treturn rows.map((r: any) => ({\n\t\t\tcountry: r.country ?? '(unknown)',\n\t\t\trevenue: Number(r.revenue ?? 0),\n\t\t\tcount: r.count,\n\t\t}))\n\t}\n\n\tasync function getRecentPurchases(\n\t\tlimit: number = 20,\n\t\tfilter: 'all' | 'team' | 'individual' = 'all',\n\t\trange: AnalyticsTimeRange = 'all',\n\t) {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions = [paidPurchase()]\n\t\tif (since) conditions.push(gte(purchases.createdAt, since))\n\n\t\tif (filter === 'team') {\n\t\t\t// Multi-seat purchases: join coupon to filter seats > 1, sort by amount\n\t\t\tconditions.push(sql`${purchases.bulkCouponId} IS NOT NULL`)\n\n\t\t\tconst rows = await db\n\t\t\t\t.select({\n\t\t\t\t\tid: purchases.id,\n\t\t\t\t\tcreatedAt: purchases.createdAt,\n\t\t\t\t\ttotalAmount: purchases.totalAmount,\n\t\t\t\t\tproductName: products.name,\n\t\t\t\t\tproductId: purchases.productId,\n\t\t\t\t\tcountry: purchases.country,\n\t\t\t\t\tcouponId: purchases.couponId,\n\t\t\t\t\tuserId: purchases.userId,\n\t\t\t\t\tuserName: users.name,\n\t\t\t\t\tuserEmail: users.email,\n\t\t\t\t\torganizationId: purchases.organizationId,\n\t\t\t\t\tseats: coupon.maxUses,\n\t\t\t\t})\n\t\t\t\t.from(purchases)\n\t\t\t\t.leftJoin(products, eq(purchases.productId, products.id))\n\t\t\t\t.leftJoin(users, eq(purchases.userId, users.id))\n\t\t\t\t.leftJoin(coupon, eq(purchases.bulkCouponId, coupon.id))\n\t\t\t\t.where(and(...conditions, gt(coupon.maxUses, 1)))\n\t\t\t\t.orderBy(desc(purchases.totalAmount))\n\t\t\t\t.limit(limit)\n\n\t\t\treturn rows.map((r: any) => ({\n\t\t\t\tid: r.id,\n\t\t\t\tcreatedAt: r.createdAt,\n\t\t\t\ttotalAmount: Number(r.totalAmount),\n\t\t\t\tproductName: r.productName ?? '(unknown)',\n\t\t\t\tproductId: r.productId,\n\t\t\t\tcountry: r.country,\n\t\t\t\tcouponId: r.couponId,\n\t\t\t\tuserName: r.userName ?? null,\n\t\t\t\tuserEmail: r.userEmail ?? null,\n\t\t\t\tisTeam: true,\n\t\t\t\tseats: r.seats ?? null,\n\t\t\t}))\n\t\t}\n\n\t\tif (filter === 'individual') {\n\t\t\tconditions.push(sql`${purchases.bulkCouponId} IS NULL`)\n\t\t}\n\n\t\tconst rows = await db.query.purchases.findMany({\n\t\t\twhere: and(...conditions),\n\t\t\torderBy: [desc(purchases.totalAmount)],\n\t\t\tlimit,\n\t\t\twith: {\n\t\t\t\tproduct: true,\n\t\t\t\tuser: true,\n\t\t\t},\n\t\t})\n\n\t\treturn rows.map((r: any) => ({\n\t\t\tid: r.id,\n\t\t\tcreatedAt: r.createdAt,\n\t\t\ttotalAmount: Number(r.totalAmount),\n\t\t\tproductName: r.product?.name ?? '(unknown)',\n\t\t\tproductId: r.productId,\n\t\t\tcountry: r.country,\n\t\t\tcouponId: r.couponId,\n\t\t\tuserName: r.user?.name ?? null,\n\t\t\tuserEmail: r.user?.email ?? null,\n\t\t\tisTeam: r.organizationId != null,\n\t\t\tseats: null as number | null,\n\t\t}))\n\t}\n\n\t// ─── Attribution ────────────────────────────────────────────────────────\n\n\tasync function getAttributionSummary(range: AnalyticsTimeRange = '30d') {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions: any[] = []\n\t\tif (since) conditions.push(gte(shortlinkAttribution.createdAt, since))\n\n\t\tconst rows = await db\n\t\t\t.select({\n\t\t\t\ttype: shortlinkAttribution.type,\n\t\t\t\tcount: count(),\n\t\t\t})\n\t\t\t.from(shortlinkAttribution)\n\t\t\t.where(conditions.length > 0 ? and(...conditions) : undefined)\n\t\t\t.groupBy(shortlinkAttribution.type)\n\n\t\treturn rows.map((r: any) => ({\n\t\t\ttype: r.type,\n\t\t\tcount: r.count,\n\t\t}))\n\t}\n\n\tasync function getShortlinkPerformance(range: AnalyticsTimeRange = '30d') {\n\t\tconst since = rangeToDate(range)\n\t\tconst clickConditions: any[] = []\n\t\tif (since) clickConditions.push(gte(shortlinkClick.timestamp, since))\n\n\t\tconst rows = await db\n\t\t\t.select({\n\t\t\t\tshortlinkId: shortlinkClick.shortlinkId,\n\t\t\t\tslug: shortlink.slug,\n\t\t\t\turl: shortlink.url,\n\t\t\t\tclicks: count(),\n\t\t\t})\n\t\t\t.from(shortlinkClick)\n\t\t\t.innerJoin(shortlink, eq(shortlinkClick.shortlinkId, shortlink.id))\n\t\t\t.where(clickConditions.length > 0 ? and(...clickConditions) : undefined)\n\t\t\t.groupBy(shortlinkClick.shortlinkId, shortlink.slug, shortlink.url)\n\t\t\t.orderBy(desc(count()))\n\t\t\t.limit(20)\n\n\t\t// Get attribution counts per shortlink\n\t\tconst attrConditions: any[] = []\n\t\tif (since) attrConditions.push(gte(shortlinkAttribution.createdAt, since))\n\n\t\tconst attrRows = await db\n\t\t\t.select({\n\t\t\t\tshortlinkId: shortlinkAttribution.shortlinkId,\n\t\t\t\ttype: shortlinkAttribution.type,\n\t\t\t\tcount: count(),\n\t\t\t})\n\t\t\t.from(shortlinkAttribution)\n\t\t\t.where(attrConditions.length > 0 ? and(...attrConditions) : undefined)\n\t\t\t.groupBy(shortlinkAttribution.shortlinkId, shortlinkAttribution.type)\n\n\t\tconst attrMap = new Map<string, { signups: number; purchases: number }>()\n\t\tfor (const a of attrRows) {\n\t\t\tconst existing = attrMap.get(a.shortlinkId) ?? {\n\t\t\t\tsignups: 0,\n\t\t\t\tpurchases: 0,\n\t\t\t}\n\t\t\tif (a.type === 'signup') existing.signups = a.count\n\t\t\tif (a.type === 'purchase') existing.purchases = a.count\n\t\t\tattrMap.set(a.shortlinkId, existing)\n\t\t}\n\n\t\treturn rows.map((r: any) => {\n\t\t\tconst attr = attrMap.get(r.shortlinkId)\n\t\t\treturn {\n\t\t\t\tshortlinkId: r.shortlinkId,\n\t\t\t\tslug: r.slug,\n\t\t\t\turl: r.url,\n\t\t\t\tclicks: r.clicks,\n\t\t\t\tsignups: attr?.signups ?? 0,\n\t\t\t\tpurchases: attr?.purchases ?? 0,\n\t\t\t}\n\t\t})\n\t}\n\n\t// ─── Revenue Attribution ─────────────────────────────────────────────────\n\n\tasync function getRevenueBySource(\n\t\trange: AnalyticsTimeRange = '30d',\n\t\tfilters: { productId?: string } = {},\n\t) {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions = [commerceRecord()]\n\t\tif (since) conditions.push(gte(purchases.createdAt, since))\n\t\tif (filters.productId)\n\t\t\tconditions.push(eq(purchases.productId, filters.productId))\n\n\t\tconst kindExpr = sql<string>`CASE\n\t\t\tWHEN ${syntheticSignalSql} THEN 'synthetic'\n\t\t\tWHEN ${purchases.totalAmount} = 0 THEN 'access_grant'\n\t\t\tWHEN ${purchases.totalAmount} > 0 THEN 'paid_conversion'\n\t\t\tELSE 'unknown'\n\t\tEND`\n\t\tconst sourceExpr = sql<string>`CASE\n\t\t\tWHEN JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.backfill')) = 'true'\n\t\t\t\tTHEN 'internal'\n\t\t\tWHEN ${shortlinkRecoveredAttributionSignalSql} THEN ${SHORTLINK_RECOVERY_LANE}\n\t\t\tELSE COALESCE(\n\t\t\t\tNULLIF(JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.attribution.source')), 'null'),\n\t\t\t\tNULLIF(JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.attribution.utm.source')), 'null'),\n\t\t\t\tNULLIF(JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.utmSource')), 'null'),\n\t\t\t\tCASE\n\t\t\t\t\tWHEN JSON_EXTRACT(${purchases.fields}, '$.attribution.shortlink.slug') IS NOT NULL THEN 'shortlink'\n\t\t\t\t\tWHEN JSON_EXTRACT(${purchases.fields}, '$.attribution.selfReportedSource') IS NOT NULL THEN 'self_reported'\n\t\t\t\t\tWHEN JSON_EXTRACT(${purchases.fields}, '$.attribution.ga.clientId') IS NOT NULL THEN 'ga4'\n\t\t\t\t\tWHEN JSON_EXTRACT(${purchases.fields}, '$.gaClientId') IS NOT NULL THEN 'ga4'\n\t\t\t\t\tELSE NULL\n\t\t\t\tEND\n\t\t\t)\n\t\tEND`\n\t\tconst mediumExpr = sql<string>`CASE\n\t\t\tWHEN JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.backfill')) = 'true'\n\t\t\t\tTHEN 'free_upgrade'\n\t\t\tWHEN ${shortlinkRecoveredAttributionSignalSql} THEN 'shortlink'\n\t\t\tELSE COALESCE(\n\t\t\t\tNULLIF(JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.attribution.medium')), 'null'),\n\t\t\t\tNULLIF(JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.attribution.utm.medium')), 'null'),\n\t\t\t\tNULLIF(JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.utmMedium')), 'null'),\n\t\t\t\tCASE\n\t\t\t\t\tWHEN JSON_EXTRACT(${purchases.fields}, '$.attribution.shortlink.slug') IS NOT NULL THEN 'shortlink'\n\t\t\t\t\tWHEN JSON_EXTRACT(${purchases.fields}, '$.attribution.selfReportedSource') IS NOT NULL THEN 'checkout_survey'\n\t\t\t\t\tWHEN JSON_EXTRACT(${purchases.fields}, '$.attribution.ga.clientId') IS NOT NULL THEN 'client_id'\n\t\t\t\t\tWHEN JSON_EXTRACT(${purchases.fields}, '$.gaClientId') IS NOT NULL THEN 'client_id'\n\t\t\t\t\tELSE NULL\n\t\t\t\tEND\n\t\t\t)\n\t\tEND`\n\t\tconst campaignExpr = sql<string>`CASE\n\t\t\tWHEN JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.backfill')) = 'true'\n\t\t\t\tTHEN COALESCE(\n\t\t\t\t\tNULLIF(JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.migrationBatchId')), 'null'),\n\t\t\t\t\t'free_upgrade'\n\t\t\t\t)\n\t\t\tWHEN ${shortlinkRecoveredAttributionSignalSql} THEN NULL\n\t\t\tELSE COALESCE(\n\t\t\t\tNULLIF(JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.attribution.campaign')), 'null'),\n\t\t\t\tNULLIF(JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.attribution.utm.campaign')), 'null'),\n\t\t\t\tNULLIF(JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.utmCampaign')), 'null'),\n\t\t\t\tNULLIF(JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.attribution.shortlink.slug')), 'null'),\n\t\t\t\tNULLIF(JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.attribution.selfReportedSource')), 'null')\n\t\t\t)\n\t\tEND`\n\n\t\tconst rows = await db\n\t\t\t.select({\n\t\t\t\tkind: kindExpr.as('kind'),\n\t\t\t\tsource: sourceExpr.as('source'),\n\t\t\t\tmedium: mediumExpr.as('medium'),\n\t\t\t\tcampaign: campaignExpr.as('campaign'),\n\t\t\t\trevenue: sum(purchases.totalAmount),\n\t\t\t\tcount: count(),\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions))\n\t\t\t.groupBy(sql`1`, sql`2`, sql`3`, sql`4`)\n\t\t\t.orderBy(desc(sum(purchases.totalAmount)), desc(count()))\n\n\t\treturn rows.map((r: any) => ({\n\t\t\tkind: r.kind ?? 'unknown',\n\t\t\tsource: r.source ?? null,\n\t\t\tmedium: r.medium ?? null,\n\t\t\tcampaign: r.campaign ?? null,\n\t\t\trevenue: Number(r.revenue ?? 0),\n\t\t\tcount: r.count,\n\t\t}))\n\t}\n\n\tasync function getConversionFunnel(range: AnalyticsTimeRange = '30d') {\n\t\tconst since = rangeToDate(range)\n\n\t\tconst userConditions = since ? [gte(users.createdAt, since)] : []\n\t\tconst purchaseConditions = [paidPurchase()]\n\t\tif (since) purchaseConditions.push(gte(purchases.createdAt, since))\n\n\t\tconst [userCount] = await db\n\t\t\t.select({ total: count() })\n\t\t\t.from(users)\n\t\t\t.where(userConditions.length > 0 ? and(...userConditions) : undefined)\n\n\t\tconst [purchaseCount] = await db\n\t\t\t.select({ total: count() })\n\t\t\t.from(purchases)\n\t\t\t.where(and(...purchaseConditions))\n\n\t\tconst [attributedCount] = await db\n\t\t\t.select({ total: count() })\n\t\t\t.from(purchases)\n\t\t\t.where(and(...purchaseConditions, attributionSignalSql))\n\n\t\tconst totalSignups = userCount?.total ?? 0\n\t\tconst totalPurchases = purchaseCount?.total ?? 0\n\t\tconst attributedPurchases = attributedCount?.total ?? 0\n\n\t\treturn {\n\t\t\ttotalSignups,\n\t\t\ttotalPurchases,\n\t\t\tattributedPurchases,\n\t\t\tconversionRate: totalSignups > 0 ? totalPurchases / totalSignups : 0,\n\t\t\tattributionCoverage:\n\t\t\t\ttotalPurchases > 0 ? attributedPurchases / totalPurchases : 0,\n\t\t}\n\t}\n\n\tasync function getCommerceLaneSummary(\n\t\trange: AnalyticsTimeRange = '30d',\n\t\tfilters: { productId?: string } = {},\n\t) {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions = [commerceRecord()]\n\t\tif (since) conditions.push(gte(purchases.createdAt, since))\n\t\tif (filters.productId)\n\t\t\tconditions.push(eq(purchases.productId, filters.productId))\n\n\t\tconst [commerce] = await db\n\t\t\t.select({ count: count() })\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions))\n\t\tconst [paid] = await db\n\t\t\t.select({ count: count(), revenue: sum(purchases.totalAmount) })\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions, paidPurchase()))\n\t\tconst [grants] = await db\n\t\t\t.select({ count: count(), revenue: sum(purchases.totalAmount) })\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions, accessGrant()))\n\t\tconst [freeUpgrades] = await db\n\t\t\t.select({ count: count() })\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions, backfillFreeUpgrade()))\n\t\tconst [synthetic] = await db\n\t\t\t.select({ count: count() })\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions, syntheticPurchase()))\n\t\tconst reasonRows = await db\n\t\t\t.select({\n\t\t\t\treason: sql<string>`COALESCE(\n\t\t\t\t\tNULLIF(JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.backfillReason')), 'null'),\n\t\t\t\t\t'access_grant'\n\t\t\t\t)`.as('reason'),\n\t\t\t\tcount: count(),\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions, accessGrant()))\n\t\t\t.groupBy(\n\t\t\t\tsql`COALESCE(\n\t\t\t\t\tNULLIF(JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.backfillReason')), 'null'),\n\t\t\t\t\t'access_grant'\n\t\t\t\t)`,\n\t\t\t)\n\n\t\treturn {\n\t\t\tcommerceRecords: commerce?.count ?? 0,\n\t\t\tpaidPurchases: paid?.count ?? 0,\n\t\t\tpaidRevenue: Number(paid?.revenue ?? 0),\n\t\t\taccessGrants: grants?.count ?? 0,\n\t\t\taccessGrantRevenue: Number(grants?.revenue ?? 0),\n\t\t\tfreeUpgrades: freeUpgrades?.count ?? 0,\n\t\t\tsyntheticPurchases: synthetic?.count ?? 0,\n\t\t\tbyAccessGrantReason: Object.fromEntries(\n\t\t\t\treasonRows.map((row: any) => [row.reason, row.count]),\n\t\t\t),\n\t\t}\n\t}\n\n\tasync function getAttributedRevenueSummary(\n\t\trange: AnalyticsTimeRange = '30d',\n\t\tfilters: { productId?: string } = {},\n\t) {\n\t\tconst since = rangeToDate(range)\n\t\tconst conditions = [paidPurchase()]\n\t\tif (since) conditions.push(gte(purchases.createdAt, since))\n\t\tif (filters.productId)\n\t\t\tconditions.push(eq(purchases.productId, filters.productId))\n\n\t\tconst [totals] = await db\n\t\t\t.select({ total: sum(purchases.totalAmount), count: count() })\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions))\n\n\t\tconst [attributed] = await db\n\t\t\t.select({ total: sum(purchases.totalAmount), count: count() })\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions, attributionSignalSql))\n\n\t\tconst [purchaseFieldAttributed] = await db\n\t\t\t.select({ total: sum(purchases.totalAmount), count: count() })\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions, purchaseFieldAttributionSignalSql))\n\n\t\tconst [recoveredFromShortlinkAttributionTable] = await db\n\t\t\t.select({ total: sum(purchases.totalAmount), count: count() })\n\t\t\t.from(purchases)\n\t\t\t.where(and(...conditions, shortlinkRecoveredAttributionSignalSql))\n\n\t\tconst signalConditions = since\n\t\t\t? [commerceRecord(), gte(purchases.createdAt, since)]\n\t\t\t: [commerceRecord()]\n\t\tif (filters.productId) {\n\t\t\tsignalConditions.push(eq(purchases.productId, filters.productId))\n\t\t}\n\t\tconst signalCount = async (condition: any) => {\n\t\t\tconst [row] = await db\n\t\t\t\t.select({ count: count() })\n\t\t\t\t.from(purchases)\n\t\t\t\t.where(and(...signalConditions, condition))\n\t\t\treturn row?.count ?? 0\n\t\t}\n\t\tconst [\n\t\t\tshortlinkCount,\n\t\t\tutmCount,\n\t\t\tclickIdCount,\n\t\t\tgaClientIdCount,\n\t\t\tselfReportedSourceCount,\n\t\t\trecoveredFromShortlinkAttributionTableCount,\n\t\t] = await Promise.all([\n\t\t\tsignalCount(\n\t\t\t\tsql`(\n\t\t\t\t\t\tJSON_EXTRACT(${purchases.fields}, '$.attribution.shortlink.slug') IS NOT NULL\n\t\t\t\t\t\tOR JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.shortlinkRef')) IS NOT NULL\n\t\t\t\t\t)`,\n\t\t\t),\n\t\t\tsignalCount(\n\t\t\t\tsql`(\n\t\t\t\t\t\tJSON_EXTRACT(${purchases.fields}, '$.attribution.utm') IS NOT NULL\n\t\t\t\t\t\tOR JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.utmSource')) IS NOT NULL\n\t\t\t\t\t)`,\n\t\t\t),\n\t\t\tsignalCount(\n\t\t\t\tsql`JSON_EXTRACT(${purchases.fields}, '$.attribution.clickIds') IS NOT NULL`,\n\t\t\t),\n\t\t\tsignalCount(\n\t\t\t\tsql`(\n\t\t\t\t\t\tJSON_EXTRACT(${purchases.fields}, '$.attribution.ga.clientId') IS NOT NULL\n\t\t\t\t\t\tOR JSON_UNQUOTE(JSON_EXTRACT(${purchases.fields}, '$.gaClientId')) IS NOT NULL\n\t\t\t\t\t)`,\n\t\t\t),\n\t\t\tsignalCount(\n\t\t\t\tsql`JSON_EXTRACT(${purchases.fields}, '$.attribution.selfReportedSource') IS NOT NULL`,\n\t\t\t),\n\t\t\tsignalCount(shortlinkRecoveredAttributionSignalSql),\n\t\t])\n\n\t\tconst commerce = await getCommerceLaneSummary(range, filters)\n\t\tconst totalRevenue = Number(totals?.total ?? 0)\n\t\tconst attributedRevenue = Number(attributed?.total ?? 0)\n\t\tconst purchaseFieldAttributedRevenue = Number(\n\t\t\tpurchaseFieldAttributed?.total ?? 0,\n\t\t)\n\t\tconst recoveredFromShortlinkAttributionTableRevenue = Number(\n\t\t\trecoveredFromShortlinkAttributionTable?.total ?? 0,\n\t\t)\n\t\tconst unattributedRevenue = totalRevenue - attributedRevenue\n\t\tconst paidPurchases = totals?.count ?? 0\n\n\t\treturn {\n\t\t\ttotalRevenue,\n\t\t\tattributedRevenue,\n\t\t\tunattributedRevenue,\n\t\t\tattributionRate: totalRevenue > 0 ? attributedRevenue / totalRevenue : 0,\n\t\t\ttotalPurchases: commerce.commerceRecords,\n\t\t\tpaidPurchases,\n\t\t\tpurchaseFieldAttributedPurchases: purchaseFieldAttributed?.count ?? 0,\n\t\t\tpurchaseFieldAttributedRevenue,\n\t\t\trecoveredFromShortlinkAttributionTablePurchases:\n\t\t\t\trecoveredFromShortlinkAttributionTable?.count ?? 0,\n\t\t\trecoveredFromShortlinkAttributionTableRevenue,\n\t\t\tcommerceRecords: commerce.commerceRecords,\n\t\t\taccessGrants: commerce.accessGrants,\n\t\t\tfreeUpgrades: commerce.freeUpgrades,\n\t\t\tsyntheticPurchases: commerce.syntheticPurchases,\n\t\t\tcommerce,\n\t\t\tsignals: {\n\t\t\t\tshortlink: shortlinkCount,\n\t\t\t\tutm: utmCount,\n\t\t\t\tpaidClickId: clickIdCount,\n\t\t\t\tgaClientId: gaClientIdCount,\n\t\t\t\tselfReportedSource: selfReportedSourceCount,\n\t\t\t\trecoveredFromShortlinkAttributionTable:\n\t\t\t\t\trecoveredFromShortlinkAttributionTableCount,\n\t\t\t\tinternalFreeUpgrade: commerce.freeUpgrades,\n\t\t\t},\n\t\t}\n\t}\n\n\tasync function getContentPurchaseCorrelation(\n\t\trange: AnalyticsTimeRange = '30d',\n\t\tlimit: number = 20,\n\t) {\n\t\tconst since = rangeToDate(range)\n\t\tconst purchaseConditions = [paidPurchase()]\n\t\tif (since) purchaseConditions.push(gte(purchases.createdAt, since))\n\n\t\tconst purchaserRows = await db\n\t\t\t.selectDistinct({ userId: purchases.userId })\n\t\t\t.from(purchases)\n\t\t\t.where(and(...purchaseConditions))\n\n\t\tconst purchaserIds = purchaserRows\n\t\t\t.map((r: any) => r.userId)\n\t\t\t.filter((id: any): id is string => id !== null)\n\n\t\tif (purchaserIds.length === 0) return []\n\n\t\tconst rows = await db\n\t\t\t.select({\n\t\t\t\tresourceId: resourceProgress.resourceId,\n\t\t\t\tpurchaserCount: count(),\n\t\t\t})\n\t\t\t.from(resourceProgress)\n\t\t\t.where(\n\t\t\t\tsql`${resourceProgress.userId} IN (${sql.join(\n\t\t\t\t\tpurchaserIds.map((id: string) => sql`${id}`),\n\t\t\t\t\tsql`, `,\n\t\t\t\t)})`,\n\t\t\t)\n\t\t\t.groupBy(resourceProgress.resourceId)\n\t\t\t.orderBy(desc(count()))\n\t\t\t.limit(limit)\n\n\t\treturn rows.map((r: any) => ({\n\t\t\tresourceId: r.resourceId,\n\t\t\tpurchaserCount: r.purchaserCount,\n\t\t}))\n\t}\n\n\t/**\n\t * Parses an unknown JSON-like value into a plain record.\n\t *\n\t * @param value Unknown input value from a JSON database column.\n\t * @returns A Record<string, any> when the value is a record, otherwise an empty object.\n\t */\n\tfunction parseJsonRecord(value: unknown): Record<string, any> {\n\t\treturn Boolean(value) && typeof value === 'object' && !Array.isArray(value)\n\t\t\t? (value as Record<string, any>)\n\t\t\t: {}\n\t}\n\n\t/**\n\t * Checks whether a record contains at least one non-empty string value.\n\t *\n\t * @param value Unknown input value to inspect.\n\t * @returns True when at least one record value is a non-empty string.\n\t */\n\tfunction hasRecordValue(value: unknown) {\n\t\treturn (\n\t\t\tBoolean(value) &&\n\t\t\ttypeof value === 'object' &&\n\t\t\t!Array.isArray(value) &&\n\t\t\tObject.values(value as Record<string, unknown>).some(\n\t\t\t\t(entry) => typeof entry === 'string' && entry.length > 0,\n\t\t\t)\n\t\t)\n\t}\n\n\t/**\n\t * Checks whether a click ID record contains a synthetic TEST_ value.\n\t *\n\t * @param value Unknown input value to inspect.\n\t * @returns True when any record value is a string starting with TEST_.\n\t */\n\tfunction hasSyntheticClickId(value: unknown) {\n\t\treturn (\n\t\t\tBoolean(value) &&\n\t\t\ttypeof value === 'object' &&\n\t\t\t!Array.isArray(value) &&\n\t\t\tObject.values(value as Record<string, unknown>).some(\n\t\t\t\t(entry) => typeof entry === 'string' && entry.startsWith('TEST_'),\n\t\t\t)\n\t\t)\n\t}\n\n\tasync function getCheckoutAttributionReceipt(opts: { purchaseId?: string }) {\n\t\tif (!opts.purchaseId) {\n\t\t\treturn {\n\t\t\t\tpurchase: null,\n\t\t\t\tchecks: {\n\t\t\t\t\tpurchaseFound: false,\n\t\t\t\t\tattributionSnapshot: false,\n\t\t\t\t\tutm: false,\n\t\t\t\t\tactualUtm: false,\n\t\t\t\t\tclickId: false,\n\t\t\t\t\tsynthetic: false,\n\t\t\t\t\tshortlink: false,\n\t\t\t\t\tselfReportedSource: false,\n\t\t\t\t\tgaClientId: false,\n\t\t\t\t},\n\t\t\t\tattribution: null,\n\t\t\t\tlegacy: {},\n\t\t\t\tfieldKeys: [],\n\t\t\t}\n\t\t}\n\n\t\tconst [row] = await db\n\t\t\t.select({\n\t\t\t\tid: purchases.id,\n\t\t\t\tcreatedAt: purchases.createdAt,\n\t\t\t\tproductId: purchases.productId,\n\t\t\t\tproductName: products.name,\n\t\t\t\ttotalAmount: purchases.totalAmount,\n\t\t\t\tstatus: purchases.status,\n\t\t\t\tcountry: purchases.country,\n\t\t\t\tfields: purchases.fields,\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.leftJoin(products, eq(purchases.productId, products.id))\n\t\t\t.where(eq(purchases.id, opts.purchaseId))\n\t\t\t.limit(1)\n\n\t\tif (!row) {\n\t\t\treturn {\n\t\t\t\tpurchase: null,\n\t\t\t\tchecks: {\n\t\t\t\t\tpurchaseFound: false,\n\t\t\t\t\tattributionSnapshot: false,\n\t\t\t\t\tutm: false,\n\t\t\t\t\tactualUtm: false,\n\t\t\t\t\tclickId: false,\n\t\t\t\t\tsynthetic: false,\n\t\t\t\t\tshortlink: false,\n\t\t\t\t\tselfReportedSource: false,\n\t\t\t\t\tgaClientId: false,\n\t\t\t\t},\n\t\t\t\tattribution: null,\n\t\t\t\tlegacy: {},\n\t\t\t\tfieldKeys: [],\n\t\t\t}\n\t\t}\n\n\t\tconst fields = parseJsonRecord(row.fields)\n\t\tconst attribution = parseJsonRecord(fields.attribution)\n\t\tconst utm = parseJsonRecord(attribution.utm)\n\t\tconst clickIds = parseJsonRecord(attribution.clickIds)\n\t\tconst shortlinkSnapshot = parseJsonRecord(attribution.shortlink)\n\t\tconst ga = parseJsonRecord(attribution.ga)\n\t\tconst legacy = Object.fromEntries(\n\t\t\t[\n\t\t\t\t'utmSource',\n\t\t\t\t'utmMedium',\n\t\t\t\t'utmCampaign',\n\t\t\t\t'gaClientId',\n\t\t\t\t'shortlinkRef',\n\t\t\t\t'landingPath',\n\t\t\t\t'referrer',\n\t\t\t\t'ltUtmSource',\n\t\t\t\t'ltUtmMedium',\n\t\t\t\t'ltUtmCampaign',\n\t\t\t]\n\t\t\t\t.map((key) => [key, fields[key]])\n\t\t\t\t.filter(([, value]) => value !== undefined && value !== null),\n\t\t)\n\t\tconst hasActualUtm = Boolean(\n\t\t\tutm.source || utm.medium || utm.campaign || fields.utmSource,\n\t\t)\n\t\tconst synthetic = Boolean(\n\t\t\tattribution.synthetic ||\n\t\t\tfields.synthetic ||\n\t\t\thasSyntheticClickId(clickIds),\n\t\t)\n\n\t\treturn {\n\t\t\tpurchase: {\n\t\t\t\tid: row.id,\n\t\t\t\tcreatedAt: row.createdAt,\n\t\t\t\tproductId: row.productId,\n\t\t\t\tproductName: row.productName ?? null,\n\t\t\t\ttotalAmount: Number(row.totalAmount ?? 0),\n\t\t\t\tstatus: row.status,\n\t\t\t\tcountry: row.country,\n\t\t\t},\n\t\t\tchecks: {\n\t\t\t\tpurchaseFound: true,\n\t\t\t\tattributionSnapshot: Object.keys(attribution).length > 0,\n\t\t\t\tutm: hasActualUtm,\n\t\t\t\tactualUtm: hasActualUtm,\n\t\t\t\tclickId: hasRecordValue(clickIds),\n\t\t\t\tsynthetic,\n\t\t\t\tshortlink: Boolean(shortlinkSnapshot.slug || fields.shortlinkRef),\n\t\t\t\tselfReportedSource: Boolean(attribution.selfReportedSource),\n\t\t\t\tgaClientId: Boolean(ga.clientId || fields.gaClientId),\n\t\t\t},\n\t\t\tattribution: Object.keys(attribution).length > 0 ? attribution : null,\n\t\t\tlegacy,\n\t\t\tfieldKeys: Object.keys(fields).sort(),\n\t\t}\n\t}\n\n\tasync function getCheckoutSurveyFallbackReport(\n\t\trange: AnalyticsTimeRange = '30d',\n\t\tlimit: number = 20,\n\t\tfilters: { productId?: string } = {},\n\t) {\n\t\tconst label = 'recovered_from_checkout_survey_response'\n\t\tif (!questionResponse) {\n\t\t\treturn {\n\t\t\t\tlabel,\n\t\t\t\tproductId: filters.productId ?? null,\n\t\t\t\ttotalDarkPurchases: 0,\n\t\t\t\ttotalDarkRevenue: 0,\n\t\t\t\texactPurchaseLinkedPurchases: 0,\n\t\t\t\texactPurchaseLinkedRevenue: 0,\n\t\t\t\tuserLinkedPurchases: 0,\n\t\t\t\tuserLinkedRevenue: 0,\n\t\t\t\tbyAnswer: [],\n\t\t\t\tnotes: ['questionResponse table was not provided to this provider'],\n\t\t\t}\n\t\t}\n\n\t\tconst since = rangeToDate(range)\n\t\tconst purchaseConditions = [\n\t\t\tpaidPurchase(),\n\t\t\tsql`NOT ${attributionSignalSql}`,\n\t\t]\n\t\tif (since) purchaseConditions.push(gte(purchases.createdAt, since))\n\t\tif (filters.productId) {\n\t\t\tpurchaseConditions.push(eq(purchases.productId, filters.productId))\n\t\t}\n\n\t\tconst darkRows = await db\n\t\t\t.select({\n\t\t\t\tid: purchases.id,\n\t\t\t\tuserId: purchases.userId,\n\t\t\t\trevenue: purchases.totalAmount,\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.where(and(...purchaseConditions))\n\n\t\tconst totalDarkRevenue = darkRows.reduce(\n\t\t\t(total: number, row: any) => total + Number(row.revenue ?? 0),\n\t\t\t0,\n\t\t)\n\n\t\tif (darkRows.length === 0) {\n\t\t\treturn {\n\t\t\t\tlabel,\n\t\t\t\tproductId: filters.productId ?? null,\n\t\t\t\ttotalDarkPurchases: 0,\n\t\t\t\ttotalDarkRevenue: 0,\n\t\t\t\texactPurchaseLinkedPurchases: 0,\n\t\t\t\texactPurchaseLinkedRevenue: 0,\n\t\t\t\tuserLinkedPurchases: 0,\n\t\t\t\tuserLinkedRevenue: 0,\n\t\t\t\tbyAnswer: [],\n\t\t\t\tnotes: ['No dark paid purchases matched the filters'],\n\t\t\t}\n\t\t}\n\n\t\tconst darkById = new Map<string, (typeof darkRows)[number]>(\n\t\t\tdarkRows.map((row: (typeof darkRows)[number]) => [row.id, row]),\n\t\t)\n\t\tconst darkByUserId = new Map<string, any[]>()\n\t\tfor (const row of darkRows) {\n\t\t\tif (!row.userId) continue\n\t\t\tconst bucket = darkByUserId.get(row.userId) ?? []\n\t\t\tbucket.push(row)\n\t\t\tdarkByUserId.set(row.userId, bucket)\n\t\t}\n\n\t\tconst responseConditions: any[] = []\n\t\tif (since) responseConditions.push(gte(questionResponse.createdAt, since))\n\t\tconst darkIds = [...darkById.keys()]\n\t\tconst darkUserIds = [...darkByUserId.keys()]\n\t\tconst exactPurchaseCondition = sql`JSON_UNQUOTE(JSON_EXTRACT(${questionResponse.fields}, '$.purchaseId')) IN (${sql.join(\n\t\t\tdarkIds.map((id) => sql`${id}`),\n\t\t\tsql`, `,\n\t\t)})`\n\t\tconst userCondition =\n\t\t\tdarkUserIds.length > 0\n\t\t\t\t? sql`${questionResponse.userId} IN (${sql.join(\n\t\t\t\t\t\tdarkUserIds.map((id) => sql`${id}`),\n\t\t\t\t\t\tsql`, `,\n\t\t\t\t\t)})`\n\t\t\t\t: sql`FALSE`\n\t\tresponseConditions.push(\n\t\t\tsql`(${exactPurchaseCondition} OR ${userCondition})`,\n\t\t)\n\n\t\tconst responseRows = await db\n\t\t\t.select({\n\t\t\t\tpurchaseId: sql<string>`JSON_UNQUOTE(JSON_EXTRACT(${questionResponse.fields}, '$.purchaseId'))`,\n\t\t\t\tanswer: sql<string>`JSON_UNQUOTE(JSON_EXTRACT(${questionResponse.fields}, '$.answer'))`,\n\t\t\t\tuserId: questionResponse.userId,\n\t\t\t\tcreatedAt: questionResponse.createdAt,\n\t\t\t})\n\t\t\t.from(questionResponse)\n\t\t\t.where(and(...responseConditions))\n\n\t\tconst exactByPurchase = new Map<string, any>()\n\t\tconst latestByUser = new Map<string, any>()\n\t\tfor (const row of responseRows) {\n\t\t\tif (row.purchaseId && darkById.has(row.purchaseId)) {\n\t\t\t\texactByPurchase.set(row.purchaseId, row)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (!row.userId) continue\n\t\t\tconst current = latestByUser.get(row.userId)\n\t\t\tconst rowTime = new Date(row.createdAt ?? 0).getTime()\n\t\t\tconst currentTime = current\n\t\t\t\t? new Date(current.createdAt ?? 0).getTime()\n\t\t\t\t: -1\n\t\t\tif (!current || rowTime >= currentTime) latestByUser.set(row.userId, row)\n\t\t}\n\n\t\tconst classified = new Map<\n\t\t\tstring,\n\t\t\t{\n\t\t\t\tconfidence: 'exact_purchase_link' | 'user_linked'\n\t\t\t\tanswer: string\n\t\t\t\trevenue: number\n\t\t\t}\n\t\t>()\n\t\tfor (const [purchaseId, response] of exactByPurchase) {\n\t\t\tconst purchase = darkById.get(purchaseId)\n\t\t\tclassified.set(purchaseId, {\n\t\t\t\tconfidence: 'exact_purchase_link',\n\t\t\t\tanswer: response.answer || '(no answer)',\n\t\t\t\trevenue: Number(purchase?.revenue ?? 0),\n\t\t\t})\n\t\t}\n\t\tfor (const row of darkRows) {\n\t\t\tif (classified.has(row.id) || !row.userId) continue\n\t\t\tconst response = latestByUser.get(row.userId)\n\t\t\tif (!response) continue\n\t\t\tclassified.set(row.id, {\n\t\t\t\tconfidence: 'user_linked',\n\t\t\t\tanswer: response.answer || '(no answer)',\n\t\t\t\trevenue: Number(row.revenue ?? 0),\n\t\t\t})\n\t\t}\n\n\t\tconst byAnswer = new Map<\n\t\t\tstring,\n\t\t\t{\n\t\t\t\tanswer: string\n\t\t\t\tconfidence: 'exact_purchase_link' | 'user_linked'\n\t\t\t\tpurchases: number\n\t\t\t\trevenue: number\n\t\t\t}\n\t\t>()\n\t\tlet exactPurchaseLinkedPurchases = 0\n\t\tlet exactPurchaseLinkedRevenue = 0\n\t\tlet userLinkedPurchases = 0\n\t\tlet userLinkedRevenue = 0\n\t\tfor (const entry of classified.values()) {\n\t\t\tif (entry.confidence === 'exact_purchase_link') {\n\t\t\t\texactPurchaseLinkedPurchases += 1\n\t\t\t\texactPurchaseLinkedRevenue += entry.revenue\n\t\t\t} else {\n\t\t\t\tuserLinkedPurchases += 1\n\t\t\t\tuserLinkedRevenue += entry.revenue\n\t\t\t}\n\t\t\tconst key = `${entry.confidence}:${entry.answer}`\n\t\t\tconst current = byAnswer.get(key) ?? {\n\t\t\t\tanswer: entry.answer,\n\t\t\t\tconfidence: entry.confidence,\n\t\t\t\tpurchases: 0,\n\t\t\t\trevenue: 0,\n\t\t\t}\n\t\t\tcurrent.purchases += 1\n\t\t\tcurrent.revenue += entry.revenue\n\t\t\tbyAnswer.set(key, current)\n\t\t}\n\n\t\treturn {\n\t\t\tlabel,\n\t\t\tproductId: filters.productId ?? null,\n\t\t\ttotalDarkPurchases: darkRows.length,\n\t\t\ttotalDarkRevenue,\n\t\t\texactPurchaseLinkedPurchases,\n\t\t\texactPurchaseLinkedRevenue,\n\t\t\tuserLinkedPurchases,\n\t\t\tuserLinkedRevenue,\n\t\t\tbyAnswer: [...byAnswer.values()]\n\t\t\t\t.sort((a, b) => b.revenue - a.revenue || b.purchases - a.purchases)\n\t\t\t\t.slice(0, limit),\n\t\t\tnotes: [\n\t\t\t\t'Report-only fallback. No purchase fields are mutated.',\n\t\t\t\t'Exact purchase-linked responses use QuestionResponse.fields.purchaseId when present.',\n\t\t\t\t'User-linked responses are lower-confidence and remain report-only.',\n\t\t\t],\n\t\t}\n\t}\n\n\t// ─── Attribution Trail ───────────────────────────────────────────────────\n\n\t/**\n\t * Trace the full attribution journey for a user by email or purchaseId.\n\t * Walks: ShortlinkClick → ShortlinkAttribution (signup) →\n\t * ResourceProgress → Purchase\n\t */\n\n\tasync function getValuePathSummary(range: AnalyticsTimeRange = '30d') {\n\t\tif (!contactEvent || !sideEffectIntent) {\n\t\t\treturn {\n\t\t\t\tcontacts: 0,\n\t\t\t\tevents: 0,\n\t\t\t\tintents: 0,\n\t\t\t\tcompletedIntents: 0,\n\t\t\t\tpendingIntents: 0,\n\t\t\t\tblockedIntents: 0,\n\t\t\t\tanswerEvents: 0,\n\t\t\t\tdripEvents: 0,\n\t\t\t\tenteredEvents: 0,\n\t\t\t\tparticipantsWithAnswerClicks: 0,\n\t\t\t\tparticipantsWithNoAnswerClicks: 0,\n\t\t\t\tterminalParticipants: 0,\n\t\t\t\tanswerOptions: [],\n\t\t\t\tanswerSteps: [],\n\t\t\t\tterminalSteps: [],\n\t\t\t\tnotes: ['Contact Event and SideEffectIntent tables are unavailable.'],\n\t\t\t}\n\t\t}\n\n\t\tconst since = rangeToDate(range)\n\t\tconst eventConditions = [sql`${contactEvent.eventType} LIKE 'value-path.%'`]\n\t\tconst intentConditions = [\n\t\t\teq(sideEffectIntent.type, 'send-value-path-email'),\n\t\t]\n\t\tif (since) {\n\t\t\teventConditions.push(gte(contactEvent.occurredAt, since))\n\t\t\tintentConditions.push(gte(sideEffectIntent.createdAt, since))\n\t\t}\n\n\t\tconst [events, intents] = await Promise.all([\n\t\t\tdb\n\t\t\t\t.select({\n\t\t\t\t\tcontactId: contactEvent.contactId,\n\t\t\t\t\teventType: contactEvent.eventType,\n\t\t\t\t\tproviderEventId: contactEvent.providerEventId,\n\t\t\t\t\toccurredAt: contactEvent.occurredAt,\n\t\t\t\t})\n\t\t\t\t.from(contactEvent)\n\t\t\t\t.where(and(...eventConditions)),\n\t\t\tdb\n\t\t\t\t.select({\n\t\t\t\t\tcontactId: sideEffectIntent.contactId,\n\t\t\t\t\tstatus: sideEffectIntent.status,\n\t\t\t\t\tmetadata: sideEffectIntent.metadata,\n\t\t\t\t\tcreatedAt: sideEffectIntent.createdAt,\n\t\t\t\t})\n\t\t\t\t.from(sideEffectIntent)\n\t\t\t\t.where(and(...intentConditions)),\n\t\t])\n\n\t\tconst contactIds = new Set<string>()\n\t\tfor (const event of events) contactIds.add(event.contactId)\n\t\tfor (const intent of intents) contactIds.add(intent.contactId)\n\n\t\tconst answerEvents = events.filter(\n\t\t\t(event: any) => event.eventType === 'value-path.answer-selected',\n\t\t)\n\t\tconst dripEvents = events.filter(\n\t\t\t(event: any) => event.eventType === 'value-path.drip-progressed',\n\t\t)\n\t\tconst enteredEvents = events.filter(\n\t\t\t(event: any) => event.eventType === 'value-path.entered',\n\t\t)\n\n\t\tconst answersByContact = new Map<string, number>()\n\t\tfor (const event of answerEvents) {\n\t\t\tanswersByContact.set(\n\t\t\t\tevent.contactId,\n\t\t\t\t(answersByContact.get(event.contactId) ?? 0) + 1,\n\t\t\t)\n\t\t}\n\n\t\tconst answerKeyCounts = new Map<string, number>()\n\t\tconst answerStepCounts = new Map<string, number>()\n\t\tfor (const event of answerEvents) {\n\t\t\tconst key = parseValuePathAnswerKey(event.providerEventId)\n\t\t\tanswerKeyCounts.set(key, (answerKeyCounts.get(key) ?? 0) + 1)\n\t\t\tconst step = answerStepFromKey(key)\n\t\t\tanswerStepCounts.set(step, (answerStepCounts.get(step) ?? 0) + 1)\n\t\t}\n\n\t\tconst latestIntentByContact = new Map<string, any>()\n\t\tfor (const intent of [...intents].sort(\n\t\t\t(a: any, b: any) =>\n\t\t\t\tnew Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(),\n\t\t)) {\n\t\t\tlatestIntentByContact.set(intent.contactId, intent)\n\t\t}\n\n\t\tconst terminalCounts = new Map<string, number>()\n\t\tfor (const intent of latestIntentByContact.values()) {\n\t\t\tconst emailResourceId = String(intent.metadata?.emailResourceId ?? '')\n\t\t\tif (!isTerminalValuePathEmail(emailResourceId)) continue\n\t\t\tterminalCounts.set(\n\t\t\t\temailResourceId,\n\t\t\t\t(terminalCounts.get(emailResourceId) ?? 0) + 1,\n\t\t\t)\n\t\t}\n\n\t\treturn {\n\t\t\tcontacts: contactIds.size,\n\t\t\tevents: events.length,\n\t\t\tintents: intents.length,\n\t\t\tcompletedIntents: intents.filter(\n\t\t\t\t(intent: any) => intent.status === 'completed',\n\t\t\t).length,\n\t\t\tpendingIntents: intents.filter(\n\t\t\t\t(intent: any) => intent.status === 'pending',\n\t\t\t).length,\n\t\t\tblockedIntents: intents.filter(\n\t\t\t\t(intent: any) => intent.status === 'blocked',\n\t\t\t).length,\n\t\t\tanswerEvents: answerEvents.length,\n\t\t\tdripEvents: dripEvents.length,\n\t\t\tenteredEvents: enteredEvents.length,\n\t\t\tparticipantsWithAnswerClicks: answersByContact.size,\n\t\t\tparticipantsWithNoAnswerClicks: Math.max(\n\t\t\t\t0,\n\t\t\t\tcontactIds.size - answersByContact.size,\n\t\t\t),\n\t\t\tterminalParticipants: [...terminalCounts.values()].reduce(\n\t\t\t\t(total, count) => total + count,\n\t\t\t\t0,\n\t\t\t),\n\t\t\tanswerOptions: [...answerKeyCounts.entries()]\n\t\t\t\t.map(([key, count]) => ({\n\t\t\t\t\tkey,\n\t\t\t\t\tstep: answerStepFromKey(key),\n\t\t\t\t\toptionValue: answerOptionFromKey(key),\n\t\t\t\t\tcount,\n\t\t\t\t}))\n\t\t\t\t.sort((a, b) => b.count - a.count),\n\t\t\tanswerSteps: [...answerStepCounts.entries()]\n\t\t\t\t.map(([step, count]) => ({ step, count }))\n\t\t\t\t.sort((a, b) => b.count - a.count),\n\t\t\tterminalSteps: [...terminalCounts.entries()]\n\t\t\t\t.map(([emailResourceId, count]) => ({ emailResourceId, count }))\n\t\t\t\t.sort((a, b) => b.count - a.count),\n\t\t\tnotes: [\n\t\t\t\t'Counts are based on Contact Events and SideEffectIntents.',\n\t\t\t\t'Kit-native opens, unsubscribes, complaints, and raw Kit link clicks are not included.',\n\t\t\t],\n\t\t}\n\t}\n\n\tfunction parseValuePathAnswerKey(providerEventId: string | null | undefined) {\n\t\tconst match = String(providerEventId ?? '').match(/:answer:(.+)$/)\n\t\treturn match?.[1] ?? 'unknown'\n\t}\n\n\tfunction answerStepFromKey(key: string) {\n\t\tconst index = key.lastIndexOf('.')\n\t\treturn index > -1 ? key.slice(0, index) : key\n\t}\n\n\tfunction answerOptionFromKey(key: string) {\n\t\tconst index = key.lastIndexOf('.')\n\t\treturn index > -1 ? key.slice(index + 1) : 'unknown'\n\t}\n\n\tfunction isTerminalValuePathEmail(emailResourceId: string) {\n\t\treturn /(?:^|\\.)(?:email-6|team-email-6)$/.test(emailResourceId)\n\t}\n\n\tasync function traceAttribution(opts: {\n\t\temail?: string\n\t\tpurchaseId?: string\n\t}): Promise<AttributionTrail> {\n\t\tconst events: AttributionTrailEvent[] = []\n\n\t\t// Resolve user\n\t\tlet userId: string | null = null\n\t\tlet userEmail: string | null = opts.email ?? null\n\t\tlet userRecord: AttributionTrail['user'] = null\n\n\t\tif (opts.purchaseId) {\n\t\t\tconst [purchase] = await db\n\t\t\t\t.select({\n\t\t\t\t\tuserId: purchases.userId,\n\t\t\t\t\temail: users.email,\n\t\t\t\t})\n\t\t\t\t.from(purchases)\n\t\t\t\t.leftJoin(users, eq(purchases.userId, users.id))\n\t\t\t\t.where(eq(purchases.id, opts.purchaseId))\n\t\t\t\t.limit(1)\n\t\t\tuserId = purchase?.userId ?? null\n\t\t\tuserEmail = purchase?.email ?? userEmail\n\t\t}\n\n\t\tif (userEmail && !userId) {\n\t\t\tconst [u] = await db\n\t\t\t\t.select({ id: users.id })\n\t\t\t\t.from(users)\n\t\t\t\t.where(eq(users.email, userEmail))\n\t\t\t\t.limit(1)\n\t\t\tuserId = u?.id ?? null\n\t\t}\n\n\t\tif (userId) {\n\t\t\tconst [u] = await db\n\t\t\t\t.select({\n\t\t\t\t\tid: users.id,\n\t\t\t\t\temail: users.email,\n\t\t\t\t\tname: users.name,\n\t\t\t\t\tcreatedAt: users.createdAt,\n\t\t\t\t})\n\t\t\t\t.from(users)\n\t\t\t\t.where(eq(users.id, userId))\n\t\t\t\t.limit(1)\n\t\t\tuserRecord = u\n\t\t\t\t? {\n\t\t\t\t\t\tid: u.id,\n\t\t\t\t\t\temail: u.email,\n\t\t\t\t\t\tname: u.name ?? null,\n\t\t\t\t\t\tcreatedAt: u.createdAt!,\n\t\t\t\t\t}\n\t\t\t\t: null\n\t\t}\n\n\t\t// Find shortlink attributions for this user (by userId or email)\n\t\tconst attrConditions: any[] = []\n\t\tif (userId) attrConditions.push(eq(shortlinkAttribution.userId, userId))\n\t\tif (userEmail)\n\t\t\tattrConditions.push(eq(shortlinkAttribution.email, userEmail))\n\n\t\tif (attrConditions.length > 0) {\n\t\t\tconst attrs = await db\n\t\t\t\t.select({\n\t\t\t\t\ttype: shortlinkAttribution.type,\n\t\t\t\t\tcreatedAt: shortlinkAttribution.createdAt,\n\t\t\t\t\tmetadata: shortlinkAttribution.metadata,\n\t\t\t\t\tshortlinkId: shortlinkAttribution.shortlinkId,\n\t\t\t\t\tslug: shortlink.slug,\n\t\t\t\t\turl: shortlink.url,\n\t\t\t\t})\n\t\t\t\t.from(shortlinkAttribution)\n\t\t\t\t.leftJoin(shortlink, eq(shortlinkAttribution.shortlinkId, shortlink.id))\n\t\t\t\t.where(sql`(${sql.join(attrConditions, sql` OR `)})`)\n\t\t\t\t.orderBy(shortlinkAttribution.createdAt)\n\n\t\t\tfor (const attr of attrs) {\n\t\t\t\t// Find clicks on this shortlink before the attribution event\n\t\t\t\tconst clicks = await db\n\t\t\t\t\t.select({\n\t\t\t\t\t\ttimestamp: shortlinkClick.timestamp,\n\t\t\t\t\t\treferrer: shortlinkClick.referrer,\n\t\t\t\t\t\tcountry: shortlinkClick.country,\n\t\t\t\t\t\tdevice: shortlinkClick.device,\n\t\t\t\t\t})\n\t\t\t\t\t.from(shortlinkClick)\n\t\t\t\t\t.where(\n\t\t\t\t\t\tand(\n\t\t\t\t\t\t\teq(shortlinkClick.shortlinkId, attr.shortlinkId),\n\t\t\t\t\t\t\tlte(shortlinkClick.timestamp, attr.createdAt),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\t.orderBy(desc(shortlinkClick.timestamp))\n\t\t\t\t\t.limit(3) // last 3 clicks before attribution\n\n\t\t\t\tfor (const click of clicks) {\n\t\t\t\t\tevents.push({\n\t\t\t\t\t\ttype: 'click',\n\t\t\t\t\t\ttimestamp: click.timestamp,\n\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\tshortlink: `/s/${attr.slug}`,\n\t\t\t\t\t\t\tdestination: attr.url,\n\t\t\t\t\t\t\treferrer: click.referrer,\n\t\t\t\t\t\t\tcountry: click.country,\n\t\t\t\t\t\t\tdevice: click.device,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tevents.push({\n\t\t\t\t\ttype: attr.type === 'purchase' ? 'purchase' : 'signup',\n\t\t\t\t\ttimestamp: attr.createdAt,\n\t\t\t\t\tdetail: {\n\t\t\t\t\t\tshortlink: `/s/${attr.slug}`,\n\t\t\t\t\t\tmetadata: attr.metadata ? JSON.parse(attr.metadata) : null,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\t// Find resource progress for this user\n\t\tif (userId) {\n\t\t\tconst progress = await db\n\t\t\t\t.select({\n\t\t\t\t\tresourceId: resourceProgress.resourceId,\n\t\t\t\t\tcompletedAt: resourceProgress.completedAt,\n\t\t\t\t\tcreatedAt: resourceProgress.createdAt,\n\t\t\t\t})\n\t\t\t\t.from(resourceProgress)\n\t\t\t\t.where(eq(resourceProgress.userId, userId))\n\t\t\t\t.orderBy(resourceProgress.createdAt)\n\t\t\t\t.limit(20) // cap at 20 most recent\n\n\t\t\tfor (const p of progress) {\n\t\t\t\tevents.push({\n\t\t\t\t\ttype: 'progress',\n\t\t\t\t\ttimestamp: p.completedAt ?? p.createdAt,\n\t\t\t\t\tdetail: { resourceId: p.resourceId },\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\t// Find purchases\n\t\tconst purchaseConditions = [paidPurchase()]\n\t\tif (opts.purchaseId) {\n\t\t\tpurchaseConditions.push(eq(purchases.id, opts.purchaseId))\n\t\t} else if (userId) {\n\t\t\tpurchaseConditions.push(eq(purchases.userId, userId))\n\t\t} else {\n\t\t\t// No user found, return empty\n\t\t\treturn { user: userRecord, events: [], purchases: [] }\n\t\t}\n\n\t\tconst purchaseRows = await db\n\t\t\t.select({\n\t\t\t\tid: purchases.id,\n\t\t\t\ttotalAmount: purchases.totalAmount,\n\t\t\t\tproductName: products.name,\n\t\t\t\tcreatedAt: purchases.createdAt,\n\t\t\t\tcountry: purchases.country,\n\t\t\t\tfields: purchases.fields,\n\t\t\t})\n\t\t\t.from(purchases)\n\t\t\t.leftJoin(products, eq(purchases.productId, products.id))\n\t\t\t.where(and(...purchaseConditions))\n\t\t\t.orderBy(purchases.createdAt)\n\n\t\tconst purchaseResults = purchaseRows.map((p: any) => {\n\t\t\tconst fields = (p.fields as Record<string, any>) ?? {}\n\t\t\tevents.push({\n\t\t\t\ttype: 'purchase',\n\t\t\t\ttimestamp: p.createdAt,\n\t\t\t\tdetail: {\n\t\t\t\t\tpurchaseId: p.id,\n\t\t\t\t\tamount: Number(p.totalAmount),\n\t\t\t\t\tproduct: p.productName,\n\t\t\t\t},\n\t\t\t})\n\t\t\treturn {\n\t\t\t\tid: p.id,\n\t\t\t\ttotalAmount: Number(p.totalAmount),\n\t\t\t\tproductName: p.productName ?? 'Unknown',\n\t\t\t\tcreatedAt: p.createdAt,\n\t\t\t\tcountry: p.country,\n\t\t\t\tutmSource: fields.utmSource ?? null,\n\t\t\t\tutmMedium: fields.utmMedium ?? null,\n\t\t\t\tutmCampaign: fields.utmCampaign ?? null,\n\t\t\t}\n\t\t})\n\n\t\t// Sort all events by timestamp\n\t\tevents.sort(\n\t\t\t(a, b) =>\n\t\t\t\tnew Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(),\n\t\t)\n\n\t\treturn { user: userRecord, events, purchases: purchaseResults }\n\t}\n\n\treturn {\n\t\tgetRevenueSummary,\n\t\tgetRevenueByDay,\n\t\tgetPreviousPeriodRevenueByDay,\n\t\tgetRevenueByProduct,\n\t\tgetRevenueByCountry,\n\t\tgetRecentPurchases,\n\t\tgetAttributionSummary,\n\t\tgetShortlinkPerformance,\n\t\tgetRevenueBySource,\n\t\tgetConversionFunnel,\n\t\tgetCommerceLaneSummary,\n\t\tgetAttributedRevenueSummary,\n\t\tgetContentPurchaseCorrelation,\n\t\tgetCheckoutAttributionReceipt,\n\t\tgetCheckoutSurveyFallbackReport,\n\t\tgetValuePathSummary,\n\t\ttraceAttribution,\n\t}\n}\n\nexport type DatabaseAnalyticsProvider = ReturnType<\n\ttypeof createDatabaseProvider\n>\n","export const SHORTLINK_RECOVERY_LANE =\n\t'recovered_from_shortlink_attribution_table' as const\n\nexport type PurchaseAttributionClass =\n\t| 'purchase_field'\n\t| typeof SHORTLINK_RECOVERY_LANE\n\t| 'dark'\n\nexport interface ShortlinkAttributionEvidence {\n\ttype?: string | null\n\tmetadata?: unknown\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction nonEmptyString(value: unknown) {\n\treturn typeof value === 'string' && value.trim().length > 0\n}\n\nfunction parseMetadata(value: unknown): Record<string, unknown> | null {\n\tif (typeof value === 'string') {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(value) as unknown\n\t\t\treturn isRecord(parsed) ? parsed : null\n\t\t} catch {\n\t\t\treturn null\n\t\t}\n\t}\n\n\treturn isRecord(value) ? value : null\n}\n\n/**\n * Detects durable purchase-field attribution on a purchase fields object.\n *\n * @param fields Unknown purchase fields payload.\n * @returns True when the purchase already has attribution, legacy UTM source, or legacy GA client ID evidence.\n * @example\n * hasPurchaseFieldAttribution({ attribution: { source: 'email' } })\n */\nexport function hasPurchaseFieldAttribution(fields: unknown) {\n\tconst record = isRecord(fields) ? fields : {}\n\tconst attribution = record.attribution\n\n\treturn Boolean(\n\t\t(isRecord(attribution) && Object.keys(attribution).length > 0) ||\n\t\tnonEmptyString(record.utmSource) ||\n\t\tnonEmptyString(record.gaClientId),\n\t)\n}\n\n/**\n * Detects exact shortlink purchase evidence for one purchase.\n *\n * @param params.purchaseId Purchase ID that must match attribution metadata.purchaseId.\n * @param params.attributions ShortlinkAttributionEvidence rows to inspect.\n * @returns True only for purchase rows with valid JSON metadata and an exact purchase ID match.\n */\nexport function hasExactShortlinkPurchaseAttribution(params: {\n\tpurchaseId: string\n\tattributions: readonly ShortlinkAttributionEvidence[]\n}) {\n\treturn params.attributions.some((attribution) => {\n\t\tif (attribution.type !== 'purchase') return false\n\t\tconst metadata = parseMetadata(attribution.metadata)\n\t\treturn metadata?.purchaseId === params.purchaseId\n\t})\n}\n\n/**\n * Classifies purchase attribution with purchase fields taking precedence.\n *\n * @param params.purchaseId Purchase ID being classified.\n * @param params.fields Purchase fields payload.\n * @param params.shortlinkAttributions ShortlinkAttributionEvidence rows used as exact fallback evidence.\n * @returns A PurchaseAttributionClass: 'purchase_field', SHORTLINK_RECOVERY_LANE, or 'dark'.\n * @example\n * classifyPurchaseAttribution({ purchaseId: 'p1', fields: {}, shortlinkAttributions: [] })\n */\nexport function classifyPurchaseAttribution(params: {\n\tpurchaseId: string\n\tfields?: unknown\n\tshortlinkAttributions?: readonly ShortlinkAttributionEvidence[]\n}): PurchaseAttributionClass {\n\tif (hasPurchaseFieldAttribution(params.fields)) return 'purchase_field'\n\tif (\n\t\thasExactShortlinkPurchaseAttribution({\n\t\t\tpurchaseId: params.purchaseId,\n\t\t\tattributions: params.shortlinkAttributions ?? [],\n\t\t})\n\t) {\n\t\treturn SHORTLINK_RECOVERY_LANE\n\t}\n\treturn 'dark'\n}\n"],"mappings":"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","names":["and","count","desc","eq","gt","gte","inArray","lte","sql","sum","SHORTLINK_RECOVERY_LANE","createDatabaseProvider","db","schema","purchases","products","users","coupon","resourceProgress","shortlink","shortlinkAttribution","shortlinkClick","questionResponse","contactEvent","sideEffectIntent","PAID_STATUSES","commerceRecord","inArray","status","paidPurchase","and","gt","totalAmount","accessGrant","sql","backfillFreeUpgrade","fields","syntheticSignalSql","syntheticPurchase","purchaseFieldAttributionSignalSql","exactShortlinkPurchaseAttributionSignalSql","type","metadata","id","shortlinkRecoveredAttributionSignalSql","attributionSignalSql","rangeToDate","range","now","Date","hours","getTime","getRevenueSummary","since","conditions","push","gte","createdAt","totals","select","totalRevenue","sum","purchaseCount","count","from","where","Number","avgOrderValue","getRevenueByDay","rows","date","as","revenue","groupBy","orderBy","map","r","getPreviousPeriodRevenueByDay","periodMs","periodStart","prevStart","lte","getRevenueByProduct","productId","productName","name","leftJoin","eq","desc","getRevenueByCountry","country","limit","getRecentPurchases","filter","bulkCouponId","couponId","userId","userName","userEmail","email","organizationId","seats","maxUses","isTeam","query","findMany","with","product","user","getAttributionSummary","length","undefined","getShortlinkPerformance","clickConditions","timestamp","shortlinkId","slug","url","clicks","innerJoin","attrConditions","attrRows","attrMap","Map","a","existing","get","signups","set","attr","getRevenueBySource","filters","kindExpr","sourceExpr","SHORTLINK_RECOVERY_LANE","mediumExpr","campaignExpr","kind","source","medium","campaign","getConversionFunnel","userConditions","purchaseConditions","userCount","total","attributedCount","totalSignups","totalPurchases","attributedPurchases","conversionRate","attributionCoverage","getCommerceLaneSummary","commerce","paid","grants","freeUpgrades","synthetic","reasonRows","reason","commerceRecords","paidPurchases","paidRevenue","accessGrants","accessGrantRevenue","syntheticPurchases","byAccessGrantReason","Object","fromEntries","row","getAttributedRevenueSummary","attributed","purchaseFieldAttributed","recoveredFromShortlinkAttributionTable","signalConditions","signalCount","condition","shortlinkCount","utmCount","clickIdCount","gaClientIdCount","selfReportedSourceCount","recoveredFromShortlinkAttributionTableCount","Promise","all","attributedRevenue","purchaseFieldAttributedRevenue","recoveredFromShortlinkAttributionTableRevenue","unattributedRevenue","attributionRate","purchaseFieldAttributedPurchases","recoveredFromShortlinkAttributionTablePurchases","signals","utm","paidClickId","gaClientId","selfReportedSource","internalFreeUpgrade","getContentPurchaseCorrelation","purchaserRows","selectDistinct","purchaserIds","resourceId","purchaserCount","join","parseJsonRecord","value","Boolean","Array","isArray","hasRecordValue","values","some","entry","hasSyntheticClickId","startsWith","getCheckoutAttributionReceipt","opts","purchaseId","purchase","checks","purchaseFound","attributionSnapshot","actualUtm","clickId","attribution","legacy","fieldKeys","clickIds","shortlinkSnapshot","ga","key","hasActualUtm","utmSource","keys","shortlinkRef","clientId","sort","getCheckoutSurveyFallbackReport","label","totalDarkPurchases","totalDarkRevenue","exactPurchaseLinkedPurchases","exactPurchaseLinkedRevenue","userLinkedPurchases","userLinkedRevenue","byAnswer","notes","darkRows","reduce","darkById","darkByUserId","bucket","responseConditions","darkIds","darkUserIds","exactPurchaseCondition","userCondition","responseRows","answer","exactByPurchase","latestByUser","has","current","rowTime","currentTime","classified","response","confidence","b","slice","getValuePathSummary","contacts","events","intents","completedIntents","pendingIntents","blockedIntents","answerEvents","dripEvents","enteredEvents","participantsWithAnswerClicks","participantsWithNoAnswerClicks","terminalParticipants","answerOptions","answerSteps","terminalSteps","eventConditions","eventType","intentConditions","occurredAt","contactId","providerEventId","contactIds","Set","event","add","intent","answersByContact","answerKeyCounts","answerStepCounts","parseValuePathAnswerKey","step","answerStepFromKey","latestIntentByContact","terminalCounts","emailResourceId","String","isTerminalValuePathEmail","size","Math","max","entries","optionValue","answerOptionFromKey","match","index","lastIndexOf","test","traceAttribution","userRecord","u","attrs","referrer","device","click","detail","destination","JSON","parse","progress","completedAt","p","purchaseRows","purchaseResults","amount","utmMedium","utmCampaign"]}