🪻 distributed transcription service thistle.dunkirk.sh
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: try to link emails with existing polar customers if possible

+100 -96
+100 -96
src/index.ts
··· 99 99 // Clean up expired sessions every hour 100 100 setInterval(cleanupExpiredSessions, 60 * 60 * 1000); 101 101 102 + // Helper function to sync user subscriptions from Polar 103 + async function syncUserSubscriptionsFromPolar( 104 + userId: number, 105 + email: string, 106 + ): Promise<void> { 107 + try { 108 + const { polar } = await import("./lib/polar"); 109 + 110 + // Search for customer by email 111 + const customers = await polar.customers.list({ 112 + organizationId: process.env.POLAR_ORGANIZATION_ID, 113 + query: email, 114 + }); 115 + 116 + if (!customers.result.items || customers.result.items.length === 0) { 117 + console.log(`[Sync] No Polar customer found for ${email}`); 118 + return; 119 + } 120 + 121 + const customer = customers.result.items[0]; 122 + 123 + // Get all subscriptions for this customer 124 + const subscriptions = await polar.subscriptions.list({ 125 + customerId: customer.id, 126 + }); 127 + 128 + if (!subscriptions.result.items || subscriptions.result.items.length === 0) { 129 + console.log(`[Sync] No subscriptions found for customer ${customer.id}`); 130 + return; 131 + } 132 + 133 + // Update each subscription in the database 134 + for (const subscription of subscriptions.result.items) { 135 + db.run( 136 + `INSERT INTO subscriptions (id, user_id, customer_id, status, current_period_start, current_period_end, cancel_at_period_end, canceled_at, updated_at) 137 + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) 138 + ON CONFLICT(id) DO UPDATE SET 139 + user_id = excluded.user_id, 140 + status = excluded.status, 141 + current_period_start = excluded.current_period_start, 142 + current_period_end = excluded.current_period_end, 143 + cancel_at_period_end = excluded.cancel_at_period_end, 144 + canceled_at = excluded.canceled_at, 145 + updated_at = excluded.updated_at`, 146 + [ 147 + subscription.id, 148 + userId, 149 + subscription.customerId, 150 + subscription.status, 151 + subscription.currentPeriodStart 152 + ? Math.floor( 153 + new Date(subscription.currentPeriodStart).getTime() / 1000, 154 + ) 155 + : null, 156 + subscription.currentPeriodEnd 157 + ? Math.floor( 158 + new Date(subscription.currentPeriodEnd).getTime() / 1000, 159 + ) 160 + : null, 161 + subscription.cancelAtPeriodEnd ? 1 : 0, 162 + subscription.canceledAt 163 + ? Math.floor(new Date(subscription.canceledAt).getTime() / 1000) 164 + : null, 165 + Math.floor(Date.now() / 1000), 166 + ], 167 + ); 168 + } 169 + 170 + console.log( 171 + `[Sync] Linked ${subscriptions.result.items.length} subscription(s) to user ${userId} (${email})`, 172 + ); 173 + } catch (error) { 174 + console.error( 175 + `[Sync] Failed to sync subscriptions for ${email}:`, 176 + error instanceof Error ? error.message : "Unknown error", 177 + ); 178 + // Don't throw - registration should succeed even if sync fails 179 + } 180 + } 181 + 182 + 102 183 // Sync with Whisper DB on startup 103 184 try { 104 185 await whisperService.syncWithWhisper(); ··· 169 250 ); 170 251 } 171 252 const user = await createUser(email, password, name); 253 + 254 + // Attempt to sync existing Polar subscriptions 255 + syncUserSubscriptionsFromPolar(user.id, user.email).catch(() => { 256 + // Silent fail - don't block registration 257 + }); 258 + 172 259 const ipAddress = 173 260 req.headers.get("x-forwarded-for") ?? 174 261 req.headers.get("x-real-ip") ?? ··· 1504 1591 return Response.json({ error: "Invalid user ID" }, { status: 400 }); 1505 1592 } 1506 1593 1507 - try { 1508 - const { polar } = await import("./lib/polar"); 1509 - 1510 - // Get user email 1511 - const user = db 1512 - .query<{ email: string }, [number]>( 1513 - "SELECT email FROM users WHERE id = ?", 1514 - ) 1515 - .get(userId); 1516 - 1517 - if (!user) { 1518 - return Response.json( 1519 - { error: "User not found" }, 1520 - { status: 404 }, 1521 - ); 1522 - } 1523 - 1524 - console.log(`[Admin] Looking for Polar customer with email: ${user.email}`); 1594 + // Get user email 1595 + const user = db 1596 + .query<{ email: string }, [number]>( 1597 + "SELECT email FROM users WHERE id = ?", 1598 + ) 1599 + .get(userId); 1525 1600 1526 - // Search for customer by email 1527 - const customers = await polar.customers.list({ 1528 - organizationId: process.env.POLAR_ORGANIZATION_ID, 1529 - query: user.email, 1530 - }); 1531 - 1532 - console.log( 1533 - `[Admin] Found ${customers.result.items?.length || 0} customer(s) matching email`, 1601 + if (!user) { 1602 + return Response.json( 1603 + { error: "User not found" }, 1604 + { status: 404 }, 1534 1605 ); 1606 + } 1535 1607 1536 - if (!customers.result.items || customers.result.items.length === 0) { 1537 - return Response.json( 1538 - { error: "No Polar customer found with this email" }, 1539 - { status: 404 }, 1540 - ); 1541 - } 1542 - 1543 - const customer = customers.result.items[0]; 1544 - console.log(`[Admin] Customer ID: ${customer.id}`); 1545 - 1546 - // Get all subscriptions for this customer 1547 - const subscriptions = await polar.subscriptions.list({ 1548 - customerId: customer.id, 1549 - }); 1550 - 1551 - console.log( 1552 - `[Admin] Found ${subscriptions.result.items?.length || 0} subscription(s) for customer`, 1553 - ); 1554 - 1555 - if (!subscriptions.result.items || subscriptions.result.items.length === 0) { 1556 - return Response.json( 1557 - { error: "No subscriptions found for this customer" }, 1558 - { status: 404 }, 1559 - ); 1560 - } 1561 - 1562 - // Update each subscription in the database 1563 - for (const subscription of subscriptions.result.items) { 1564 - db.run( 1565 - `INSERT INTO subscriptions (id, user_id, customer_id, status, current_period_start, current_period_end, cancel_at_period_end, canceled_at, updated_at) 1566 - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) 1567 - ON CONFLICT(id) DO UPDATE SET 1568 - user_id = excluded.user_id, 1569 - status = excluded.status, 1570 - current_period_start = excluded.current_period_start, 1571 - current_period_end = excluded.current_period_end, 1572 - cancel_at_period_end = excluded.cancel_at_period_end, 1573 - canceled_at = excluded.canceled_at, 1574 - updated_at = excluded.updated_at`, 1575 - [ 1576 - subscription.id, 1577 - userId, 1578 - subscription.customerId, 1579 - subscription.status, 1580 - subscription.currentPeriodStart 1581 - ? Math.floor( 1582 - new Date(subscription.currentPeriodStart).getTime() / 1583 - 1000, 1584 - ) 1585 - : null, 1586 - subscription.currentPeriodEnd 1587 - ? Math.floor( 1588 - new Date(subscription.currentPeriodEnd).getTime() / 1589 - 1000, 1590 - ) 1591 - : null, 1592 - subscription.cancelAtPeriodEnd ? 1 : 0, 1593 - subscription.canceledAt 1594 - ? Math.floor( 1595 - new Date(subscription.canceledAt).getTime() / 1000, 1596 - ) 1597 - : null, 1598 - Math.floor(Date.now() / 1000), 1599 - ], 1600 - ); 1601 - } 1602 - 1603 - console.log( 1604 - `[Admin] Synced ${subscriptions.result.items.length} subscription(s) for user ${userId} (${user.email})`, 1605 - ); 1608 + try { 1609 + await syncUserSubscriptionsFromPolar(userId, user.email); 1606 1610 return Response.json({ 1607 1611 success: true, 1608 1612 message: "Subscription synced successfully",