diff options
| author | Dhravya <[email protected]> | 2024-06-23 20:45:05 -0500 |
|---|---|---|
| committer | Dhravya <[email protected]> | 2024-06-23 20:45:05 -0500 |
| commit | 75585fd97d7abaf68e0c314f41d0cef414a57b1e (patch) | |
| tree | 6f98b26f81d3481c857108f1ec60794d30a6421a /apps/web/app/api | |
| parent | made and documented the telegram bot (HYPE) (diff) | |
| download | supermemory-75585fd97d7abaf68e0c314f41d0cef414a57b1e.tar.xz supermemory-75585fd97d7abaf68e0c314f41d0cef414a57b1e.zip | |
some important housekeeping, crushed all build errors
Diffstat (limited to 'apps/web/app/api')
| -rw-r--r-- | apps/web/app/api/store/route.ts | 114 | ||||
| -rw-r--r-- | apps/web/app/api/telegram/route.ts | 18 | ||||
| -rw-r--r-- | apps/web/app/api/unfirlsite/route.ts | 162 |
3 files changed, 100 insertions, 194 deletions
diff --git a/apps/web/app/api/store/route.ts b/apps/web/app/api/store/route.ts deleted file mode 100644 index cb10db24..00000000 --- a/apps/web/app/api/store/route.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { db } from "@/server/db"; -import { and, eq, sql, inArray } from "drizzle-orm"; -import { - contentToSpace, - sessions, - storedContent, - users, - space, -} from "@/server/db/schema"; -import { type NextRequest, NextResponse } from "next/server"; -import { getMetaData } from "@/lib/get-metadata"; -import { ensureAuth } from "../ensureAuth"; -import { limit } from "@/app/actions/doers"; -import { LIMITS } from "@/lib/constants"; - -export const runtime = "edge"; - -export async function POST(req: NextRequest) { - const session = await ensureAuth(req); - - if (!session) { - return new Response("Unauthorized", { status: 401 }); - } - - const data = (await req.json()) as { - pageContent: string; - url: string; - spaces?: string[]; - }; - - const metadata = await getMetaData(data.url); - let storeToSpaces = data.spaces; - - if (!storeToSpaces) { - storeToSpaces = []; - } - - if (!(await limit(session.user.id))) { - return NextResponse.json( - { - message: "Error: Ratelimit exceeded", - error: `You have exceeded the limit of ${LIMITS["page"]} pages.`, - }, - { status: 429 }, - ); - } - - const rep = await db - .insert(storedContent) - .values({ - content: data.pageContent, - title: metadata.title, - description: metadata.description, - url: data.url, - baseUrl: metadata.baseUrl, - image: metadata.image, - savedAt: new Date(), - userId: session.user.id, - }) - .returning({ id: storedContent.id }); - - const id = rep[0]?.id; - - if (!id) { - return NextResponse.json( - { message: "Error", error: "Error in CF function" }, - { status: 500 }, - ); - } - - if (storeToSpaces.length > 0) { - const spaceData = await db - .select() - .from(space) - .where( - and( - inArray(space.name, storeToSpaces ?? []), - eq(space.user, session.user.id), - ), - ) - .all(); - - await Promise.all([ - spaceData.forEach(async (space) => { - await db - .insert(contentToSpace) - .values({ contentId: id, spaceId: space.id }); - }), - ]); - } - - const res = (await Promise.race([ - fetch("https://cf-ai-backend.dhravya.workers.dev/add", { - method: "POST", - headers: { - "X-Custom-Auth-Key": process.env.BACKEND_SECURITY_KEY, - }, - body: JSON.stringify({ ...data, user: session.user.email }), - }), - new Promise((_, reject) => - setTimeout(() => reject(new Error("Request timed out")), 40000), - ), - ])) as Response; - - if (res.status !== 200) { - console.log(res.status, res.statusText); - return NextResponse.json( - { message: "Error", error: "Error in CF function" }, - { status: 500 }, - ); - } - - return NextResponse.json({ message: "OK", data: "Success" }, { status: 200 }); -} diff --git a/apps/web/app/api/telegram/route.ts b/apps/web/app/api/telegram/route.ts index 065a102a..b0d05655 100644 --- a/apps/web/app/api/telegram/route.ts +++ b/apps/web/app/api/telegram/route.ts @@ -1,6 +1,6 @@ import { db } from "@/server/db"; import { storedContent, users } from "@/server/db/schema"; -import { cipher, decipher } from "@/server/encrypt"; +import { cipher } from "@/server/encrypt"; import { eq } from "drizzle-orm"; import { Bot, webhookCallback } from "grammy"; import { User } from "grammy/types"; @@ -16,16 +16,9 @@ const token = process.env.TELEGRAM_BOT_TOKEN; const bot = new Bot(token); -const getUserByTelegramId = async (telegramId: string) => { - return await db.query.users - .findFirst({ - where: eq(users.telegramId, telegramId), - }) - .execute(); -}; - bot.command("start", async (ctx) => { const user: User = (await ctx.getAuthor()).user; + const cipherd = cipher(user.id.toString()); await ctx.reply( `Welcome to Supermemory bot. I am here to help you remember things better. Click here to create and link your accont: http://localhost:3000/signin?telegramUser=${cipherd}`, @@ -34,9 +27,14 @@ bot.command("start", async (ctx) => { bot.on("message", async (ctx) => { const user: User = (await ctx.getAuthor()).user; + const cipherd = cipher(user.id.toString()); - const dbUser = await getUserByTelegramId(user.id.toString()); + const dbUser = await db.query.users + .findFirst({ + where: eq(users.telegramId, user.id.toString()), + }) + .execute(); if (!dbUser) { await ctx.reply( diff --git a/apps/web/app/api/unfirlsite/route.ts b/apps/web/app/api/unfirlsite/route.ts index 4b8b4858..87f5348e 100644 --- a/apps/web/app/api/unfirlsite/route.ts +++ b/apps/web/app/api/unfirlsite/route.ts @@ -1,4 +1,4 @@ -import { load } from 'cheerio' +import { load } from "cheerio"; import { AwsClient } from "aws4fetch"; import type { NextRequest } from "next/server"; @@ -6,14 +6,60 @@ import { ensureAuth } from "../ensureAuth"; export const runtime = "edge"; -const r2 = new AwsClient({ - accessKeyId: process.env.R2_ACCESS_KEY_ID, - secretAccessKey: process.env.R2_SECRET_ACCESS_KEY, -}); +export async function POST(request: NextRequest) { + const r2 = new AwsClient({ + accessKeyId: process.env.R2_ACCESS_KEY_ID, + secretAccessKey: process.env.R2_SECRET_ACCESS_KEY, + }); + + async function unfurl(url: string) { + const response = await fetch(url); + if (response.status >= 400) { + throw new Error(`Error fetching url: ${response.status}`); + } + const contentType = response.headers.get("content-type"); + if (!contentType?.includes("text/html")) { + throw new Error(`Content-type not right: ${contentType}`); + } + const content = await response.text(); + const $ = load(content); + + const og: { [key: string]: string | undefined } = {}; + const twitter: { [key: string]: string | undefined } = {}; + + // @ts-ignore, it just works so why care of type safety if someone has better way go ahead + $("meta[property^=og:]").each( + (_, el) => (og[$(el).attr("property")!] = $(el).attr("content")), + ); + // @ts-ignore + $("meta[name^=twitter:]").each( + (_, el) => (twitter[$(el).attr("name")!] = $(el).attr("content")), + ); + + const title = + og["og:title"] ?? + twitter["twitter:title"] ?? + $("title").text() ?? + undefined; + const description = + og["og:description"] ?? + twitter["twitter:description"] ?? + $('meta[name="description"]').attr("content") ?? + undefined; + const image = + og["og:image:secure_url"] ?? + og["og:image"] ?? + twitter["twitter:image"] ?? + undefined; + + return { + title, + description, + image, + }; + } -export async function POST(request: NextRequest) { - const d = await ensureAuth(request); if (!d) { return new Response("Unauthorized", { status: 401 }); @@ -32,7 +78,7 @@ export async function POST(request: NextRequest) { } const website = new URL(request.url).searchParams.get("website"); - + if (!website) { return new Response("Missing website", { status: 400 }); } @@ -41,27 +87,33 @@ export async function POST(request: NextRequest) { const encodeWebsite = `${encodeURIComponent(website)}${salt()}`; try { - // this returns the og image, description and title of website + // this returns the og image, description and title of website const response = await unfurl(website); - if (!response.image){ - return new Response(JSON.stringify(response)) + if (!response.image) { + return new Response(JSON.stringify(response)); } - const imageUrl = await process.env.DEV_IMAGES.get(encodeWebsite) - if (imageUrl){ - return new Response(JSON.stringify({ - image: imageUrl, - title: response.title, - description: response.description, - })) + if (!process.env.DEV_IMAGES) { + return new Response("Missing DEV_IMAGES namespace.", { status: 500 }); } - const res = await fetch(`${response.image}`) + const imageUrl = await process.env.DEV_IMAGES!.get(encodeWebsite); + if (imageUrl) { + return new Response( + JSON.stringify({ + image: imageUrl, + title: response.title, + description: response.description, + }), + ); + } + + const res = await fetch(`${response.image}`); const image = await res.blob(); const url = new URL( - `https://${process.env.R2_BUCKET_NAME}.${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com` + `https://${process.env.R2_BUCKET_NAME}.${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`, ); url.pathname = encodeWebsite; @@ -73,62 +125,32 @@ export async function POST(request: NextRequest) { }), { aws: { signQuery: true }, - } + }, ); await fetch(signedPuturl.url, { - method: 'PUT', + method: "PUT", body: image, }); - await process.env.DEV_IMAGES.put(encodeWebsite, `${process.env.R2_PUBLIC_BUCKET_ADDRESS}/${encodeWebsite}`) - - return new Response(JSON.stringify({ - image: `${process.env.R2_PUBLIC_BUCKET_ADDRESS}/${encodeWebsite}`, - title: response.title, - description: response.description, - })); + await process.env.DEV_IMAGES.put( + encodeWebsite, + `${process.env.R2_PUBLIC_BUCKET_ADDRESS}/${encodeWebsite}`, + ); + return new Response( + JSON.stringify({ + image: `${process.env.R2_PUBLIC_BUCKET_ADDRESS}/${encodeWebsite}`, + title: response.title, + description: response.description, + }), + ); } catch (error) { - console.log(error) - return new Response(JSON.stringify({ - status: 500, - error: error, - })) - } + console.log(error); + return new Response( + JSON.stringify({ + status: 500, + error: error, + }), + ); } - -export async function unfurl(url: string) { - const response = await fetch(url) - if (response.status >= 400) { - throw new Error(`Error fetching url: ${response.status}`) - } - const contentType = response.headers.get('content-type') - if (!contentType?.includes('text/html')) { - throw new Error(`Content-type not right: ${contentType}`) - } - - const content = await response.text() - const $ = load(content) - - const og: { [key: string]: string | undefined } = {} - const twitter: { [key: string]: string | undefined } = {} - - // @ts-ignore, it just works so why care of type safety if someone has better way go ahead - $('meta[property^=og:]').each((_, el) => (og[$(el).attr('property')!] = $(el).attr('content'))) - // @ts-ignore - $('meta[name^=twitter:]').each((_, el) => (twitter[$(el).attr('name')!] = $(el).attr('content'))) - - const title = og['og:title'] ?? twitter['twitter:title'] ?? $('title').text() ?? undefined - const description = - og['og:description'] ?? - twitter['twitter:description'] ?? - $('meta[name="description"]').attr('content') ?? - undefined - const image = og['og:image:secure_url'] ?? og['og:image'] ?? twitter['twitter:image'] ?? undefined - - return { - title, - description, - image, - } } |