aboutsummaryrefslogtreecommitdiff
path: root/apps/backend/src
diff options
context:
space:
mode:
authorDhravya Shah <[email protected]>2025-02-14 15:53:44 -0800
committerDhravya Shah <[email protected]>2025-02-14 15:53:44 -0800
commitaf1093d4aab6d5654364e7cd9df76fd766bbee03 (patch)
treef128bdb8cac4b44ed41289dc9a158c33fe86c5ec /apps/backend/src
parenttwitter import fix (diff)
downloadsupermemory-af1093d4aab6d5654364e7cd9df76fd766bbee03.tar.xz
supermemory-af1093d4aab6d5654364e7cd9df76fd766bbee03.zip
intuitive memory movement, avoid duplicates in home
Diffstat (limited to 'apps/backend/src')
-rw-r--r--apps/backend/src/index.tsx4
-rw-r--r--apps/backend/src/routes/memories.ts32
-rw-r--r--apps/backend/src/routes/spaces.ts116
3 files changed, 146 insertions, 6 deletions
diff --git a/apps/backend/src/index.tsx b/apps/backend/src/index.tsx
index 1d62b543..48790e90 100644
--- a/apps/backend/src/index.tsx
+++ b/apps/backend/src/index.tsx
@@ -47,6 +47,10 @@ export const app = new Hono<{ Variables: Variables; Bindings: Env }>()
.use("/v1/*", auth)
.use("/v1/*", (c, next) => {
const user = c.get("user");
+
+ if (c.env.NODE_ENV === "development") {
+ return next();
+ }
// RATELIMITS
const rateLimitConfig = {
diff --git a/apps/backend/src/routes/memories.ts b/apps/backend/src/routes/memories.ts
index efcc6fb7..aa35877b 100644
--- a/apps/backend/src/routes/memories.ts
+++ b/apps/backend/src/routes/memories.ts
@@ -8,7 +8,7 @@ import {
spaceAccess,
contentToSpace,
} from "@supermemory/db/schema";
-import { and, database, desc, eq, or, sql } from "@supermemory/db";
+import { and, database, desc, eq, or, sql, isNull } from "@supermemory/db";
const memories = new Hono<{ Variables: Variables; Bindings: Env }>()
.get(
@@ -124,9 +124,20 @@ const memories = new Hono<{ Variables: Variables; Bindings: Env }>()
const [items, [{ total }]] = await Promise.all([
db
- .select()
+ .select({
+ documents: documents,
+ })
.from(documents)
- .where(eq(documents.userId, user.id))
+ .leftJoin(
+ contentToSpace,
+ eq(documents.id, contentToSpace.contentId)
+ )
+ .where(
+ and(
+ eq(documents.userId, user.id),
+ isNull(contentToSpace.contentId)
+ )
+ )
.orderBy(desc(documents.createdAt))
.limit(count)
.offset(start),
@@ -135,13 +146,22 @@ const memories = new Hono<{ Variables: Variables; Bindings: Env }>()
total: sql<number>`count(*)`.as("total"),
})
.from(documents)
- .where(eq(documents.userId, user.id)),
+ .leftJoin(
+ contentToSpace,
+ eq(documents.id, contentToSpace.contentId)
+ )
+ .where(
+ and(
+ eq(documents.userId, user.id),
+ isNull(contentToSpace.contentId)
+ )
+ ),
]);
return c.json({
items: items.map((item) => ({
- ...item,
- id: item.uuid,
+ ...item.documents,
+ id: item.documents.uuid,
})),
total,
});
diff --git a/apps/backend/src/routes/spaces.ts b/apps/backend/src/routes/spaces.ts
index 2ca2e461..bede366c 100644
--- a/apps/backend/src/routes/spaces.ts
+++ b/apps/backend/src/routes/spaces.ts
@@ -99,6 +99,7 @@ const spacesRoute = new Hono<{ Variables: Variables; Bindings: Env }>()
const spaceId = c.req.param("spaceId");
const db = database(c.env.HYPERDRIVE.connectionString);
+
const space = await db
.select()
.from(spaces)
@@ -178,6 +179,10 @@ const spacesRoute = new Hono<{ Variables: Variables; Bindings: Env }>()
return c.json({ error: "Unauthorized" }, 401);
}
+ if (body.spaceName.trim() === "<HOME>") {
+ return c.json({ error: "Cannot create space with name <HOME>" }, 400);
+ }
+
const db = database(c.env.HYPERDRIVE.connectionString);
const uuid = randomId();
@@ -264,6 +269,99 @@ const spacesRoute = new Hono<{ Variables: Variables; Bindings: Env }>()
}
)
.post(
+ "/moveContent",
+ zValidator(
+ "json",
+ z.object({
+ spaceId: z.string(),
+ documentId: z.string(),
+ })
+ ),
+ async (c) => {
+ const body = c.req.valid("json");
+ const user = c.get("user");
+ const { spaceId, documentId } = body;
+
+ if (!user) {
+ return c.json({ error: "Unauthorized" }, 401);
+ }
+
+ const db = database(c.env.HYPERDRIVE.connectionString);
+
+ try {
+ await db.transaction(async (tx) => {
+ // If moving to <HOME>, just remove all space connections
+ if (spaceId === "<HOME>") {
+ const doc = await tx
+ .select()
+ .from(documents)
+ .where(eq(documents.uuid, documentId))
+ .limit(1);
+
+ if (!doc[0]) {
+ return c.json({ error: "Document not found" }, 404);
+ }
+
+ await tx
+ .delete(contentToSpace)
+ .where(eq(contentToSpace.contentId, doc[0].id));
+ return;
+ }
+
+ // Get space and document, verify space ownership
+ const results = (
+ await tx
+ .select({
+ spaceId: spaces.id,
+ documentId: documents.id,
+ ownerId: spaces.ownerId,
+ spaceName: spaces.name,
+ })
+ .from(spaces)
+ .innerJoin(
+ documents,
+ and(eq(spaces.uuid, spaceId), eq(documents.uuid, documentId))
+ )
+ .limit(1)
+ )[0];
+
+ if (!results) {
+ return c.json({ error: "Space or document not found" }, 404);
+ }
+
+ if (results.ownerId !== user.id) {
+ return c.json(
+ { error: "Not authorized to modify this space" },
+ 403
+ );
+ }
+
+ // Delete existing space relations for this document
+ await tx
+ .delete(contentToSpace)
+ .where(eq(contentToSpace.contentId, results.documentId));
+
+ // Add new space relation
+ await tx.insert(contentToSpace).values({
+ contentId: results.documentId,
+ spaceId: results.spaceId,
+ });
+ });
+
+ return c.json({ success: true, spaceId });
+ } catch (e) {
+ console.error("Failed to move content to space:", e);
+ return c.json(
+ {
+ error: "Failed to move content to space",
+ details: e instanceof Error ? e.message : "Unknown error",
+ },
+ 500
+ );
+ }
+ }
+ )
+ .post(
"/addContent",
zValidator(
"json",
@@ -285,6 +383,24 @@ const spacesRoute = new Hono<{ Variables: Variables; Bindings: Env }>()
try {
await db.transaction(async (tx) => {
+ // If adding to <HOME>, just remove all space connections
+ if (spaceId === "<HOME>") {
+ const doc = await tx
+ .select()
+ .from(documents)
+ .where(eq(documents.uuid, documentId))
+ .limit(1);
+
+ if (!doc[0]) {
+ return c.json({ error: "Document not found" }, 404);
+ }
+
+ await tx
+ .delete(contentToSpace)
+ .where(eq(contentToSpace.contentId, doc[0].id));
+ return;
+ }
+
// Get space and document, verify space ownership
const results = (
await tx