diff options
| author | Dhravya Shah <[email protected]> | 2025-01-31 15:42:02 -0700 |
|---|---|---|
| committer | Dhravya Shah <[email protected]> | 2025-01-31 15:42:16 -0700 |
| commit | feb3c34a967f9b6641d3017e2437ab4bc700da75 (patch) | |
| tree | 59d59cdfdc361348dfbda3cd42ebd1a878ab1690 /apps/backend | |
| parent | add api reference (diff) | |
| download | supermemory-feb3c34a967f9b6641d3017e2437ab4bc700da75.tar.xz supermemory-feb3c34a967f9b6641d3017e2437ab4bc700da75.zip | |
docs: v1
Diffstat (limited to 'apps/backend')
| -rw-r--r-- | apps/backend/src/routes/actions.ts | 64 |
1 files changed, 62 insertions, 2 deletions
diff --git a/apps/backend/src/routes/actions.ts b/apps/backend/src/routes/actions.ts index 142d2a01..bcddec43 100644 --- a/apps/backend/src/routes/actions.ts +++ b/apps/backend/src/routes/actions.ts @@ -21,6 +21,7 @@ import { spaces as spaceInDb, spaceAccess, type Space, + contentToSpace, } from "@supermemory/db/schema"; import { google, openai } from "../providers"; import { randomId } from "@supermemory/shared"; @@ -30,6 +31,8 @@ import { database, desc, eq, + exists, + inArray, or, sql, } from "@supermemory/db"; @@ -457,16 +460,55 @@ const actions = new Hono<{ Variables: Variables; Bindings: Env }>() query: z.string().min(1, "Search query cannot be empty"), limit: z.number().min(1).max(50).default(10), threshold: z.number().min(0).max(1).default(0), + spaces: z.array(z.string()).optional(), }) ), async (c) => { - const { query, limit, threshold } = c.req.valid("json"); + const { query, limit, threshold, spaces } = c.req.valid("json"); const user = c.get("user"); if (!user) { return c.json({ error: "Unauthorized" }, 401); } + const db = database(c.env.HYPERDRIVE.connectionString); + + if (spaces && spaces.length > 0) { + const spaceDetails = await Promise.all( + spaces.map(async (spaceId) => { + const space = await db + .select() + .from(spaceInDb) + .where(eq(spaceInDb.uuid, spaceId)) + .limit(1); + + if (space.length === 0) return null; + return { + id: space[0].id, + ownerId: space[0].ownerId, + uuid: space[0].uuid + }; + }) + ); + + // Filter out any null values and check permissions + const validSpaces = spaceDetails.filter((s): s is NonNullable<typeof s> => s !== null); + const unauthorized = validSpaces.filter(s => s.ownerId !== user.id); + + if (unauthorized.length > 0) { + return c.json( + { + error: "Space permission denied", + details: unauthorized.map(s => s.uuid).join(", "), + }, + 403 + ); + } + + // Replace UUIDs with IDs for the database query + spaces.splice(0, spaces.length, ...validSpaces.map(s => s.id.toString())); + } + try { // Generate embedding for the search query const embeddings = await c.env.AI.run("@cf/baai/bge-base-en-v1.5", { @@ -497,7 +539,25 @@ const actions = new Hono<{ Variables: Variables; Bindings: Env }>() .where( and( eq(documents.userId, user.id), - sql`1 - (embeddings <=> ${JSON.stringify(embeddings.data[0])}::vector) >= ${threshold}` + sql`1 - (embeddings <=> ${JSON.stringify(embeddings.data[0])}::vector) >= ${threshold}`, + ...(spaces && spaces.length > 0 + ? [ + exists( + db + .select() + .from(contentToSpace) + .where( + and( + eq(contentToSpace.contentId, documents.id), + inArray( + contentToSpace.spaceId, + spaces.map((spaceId) => Number(spaceId)) + ) + ) + ) + ), + ] + : []) ) ) .orderBy( |