Implementa o MVP do Adaptador de Planilhas no Elo Pro.

O módulo usa a identidade Supabase, isola cada workspace e registra storage, TTL, runner e biblioteca XLSX como decisões ainda abertas.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
camilafagundesandCursor committed 2026-10-02 23:02:00 -03:00
commit 6e23f1533b
144 files changed
+19060

No files matched your search

+32
View File
@@ -0,0 +1,32 @@
import { createHmac, timingSafeEqual } from "node:crypto";
export type DevSession = { userId: string; workspaceId: string; exp: number };
export function devAuthEnabled(): boolean {
return process.env.NODE_ENV !== "production" && process.env.ADAPTER_DEV_AUTH === "1" && Boolean(process.env.ADAPTER_DEV_AUTH_SECRET);
}
function secret(): string {
const value = process.env.ADAPTER_DEV_AUTH_SECRET;
if (!value) throw new Error("ADAPTER_DEV_AUTH_SECRET ausente.");
return value;
}
export function signDevSession(userId: string, workspaceId: string, ttlSeconds = 60 * 60 * 8): string {
const body = Buffer.from(JSON.stringify({ userId, workspaceId, exp: Date.now() + ttlSeconds * 1000 })).toString("base64url");
const sig = createHmac("sha256", secret()).update(body).digest("base64url");
return `${body}.${sig}`;
}
export function verifyDevSession(token: string): DevSession | null {
if (!devAuthEnabled()) return null;
const [body, sig] = token.split(".");
if (!body || !sig) return null;
const expected = createHmac("sha256", secret()).update(body).digest("base64url");
const left = Buffer.from(sig);
const right = Buffer.from(expected);
if (left.length !== right.length || !timingSafeEqual(left, right)) return null;
const parsed = JSON.parse(Buffer.from(body, "base64url").toString("utf8")) as DevSession;
if (!parsed.exp || parsed.exp < Date.now()) return null;
return parsed;
}