Repository: raycast/extensions
Pull request #18254: Update memos extension
Author: login: JakeLaoyu
Labels: name: extension fix / improvement
description: Label for PRs with extension's fix improvements
name: OP is author
description: The OP of the PR is the author of the extension
name: extension: memos
description: Issues related to the memos extension
Created: 2025-03-31T00:14:01Z | Merged: 2025-03-31T10:16:39Z

## Description

<!-- A summary of your change. If you add a new extension or command, explain what it does. -->
Support usememo@0.24.0 #18224 

## Screencast

<!-- If you add a new extension or command, include a screencast (or screenshot for straightforward changes). A good screencast will make the review much faster - especially if your extension requires registration in other services.  -->

## Checklist

- [x] I read the [extension guidelines](https://developers.raycast.com/basics/prepare-an-extension-for-store)
- [x] I read the [documentation about publishing](https://developers.raycast.com/basics/publish-an-extension)
- [x] I ran `npm run build` and [tested this distribution build in Raycast](https://developers.raycast.com/basics/prepare-an-extension-for-store#metadata-and-configuration)
- [x] I checked that files in the `assets` folder are used by the extension itself
- [x] I checked that assets used by the `README` are placed outside of the `metadata` folder



Diff:
diff --git a/extensions/memos/CHANGELOG.md b/extensions/memos/CHANGELOG.md
index c6cfb81fa5f..a604921139d 100644
--- a/extensions/memos/CHANGELOG.md
+++ b/extensions/memos/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Send To Memos Changelog
 
+## [Update] - 2025-03-31
+
+- support memos@0.24.0.
+
 ## [Update] - 2024-12-23
 
 - support memos@0.23.0.
diff --git a/extensions/memos/src/api.ts b/extensions/memos/src/api.ts
index d0c56048745..b44b1ce44f5 100644
--- a/extensions/memos/src/api.ts
+++ b/extensions/memos/src/api.ts
@@ -134,14 +134,14 @@ export const getRecentTags = async (): Promise<string[]> => {
   const memos = await getFetch<{
     memos: MemoInfoResponse[];
   }>({
-    url: getRequestUrl(`/api/v1/memos?pageSize=50&filter=creator=='users/${me.id}'`),
+    url: getRequestUrl(`/api/v1/memos?pageSize=50&parent=${encodeURIComponent(me.name)}`),
     method: "GET",
   });
 
   const recentTags: string[] = [];
 
   memos.memos.forEach((memo) => {
-    const tags = memo.property?.tags || [];
+    const tags = memo.tags || [];
 
     tags.forEach((tag) => {
       if (!recentTags.includes(tag)) {
@@ -185,14 +185,14 @@ export const postMemoResources = (memoName: string, resources: Partial<ResourceO
   });
 };
 
-export const getAllMemos = (currentUserId?: number) => {
-  let filter = encodeURIComponent(`creator=='users/${currentUserId}'`);
+export const getAllMemos = (currentUserId?: number, { state = ROW_STATUS.NORMAL } = {}) => {
+  let parent = "";
 
-  if (!currentUserId) {
-    filter = "";
+  if (currentUserId) {
+    parent = encodeURIComponent(`users/${currentUserId}`);
   }
 
-  const url = getRequestUrl(`/api/v1/memos?filter=${filter}&pageSize=20`);
+  const url = getRequestUrl(`/api/v1/memos?parent=${parent}&state=${state}&pageSize=20`);
 
   const { isLoading, data, revalidate, pagination } = useFetch<
     {
@@ -226,33 +226,32 @@ export const getAllMemos = (currentUserId?: number) => {
   return { isLoading, data: currentUserId ? data : [], revalidate, pagination };
 };
 
-export const patchMemo = (memoId: string, { rowStatus = ROW_STATUS.NORMAL } = {}) => {
-  const url = getRequestUrl(`/api/v1/memo/${memoId}`);
+export const patchMemo = (memoName: string, { state = ROW_STATUS.NORMAL } = {}) => {
+  const url = getRequestUrl(`/api/v1/${memoName}`);
 
   return getFetch<ResponseData<MemoInfoResponse>>({
     url,
     method: "PATCH",
     data: {
-      id: memoId,
-      rowStatus,
+      state,
     },
   });
 };
 
-export const archiveMemo = (memoId: string) => {
-  return patchMemo(memoId, {
-    rowStatus: ROW_STATUS.ARCHIVED,
+export const archiveMemo = (memoName: string) => {
+  return patchMemo(memoName, {
+    state: ROW_STATUS.ARCHIVED,
   });
 };
 
-export const restoreMemo = (memoId: string) => {
-  return patchMemo(memoId, {
-    rowStatus: ROW_STATUS.NORMAL,
+export const restoreMemo = (memoName: string) => {
+  return patchMemo(memoName, {
+    state: ROW_STATUS.NORMAL,
   });
 };
 
-export const deleteMemo = (memoId: string) => {
-  const url = getRequestUrl(`/api/v1/memo/${memoId}?openId=${getOpenId()}`);
+export const deleteMemo = (memoName: string) => {
+  const url = getRequestUrl(`/api/v1/${memoName}?openId=${getOpenId()}`);
 
   return getFetch<ResponseData<MemoInfoResponse>>({
     url,
@@ -260,12 +259,28 @@ export const deleteMemo = (memoId: string) => {
   });
 };
 
-export const getResourceBin = (resourceName: string, resourceFilename: string) => {
-  const url = getRequestUrl(`/file/${resourceName}/${resourceFilename}`);
+export const getResourceBinToBase64 = async (resourceName: string, resourceFilename: string) => {
+  const url = getRequestUrl(`/file/${resourceName}/${resourceFilename}?thumbnail=1`);
 
-  return getFetch<Blob>({
+  const blob = await getFetch<ArrayBuffer>({
+    url,
+    method: "GET",
+    responseType: "arraybuffer",
+  });
+
+  const base64 = Buffer.from(blob).toString("base64");
+
+  const mimeType = mime.getType(resourceFilename) || "image/jpeg";
+  const fullBase64 = `data:${mimeType};base64,${base64}`;
+
+  return fullBase64;
+};
+
+export const getMemoByName = (memoName: string) => {
+  const url = getRequestUrl(`/api/v1/${memoName}`);
+
+  return getFetch<MemoInfoResponse>({
     url,
     method: "GET",
-    responseType: "blob",
   });
 };
diff --git a/extensions/memos/src/memosList.tsx b/extensions/memos/src/memosList.tsx
index 85dd3c3dc87..ec4e126334f 100644
--- a/extensions/memos/src/memosList.tsx
+++ b/extensions/memos/src/memosList.tsx
@@ -1,18 +1,20 @@
 import { useEffect, useState } from "react";
 import { List, ActionPanel, Action, Icon, confirmAlert, Alert, showToast, Toast } from "@raycast/api";
-import { archiveMemo, deleteMemo, getAllMemos, getMe, getRequestUrl, restoreMemo } from "./api";
+import { archiveMemo, deleteMemo, getAllMemos, getMe, getRequestUrl, getResourceBinToBase64, restoreMemo } from "./api";
 import { MemoInfoResponse, ROW_STATUS } from "./types";
 
 export default function MemosListCommand(): JSX.Element {
   const [searchText, setSearchText] = useState("");
   const [currentUserId, setCurrentUserId] = useState<number>();
-  const { isLoading, data, revalidate, pagination } = getAllMemos(currentUserId);
+  const [state, setState] = useState(ROW_STATUS.NORMAL);
+  const { isLoading, data, revalidate, pagination } = getAllMemos(currentUserId, { state });
   const { isLoading: isLoadingUser, data: user } = getMe();
   const [filterList, setFilterList] = useState<MemoInfoResponse[]>([]);
 
   useEffect(() => {
-    if (!isLoadingUser && user.id) {
-      setCurrentUserId(user.id);
+    if (!isLoadingUser && user.name) {
+      const userId = +user.name.split("/")[1];
+      setCurrentUserId(userId);
     }
   }, [isLoadingUser]);
 
@@ -25,35 +27,62 @@ export default function MemosListCommand(): JSX.Element {
   useEffect(() => {
     const dataList = data || [];
 
-    setFilterList(dataList.filter((item) => item.content.includes(searchText)) || []);
+    setFilterList(
+      dataList
+        .filter((item) => item.content.includes(searchText))
+        .map((item) => {
+          item.markdown = item.content;
+          if (item.resources.length > 0) {
+            getItemMarkdown(item);
+          }
+          return item;
+        }) || [],
+    );
   }, [searchText]);
 
   useEffect(() => {
     const dataList = data || [];
-    setFilterList(dataList);
+    setFilterList(
+      dataList.map((item) => {
+        item.markdown = item.content;
+
+        if (item.resources.length > 0) {
+          getItemMarkdown(item);
+        }
+
+        return item;
+      }),
+    );
   }, [data]);
 
   function getItemUrl(item: MemoInfoResponse) {
-    const url = getRequestUrl(`/m/${item.uid}`);
+    const url = getRequestUrl(`/${item.name}`);
 
     return url;
   }
 
-  function getItemMarkdown(item: MemoInfoResponse) {
+  async function getItemMarkdown(item: MemoInfoResponse) {
     const { content, resources } = item;
     let markdown = content;
 
-    resources.forEach((resource, index) => {
-      const resourceUrl = getRequestUrl(`/file/${resource.name}/${resource.filename}`);
-
-      if (index === 0) {
-        markdown += "\n\n";
-      }
-
-      markdown += ` ![${resource.filename}](${resourceUrl})`;
+    const resourceMarkdowns = await Promise.all(
+      resources.map(async (resource) => {
+        const resourceBlobUrl = await getResourceBinToBase64(resource.name, resource.filename);
+        return `\n\n![${resource.filename}](${resourceBlobUrl})`;
+      }),
+    );
+
+    markdown += resourceMarkdowns.join("");
+
+    setFilterList((prevList) => {
+      const updatedList = prevList.map((prevItem) => {
+        if (prevItem.name === item.name) {
+          return { ...prevItem, markdown };
+        }
+        return prevItem;
+      });
+      return updatedList;
     });
-
-    return markdown;
   }
 
   async function onArchive(item: MemoInfoResponse) {
@@ -71,7 +100,7 @@ export default function MemosListCommand(): JSX.Element {
         style: Toast.Style.Animated,
         title: "Archive...",
       });
-      const res = await archiveMemo(item.uid).catch(() => {
+      const res = await archiveMemo(item.name).catch(() => {
         //
       });
 
@@ -100,7 +129,7 @@ export default function MemosListCommand(): JSX.Element {
         style: Toast.Style.Animated,
         title: "Delete...",
       });
-      const res = await deleteMemo(item.uid).catch(() => {
+      const res = await deleteMemo(item.name).catch(() => {
         //
       });
 
@@ -129,7 +158,7 @@ export default function MemosListCommand(): JSX.Element {
         style: Toast.Style.Animated,
         title: "Restore...",
       });
-      const res = await restoreMemo(item.uid).catch(() => {
+      const res = await restoreMemo(item.name).catch(() => {
         //
       });
 
@@ -164,20 +193,31 @@ export default function MemosListCommand(): JSX.Element {
       searchBarPlaceholder="Search your memo..."
       isShowingDetail
       pagination={pagination}
+      searchBarAccessory={
+        <List.Dropdown
+          tooltip="Dropdown With Items"
+          onChange={(newValue) => {
+            setState(newValue as ROW_STATUS);
+          }}
+        >
+          <List.Dropdown.Item title={ROW_STATUS.NORMAL} value={ROW_STATUS.NORMAL} />
+          <List.Dropdown.Item title={ROW_STATUS.ARCHIVED} value={ROW_STATUS.ARCHIVED} />
+        </List.Dropdown>
+      }
     >
       {filterList.map((item) => (
         <List.Item
-          key={item.uid}
+          key={item.name}
           title={item.content}
           actions={
             <ActionPanel>
               <Action.OpenInBrowser url={getItemUrl(item)} />
-              {(item.rowStatus === ROW_STATUS.NORMAL && archiveComponent(item)) || null}
-              {(item.rowStatus === ROW_STATUS.ARCHIVED && restoreComponent(item)) || null}
-              {(item.rowStatus === ROW_STATUS.ARCHIVED && deleteComponent(item)) || null}
+              {(item.state === ROW_STATUS.NORMAL && archiveComponent(item)) || null}
+              {(item.state === ROW_STATUS.ARCHIVED && restoreComponent(item)) || null}
+              {(item.state === ROW_STATUS.ARCHIVED && deleteComponent(item)) || null}
             </ActionPanel>
           }
-          detail={<List.Item.Detail markdown={getItemMarkdown(item)} />}
+          detail={<List.Item.Detail markdown={item.markdown} />}
         />
       ))}
     </List>
diff --git a/extensions/memos/src/sendMemo.tsx b/extensions/memos/src/sendMemo.tsx
index bffb6cf544d..9f98a0857d2 100644
--- a/extensions/memos/src/sendMemo.tsx
+++ b/extensions/memos/src/sendMemo.tsx
@@ -19,7 +19,7 @@ export default async function Command(props: LaunchProps<{ arguments: TodoArgume
     resourceIdList: [],
   });
 
-  if (response?.uid) {
+  if (response?.name) {
     showToast({
       style: Toast.Style.Success,
       title: "Sent",
diff --git a/extensions/memos/src/sendMemoForm.tsx b/extensions/memos/src/sendMemoForm.tsx
index 5b86df70e1d..14b1de1dc67 100644
--- a/extensions/memos/src/sendMemoForm.tsx
+++ b/extensions/memos/src/sendMemoForm.tsx
@@ -1,8 +1,18 @@
 import { Form, Detail, ActionPanel, Action, showToast, Toast, open, popToRoot } from "@raycast/api";
 import { useEffect, useState } from "react";
 import { MemoInfoResponse, PostFileResponse, PostMemoParams } from "./types";
-import { getOriginUrl, getRecentTags, getRequestUrl, postFile, postMemoResources, sendMemo } from "./api";
+import {
+  getMemoByName,
+  getOriginUrl,
+  getRecentTags,
+  getRequestUrl,
+  getResourceBinToBase64,
+  postFile,
+  postMemoResources,
+  sendMemo,
+} from "./api";
 import { VISIBILITY } from "./constant";
+import { showFailureToast } from "@raycast/utils";
 
 interface FormData {
   content: string;
@@ -18,6 +28,7 @@ export default function SendMemoFormCommand(): JSX.Element {
   const [createdUrl, setCreatedUrl] = useState<string>();
   const [isLoading, setIsLoading] = useState(true);
   const [recentTags, setRecentTags] = useState<string[]>([]);
+  const [loadingDetail, setLoadingDetail] = useState(false);
 
   useEffect(() => {
     getRecentTags()
@@ -36,27 +47,37 @@ export default function SendMemoFormCommand(): JSX.Element {
   }
 
   function computedCreatedUrl(data: MemoInfoResponse) {
-    const { uid } = data;
-    const url = getRequestUrl(`/m/${uid}`);
+    const { name } = data;
+    const url = getRequestUrl(`/${name}`);
 
     setCreatedUrl(url);
   }
 
-  function computedCreatedMarkdown(data: MemoInfoResponse) {
-    const { content, resources } = data;
-    let markdown = content;
+  async function computedCreatedMarkdown(data: MemoInfoResponse) {
+    setCreatedMarkdown(data.content);
+    setLoadingDetail(true);
 
-    resources.forEach((resource, index) => {
-      const resourceUrl = getRequestUrl(`/file/${resource.name}?thumbnail=1`);
+    try {
+      const memoData = await getMemoByName(data.name);
 
-      if (index === 0) {
-        markdown += "\n\n";
+      const { content, resources } = memoData;
+      let markdown = content;
+
+      for (const resource of resources) {
+        const resourceUrl = await getResourceBinToBase64(resource.name, resource.filename);
+        console.log("resourceUrl", resourceUrl);
+        markdown += `\n\n ![${resource.filename}](${resourceUrl})`;
       }
 
-      markdown += ` ![${resource.filename}](${resourceUrl})`;
-    });
+      setCreatedMarkdown(markdown);
+    } catch (error) {
+      showFailureToast(error, { title: "Failed to fetch memo details" });
+    }
 
-    setCreatedMarkdown(markdown);
+    setLoadingDetail(false);
+    setTimeout(() => {
+      popToRoot({ clearSearchBar: true });
+    }, 5000);
   }
 
   const onSubmit = async (values: FormData) => {
@@ -80,18 +101,16 @@ export default function SendMemoFormCommand(): JSX.Element {
       showToast(Toast.Style.Failure, "Send Memo Failed");
     });
 
-    if (res?.uid) {
+    console.log("res", res);
+
+    if (res?.name) {
       if (files.length) {
         await setMemoResource(res, files);
       }
 
       showToast(Toast.Style.Success, "Send Memo Success");
-      computedCreatedMarkdown(res);
       computedCreatedUrl(res);
-
-      setTimeout(() => {
-        popToRoot({ clearSearchBar: true });
-      }, 5000);
+      computedCreatedMarkdown(res);
     }
   };
 
@@ -129,6 +148,7 @@ export default function SendMemoFormCommand(): JSX.Element {
   return createdMarkdown ? (
     <Detail
       markdown={createdMarkdown}
+      isLoading={loadingDetail}
       actions={
         createdUrl && (
           <ActionPanel>
diff --git a/extensions/memos/src/types.ts b/extensions/memos/src/types.ts
index fc641a312e6..f252b40eb7c 100644
--- a/extensions/memos/src/types.ts
+++ b/extensions/memos/src/types.ts
@@ -41,20 +41,20 @@ export interface ResourceObj {
 }
 
 export interface MemoInfoResponse {
-  uid: string;
   name: string;
-  rowStatus: string;
+  state: string;
   creator: string;
   createTime: string;
   updateTime: string;
   displayTime: string;
   content: string;
+  markdown?: string;
   visibility: string;
   pinned: boolean;
   displayTs: number;
   resources: ResourceObj[];
+  tags: string[];
   property: {
-    tags: string[];
     hasLink: boolean;
     hasTaskList: boolean;
     hasCode: boolean;
@@ -63,7 +63,6 @@ export interface MemoInfoResponse {
 }
 
 export interface MeResponse {
-  id: number;
   name: string;
   rowStatus: "ACTIVE";
   createdTime: number;


Reviews:
user: login: greptile-apps[bot]
body: 
## PR Summary

This PR updates the memos extension to support usememo@0.24.0 by refactoring API calls, component logic, and types for the new memo schema.

• File: extensions/memos/CHANGELOG.md – The new entry still uses an actual date; update it to use the {PR_MERGE_DATE} template string.  
• File: extensions/memos/src/memosList.tsx – Using split on user.name for user id extraction and asynchronous markdown updates may risk unexpected behavior.  
• File: extensions/memos/src/api.ts – Verify the new URL structures and state parameter align with backend requirements.  
• Files: extensions/memos/src/sendMemo.tsx & sendMemoForm.tsx – Updated response checks to use memo name rather than uid.  
• File: extensions/memos/src/types.ts – Adjustments to MemoInfoResponse (uid removal, rowStatus→state) require downstream consistency.

<sub>💡 (1/5) You can manually trigger the bot by mentioning @greptileai in a comment!</sub>

<sub>6 file(s) reviewed, 4 comment(s)</sub>
<sub>[Edit PR Review Bot Settings](https://app.greptile.com/review/github) | [Greptile](https://greptile.com?utm_source=greptile_expert&utm_medium=github&utm_campaign=code_reviews&utm_content=extensions_18254)</sub>
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T00:19:43Z
user: login: pernielsentikaer
body: Hi 👋 

Looks good to me, approved 🔥
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-31T10:15:27Z

Review comments:
diff_hunk: @@ -1,5 +1,9 @@
 # Send To Memos Changelog
 
+## [Update] - 2025-03-30
+
+- support memos@0.24.0.
+
path: extensions/memos/CHANGELOG.md
user: login: greptile-apps[bot]
body: logic: New changelog title must end with {PR_MERGE_DATE} instead of using an actual date (e.g. '## [Update] - {PR_MERGE_DATE}').

```suggestion
## [Update] - {PR_MERGE_DATE}

- support memos@0.24.0.
```
created_at: 2025-03-31T00:17:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -25,35 +27,59 @@ export default function MemosListCommand(): JSX.Element {
   useEffect(() => {
     const dataList = data || [];
 
-    setFilterList(dataList.filter((item) => item.content.includes(searchText)) || []);
+    setFilterList(
+      dataList
+        .filter((item) => item.content.includes(searchText))
+        .map((item) => {
+          item.markdown = item.content;
+          if (item.resources.length > 0) {
+            getItemMarkdown(item);
+          }
+          return item;
+        }) || [],
+    );
   }, [searchText]);
 
   useEffect(() => {
     const dataList = data || [];
-    setFilterList(dataList);
+    setFilterList(
+      dataList.map((item) => {
+        item.markdown = item.content;
+
+        if (item.resources.length > 0) {
+          getItemMarkdown(item);
+        }
+
+        return item;
+      }),
+    );
   }, [data]);
 
   function getItemUrl(item: MemoInfoResponse) {
-    const url = getRequestUrl(`/m/${item.uid}`);
+    const url = getRequestUrl(`/${item.name}`);
 
     return url;
   }
 
-  function getItemMarkdown(item: MemoInfoResponse) {
+  async function getItemMarkdown(item: MemoInfoResponse) {
     const { content, resources } = item;
     let markdown = content;
 
-    resources.forEach((resource, index) => {
-      const resourceUrl = getRequestUrl(`/file/${resource.name}/${resource.filename}`);
+    for (const resource of resources) {
+      const resourceBlobUrl = await getResourceBinToBase64(resource.name, resource.filename);
 
-      if (index === 0) {
-        markdown += "\n\n";
-      }
+      markdown += `\n\n![${resource.filename}](${resourceBlobUrl})`;
+    }
 
-      markdown += ` ![${resource.filename}](${resourceUrl})`;
+    setFilterList((prevList) => {
+      const updatedList = prevList.map((prevItem) => {
+        if (prevItem.name === item.name) {
+          return { ...prevItem, markdown };
+        }
+        return prevItem;
+      });
+      return updatedList;
     });
-
-    return markdown;
   }
path: extensions/memos/src/memosList.tsx
user: login: greptile-apps[bot]
body: logic: Consider using Promise.all to process resources in getItemMarkdown to avoid potential race conditions during async updates.
created_at: 2025-03-31T00:17:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -226,46 +226,62 @@ export const getAllMemos = (currentUserId?: number) => {
   return { isLoading, data: currentUserId ? data : [], revalidate, pagination };
 };
 
-export const patchMemo = (memoId: string, { rowStatus = ROW_STATUS.NORMAL } = {}) => {
-  const url = getRequestUrl(`/api/v1/memo/${memoId}`);
+export const patchMemo = (memoName: string, { state = ROW_STATUS.NORMAL } = {}) => {
+  const url = getRequestUrl(`/api/v1/${memoName}`);
 
   return getFetch<ResponseData<MemoInfoResponse>>({
     url,
     method: "PATCH",
     data: {
-      id: memoId,
-      rowStatus,
+      state,
     },
   });
 };
 
-export const archiveMemo = (memoId: string) => {
-  return patchMemo(memoId, {
-    rowStatus: ROW_STATUS.ARCHIVED,
+export const archiveMemo = (memoName: string) => {
+  return patchMemo(memoName, {
+    state: ROW_STATUS.ARCHIVED,
   });
 };
 
-export const restoreMemo = (memoId: string) => {
-  return patchMemo(memoId, {
-    rowStatus: ROW_STATUS.NORMAL,
+export const restoreMemo = (memoName: string) => {
+  return patchMemo(memoName, {
+    state: ROW_STATUS.NORMAL,
   });
 };
 
-export const deleteMemo = (memoId: string) => {
-  const url = getRequestUrl(`/api/v1/memo/${memoId}?openId=${getOpenId()}`);
+export const deleteMemo = (memoName: string) => {
+  const url = getRequestUrl(`/api/v1/${memoName}?openId=${getOpenId()}`);
 
   return getFetch<ResponseData<MemoInfoResponse>>({
     url,
     method: "DELETE",
   });
 };
 
-export const getResourceBin = (resourceName: string, resourceFilename: string) => {
-  const url = getRequestUrl(`/file/${resourceName}/${resourceFilename}`);
+export const getResourceBinToBase64 = async (resourceName: string, resourceFilename: string) => {
+  const url = getRequestUrl(`/file/${resourceName}/${resourceFilename}?thumbnail=1`);
+  console.log("url", url);
path: extensions/memos/src/api.ts
user: login: greptile-apps[bot]
body: style: Remove console.log debug statement for production.

```suggestion

```
created_at: 2025-03-31T00:17:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -36,27 +46,37 @@ export default function SendMemoFormCommand(): JSX.Element {
   }
 
   function computedCreatedUrl(data: MemoInfoResponse) {
-    const { uid } = data;
-    const url = getRequestUrl(`/m/${uid}`);
+    const { name } = data;
+    const url = getRequestUrl(`/${name}`);
 
     setCreatedUrl(url);
   }
 
-  function computedCreatedMarkdown(data: MemoInfoResponse) {
-    const { content, resources } = data;
-    let markdown = content;
+  async function computedCreatedMarkdown(data: MemoInfoResponse) {
+    setCreatedMarkdown(data.content);
+    setLoadingDetail(true);
 
-    resources.forEach((resource, index) => {
-      const resourceUrl = getRequestUrl(`/file/${resource.name}?thumbnail=1`);
+    try {
+      const memoData = await getMemoByName(data.name);
 
-      if (index === 0) {
-        markdown += "\n\n";
+      const { content, resources } = memoData;
+      let markdown = content;
+
+      for (const resource of resources) {
+        const resourceUrl = await getResourceBinToBase64(resource.name, resource.filename);
+        console.log("resourceUrl", resourceUrl);
+        markdown += `\n\n ![${resource.filename}](${resourceUrl})`;
       }
 
-      markdown += ` ![${resource.filename}](${resourceUrl})`;
-    });
+      setCreatedMarkdown(markdown);
+    } catch (error) {
+      //
+    }
path: extensions/memos/src/sendMemoForm.tsx
user: login: greptile-apps[bot]
body: logic: Empty catch block may hide errors when fetching memo details. Consider logging the error (e.g., console.error(error)) or showing a toast for failure.

```suggestion
    } catch (error) {
      showFailureToast(error, { title: "Failed to fetch memo details" });
    }
```
created_at: 2025-03-31T00:18:26Z
author_association: CONTRIBUTOR

PR comments:
user: login: raycastbot
created_at: 2025-03-31T00:14:19Z
body: Thank you for the update! :tada:

You can expect an initial review within five business days.
author_association: COLLABORATOR
user: login: github-actions[bot]
created_at: 2025-03-31T10:17:33Z
body: <!-- add-pr-comment:add-pr-comment -->

**Published to the Raycast Store:**
https://raycast.com/JakeYu/memos
author_association: CONTRIBUTOR
user: login: raycastbot
created_at: 2025-03-31T10:17:35Z
body: :tada: :tada: :tada:

We've rewarded your Raycast account with some credits. You will soon be able to exchange them for some swag.
author_association: COLLABORATOR