aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2025-03-09 15:03:39 +0000
committerMohamed Bassem <me@mbassem.com>2025-03-09 21:38:51 +0000
commitdbe6c1de20bc38e54c848983d75c861be288dfe1 (patch)
tree1e8b1ab6236dc13c4cc8c0ad90fe659ad98b0aae
parentd2c37c2e6ab2ec6b44b80caf34691aa2e18d12e7 (diff)
downloadkarakeep-dbe6c1de20bc38e54c848983d75c861be288dfe1.tar.zst
fix: Harden getBookmarks endpoint against inconsistent bookmarks. Fixes #1094
-rw-r--r--packages/shared/types/bookmarks.ts4
-rw-r--r--packages/trpc/routers/bookmarks.ts122
2 files changed, 60 insertions, 66 deletions
diff --git a/packages/shared/types/bookmarks.ts b/packages/shared/types/bookmarks.ts
index 9644095c..9e6e6f3f 100644
--- a/packages/shared/types/bookmarks.ts
+++ b/packages/shared/types/bookmarks.ts
@@ -3,7 +3,7 @@ import { z } from "zod";
import { zCursorV2 } from "./pagination";
import { zBookmarkTagSchema } from "./tags";
-const MAX_TITLE_LENGTH = 250;
+const MAX_TITLE_LENGTH = 1000;
export const enum BookmarkTypes {
LINK = "link",
@@ -78,7 +78,7 @@ export const zBareBookmarkSchema = z.object({
id: z.string(),
createdAt: z.date(),
modifiedAt: z.date().nullable(),
- title: z.string().max(MAX_TITLE_LENGTH).nullish(),
+ title: z.string().nullish(),
archived: z.boolean(),
favourited: z.boolean(),
taggingStatus: z.enum(["success", "failure", "pending"]).nullable(),
diff --git a/packages/trpc/routers/bookmarks.ts b/packages/trpc/routers/bookmarks.ts
index 7025c3da..1849f43c 100644
--- a/packages/trpc/routers/bookmarks.ts
+++ b/packages/trpc/routers/bookmarks.ts
@@ -191,44 +191,42 @@ function toZodSchema(bookmark: BookmarkQueryReturnType): ZBookmark {
let content: ZBookmarkContent = {
type: BookmarkTypes.UNKNOWN,
};
- switch (bookmark.type) {
- case BookmarkTypes.LINK:
- content = {
- type: bookmark.type,
- screenshotAssetId: assets.find(
- (a) => a.assetType == AssetTypes.LINK_SCREENSHOT,
- )?.id,
- fullPageArchiveAssetId: assets.find(
- (a) => a.assetType == AssetTypes.LINK_FULL_PAGE_ARCHIVE,
- )?.id,
- precrawledArchiveAssetId: assets.find(
- (a) => a.assetType == AssetTypes.LINK_PRECRAWLED_ARCHIVE,
- )?.id,
- imageAssetId: assets.find(
- (a) => a.assetType == AssetTypes.LINK_BANNER_IMAGE,
- )?.id,
- videoAssetId: assets.find((a) => a.assetType == AssetTypes.LINK_VIDEO)
- ?.id,
- ...link,
- };
- break;
- case BookmarkTypes.TEXT:
- content = {
- type: bookmark.type,
- text: text.text ?? "",
- sourceUrl: text.sourceUrl,
- };
- break;
- case BookmarkTypes.ASSET:
- content = {
- type: bookmark.type,
- assetType: asset.assetType,
- assetId: asset.assetId,
- fileName: asset.fileName,
- sourceUrl: asset.sourceUrl,
- size: assets.find((a) => a.id == asset.assetId)?.size,
- };
- break;
+ if (bookmark.link) {
+ content = {
+ type: BookmarkTypes.LINK,
+ screenshotAssetId: assets.find(
+ (a) => a.assetType == AssetTypes.LINK_SCREENSHOT,
+ )?.id,
+ fullPageArchiveAssetId: assets.find(
+ (a) => a.assetType == AssetTypes.LINK_FULL_PAGE_ARCHIVE,
+ )?.id,
+ precrawledArchiveAssetId: assets.find(
+ (a) => a.assetType == AssetTypes.LINK_PRECRAWLED_ARCHIVE,
+ )?.id,
+ imageAssetId: assets.find(
+ (a) => a.assetType == AssetTypes.LINK_BANNER_IMAGE,
+ )?.id,
+ videoAssetId: assets.find((a) => a.assetType == AssetTypes.LINK_VIDEO)
+ ?.id,
+ ...link,
+ };
+ }
+ if (bookmark.text) {
+ content = {
+ type: BookmarkTypes.TEXT,
+ text: text.text ?? "",
+ sourceUrl: text.sourceUrl,
+ };
+ }
+ if (bookmark.asset) {
+ content = {
+ type: BookmarkTypes.ASSET,
+ assetType: asset.assetType,
+ assetId: asset.assetId,
+ fileName: asset.fileName,
+ sourceUrl: asset.sourceUrl,
+ size: assets.find((a) => a.id == asset.assetId)?.size,
+ };
}
return {
@@ -269,8 +267,8 @@ export const bookmarksAppRouter = router({
.insert(bookmarks)
.values({
userId: ctx.user.id,
- type: input.type,
title: input.title,
+ type: input.type,
archived: input.archived,
favourited: input.favourited,
note: input.note,
@@ -757,31 +755,27 @@ export const bookmarksAppRouter = router({
const bookmarkId = row.bookmarksSq.id;
if (!acc[bookmarkId]) {
let content: ZBookmarkContent;
- switch (row.bookmarksSq.type) {
- case BookmarkTypes.LINK: {
- content = { type: row.bookmarksSq.type, ...row.bookmarkLinks! };
- break;
- }
- case BookmarkTypes.TEXT: {
- content = {
- type: row.bookmarksSq.type,
- text: row.bookmarkTexts?.text ?? "",
- sourceUrl: row.bookmarkTexts?.sourceUrl ?? null,
- };
- break;
- }
- case BookmarkTypes.ASSET: {
- const bookmarkAssets = row.bookmarkAssets!;
- content = {
- type: row.bookmarksSq.type,
- assetId: bookmarkAssets.assetId,
- assetType: bookmarkAssets.assetType,
- fileName: bookmarkAssets.fileName,
- sourceUrl: bookmarkAssets.sourceUrl ?? null,
- size: null, // This will get filled in the asset loop
- };
- break;
- }
+ if (row.bookmarkLinks) {
+ content = { type: BookmarkTypes.LINK, ...row.bookmarkLinks };
+ } else if (row.bookmarkTexts) {
+ content = {
+ type: BookmarkTypes.TEXT,
+ text: row.bookmarkTexts.text ?? "",
+ sourceUrl: row.bookmarkTexts.sourceUrl ?? null,
+ };
+ } else if (row.bookmarkAssets) {
+ content = {
+ type: BookmarkTypes.ASSET,
+ assetId: row.bookmarkAssets.assetId,
+ assetType: row.bookmarkAssets.assetType,
+ fileName: row.bookmarkAssets.fileName,
+ sourceUrl: row.bookmarkAssets.sourceUrl ?? null,
+ size: null, // This will get filled in the asset loop
+ };
+ } else {
+ content = {
+ type: BookmarkTypes.UNKNOWN,
+ };
}
acc[bookmarkId] = {
...row.bookmarksSq,