aboutsummaryrefslogtreecommitdiffstats
path: root/apps/web/app
diff options
context:
space:
mode:
authorMohamedBassem <me@mbassem.com>2024-10-05 14:42:22 +0000
committerMohamedBassem <me@mbassem.com>2024-10-05 14:42:22 +0000
commitc8a3c1ee02e917b2e553d403b7bf94cbc736f51d (patch)
treeef1135578055968e761fd14a7dabb505544e95f1 /apps/web/app
parent463d041f0b321348593087047a14a0d9a433d60f (diff)
downloadkarakeep-c8a3c1ee02e917b2e553d403b7bf94cbc736f51d.tar.zst
feature(web): Allow users to export their links and notes
Diffstat (limited to 'apps/web/app')
-rw-r--r--apps/web/app/api/bookmarks/export/route.tsx66
1 files changed, 66 insertions, 0 deletions
diff --git a/apps/web/app/api/bookmarks/export/route.tsx b/apps/web/app/api/bookmarks/export/route.tsx
new file mode 100644
index 00000000..3b12b878
--- /dev/null
+++ b/apps/web/app/api/bookmarks/export/route.tsx
@@ -0,0 +1,66 @@
+import { api, createContextFromRequest } from "@/server/api/client";
+
+import type { ZBookmark } from "@hoarder/shared/types/bookmarks";
+import {
+ BookmarkTypes,
+ MAX_NUM_BOOKMARKS_PER_PAGE,
+} from "@hoarder/shared/types/bookmarks";
+
+function toExportFormat(bookmark: ZBookmark) {
+ return {
+ createdAt: bookmark.createdAt.toISOString(),
+ title:
+ bookmark.title ??
+ (bookmark.content.type === BookmarkTypes.LINK
+ ? bookmark.content.title
+ : null),
+ tags: bookmark.tags.map((t) => t.name),
+ type: bookmark.content.type,
+ url:
+ bookmark.content.type === BookmarkTypes.LINK
+ ? bookmark.content.url
+ : undefined,
+ text:
+ bookmark.content.type === BookmarkTypes.TEXT
+ ? bookmark.content.text
+ : undefined,
+ note: bookmark.note,
+ };
+}
+
+export const dynamic = "force-dynamic";
+export async function GET(request: Request) {
+ const ctx = await createContextFromRequest(request);
+ if (!ctx.user) {
+ return Response.json({ error: "Unauthorized" }, { status: 401 });
+ }
+ const req = {
+ limit: MAX_NUM_BOOKMARKS_PER_PAGE,
+ useCursorV2: true,
+ };
+
+ let resp = await api.bookmarks.getBookmarks(req);
+ let results = resp.bookmarks.map(toExportFormat);
+
+ while (resp.nextCursor) {
+ resp = await api.bookmarks.getBookmarks({
+ ...request,
+ cursor: resp.nextCursor,
+ });
+ results = [...results, ...resp.bookmarks.map(toExportFormat)];
+ }
+
+ return new Response(
+ JSON.stringify({
+ // Exclude asset types for now
+ bookmarks: results.filter((b) => b.type !== BookmarkTypes.ASSET),
+ }),
+ {
+ status: 200,
+ headers: {
+ "Content-type": "application/json",
+ "Content-disposition": `attachment; filename="hoarder-export-${new Date().toISOString()}.json"`,
+ },
+ },
+ );
+}