Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions platforms/esigner-api/src/controllers/FileController.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,8 +2,10 @@ import { Request, Response } from "express";
import { FileService, ReservedFileNameError } from "../services/FileService";
import multer from "multer";

export const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB limit

const upload = multer({
limits: { fileSize: 10 * 1024 * 1024 }, // 10MB limit
limits: { fileSize: MAX_FILE_SIZE },
storage: multer.memoryStorage(),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
});

Expand DownExpand Up@@ -200,7 +202,7 @@ export class FileController {
}

const signatures = await this.fileService.getFileSignatures(fileId);

res.json(signatures.map(sig => ({
id: sig.id,
userId: sig.userId,
Expand Down
32 changes: 27 additions & 5 deletions platforms/esigner-api/src/index.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,8 @@ import { config } from "dotenv";
import { AppDataSource } from "./database/data-source";
import path from "path";
import { AuthController } from "./controllers/AuthController";
import { FileController } from "./controllers/FileController";
import { FileController, MAX_FILE_SIZE } from "./controllers/FileController";
import multer from "multer";
import { InvitationController } from "./controllers/InvitationController";
import { SignatureController } from "./controllers/SignatureController";
import { UserController } from "./controllers/UserController";
Expand All@@ -24,12 +25,12 @@ AppDataSource.initialize()
.then(async () => {
console.log("Database connection established");
console.log("Web3 adapter initialized");

// Initialize platform eVault for eSigner
try {
const platformService = PlatformEVaultService.getInstance();
const exists = await platformService.checkPlatformEVaultExists();

if (!exists) {
console.log("🔧 Creating platform eVault for eSigner...");
const result = await platformService.createPlatformEVault();
Expand DownExpand Up@@ -61,8 +62,8 @@ app.use(
credentials: true,
}),
);
app.use(express.json({ limit: "50mb" }));
app.use(express.urlencoded({ limit: "50mb", extended: true }));
app.use(express.json({ limit: "20mb" }));
app.use(express.urlencoded({ limit: "20mb", extended: true }));

// Controllers
const authController = new AuthController();
Expand DownExpand Up@@ -105,6 +106,27 @@ app.post("/api/signatures/session", authGuard, signatureController.createSigning
app.get("/api/signatures/session/:id", signatureController.getSigningSessionStatus);
app.post("/api/signatures/callback", signatureController.handleSignedPayload);

// Global error handler for multer file size errors
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
if (err instanceof multer.MulterError && err.code === "LIMIT_FILE_SIZE") {
const maxSizeMB = Math.round(MAX_FILE_SIZE / (1024 * 1024));
return res.status(413).json({
error: `File size exceeds the maximum limit of ${maxSizeMB} MB`,
code: "LIMIT_FILE_SIZE",
maxSize: MAX_FILE_SIZE,
});
}
// Handle other multer errors
if (err instanceof multer.MulterError) {
return res.status(400).json({
error: err.message,
code: err.code,
});
}
// Pass other errors to the default handler
next(err);
});

// Start server
app.listen(port, () => {
console.log(`eSigner API server running on port ${port}`);
Expand Down
33 changes: 32 additions & 1 deletion platforms/esigner/src/lib/stores/files.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,7 +65,25 @@ export const fetchDocuments = async () => {
// Keep fetchFiles alias for backward compatibility
export const fetchFiles = fetchDocuments;

const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB limit

export class FileSizeError extends Error {
constructor(public fileSize: number, public maxSize: number = MAX_FILE_SIZE) {
const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);
const maxSizeMB = (maxSize / (1024 * 1024)).toFixed(0);
super(`File size (${fileSizeMB} MB) exceeds the maximum limit of ${maxSizeMB} MB`);
this.name = 'FileSizeError';
}
}

export const uploadFile = async (file: File, displayName?: string, description?: string) => {
// Client-side file size validation
if (file.size > MAX_FILE_SIZE) {
const err = new FileSizeError(file.size, MAX_FILE_SIZE);
error.set(err.message);
throw err;
}

try {
isLoading.set(true);
error.set(null);
Expand All@@ -84,7 +102,20 @@ export const uploadFile = async (file: File, displayName?: string, description?:
});
await fetchDocuments();
return response.data;
} catch (err) {
} catch (err: unknown) {
// Handle HTTP 413 Payload Too Large
if (err && typeof err === 'object' && 'response' in err) {
const axiosError = err as { response?: { status?: number; data?: { error?: string; maxSize?: number; fileSize?: number } } };
if (axiosError.response?.status === 413) {
const data = axiosError.response.data;
const fileSizeErr = new FileSizeError(
data?.fileSize || file.size,
data?.maxSize || MAX_FILE_SIZE
);
error.set(fileSizeErr.message);
throw fileSizeErr;
}
}
error.set(err instanceof Error ? err.message : 'Failed to upload file');
throw err;
} finally {
Expand Down
14 changes: 9 additions & 5 deletions platforms/esigner/src/routes/(protected)/files/new/+page.svelte
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import { isAuthenticated } from '$lib/stores/auth';
import { uploadFile } from '$lib/stores/files';
import { files, fetchFiles, uploadFile, FileSizeError } from '$lib/stores/files';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

rg -n '\b(files|fetchFiles)\b''platforms/esigner/src/routes/(protected)/files/new/+page.svelte'| grep -v 'import'

Repository: MetaState-Prototype-Project/prototype

Length of output: 1067


Remove unused imports files and fetchFiles.

The imports files and fetchFiles are not used in this file. Only uploadFile and FileSizeError are referenced. Remove the unused imports from line 5.

🤖 Prompt for AI Agents
In `@platforms/esigner/src/routes/`(protected)/files/new/+page.svelte at line 5,
The import line currently brings in unused symbols `files` and `fetchFiles`;
remove those two from the import so only `uploadFile` and `FileSizeError` are
imported (i.e., change the import that references `files, fetchFiles,
uploadFile, FileSizeError` to import just `uploadFile` and `FileSizeError`) to
eliminate dead imports and related lint warnings.

import { apiClient } from '$lib/utils/axios';
import { inviteSignees } from '$lib/stores/invitations';

Expand DownExpand Up@@ -59,7 +59,11 @@
}
} catch (err) {
console.error('Upload failed:', err);
alert('Failed to upload file');
if (err instanceof FileSizeError) {
alert(err.message);
} else {
alert('Failed to upload file. Please try again.');
}
throw err;
} finally {
isLoading = false;
Expand DownExpand Up@@ -126,7 +130,7 @@
alert('You cannot invite yourself. You are automatically added as a signee.');
return;
}

if (!selectedUsers.find(u => u.id === user.id)) {
selectedUsers = [...selectedUsers, user];
}
Expand All@@ -147,10 +151,10 @@
try {
isSubmitting = true;
const userIds = selectedUsers.map(u => u.id);

// Backend will automatically add owner as signee
await inviteSignees(selectedFile.id, userIds);

goto(`/files/${selectedFile.id}`);
} catch (err) {
console.error('Failed to create invitations:', err);
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions platforms/esigner-api/src/controllers/FileController.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,8 +2,10 @@ import { Request, Response } from "express";
import { FileService, ReservedFileNameError } from "../services/FileService";
import multer from "multer";

export const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB limit

const upload = multer({
limits: { fileSize: 10 * 1024 * 1024 }, // 10MB limit
limits: { fileSize: MAX_FILE_SIZE },
storage: multer.memoryStorage(),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
});

Expand DownExpand Up@@ -200,7 +202,7 @@ export class FileController {
}

const signatures = await this.fileService.getFileSignatures(fileId);

res.json(signatures.map(sig => ({
id: sig.id,
userId: sig.userId,
Expand Down
32 changes: 27 additions & 5 deletions platforms/esigner-api/src/index.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,8 @@ import { config } from "dotenv";
import { AppDataSource } from "./database/data-source";
import path from "path";
import { AuthController } from "./controllers/AuthController";
import { FileController } from "./controllers/FileController";
import { FileController, MAX_FILE_SIZE } from "./controllers/FileController";
import multer from "multer";
import { InvitationController } from "./controllers/InvitationController";
import { SignatureController } from "./controllers/SignatureController";
import { UserController } from "./controllers/UserController";
Expand All@@ -24,12 +25,12 @@ AppDataSource.initialize()
.then(async () => {
console.log("Database connection established");
console.log("Web3 adapter initialized");

// Initialize platform eVault for eSigner
try {
const platformService = PlatformEVaultService.getInstance();
const exists = await platformService.checkPlatformEVaultExists();

if (!exists) {
console.log("🔧 Creating platform eVault for eSigner...");
const result = await platformService.createPlatformEVault();
Expand DownExpand Up@@ -61,8 +62,8 @@ app.use(
credentials: true,
}),
);
app.use(express.json({ limit: "50mb" }));
app.use(express.urlencoded({ limit: "50mb", extended: true }));
app.use(express.json({ limit: "20mb" }));
app.use(express.urlencoded({ limit: "20mb", extended: true }));

// Controllers
const authController = new AuthController();
Expand DownExpand Up@@ -105,6 +106,27 @@ app.post("/api/signatures/session", authGuard, signatureController.createSigning
app.get("/api/signatures/session/:id", signatureController.getSigningSessionStatus);
app.post("/api/signatures/callback", signatureController.handleSignedPayload);

// Global error handler for multer file size errors
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
if (err instanceof multer.MulterError && err.code === "LIMIT_FILE_SIZE") {
const maxSizeMB = Math.round(MAX_FILE_SIZE / (1024 * 1024));
return res.status(413).json({
error: `File size exceeds the maximum limit of ${maxSizeMB} MB`,
code: "LIMIT_FILE_SIZE",
maxSize: MAX_FILE_SIZE,
});
}
// Handle other multer errors
if (err instanceof multer.MulterError) {
return res.status(400).json({
error: err.message,
code: err.code,
});
}
// Pass other errors to the default handler
next(err);
});

// Start server
app.listen(port, () => {
console.log(`eSigner API server running on port ${port}`);
Expand Down
33 changes: 32 additions & 1 deletion platforms/esigner/src/lib/stores/files.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,7 +65,25 @@ export const fetchDocuments = async () => {
// Keep fetchFiles alias for backward compatibility
export const fetchFiles = fetchDocuments;

const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB limit

export class FileSizeError extends Error {
constructor(public fileSize: number, public maxSize: number = MAX_FILE_SIZE) {
const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);
const maxSizeMB = (maxSize / (1024 * 1024)).toFixed(0);
super(`File size (${fileSizeMB} MB) exceeds the maximum limit of ${maxSizeMB} MB`);
this.name = 'FileSizeError';
}
}

export const uploadFile = async (file: File, displayName?: string, description?: string) => {
// Client-side file size validation
if (file.size > MAX_FILE_SIZE) {
const err = new FileSizeError(file.size, MAX_FILE_SIZE);
error.set(err.message);
throw err;
}

try {
isLoading.set(true);
error.set(null);
Expand All@@ -84,7 +102,20 @@ export const uploadFile = async (file: File, displayName?: string, description?:
});
await fetchDocuments();
return response.data;
} catch (err) {
} catch (err: unknown) {
// Handle HTTP 413 Payload Too Large
if (err && typeof err === 'object' && 'response' in err) {
const axiosError = err as { response?: { status?: number; data?: { error?: string; maxSize?: number; fileSize?: number } } };
if (axiosError.response?.status === 413) {
const data = axiosError.response.data;
const fileSizeErr = new FileSizeError(
data?.fileSize || file.size,
data?.maxSize || MAX_FILE_SIZE
);
error.set(fileSizeErr.message);
throw fileSizeErr;
}
}
error.set(err instanceof Error ? err.message : 'Failed to upload file');
throw err;
} finally {
Expand Down
14 changes: 9 additions & 5 deletions platforms/esigner/src/routes/(protected)/files/new/+page.svelte
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import { isAuthenticated } from '$lib/stores/auth';
import { uploadFile } from '$lib/stores/files';
import { files, fetchFiles, uploadFile, FileSizeError } from '$lib/stores/files';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

rg -n '\b(files|fetchFiles)\b''platforms/esigner/src/routes/(protected)/files/new/+page.svelte'| grep -v 'import'

Repository: MetaState-Prototype-Project/prototype

Length of output: 1067


Remove unused imports files and fetchFiles.

The imports files and fetchFiles are not used in this file. Only uploadFile and FileSizeError are referenced. Remove the unused imports from line 5.

🤖 Prompt for AI Agents
In `@platforms/esigner/src/routes/`(protected)/files/new/+page.svelte at line 5,
The import line currently brings in unused symbols `files` and `fetchFiles`;
remove those two from the import so only `uploadFile` and `FileSizeError` are
imported (i.e., change the import that references `files, fetchFiles,
uploadFile, FileSizeError` to import just `uploadFile` and `FileSizeError`) to
eliminate dead imports and related lint warnings.

import { apiClient } from '$lib/utils/axios';
import { inviteSignees } from '$lib/stores/invitations';

Expand DownExpand Up@@ -59,7 +59,11 @@
}
} catch (err) {
console.error('Upload failed:', err);
alert('Failed to upload file');
if (err instanceof FileSizeError) {
alert(err.message);
} else {
alert('Failed to upload file. Please try again.');
}
throw err;
} finally {
isLoading = false;
Expand DownExpand Up@@ -126,7 +130,7 @@
alert('You cannot invite yourself. You are automatically added as a signee.');
return;
}

if (!selectedUsers.find(u => u.id === user.id)) {
selectedUsers = [...selectedUsers, user];
}
Expand All@@ -147,10 +151,10 @@
try {
isSubmitting = true;
const userIds = selectedUsers.map(u => u.id);

// Backend will automatically add owner as signee
await inviteSignees(selectedFile.id, userIds);

goto(`/files/${selectedFile.id}`);
} catch (err) {
console.error('Failed to create invitations:', err);
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions platforms/esigner-api/src/controllers/FileController.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,8 +2,10 @@ import { Request, Response } from "express";
import { FileService, ReservedFileNameError } from "../services/FileService";
import multer from "multer";

export const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB limit

const upload = multer({
limits: { fileSize: 10 * 1024 * 1024 }, // 10MB limit
limits: { fileSize: MAX_FILE_SIZE },
storage: multer.memoryStorage(),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
});

Expand DownExpand Up@@ -200,7 +202,7 @@ export class FileController {
}

const signatures = await this.fileService.getFileSignatures(fileId);

res.json(signatures.map(sig => ({
id: sig.id,
userId: sig.userId,
Expand Down
32 changes: 27 additions & 5 deletions platforms/esigner-api/src/index.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,8 @@ import { config } from "dotenv";
import { AppDataSource } from "./database/data-source";
import path from "path";
import { AuthController } from "./controllers/AuthController";
import { FileController } from "./controllers/FileController";
import { FileController, MAX_FILE_SIZE } from "./controllers/FileController";
import multer from "multer";
import { InvitationController } from "./controllers/InvitationController";
import { SignatureController } from "./controllers/SignatureController";
import { UserController } from "./controllers/UserController";
Expand All@@ -24,12 +25,12 @@ AppDataSource.initialize()
.then(async () => {
console.log("Database connection established");
console.log("Web3 adapter initialized");

// Initialize platform eVault for eSigner
try {
const platformService = PlatformEVaultService.getInstance();
const exists = await platformService.checkPlatformEVaultExists();

if (!exists) {
console.log("🔧 Creating platform eVault for eSigner...");
const result = await platformService.createPlatformEVault();
Expand DownExpand Up@@ -61,8 +62,8 @@ app.use(
credentials: true,
}),
);
app.use(express.json({ limit: "50mb" }));
app.use(express.urlencoded({ limit: "50mb", extended: true }));
app.use(express.json({ limit: "20mb" }));
app.use(express.urlencoded({ limit: "20mb", extended: true }));

// Controllers
const authController = new AuthController();
Expand DownExpand Up@@ -105,6 +106,27 @@ app.post("/api/signatures/session", authGuard, signatureController.createSigning
app.get("/api/signatures/session/:id", signatureController.getSigningSessionStatus);
app.post("/api/signatures/callback", signatureController.handleSignedPayload);

// Global error handler for multer file size errors
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
if (err instanceof multer.MulterError && err.code === "LIMIT_FILE_SIZE") {
const maxSizeMB = Math.round(MAX_FILE_SIZE / (1024 * 1024));
return res.status(413).json({
error: `File size exceeds the maximum limit of ${maxSizeMB} MB`,
code: "LIMIT_FILE_SIZE",
maxSize: MAX_FILE_SIZE,
});
}
// Handle other multer errors
if (err instanceof multer.MulterError) {
return res.status(400).json({
error: err.message,
code: err.code,
});
}
// Pass other errors to the default handler
next(err);
});

// Start server
app.listen(port, () => {
console.log(`eSigner API server running on port ${port}`);
Expand Down
33 changes: 32 additions & 1 deletion platforms/esigner/src/lib/stores/files.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,7 +65,25 @@ export const fetchDocuments = async () => {
// Keep fetchFiles alias for backward compatibility
export const fetchFiles = fetchDocuments;

const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB limit

export class FileSizeError extends Error {
constructor(public fileSize: number, public maxSize: number = MAX_FILE_SIZE) {
const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);
const maxSizeMB = (maxSize / (1024 * 1024)).toFixed(0);
super(`File size (${fileSizeMB} MB) exceeds the maximum limit of ${maxSizeMB} MB`);
this.name = 'FileSizeError';
}
}

export const uploadFile = async (file: File, displayName?: string, description?: string) => {
// Client-side file size validation
if (file.size > MAX_FILE_SIZE) {
const err = new FileSizeError(file.size, MAX_FILE_SIZE);
error.set(err.message);
throw err;
}

try {
isLoading.set(true);
error.set(null);
Expand All@@ -84,7 +102,20 @@ export const uploadFile = async (file: File, displayName?: string, description?:
});
await fetchDocuments();
return response.data;
} catch (err) {
} catch (err: unknown) {
// Handle HTTP 413 Payload Too Large
if (err && typeof err === 'object' && 'response' in err) {
const axiosError = err as { response?: { status?: number; data?: { error?: string; maxSize?: number; fileSize?: number } } };
if (axiosError.response?.status === 413) {
const data = axiosError.response.data;
const fileSizeErr = new FileSizeError(
data?.fileSize || file.size,
data?.maxSize || MAX_FILE_SIZE
);
error.set(fileSizeErr.message);
throw fileSizeErr;
}
}
error.set(err instanceof Error ? err.message : 'Failed to upload file');
throw err;
} finally {
Expand Down
14 changes: 9 additions & 5 deletions platforms/esigner/src/routes/(protected)/files/new/+page.svelte
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import { isAuthenticated } from '$lib/stores/auth';
import { uploadFile } from '$lib/stores/files';
import { files, fetchFiles, uploadFile, FileSizeError } from '$lib/stores/files';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

rg -n '\b(files|fetchFiles)\b''platforms/esigner/src/routes/(protected)/files/new/+page.svelte'| grep -v 'import'

Repository: MetaState-Prototype-Project/prototype

Length of output: 1067


Remove unused imports files and fetchFiles.

The imports files and fetchFiles are not used in this file. Only uploadFile and FileSizeError are referenced. Remove the unused imports from line 5.

🤖 Prompt for AI Agents
In `@platforms/esigner/src/routes/`(protected)/files/new/+page.svelte at line 5,
The import line currently brings in unused symbols `files` and `fetchFiles`;
remove those two from the import so only `uploadFile` and `FileSizeError` are
imported (i.e., change the import that references `files, fetchFiles,
uploadFile, FileSizeError` to import just `uploadFile` and `FileSizeError`) to
eliminate dead imports and related lint warnings.

import { apiClient } from '$lib/utils/axios';
import { inviteSignees } from '$lib/stores/invitations';

Expand DownExpand Up@@ -59,7 +59,11 @@
}
} catch (err) {
console.error('Upload failed:', err);
alert('Failed to upload file');
if (err instanceof FileSizeError) {
alert(err.message);
} else {
alert('Failed to upload file. Please try again.');
}
throw err;
} finally {
isLoading = false;
Expand DownExpand Up@@ -126,7 +130,7 @@
alert('You cannot invite yourself. You are automatically added as a signee.');
return;
}

if (!selectedUsers.find(u => u.id === user.id)) {
selectedUsers = [...selectedUsers, user];
}
Expand All@@ -147,10 +151,10 @@
try {
isSubmitting = true;
const userIds = selectedUsers.map(u => u.id);

// Backend will automatically add owner as signee
await inviteSignees(selectedFile.id, userIds);

goto(`/files/${selectedFile.id}`);
} catch (err) {
console.error('Failed to create invitations:', err);
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions platforms/esigner-api/src/controllers/FileController.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,8 +2,10 @@ import { Request, Response } from "express";
import { FileService, ReservedFileNameError } from "../services/FileService";
import multer from "multer";

export const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB limit

const upload = multer({
limits: { fileSize: 10 * 1024 * 1024 }, // 10MB limit
limits: { fileSize: MAX_FILE_SIZE },
storage: multer.memoryStorage(),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
});

Expand DownExpand Up@@ -200,7 +202,7 @@ export class FileController {
}

const signatures = await this.fileService.getFileSignatures(fileId);

res.json(signatures.map(sig => ({
id: sig.id,
userId: sig.userId,
Expand Down
32 changes: 27 additions & 5 deletions platforms/esigner-api/src/index.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,8 @@ import { config } from "dotenv";
import { AppDataSource } from "./database/data-source";
import path from "path";
import { AuthController } from "./controllers/AuthController";
import { FileController } from "./controllers/FileController";
import { FileController, MAX_FILE_SIZE } from "./controllers/FileController";
import multer from "multer";
import { InvitationController } from "./controllers/InvitationController";
import { SignatureController } from "./controllers/SignatureController";
import { UserController } from "./controllers/UserController";
Expand All@@ -24,12 +25,12 @@ AppDataSource.initialize()
.then(async () => {
console.log("Database connection established");
console.log("Web3 adapter initialized");

// Initialize platform eVault for eSigner
try {
const platformService = PlatformEVaultService.getInstance();
const exists = await platformService.checkPlatformEVaultExists();

if (!exists) {
console.log("🔧 Creating platform eVault for eSigner...");
const result = await platformService.createPlatformEVault();
Expand DownExpand Up@@ -61,8 +62,8 @@ app.use(
credentials: true,
}),
);
app.use(express.json({ limit: "50mb" }));
app.use(express.urlencoded({ limit: "50mb", extended: true }));
app.use(express.json({ limit: "20mb" }));
app.use(express.urlencoded({ limit: "20mb", extended: true }));

// Controllers
const authController = new AuthController();
Expand DownExpand Up@@ -105,6 +106,27 @@ app.post("/api/signatures/session", authGuard, signatureController.createSigning
app.get("/api/signatures/session/:id", signatureController.getSigningSessionStatus);
app.post("/api/signatures/callback", signatureController.handleSignedPayload);

// Global error handler for multer file size errors
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
if (err instanceof multer.MulterError && err.code === "LIMIT_FILE_SIZE") {
const maxSizeMB = Math.round(MAX_FILE_SIZE / (1024 * 1024));
return res.status(413).json({
error: `File size exceeds the maximum limit of ${maxSizeMB} MB`,
code: "LIMIT_FILE_SIZE",
maxSize: MAX_FILE_SIZE,
});
}
// Handle other multer errors
if (err instanceof multer.MulterError) {
return res.status(400).json({
error: err.message,
code: err.code,
});
}
// Pass other errors to the default handler
next(err);
});

// Start server
app.listen(port, () => {
console.log(`eSigner API server running on port ${port}`);
Expand Down
33 changes: 32 additions & 1 deletion platforms/esigner/src/lib/stores/files.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,7 +65,25 @@ export const fetchDocuments = async () => {
// Keep fetchFiles alias for backward compatibility
export const fetchFiles = fetchDocuments;

const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB limit

export class FileSizeError extends Error {
constructor(public fileSize: number, public maxSize: number = MAX_FILE_SIZE) {
const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);
const maxSizeMB = (maxSize / (1024 * 1024)).toFixed(0);
super(`File size (${fileSizeMB} MB) exceeds the maximum limit of ${maxSizeMB} MB`);
this.name = 'FileSizeError';
}
}

export const uploadFile = async (file: File, displayName?: string, description?: string) => {
// Client-side file size validation
if (file.size > MAX_FILE_SIZE) {
const err = new FileSizeError(file.size, MAX_FILE_SIZE);
error.set(err.message);
throw err;
}

try {
isLoading.set(true);
error.set(null);
Expand All@@ -84,7 +102,20 @@ export const uploadFile = async (file: File, displayName?: string, description?:
});
await fetchDocuments();
return response.data;
} catch (err) {
} catch (err: unknown) {
// Handle HTTP 413 Payload Too Large
if (err && typeof err === 'object' && 'response' in err) {
const axiosError = err as { response?: { status?: number; data?: { error?: string; maxSize?: number; fileSize?: number } } };
if (axiosError.response?.status === 413) {
const data = axiosError.response.data;
const fileSizeErr = new FileSizeError(
data?.fileSize || file.size,
data?.maxSize || MAX_FILE_SIZE
);
error.set(fileSizeErr.message);
throw fileSizeErr;
}
}
error.set(err instanceof Error ? err.message : 'Failed to upload file');
throw err;
} finally {
Expand Down
14 changes: 9 additions & 5 deletions platforms/esigner/src/routes/(protected)/files/new/+page.svelte
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import { isAuthenticated } from '$lib/stores/auth';
import { uploadFile } from '$lib/stores/files';
import { files, fetchFiles, uploadFile, FileSizeError } from '$lib/stores/files';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

rg -n '\b(files|fetchFiles)\b''platforms/esigner/src/routes/(protected)/files/new/+page.svelte'| grep -v 'import'

Repository: MetaState-Prototype-Project/prototype

Length of output: 1067


Remove unused imports files and fetchFiles.

The imports files and fetchFiles are not used in this file. Only uploadFile and FileSizeError are referenced. Remove the unused imports from line 5.

🤖 Prompt for AI Agents
In `@platforms/esigner/src/routes/`(protected)/files/new/+page.svelte at line 5,
The import line currently brings in unused symbols `files` and `fetchFiles`;
remove those two from the import so only `uploadFile` and `FileSizeError` are
imported (i.e., change the import that references `files, fetchFiles,
uploadFile, FileSizeError` to import just `uploadFile` and `FileSizeError`) to
eliminate dead imports and related lint warnings.

import { apiClient } from '$lib/utils/axios';
import { inviteSignees } from '$lib/stores/invitations';

Expand DownExpand Up@@ -59,7 +59,11 @@
}
} catch (err) {
console.error('Upload failed:', err);
alert('Failed to upload file');
if (err instanceof FileSizeError) {
alert(err.message);
} else {
alert('Failed to upload file. Please try again.');
}
throw err;
} finally {
isLoading = false;
Expand DownExpand Up@@ -126,7 +130,7 @@
alert('You cannot invite yourself. You are automatically added as a signee.');
return;
}

if (!selectedUsers.find(u => u.id === user.id)) {
selectedUsers = [...selectedUsers, user];
}
Expand All@@ -147,10 +151,10 @@
try {
isSubmitting = true;
const userIds = selectedUsers.map(u => u.id);

// Backend will automatically add owner as signee
await inviteSignees(selectedFile.id, userIds);

goto(`/files/${selectedFile.id}`);
} catch (err) {
console.error('Failed to create invitations:', err);
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions platforms/esigner-api/src/controllers/FileController.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,8 +2,10 @@ import { Request, Response } from "express";
import { FileService, ReservedFileNameError } from "../services/FileService";
import multer from "multer";

export const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB limit

const upload = multer({
limits: { fileSize: 10 * 1024 * 1024 }, // 10MB limit
limits: { fileSize: MAX_FILE_SIZE },
storage: multer.memoryStorage(),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
});

Expand DownExpand Up@@ -200,7 +202,7 @@ export class FileController {
}

const signatures = await this.fileService.getFileSignatures(fileId);

res.json(signatures.map(sig => ({
id: sig.id,
userId: sig.userId,
Expand Down
32 changes: 27 additions & 5 deletions platforms/esigner-api/src/index.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,8 @@ import { config } from "dotenv";
import { AppDataSource } from "./database/data-source";
import path from "path";
import { AuthController } from "./controllers/AuthController";
import { FileController } from "./controllers/FileController";
import { FileController, MAX_FILE_SIZE } from "./controllers/FileController";
import multer from "multer";
import { InvitationController } from "./controllers/InvitationController";
import { SignatureController } from "./controllers/SignatureController";
import { UserController } from "./controllers/UserController";
Expand All@@ -24,12 +25,12 @@ AppDataSource.initialize()
.then(async () => {
console.log("Database connection established");
console.log("Web3 adapter initialized");

// Initialize platform eVault for eSigner
try {
const platformService = PlatformEVaultService.getInstance();
const exists = await platformService.checkPlatformEVaultExists();

if (!exists) {
console.log("🔧 Creating platform eVault for eSigner...");
const result = await platformService.createPlatformEVault();
Expand DownExpand Up@@ -61,8 +62,8 @@ app.use(
credentials: true,
}),
);
app.use(express.json({ limit: "50mb" }));
app.use(express.urlencoded({ limit: "50mb", extended: true }));
app.use(express.json({ limit: "20mb" }));
app.use(express.urlencoded({ limit: "20mb", extended: true }));

// Controllers
const authController = new AuthController();
Expand DownExpand Up@@ -105,6 +106,27 @@ app.post("/api/signatures/session", authGuard, signatureController.createSigning
app.get("/api/signatures/session/:id", signatureController.getSigningSessionStatus);
app.post("/api/signatures/callback", signatureController.handleSignedPayload);

// Global error handler for multer file size errors
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
if (err instanceof multer.MulterError && err.code === "LIMIT_FILE_SIZE") {
const maxSizeMB = Math.round(MAX_FILE_SIZE / (1024 * 1024));
return res.status(413).json({
error: `File size exceeds the maximum limit of ${maxSizeMB} MB`,
code: "LIMIT_FILE_SIZE",
maxSize: MAX_FILE_SIZE,
});
}
// Handle other multer errors
if (err instanceof multer.MulterError) {
return res.status(400).json({
error: err.message,
code: err.code,
});
}
// Pass other errors to the default handler
next(err);
});

// Start server
app.listen(port, () => {
console.log(`eSigner API server running on port ${port}`);
Expand Down
33 changes: 32 additions & 1 deletion platforms/esigner/src/lib/stores/files.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,7 +65,25 @@ export const fetchDocuments = async () => {
// Keep fetchFiles alias for backward compatibility
export const fetchFiles = fetchDocuments;

const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB limit

export class FileSizeError extends Error {
constructor(public fileSize: number, public maxSize: number = MAX_FILE_SIZE) {
const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);
const maxSizeMB = (maxSize / (1024 * 1024)).toFixed(0);
super(`File size (${fileSizeMB} MB) exceeds the maximum limit of ${maxSizeMB} MB`);
this.name = 'FileSizeError';
}
}

export const uploadFile = async (file: File, displayName?: string, description?: string) => {
// Client-side file size validation
if (file.size > MAX_FILE_SIZE) {
const err = new FileSizeError(file.size, MAX_FILE_SIZE);
error.set(err.message);
throw err;
}

try {
isLoading.set(true);
error.set(null);
Expand All@@ -84,7 +102,20 @@ export const uploadFile = async (file: File, displayName?: string, description?:
});
await fetchDocuments();
return response.data;
} catch (err) {
} catch (err: unknown) {
// Handle HTTP 413 Payload Too Large
if (err && typeof err === 'object' && 'response' in err) {
const axiosError = err as { response?: { status?: number; data?: { error?: string; maxSize?: number; fileSize?: number } } };
if (axiosError.response?.status === 413) {
const data = axiosError.response.data;
const fileSizeErr = new FileSizeError(
data?.fileSize || file.size,
data?.maxSize || MAX_FILE_SIZE
);
error.set(fileSizeErr.message);
throw fileSizeErr;
}
}
error.set(err instanceof Error ? err.message : 'Failed to upload file');
throw err;
} finally {
Expand Down
14 changes: 9 additions & 5 deletions platforms/esigner/src/routes/(protected)/files/new/+page.svelte
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import { isAuthenticated } from '$lib/stores/auth';
import { uploadFile } from '$lib/stores/files';
import { files, fetchFiles, uploadFile, FileSizeError } from '$lib/stores/files';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

rg -n '\b(files|fetchFiles)\b''platforms/esigner/src/routes/(protected)/files/new/+page.svelte'| grep -v 'import'

Repository: MetaState-Prototype-Project/prototype

Length of output: 1067


Remove unused imports files and fetchFiles.

The imports files and fetchFiles are not used in this file. Only uploadFile and FileSizeError are referenced. Remove the unused imports from line 5.

🤖 Prompt for AI Agents
In `@platforms/esigner/src/routes/`(protected)/files/new/+page.svelte at line 5,
The import line currently brings in unused symbols `files` and `fetchFiles`;
remove those two from the import so only `uploadFile` and `FileSizeError` are
imported (i.e., change the import that references `files, fetchFiles,
uploadFile, FileSizeError` to import just `uploadFile` and `FileSizeError`) to
eliminate dead imports and related lint warnings.

import { apiClient } from '$lib/utils/axios';
import { inviteSignees } from '$lib/stores/invitations';

Expand DownExpand Up@@ -59,7 +59,11 @@
}
} catch (err) {
console.error('Upload failed:', err);
alert('Failed to upload file');
if (err instanceof FileSizeError) {
alert(err.message);
} else {
alert('Failed to upload file. Please try again.');
}
throw err;
} finally {
isLoading = false;
Expand DownExpand Up@@ -126,7 +130,7 @@
alert('You cannot invite yourself. You are automatically added as a signee.');
return;
}

if (!selectedUsers.find(u => u.id === user.id)) {
selectedUsers = [...selectedUsers, user];
}
Expand All@@ -147,10 +151,10 @@
try {
isSubmitting = true;
const userIds = selectedUsers.map(u => u.id);

// Backend will automatically add owner as signee
await inviteSignees(selectedFile.id, userIds);

goto(`/files/${selectedFile.id}`);
} catch (err) {
console.error('Failed to create invitations:', err);
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions platforms/esigner-api/src/controllers/FileController.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,8 +2,10 @@ import { Request, Response } from "express";
import { FileService, ReservedFileNameError } from "../services/FileService";
import multer from "multer";

export const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB limit

const upload = multer({
limits: { fileSize: 10 * 1024 * 1024 }, // 10MB limit
limits: { fileSize: MAX_FILE_SIZE },
storage: multer.memoryStorage(),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
});

Expand DownExpand Up@@ -200,7 +202,7 @@ export class FileController {
}

const signatures = await this.fileService.getFileSignatures(fileId);

res.json(signatures.map(sig => ({
id: sig.id,
userId: sig.userId,
Expand Down
32 changes: 27 additions & 5 deletions platforms/esigner-api/src/index.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,8 @@ import { config } from "dotenv";
import { AppDataSource } from "./database/data-source";
import path from "path";
import { AuthController } from "./controllers/AuthController";
import { FileController } from "./controllers/FileController";
import { FileController, MAX_FILE_SIZE } from "./controllers/FileController";
import multer from "multer";
import { InvitationController } from "./controllers/InvitationController";
import { SignatureController } from "./controllers/SignatureController";
import { UserController } from "./controllers/UserController";
Expand All@@ -24,12 +25,12 @@ AppDataSource.initialize()
.then(async () => {
console.log("Database connection established");
console.log("Web3 adapter initialized");

// Initialize platform eVault for eSigner
try {
const platformService = PlatformEVaultService.getInstance();
const exists = await platformService.checkPlatformEVaultExists();

if (!exists) {
console.log("🔧 Creating platform eVault for eSigner...");
const result = await platformService.createPlatformEVault();
Expand DownExpand Up@@ -61,8 +62,8 @@ app.use(
credentials: true,
}),
);
app.use(express.json({ limit: "50mb" }));
app.use(express.urlencoded({ limit: "50mb", extended: true }));
app.use(express.json({ limit: "20mb" }));
app.use(express.urlencoded({ limit: "20mb", extended: true }));

// Controllers
const authController = new AuthController();
Expand DownExpand Up@@ -105,6 +106,27 @@ app.post("/api/signatures/session", authGuard, signatureController.createSigning
app.get("/api/signatures/session/:id", signatureController.getSigningSessionStatus);
app.post("/api/signatures/callback", signatureController.handleSignedPayload);

// Global error handler for multer file size errors
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
if (err instanceof multer.MulterError && err.code === "LIMIT_FILE_SIZE") {
const maxSizeMB = Math.round(MAX_FILE_SIZE / (1024 * 1024));
return res.status(413).json({
error: `File size exceeds the maximum limit of ${maxSizeMB} MB`,
code: "LIMIT_FILE_SIZE",
maxSize: MAX_FILE_SIZE,
});
}
// Handle other multer errors
if (err instanceof multer.MulterError) {
return res.status(400).json({
error: err.message,
code: err.code,
});
}
// Pass other errors to the default handler
next(err);
});

// Start server
app.listen(port, () => {
console.log(`eSigner API server running on port ${port}`);
Expand Down
33 changes: 32 additions & 1 deletion platforms/esigner/src/lib/stores/files.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,7 +65,25 @@ export const fetchDocuments = async () => {
// Keep fetchFiles alias for backward compatibility
export const fetchFiles = fetchDocuments;

const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB limit

export class FileSizeError extends Error {
constructor(public fileSize: number, public maxSize: number = MAX_FILE_SIZE) {
const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);
const maxSizeMB = (maxSize / (1024 * 1024)).toFixed(0);
super(`File size (${fileSizeMB} MB) exceeds the maximum limit of ${maxSizeMB} MB`);
this.name = 'FileSizeError';
}
}

export const uploadFile = async (file: File, displayName?: string, description?: string) => {
// Client-side file size validation
if (file.size > MAX_FILE_SIZE) {
const err = new FileSizeError(file.size, MAX_FILE_SIZE);
error.set(err.message);
throw err;
}

try {
isLoading.set(true);
error.set(null);
Expand All@@ -84,7 +102,20 @@ export const uploadFile = async (file: File, displayName?: string, description?:
});
await fetchDocuments();
return response.data;
} catch (err) {
} catch (err: unknown) {
// Handle HTTP 413 Payload Too Large
if (err && typeof err === 'object' && 'response' in err) {
const axiosError = err as { response?: { status?: number; data?: { error?: string; maxSize?: number; fileSize?: number } } };
if (axiosError.response?.status === 413) {
const data = axiosError.response.data;
const fileSizeErr = new FileSizeError(
data?.fileSize || file.size,
data?.maxSize || MAX_FILE_SIZE
);
error.set(fileSizeErr.message);
throw fileSizeErr;
}
}
error.set(err instanceof Error ? err.message : 'Failed to upload file');
throw err;
} finally {
Expand Down
14 changes: 9 additions & 5 deletions platforms/esigner/src/routes/(protected)/files/new/+page.svelte
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import { isAuthenticated } from '$lib/stores/auth';
import { uploadFile } from '$lib/stores/files';
import { files, fetchFiles, uploadFile, FileSizeError } from '$lib/stores/files';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

rg -n '\b(files|fetchFiles)\b''platforms/esigner/src/routes/(protected)/files/new/+page.svelte'| grep -v 'import'

Repository: MetaState-Prototype-Project/prototype

Length of output: 1067


Remove unused imports files and fetchFiles.

The imports files and fetchFiles are not used in this file. Only uploadFile and FileSizeError are referenced. Remove the unused imports from line 5.

🤖 Prompt for AI Agents
In `@platforms/esigner/src/routes/`(protected)/files/new/+page.svelte at line 5,
The import line currently brings in unused symbols `files` and `fetchFiles`;
remove those two from the import so only `uploadFile` and `FileSizeError` are
imported (i.e., change the import that references `files, fetchFiles,
uploadFile, FileSizeError` to import just `uploadFile` and `FileSizeError`) to
eliminate dead imports and related lint warnings.

import { apiClient } from '$lib/utils/axios';
import { inviteSignees } from '$lib/stores/invitations';

Expand DownExpand Up@@ -59,7 +59,11 @@
}
} catch (err) {
console.error('Upload failed:', err);
alert('Failed to upload file');
if (err instanceof FileSizeError) {
alert(err.message);
} else {
alert('Failed to upload file. Please try again.');
}
throw err;
} finally {
isLoading = false;
Expand DownExpand Up@@ -126,7 +130,7 @@
alert('You cannot invite yourself. You are automatically added as a signee.');
return;
}

if (!selectedUsers.find(u => u.id === user.id)) {
selectedUsers = [...selectedUsers, user];
}
Expand All@@ -147,10 +151,10 @@
try {
isSubmitting = true;
const userIds = selectedUsers.map(u => u.id);

// Backend will automatically add owner as signee
await inviteSignees(selectedFile.id, userIds);

goto(`/files/${selectedFile.id}`);
} catch (err) {
console.error('Failed to create invitations:', err);
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions platforms/esigner-api/src/controllers/FileController.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,8 +2,10 @@ import { Request, Response } from "express";
import { FileService, ReservedFileNameError } from "../services/FileService";
import multer from "multer";

export const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB limit

const upload = multer({
limits: { fileSize: 10 * 1024 * 1024 }, // 10MB limit
limits: { fileSize: MAX_FILE_SIZE },
storage: multer.memoryStorage(),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
});

Expand DownExpand Up@@ -200,7 +202,7 @@ export class FileController {
}

const signatures = await this.fileService.getFileSignatures(fileId);

res.json(signatures.map(sig => ({
id: sig.id,
userId: sig.userId,
Expand Down
32 changes: 27 additions & 5 deletions platforms/esigner-api/src/index.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,8 @@ import { config } from "dotenv";
import { AppDataSource } from "./database/data-source";
import path from "path";
import { AuthController } from "./controllers/AuthController";
import { FileController } from "./controllers/FileController";
import { FileController, MAX_FILE_SIZE } from "./controllers/FileController";
import multer from "multer";
import { InvitationController } from "./controllers/InvitationController";
import { SignatureController } from "./controllers/SignatureController";
import { UserController } from "./controllers/UserController";
Expand All@@ -24,12 +25,12 @@ AppDataSource.initialize()
.then(async () => {
console.log("Database connection established");
console.log("Web3 adapter initialized");

// Initialize platform eVault for eSigner
try {
const platformService = PlatformEVaultService.getInstance();
const exists = await platformService.checkPlatformEVaultExists();

if (!exists) {
console.log("🔧 Creating platform eVault for eSigner...");
const result = await platformService.createPlatformEVault();
Expand DownExpand Up@@ -61,8 +62,8 @@ app.use(
credentials: true,
}),
);
app.use(express.json({ limit: "50mb" }));
app.use(express.urlencoded({ limit: "50mb", extended: true }));
app.use(express.json({ limit: "20mb" }));
app.use(express.urlencoded({ limit: "20mb", extended: true }));

// Controllers
const authController = new AuthController();
Expand DownExpand Up@@ -105,6 +106,27 @@ app.post("/api/signatures/session", authGuard, signatureController.createSigning
app.get("/api/signatures/session/:id", signatureController.getSigningSessionStatus);
app.post("/api/signatures/callback", signatureController.handleSignedPayload);

// Global error handler for multer file size errors
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
if (err instanceof multer.MulterError && err.code === "LIMIT_FILE_SIZE") {
const maxSizeMB = Math.round(MAX_FILE_SIZE / (1024 * 1024));
return res.status(413).json({
error: `File size exceeds the maximum limit of ${maxSizeMB} MB`,
code: "LIMIT_FILE_SIZE",
maxSize: MAX_FILE_SIZE,
});
}
// Handle other multer errors
if (err instanceof multer.MulterError) {
return res.status(400).json({
error: err.message,
code: err.code,
});
}
// Pass other errors to the default handler
next(err);
});

// Start server
app.listen(port, () => {
console.log(`eSigner API server running on port ${port}`);
Expand Down
33 changes: 32 additions & 1 deletion platforms/esigner/src/lib/stores/files.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,7 +65,25 @@ export const fetchDocuments = async () => {
// Keep fetchFiles alias for backward compatibility
export const fetchFiles = fetchDocuments;

const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB limit

export class FileSizeError extends Error {
constructor(public fileSize: number, public maxSize: number = MAX_FILE_SIZE) {
const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);
const maxSizeMB = (maxSize / (1024 * 1024)).toFixed(0);
super(`File size (${fileSizeMB} MB) exceeds the maximum limit of ${maxSizeMB} MB`);
this.name = 'FileSizeError';
}
}

export const uploadFile = async (file: File, displayName?: string, description?: string) => {
// Client-side file size validation
if (file.size > MAX_FILE_SIZE) {
const err = new FileSizeError(file.size, MAX_FILE_SIZE);
error.set(err.message);
throw err;
}

try {
isLoading.set(true);
error.set(null);
Expand All@@ -84,7 +102,20 @@ export const uploadFile = async (file: File, displayName?: string, description?:
});
await fetchDocuments();
return response.data;
} catch (err) {
} catch (err: unknown) {
// Handle HTTP 413 Payload Too Large
if (err && typeof err === 'object' && 'response' in err) {
const axiosError = err as { response?: { status?: number; data?: { error?: string; maxSize?: number; fileSize?: number } } };
if (axiosError.response?.status === 413) {
const data = axiosError.response.data;
const fileSizeErr = new FileSizeError(
data?.fileSize || file.size,
data?.maxSize || MAX_FILE_SIZE
);
error.set(fileSizeErr.message);
throw fileSizeErr;
}
}
error.set(err instanceof Error ? err.message : 'Failed to upload file');
throw err;
} finally {
Expand Down
14 changes: 9 additions & 5 deletions platforms/esigner/src/routes/(protected)/files/new/+page.svelte
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import { isAuthenticated } from '$lib/stores/auth';
import { uploadFile } from '$lib/stores/files';
import { files, fetchFiles, uploadFile, FileSizeError } from '$lib/stores/files';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

rg -n '\b(files|fetchFiles)\b''platforms/esigner/src/routes/(protected)/files/new/+page.svelte'| grep -v 'import'

Repository: MetaState-Prototype-Project/prototype

Length of output: 1067


Remove unused imports files and fetchFiles.

The imports files and fetchFiles are not used in this file. Only uploadFile and FileSizeError are referenced. Remove the unused imports from line 5.

🤖 Prompt for AI Agents
In `@platforms/esigner/src/routes/`(protected)/files/new/+page.svelte at line 5,
The import line currently brings in unused symbols `files` and `fetchFiles`;
remove those two from the import so only `uploadFile` and `FileSizeError` are
imported (i.e., change the import that references `files, fetchFiles,
uploadFile, FileSizeError` to import just `uploadFile` and `FileSizeError`) to
eliminate dead imports and related lint warnings.

import { apiClient } from '$lib/utils/axios';
import { inviteSignees } from '$lib/stores/invitations';

Expand DownExpand Up@@ -59,7 +59,11 @@
}
} catch (err) {
console.error('Upload failed:', err);
alert('Failed to upload file');
if (err instanceof FileSizeError) {
alert(err.message);
} else {
alert('Failed to upload file. Please try again.');
}
throw err;
} finally {
isLoading = false;
Expand DownExpand Up@@ -126,7 +130,7 @@
alert('You cannot invite yourself. You are automatically added as a signee.');
return;
}

if (!selectedUsers.find(u => u.id === user.id)) {
selectedUsers = [...selectedUsers, user];
}
Expand All@@ -147,10 +151,10 @@
try {
isSubmitting = true;
const userIds = selectedUsers.map(u => u.id);

// Backend will automatically add owner as signee
await inviteSignees(selectedFile.id, userIds);

goto(`/files/${selectedFile.id}`);
} catch (err) {
console.error('Failed to create invitations:', err);
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions platforms/esigner-api/src/controllers/FileController.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,8 +2,10 @@ import { Request, Response } from "express";
import { FileService, ReservedFileNameError } from "../services/FileService";
import multer from "multer";

export const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB limit

const upload = multer({
limits: { fileSize: 10 * 1024 * 1024 }, // 10MB limit
limits: { fileSize: MAX_FILE_SIZE },
storage: multer.memoryStorage(),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
});

Expand DownExpand Up@@ -200,7 +202,7 @@ export class FileController {
}

const signatures = await this.fileService.getFileSignatures(fileId);

res.json(signatures.map(sig => ({
id: sig.id,
userId: sig.userId,
Expand Down
32 changes: 27 additions & 5 deletions platforms/esigner-api/src/index.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,8 @@ import { config } from "dotenv";
import { AppDataSource } from "./database/data-source";
import path from "path";
import { AuthController } from "./controllers/AuthController";
import { FileController } from "./controllers/FileController";
import { FileController, MAX_FILE_SIZE } from "./controllers/FileController";
import multer from "multer";
import { InvitationController } from "./controllers/InvitationController";
import { SignatureController } from "./controllers/SignatureController";
import { UserController } from "./controllers/UserController";
Expand All@@ -24,12 +25,12 @@ AppDataSource.initialize()
.then(async () => {
console.log("Database connection established");
console.log("Web3 adapter initialized");

// Initialize platform eVault for eSigner
try {
const platformService = PlatformEVaultService.getInstance();
const exists = await platformService.checkPlatformEVaultExists();

if (!exists) {
console.log("🔧 Creating platform eVault for eSigner...");
const result = await platformService.createPlatformEVault();
Expand DownExpand Up@@ -61,8 +62,8 @@ app.use(
credentials: true,
}),
);
app.use(express.json({ limit: "50mb" }));
app.use(express.urlencoded({ limit: "50mb", extended: true }));
app.use(express.json({ limit: "20mb" }));
app.use(express.urlencoded({ limit: "20mb", extended: true }));

// Controllers
const authController = new AuthController();
Expand DownExpand Up@@ -105,6 +106,27 @@ app.post("/api/signatures/session", authGuard, signatureController.createSigning
app.get("/api/signatures/session/:id", signatureController.getSigningSessionStatus);
app.post("/api/signatures/callback", signatureController.handleSignedPayload);

// Global error handler for multer file size errors
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
if (err instanceof multer.MulterError && err.code === "LIMIT_FILE_SIZE") {
const maxSizeMB = Math.round(MAX_FILE_SIZE / (1024 * 1024));
return res.status(413).json({
error: `File size exceeds the maximum limit of ${maxSizeMB} MB`,
code: "LIMIT_FILE_SIZE",
maxSize: MAX_FILE_SIZE,
});
}
// Handle other multer errors
if (err instanceof multer.MulterError) {
return res.status(400).json({
error: err.message,
code: err.code,
});
}
// Pass other errors to the default handler
next(err);
});

// Start server
app.listen(port, () => {
console.log(`eSigner API server running on port ${port}`);
Expand Down
33 changes: 32 additions & 1 deletion platforms/esigner/src/lib/stores/files.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,7 +65,25 @@ export const fetchDocuments = async () => {
// Keep fetchFiles alias for backward compatibility
export const fetchFiles = fetchDocuments;

const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB limit

export class FileSizeError extends Error {
constructor(public fileSize: number, public maxSize: number = MAX_FILE_SIZE) {
const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);
const maxSizeMB = (maxSize / (1024 * 1024)).toFixed(0);
super(`File size (${fileSizeMB} MB) exceeds the maximum limit of ${maxSizeMB} MB`);
this.name = 'FileSizeError';
}
}

export const uploadFile = async (file: File, displayName?: string, description?: string) => {
// Client-side file size validation
if (file.size > MAX_FILE_SIZE) {
const err = new FileSizeError(file.size, MAX_FILE_SIZE);
error.set(err.message);
throw err;
}

try {
isLoading.set(true);
error.set(null);
Expand All@@ -84,7 +102,20 @@ export const uploadFile = async (file: File, displayName?: string, description?:
});
await fetchDocuments();
return response.data;
} catch (err) {
} catch (err: unknown) {
// Handle HTTP 413 Payload Too Large
if (err && typeof err === 'object' && 'response' in err) {
const axiosError = err as { response?: { status?: number; data?: { error?: string; maxSize?: number; fileSize?: number } } };
if (axiosError.response?.status === 413) {
const data = axiosError.response.data;
const fileSizeErr = new FileSizeError(
data?.fileSize || file.size,
data?.maxSize || MAX_FILE_SIZE
);
error.set(fileSizeErr.message);
throw fileSizeErr;
}
}
error.set(err instanceof Error ? err.message : 'Failed to upload file');
throw err;
} finally {
Expand Down
14 changes: 9 additions & 5 deletions platforms/esigner/src/routes/(protected)/files/new/+page.svelte
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import { isAuthenticated } from '$lib/stores/auth';
import { uploadFile } from '$lib/stores/files';
import { files, fetchFiles, uploadFile, FileSizeError } from '$lib/stores/files';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

rg -n '\b(files|fetchFiles)\b''platforms/esigner/src/routes/(protected)/files/new/+page.svelte'| grep -v 'import'

Repository: MetaState-Prototype-Project/prototype

Length of output: 1067


Remove unused imports files and fetchFiles.

The imports files and fetchFiles are not used in this file. Only uploadFile and FileSizeError are referenced. Remove the unused imports from line 5.

🤖 Prompt for AI Agents
In `@platforms/esigner/src/routes/`(protected)/files/new/+page.svelte at line 5,
The import line currently brings in unused symbols `files` and `fetchFiles`;
remove those two from the import so only `uploadFile` and `FileSizeError` are
imported (i.e., change the import that references `files, fetchFiles,
uploadFile, FileSizeError` to import just `uploadFile` and `FileSizeError`) to
eliminate dead imports and related lint warnings.

import { apiClient } from '$lib/utils/axios';
import { inviteSignees } from '$lib/stores/invitations';

Expand DownExpand Up@@ -59,7 +59,11 @@
}
} catch (err) {
console.error('Upload failed:', err);
alert('Failed to upload file');
if (err instanceof FileSizeError) {
alert(err.message);
} else {
alert('Failed to upload file. Please try again.');
}
throw err;
} finally {
isLoading = false;
Expand DownExpand Up@@ -126,7 +130,7 @@
alert('You cannot invite yourself. You are automatically added as a signee.');
return;
}

if (!selectedUsers.find(u => u.id === user.id)) {
selectedUsers = [...selectedUsers, user];
}
Expand All@@ -147,10 +151,10 @@
try {
isSubmitting = true;
const userIds = selectedUsers.map(u => u.id);

// Backend will automatically add owner as signee
await inviteSignees(selectedFile.id, userIds);

goto(`/files/${selectedFile.id}`);
} catch (err) {
console.error('Failed to create invitations:', err);
Expand Down