Saltar al contenido principal

Supabase

Instalaciones

npm i @supabase/supabase-js

bun add @supabase/supabase-js

Variables de entorno

name = ""
compatibility_date = "2023-12-01"

[vars]
SUPABASE_URL=""
SUPABASE_KEY=""

Middleware

  1. Agregar el cliente de Supabase al contexto para extraerlo fácilmente en cualquier ruta
src\middleware\supabase.ts
import { createClient, SupabaseClient } from "@supabase/supabase-js";
import { Context, MiddlewareHandler } from "hono";

export const idCtxSupabase = "supabase-ctx";

/** Supabase Middleware
 *  Crea el cliente de Supabase y lo agrega al contexto
 *  Para usarlo en las rutas
 */
export const supabaseMiddleware: MiddlewareHandler = async (c, next) => {
  try {
 
    if (getSupabase(c)) return await next();
   
    // Validar variables de entorno
    if (!c.env.SUPABASE_URL || !c.env.SUPABASE_KEY) {
      throw new Error("Variables de entorno de Supabase no definidas");
    }

    // Crear cliente de Supabase y agregarlo al contexto
    const supabase = createClient(c.env.SUPABASE_URL, c.env.SUPABASE_KEY);
    c.set(idCtxSupabase, supabase);
   
    await next();
  } catch (error: any) {
    return c.json({ error: error.message }, 500);
  }
};

/**
 * Obtiene el cliente de Supabase del contexto listo para usar
 * @param c Contexto
 */
export const getSupabase = (c: Context): SupabaseClient => c.get(idCtxSupabase);
  1. Agregar al app.use()
src\users\index.ts
const userApp = new Hono();

// Agregar middleware al módulo de usuarios
userApp.use("*", supabaseMiddleware);

userApp.get("/", async (c) => {}

Uso

import { Hono } from "hono";
import { getSupabase, supabaseMiddleware } from "../middleware/supabase";
import { zUserValidator } from "./validator";

const userApp = new Hono();

// Agregar middleware al módulo de usuarios
userApp.use("*", supabaseMiddleware);

userApp.get("/", async (c) => {
  const supabase = getSupabase(c); // Extraer el cliente del Ctx
  const { data, error } = await supabase.from("users").select("*");
  return c.json({ data, error });
});

//userApp.post("/", zValidator("form", userSchema), async (c) => { });
userApp.post("/", zUserValidator, async (c) => {
  // Extraer el cuerpo de la petición (ya validado)
  // form-data, x-www-form-urlencoded
  const body = await c.req.parseBody();
  const supabase = getSupabase(c);
  const { data, error } = await supabase.from("users").insert(body).select();
  return c.json({ data, error });
});

export default userApp; // import userApp from "./users";
// export { userApp }; // import { userApp } from "./users";

Archivos

src\storage\index.ts
import { Hono } from "hono";
import { getMimeType } from "hono/utils/mime";
import { getSupabase, supabaseMiddleware } from "../middleware/supabase";

export type Env = {
  SUPABASE_URL: string;
  SUPABASE_KEY: string;
};

const storage = new Hono<{ Bindings: Env }>();

storage.post("/upload", supabaseMiddleware, async (c) => {
  const supabase = getSupabase(c);
  const body = await c.req.parseBody();
  const file = body["file"] as File;

  const { data, error } = await supabase.storage
    .from("FirstBucket")
    .upload(`public/users/${file.name}`, file);

  return c.json({ data, error });
});

storage.get("/download/:filename", supabaseMiddleware, async (c) => {
  const supabase = getSupabase(c);
  const { filename } = c.req.param();

  const { data, error } = await supabase.storage
    .from("FirstBucket")
    .download(`public/users/${filename}`);

  if (error) return c.json({ error: error.message }, 500);
  if (!data) return c.json({ error: "File not found" }, 404);

  // Convertir el archivo a un Uint8Array
  const uint8Array = new Uint8Array(await data!.arrayBuffer());

  // Determinar el tipo MIME basado en la extensión del archivo
  const mimeType = getMimeType(filename) || "";

  // Devolver la imagen con el tipo MIME correcto
  return c.body(uint8Array, 200, {
    "Content-Type": mimeType,
    "Content-Disposition": `inline; filename="${filename}"`,
  });
});

export default storage;