← back to Trademarks Copyright

src/app/api/drops/pixel/[id]/route.ts

40 lines

import { NextRequest } from "next/server";
import { query } from "@/lib/db";

/**
 * 1×1 transparent GIF tracking pixel.
 * GET /api/drops/pixel/<deliveryId> — marks the delivery as opened.
 * Embedded in drop HTML as <img src=".../pixel/123"> at the bottom.
 */

// 43-byte transparent GIF (1×1).
const PIXEL = Uint8Array.from([
  0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01, 0x00, 0x80, 0x00,
  0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x21, 0xf9, 0x04, 0x01, 0x00,
  0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
  0x00, 0x02, 0x02, 0x44, 0x01, 0x00, 0x3b,
]);

export async function GET(
  _req: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params;
  const deliveryId = Number(id);
  if (Number.isFinite(deliveryId)) {
    // Stamp opened_at (only the first time — keep origin IP out of logs for privacy).
    await query(
      `UPDATE deliveries SET opened_at = NOW() WHERE id = $1 AND opened_at IS NULL`,
      [deliveryId]
    ).catch(() => {});
  }
  return new Response(PIXEL, {
    headers: {
      "content-type": "image/gif",
      "content-length": String(PIXEL.length),
      "cache-control": "no-store, no-cache, must-revalidate",
      pragma: "no-cache",
    },
  });
}