mirror of
				https://github.com/kyantech/Palmr.git
				synced 2025-11-03 21:43:20 +00:00 
			
		
		
		
	Compare commits
	
		
			3 Commits
		
	
	
		
			next
			...
			v3.2.2-bet
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					f3aeaf66df | ||
| 
						 | 
					331624e2f2 | ||
| 
						 | 
					ba512ebe95 | 
							
								
								
									
										11
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								README.md
									
									
									
									
									
								
							@@ -6,6 +6,17 @@
 | 
			
		||||
 | 
			
		||||
**Palmr.** is a **flexible** and **open-source** alternative to file transfer services like **WeTransfer**, **SendGB**, **Send Anywhere**, and **Files.fm**.
 | 
			
		||||
 | 
			
		||||
<div align="center">
 | 
			
		||||
  <div style="background: linear-gradient(135deg, #ff4757, #ff3838); padding: 20px; border-radius: 12px; margin: 20px 0; box-shadow: 0 4px 15px rgba(255, 71, 87, 0.3); border: 2px solid #ff3838;">
 | 
			
		||||
    <h3 style="color: white; margin: 0 0 10px 0; font-size: 18px; font-weight: bold;">
 | 
			
		||||
      ⚠️ BETA VERSION
 | 
			
		||||
    </h3>
 | 
			
		||||
    <p style="color: white; margin: 0; font-size: 14px; opacity: 0.95;">
 | 
			
		||||
      <strong>This project is currently in beta phase.</strong><br>
 | 
			
		||||
      Not recommended for production environments.
 | 
			
		||||
    </p>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
🔗 **For detailed documentation visit:** [Palmr. - Documentation](https://palmr.kyantech.com.br)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "palmr-docs",
 | 
			
		||||
  "version": "3.2.1-beta",
 | 
			
		||||
  "version": "3.2.2-beta",
 | 
			
		||||
  "description": "Docs for Palmr",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "author": "Daniel Luiz Alves <daniel@kyantech.com.br>",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "palmr-api",
 | 
			
		||||
  "version": "3.2.1-beta",
 | 
			
		||||
  "version": "3.2.2-beta",
 | 
			
		||||
  "description": "API for Palmr",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "author": "Daniel Luiz Alves <daniel@kyantech.com.br>",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
import bcrypt from "bcryptjs";
 | 
			
		||||
import { FastifyReply, FastifyRequest } from "fastify";
 | 
			
		||||
 | 
			
		||||
import { env } from "../../env";
 | 
			
		||||
@@ -183,6 +184,7 @@ export class FileController {
 | 
			
		||||
        objectName: string;
 | 
			
		||||
      };
 | 
			
		||||
      const objectName = decodeURIComponent(encodedObjectName);
 | 
			
		||||
      const { password } = request.query as { password?: string };
 | 
			
		||||
 | 
			
		||||
      if (!objectName) {
 | 
			
		||||
        return reply.status(400).send({ error: "The 'objectName' parameter is required." });
 | 
			
		||||
@@ -193,6 +195,51 @@ export class FileController {
 | 
			
		||||
      if (!fileRecord) {
 | 
			
		||||
        return reply.status(404).send({ error: "File not found." });
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      let hasAccess = false;
 | 
			
		||||
 | 
			
		||||
      console.log("Requested file with password " + password);
 | 
			
		||||
 | 
			
		||||
      const shares = await prisma.share.findMany({
 | 
			
		||||
        where: {
 | 
			
		||||
          files: {
 | 
			
		||||
            some: {
 | 
			
		||||
              id: fileRecord.id,
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        include: {
 | 
			
		||||
          security: true,
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      for (const share of shares) {
 | 
			
		||||
        if (!share.security.password) {
 | 
			
		||||
          hasAccess = true;
 | 
			
		||||
          break;
 | 
			
		||||
        } else if (password) {
 | 
			
		||||
          const isPasswordValid = await bcrypt.compare(password, share.security.password);
 | 
			
		||||
          if (isPasswordValid) {
 | 
			
		||||
            hasAccess = true;
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!hasAccess) {
 | 
			
		||||
        try {
 | 
			
		||||
          await request.jwtVerify();
 | 
			
		||||
          const userId = (request as any).user?.userId;
 | 
			
		||||
          if (userId && fileRecord.userId === userId) {
 | 
			
		||||
            hasAccess = true;
 | 
			
		||||
          }
 | 
			
		||||
        } catch (err) {}
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!hasAccess) {
 | 
			
		||||
        return reply.status(401).send({ error: "Unauthorized access to file." });
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const fileName = fileRecord.name;
 | 
			
		||||
      const expires = parseInt(env.PRESIGNED_URL_EXPIRATION);
 | 
			
		||||
      const url = await this.fileService.getPresignedGetUrl(objectName, expires, fileName);
 | 
			
		||||
 
 | 
			
		||||
@@ -108,7 +108,6 @@ export async function fileRoutes(app: FastifyInstance) {
 | 
			
		||||
  app.get(
 | 
			
		||||
    "/files/:objectName/download",
 | 
			
		||||
    {
 | 
			
		||||
      preValidation,
 | 
			
		||||
      schema: {
 | 
			
		||||
        tags: ["File"],
 | 
			
		||||
        operationId: "getDownloadUrl",
 | 
			
		||||
@@ -117,6 +116,9 @@ export async function fileRoutes(app: FastifyInstance) {
 | 
			
		||||
        params: z.object({
 | 
			
		||||
          objectName: z.string().min(1, "The objectName is required"),
 | 
			
		||||
        }),
 | 
			
		||||
        querystring: z.object({
 | 
			
		||||
          password: z.string().optional().describe("Share password if required"),
 | 
			
		||||
        }),
 | 
			
		||||
        response: {
 | 
			
		||||
          200: z.object({
 | 
			
		||||
            url: z.string().describe("The download URL"),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "palmr-web",
 | 
			
		||||
  "version": "3.2.1-beta",
 | 
			
		||||
  "version": "3.2.2-beta",
 | 
			
		||||
  "description": "Frontend for Palmr",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "author": "Daniel Luiz Alves <daniel@kyantech.com.br>",
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@ interface ShareFilesTableProps {
 | 
			
		||||
  onDownloadFolder?: (folderId: string, folderName: string) => Promise<void>;
 | 
			
		||||
  onNavigateToFolder?: (folderId: string) => void;
 | 
			
		||||
  enableNavigation?: boolean;
 | 
			
		||||
  sharePassword?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function ShareFilesTable({
 | 
			
		||||
@@ -39,6 +40,7 @@ export function ShareFilesTable({
 | 
			
		||||
  onDownloadFolder,
 | 
			
		||||
  onNavigateToFolder,
 | 
			
		||||
  enableNavigation = false,
 | 
			
		||||
  sharePassword,
 | 
			
		||||
}: ShareFilesTableProps) {
 | 
			
		||||
  const t = useTranslations();
 | 
			
		||||
  const [isPreviewOpen, setIsPreviewOpen] = useState(false);
 | 
			
		||||
@@ -213,7 +215,14 @@ export function ShareFilesTable({
 | 
			
		||||
        </Table>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      {selectedFile && <FilePreviewModal isOpen={isPreviewOpen} onClose={handleClosePreview} file={selectedFile} />}
 | 
			
		||||
      {selectedFile && (
 | 
			
		||||
        <FilePreviewModal
 | 
			
		||||
          isOpen={isPreviewOpen}
 | 
			
		||||
          onClose={handleClosePreview}
 | 
			
		||||
          file={selectedFile}
 | 
			
		||||
          sharePassword={sharePassword}
 | 
			
		||||
        />
 | 
			
		||||
      )}
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ interface Folder {
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface ShareDetailsPropsExtended extends Omit<ShareDetailsProps, "onBulkDownload" | "password"> {
 | 
			
		||||
interface ShareDetailsPropsExtended extends Omit<ShareDetailsProps, "onBulkDownload"> {
 | 
			
		||||
  onBulkDownload?: () => Promise<void>;
 | 
			
		||||
  onSelectedItemsBulkDownload?: (files: File[], folders: Folder[]) => Promise<void>;
 | 
			
		||||
  folders: Folder[];
 | 
			
		||||
@@ -60,6 +60,7 @@ interface ShareDetailsPropsExtended extends Omit<ShareDetailsProps, "onBulkDownl
 | 
			
		||||
 | 
			
		||||
export function ShareDetails({
 | 
			
		||||
  share,
 | 
			
		||||
  password,
 | 
			
		||||
  onDownload,
 | 
			
		||||
  onBulkDownload,
 | 
			
		||||
  onSelectedItemsBulkDownload,
 | 
			
		||||
@@ -186,6 +187,7 @@ export function ShareDetails({
 | 
			
		||||
            setSelectedFile(null);
 | 
			
		||||
          }}
 | 
			
		||||
          file={selectedFile}
 | 
			
		||||
          sharePassword={password}
 | 
			
		||||
        />
 | 
			
		||||
      )}
 | 
			
		||||
    </>
 | 
			
		||||
 
 | 
			
		||||
@@ -232,6 +232,7 @@ export function usePublicShare() {
 | 
			
		||||
      await downloadShareFolderWithQueue(folderId, folderName, share.files || [], share.folders || [], {
 | 
			
		||||
        silent: true,
 | 
			
		||||
        showToasts: false,
 | 
			
		||||
        sharePassword: password,
 | 
			
		||||
      });
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      console.error("Error downloading folder:", error);
 | 
			
		||||
@@ -253,6 +254,7 @@ export function usePublicShare() {
 | 
			
		||||
          downloadFileWithQueue(objectName, fileName, {
 | 
			
		||||
            silent: true,
 | 
			
		||||
            showToasts: false,
 | 
			
		||||
            sharePassword: password,
 | 
			
		||||
          }),
 | 
			
		||||
          {
 | 
			
		||||
            loading: t("share.messages.downloadStarted"),
 | 
			
		||||
@@ -320,9 +322,15 @@ export function usePublicShare() {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      toast.promise(
 | 
			
		||||
        bulkDownloadShareWithQueue(allItems, share.files || [], share.folders || [], zipName, undefined, true).then(
 | 
			
		||||
          () => {}
 | 
			
		||||
        ),
 | 
			
		||||
        bulkDownloadShareWithQueue(
 | 
			
		||||
          allItems,
 | 
			
		||||
          share.files || [],
 | 
			
		||||
          share.folders || [],
 | 
			
		||||
          zipName,
 | 
			
		||||
          undefined,
 | 
			
		||||
          true,
 | 
			
		||||
          password
 | 
			
		||||
        ).then(() => {}),
 | 
			
		||||
        {
 | 
			
		||||
          loading: t("shareManager.creatingZip"),
 | 
			
		||||
          success: t("shareManager.zipDownloadSuccess"),
 | 
			
		||||
@@ -387,9 +395,15 @@ export function usePublicShare() {
 | 
			
		||||
      const zipName = `${share.name || t("shareManager.defaultShareName")}-selected.zip`;
 | 
			
		||||
 | 
			
		||||
      toast.promise(
 | 
			
		||||
        bulkDownloadShareWithQueue(allItems, share.files || [], share.folders || [], zipName, undefined, false).then(
 | 
			
		||||
          () => {}
 | 
			
		||||
        ),
 | 
			
		||||
        bulkDownloadShareWithQueue(
 | 
			
		||||
          allItems,
 | 
			
		||||
          share.files || [],
 | 
			
		||||
          share.folders || [],
 | 
			
		||||
          zipName,
 | 
			
		||||
          undefined,
 | 
			
		||||
          false,
 | 
			
		||||
          password
 | 
			
		||||
        ).then(() => {}),
 | 
			
		||||
        {
 | 
			
		||||
          loading: t("shareManager.creatingZip"),
 | 
			
		||||
          success: t("shareManager.zipDownloadSuccess"),
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,7 @@ export default function PublicSharePage() {
 | 
			
		||||
          {share && (
 | 
			
		||||
            <ShareDetails
 | 
			
		||||
              share={share}
 | 
			
		||||
              password={password}
 | 
			
		||||
              onDownload={handleDownload}
 | 
			
		||||
              onBulkDownload={handleBulkDownload}
 | 
			
		||||
              onSelectedItemsBulkDownload={handleSelectedItemsBulkDownload}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,9 @@ export async function GET(req: NextRequest, { params }: { params: Promise<{ obje
 | 
			
		||||
  const { objectPath } = await params;
 | 
			
		||||
  const cookieHeader = req.headers.get("cookie");
 | 
			
		||||
  const objectName = objectPath.join("/");
 | 
			
		||||
  const url = `${API_BASE_URL}/files/${encodeURIComponent(objectName)}/download`;
 | 
			
		||||
  const searchParams = req.nextUrl.searchParams;
 | 
			
		||||
  const queryString = searchParams.toString();
 | 
			
		||||
  const url = `${API_BASE_URL}/files/${encodeURIComponent(objectName)}/download${queryString ? `?${queryString}` : ""}`;
 | 
			
		||||
 | 
			
		||||
  const apiRes = await fetch(url, {
 | 
			
		||||
    method: "GET",
 | 
			
		||||
 
 | 
			
		||||
@@ -20,11 +20,18 @@ interface FilePreviewModalProps {
 | 
			
		||||
    description?: string;
 | 
			
		||||
  };
 | 
			
		||||
  isReverseShare?: boolean;
 | 
			
		||||
  sharePassword?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function FilePreviewModal({ isOpen, onClose, file, isReverseShare = false }: FilePreviewModalProps) {
 | 
			
		||||
export function FilePreviewModal({
 | 
			
		||||
  isOpen,
 | 
			
		||||
  onClose,
 | 
			
		||||
  file,
 | 
			
		||||
  isReverseShare = false,
 | 
			
		||||
  sharePassword,
 | 
			
		||||
}: FilePreviewModalProps) {
 | 
			
		||||
  const t = useTranslations();
 | 
			
		||||
  const previewState = useFilePreview({ file, isOpen, isReverseShare });
 | 
			
		||||
  const previewState = useFilePreview({ file, isOpen, isReverseShare, sharePassword });
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Dialog open={isOpen} onOpenChange={onClose}>
 | 
			
		||||
 
 | 
			
		||||
@@ -27,9 +27,10 @@ interface UseFilePreviewProps {
 | 
			
		||||
  };
 | 
			
		||||
  isOpen: boolean;
 | 
			
		||||
  isReverseShare?: boolean;
 | 
			
		||||
  sharePassword?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useFilePreview({ file, isOpen, isReverseShare = false }: UseFilePreviewProps) {
 | 
			
		||||
export function useFilePreview({ file, isOpen, isReverseShare = false, sharePassword }: UseFilePreviewProps) {
 | 
			
		||||
  const t = useTranslations();
 | 
			
		||||
  const [state, setState] = useState<FilePreviewState>({
 | 
			
		||||
    previewUrl: null,
 | 
			
		||||
@@ -181,7 +182,17 @@ export function useFilePreview({ file, isOpen, isReverseShare = false }: UseFile
 | 
			
		||||
        url = response.data.url;
 | 
			
		||||
      } else {
 | 
			
		||||
        const encodedObjectName = encodeURIComponent(file.objectName);
 | 
			
		||||
        const response = await getDownloadUrl(encodedObjectName);
 | 
			
		||||
        const params: Record<string, string> = {};
 | 
			
		||||
        if (sharePassword) params.password = sharePassword;
 | 
			
		||||
 | 
			
		||||
        const response = await getDownloadUrl(
 | 
			
		||||
          encodedObjectName,
 | 
			
		||||
          Object.keys(params).length > 0
 | 
			
		||||
            ? {
 | 
			
		||||
                params: { ...params },
 | 
			
		||||
              }
 | 
			
		||||
            : undefined
 | 
			
		||||
        );
 | 
			
		||||
        url = response.data.url;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@@ -218,6 +229,7 @@ export function useFilePreview({ file, isOpen, isReverseShare = false }: UseFile
 | 
			
		||||
    file.id,
 | 
			
		||||
    file.objectName,
 | 
			
		||||
    fileType,
 | 
			
		||||
    sharePassword,
 | 
			
		||||
    loadVideoPreview,
 | 
			
		||||
    loadAudioPreview,
 | 
			
		||||
    loadPdfPreview,
 | 
			
		||||
@@ -236,13 +248,14 @@ export function useFilePreview({ file, isOpen, isReverseShare = false }: UseFile
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        await downloadFileWithQueue(file.objectName, file.name, {
 | 
			
		||||
          sharePassword,
 | 
			
		||||
          onFail: () => toast.error(t("filePreview.downloadError")),
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      console.error("Download error:", error);
 | 
			
		||||
    }
 | 
			
		||||
  }, [isReverseShare, file.id, file.objectName, file.name, t]);
 | 
			
		||||
  }, [isReverseShare, file.id, file.objectName, file.name, sharePassword, t]);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const fileKey = isReverseShare ? file.id : file.objectName;
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ interface DownloadWithQueueOptions {
 | 
			
		||||
  useQueue?: boolean;
 | 
			
		||||
  silent?: boolean;
 | 
			
		||||
  showToasts?: boolean;
 | 
			
		||||
  sharePassword?: string;
 | 
			
		||||
  onStart?: (downloadId: string) => void;
 | 
			
		||||
  onComplete?: (downloadId: string) => void;
 | 
			
		||||
  onFail?: (downloadId: string, error: string) => void;
 | 
			
		||||
@@ -89,7 +90,7 @@ export async function downloadFileWithQueue(
 | 
			
		||||
  fileName: string,
 | 
			
		||||
  options: DownloadWithQueueOptions = {}
 | 
			
		||||
): Promise<void> {
 | 
			
		||||
  const { useQueue = true, silent = false, showToasts = true } = options;
 | 
			
		||||
  const { useQueue = true, silent = false, showToasts = true, sharePassword } = options;
 | 
			
		||||
  const downloadId = `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
@@ -98,7 +99,18 @@ export async function downloadFileWithQueue(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const encodedObjectName = encodeURIComponent(objectName);
 | 
			
		||||
    const response = await getDownloadUrl(encodedObjectName);
 | 
			
		||||
 | 
			
		||||
    const params: Record<string, string> = {};
 | 
			
		||||
    if (sharePassword) params.password = sharePassword;
 | 
			
		||||
 | 
			
		||||
    const response = await getDownloadUrl(
 | 
			
		||||
      encodedObjectName,
 | 
			
		||||
      Object.keys(params).length > 0
 | 
			
		||||
        ? {
 | 
			
		||||
            params: { ...params },
 | 
			
		||||
          }
 | 
			
		||||
        : undefined
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (response.status === 202 && useQueue) {
 | 
			
		||||
      if (!silent && showToasts) {
 | 
			
		||||
@@ -181,7 +193,8 @@ export async function downloadFileAsBlobWithQueue(
 | 
			
		||||
  objectName: string,
 | 
			
		||||
  fileName: string,
 | 
			
		||||
  isReverseShare: boolean = false,
 | 
			
		||||
  fileId?: string
 | 
			
		||||
  fileId?: string,
 | 
			
		||||
  sharePassword?: string
 | 
			
		||||
): Promise<Blob> {
 | 
			
		||||
  try {
 | 
			
		||||
    let downloadUrl: string;
 | 
			
		||||
@@ -196,7 +209,18 @@ export async function downloadFileAsBlobWithQueue(
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      const encodedObjectName = encodeURIComponent(objectName);
 | 
			
		||||
      const response = await getDownloadUrl(encodedObjectName);
 | 
			
		||||
 | 
			
		||||
      const params: Record<string, string> = {};
 | 
			
		||||
      if (sharePassword) params.password = sharePassword;
 | 
			
		||||
 | 
			
		||||
      const response = await getDownloadUrl(
 | 
			
		||||
        encodedObjectName,
 | 
			
		||||
        Object.keys(params).length > 0
 | 
			
		||||
          ? {
 | 
			
		||||
              params: { ...params },
 | 
			
		||||
            }
 | 
			
		||||
          : undefined
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      if (response.status === 202) {
 | 
			
		||||
        downloadUrl = await waitForDownloadReady(objectName, fileName);
 | 
			
		||||
@@ -345,7 +369,7 @@ export async function downloadShareFolderWithQueue(
 | 
			
		||||
  shareFolders: any[],
 | 
			
		||||
  options: DownloadWithQueueOptions = {}
 | 
			
		||||
): Promise<void> {
 | 
			
		||||
  const { silent = false, showToasts = true } = options;
 | 
			
		||||
  const { silent = false, showToasts = true, sharePassword } = options;
 | 
			
		||||
  const downloadId = `share-folder-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
@@ -373,7 +397,7 @@ export async function downloadShareFolderWithQueue(
 | 
			
		||||
 | 
			
		||||
    for (const file of folderFiles) {
 | 
			
		||||
      try {
 | 
			
		||||
        const blob = await downloadFileAsBlobWithQueue(file.objectName, file.name);
 | 
			
		||||
        const blob = await downloadFileAsBlobWithQueue(file.objectName, file.name, false, undefined, sharePassword);
 | 
			
		||||
        zip.file(file.zipPath, blob);
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        console.error(`Error downloading file ${file.name}:`, error);
 | 
			
		||||
@@ -515,7 +539,8 @@ export async function bulkDownloadShareWithQueue(
 | 
			
		||||
  shareFolders: any[],
 | 
			
		||||
  zipName: string,
 | 
			
		||||
  onProgress?: (current: number, total: number) => void,
 | 
			
		||||
  wrapInFolder?: boolean
 | 
			
		||||
  wrapInFolder?: boolean,
 | 
			
		||||
  sharePassword?: string
 | 
			
		||||
): Promise<void> {
 | 
			
		||||
  try {
 | 
			
		||||
    const JSZip = (await import("jszip")).default;
 | 
			
		||||
@@ -562,7 +587,7 @@ export async function bulkDownloadShareWithQueue(
 | 
			
		||||
    for (let i = 0; i < allFilesToDownload.length; i++) {
 | 
			
		||||
      const file = allFilesToDownload[i];
 | 
			
		||||
      try {
 | 
			
		||||
        const blob = await downloadFileAsBlobWithQueue(file.objectName, file.name);
 | 
			
		||||
        const blob = await downloadFileAsBlobWithQueue(file.objectName, file.name, false, undefined, sharePassword);
 | 
			
		||||
        zip.file(file.zipPath, blob);
 | 
			
		||||
        onProgress?.(i + 1, allFilesToDownload.length);
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "palmr-monorepo",
 | 
			
		||||
  "version": "3.2.1-beta",
 | 
			
		||||
  "version": "3.2.2-beta",
 | 
			
		||||
  "description": "Palmr monorepo with Husky configuration",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "packageManager": "pnpm@10.6.0",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user