import { Router } from 'express'; import { env } from '../config/env.js'; import { createLogger } from '../lib/logger.js'; const log = createLogger('tesla'); const router = Router(); // ─── Domain verification ──────────────────────────────────────────────────── // Tesla fetches this path to confirm you own the domain registered with the // Fleet API partner account. The body must be the EXACT PEM the partner key // is registered with (the EC public key from your prime256v1 keypair). // // Set TESLA_FLEET_PUBLIC_KEY in Dokku config to the full PEM contents — // including the BEGIN/END lines. Multi-line env vars work fine with Dokku // when set via `dokku config:set roadtrip TESLA_FLEET_PUBLIC_KEY="$(cat key.pem)"`. router.get('/.well-known/appspecific/com.tesla.3p.public-key.pem', (_req, res) => { if (!env.tesla.publicKey) { log.warn('Tesla public key requested but TESLA_FLEET_PUBLIC_KEY is empty'); res.status(404).type('text/plain').send('Public key not configured'); return; } res.type('application/x-pem-file'); res.set('Cache-Control', 'public, max-age=300'); res.send(env.tesla.publicKey); }); // ─── OAuth callback (stub) ────────────────────────────────────────────────── // Tesla redirects here with ?code=… after the user grants access. We exchange // the code for a refresh token and store it against the logged-in user. // Full implementation lands once partner approval is granted. router.get('/api/auth/tesla/callback', async (req, res) => { const { code, state, error } = req.query as Record; if (error) { log.warn({ error, state }, 'Tesla OAuth error returned to callback'); res.redirect(`/?tesla_error=${encodeURIComponent(error)}`); return; } if (!code) { res.status(400).type('text/plain').send('Missing ?code from Tesla'); return; } if (!env.tesla.clientId || !env.tesla.clientSecret) { log.warn('Tesla OAuth callback hit but client credentials not configured'); res.status(503).type('text/plain').send('Tesla integration not yet configured'); return; } // TODO once Tesla approves partner registration: // 1. POST to https://auth.tesla.com/oauth2/v3/token with grant_type=authorization_code // 2. Decode the id_token, persist refresh_token against req.auth.userId // 3. Optional: enrol the vehicle via /api/1/partner_accounts/public_key // 4. Redirect to / with a success flag log.info({ codeLen: code.length, state }, 'Tesla OAuth callback received (stub)'); res.redirect('/?tesla_connected=pending'); }); // ─── Vehicle state (stub) ─────────────────────────────────────────────────── // Returns the current battery %, range and location for the connected vehicle. // Until partner approval, returns 503 so the client can hide the integration UI. router.get('/api/tesla/state', async (_req, res) => { if (!env.tesla.clientId) { res.status(503).json({ connected: false, reason: 'pending_partner_approval' }); return; } // TODO: look up the user's stored refresh token, exchange for access token, // call https://fleet-api.prd.eu.vn.cloud.tesla.com/api/1/vehicles/{id}/vehicle_data, // and shape the response into { battery, range, lat, lng, state, etc. }. res.status(501).json({ connected: false, reason: 'not_implemented' }); }); export default router;