MCPcopy
hub / github.com/lobehub/lobehub / uploadLocalFile

Function uploadLocalFile

apps/cli/src/utils/uploadLocalFile.ts:57–125  ·  view source on GitHub ↗
(
  client: TrpcClient,
  filePath: string,
  options: UploadLocalFileOptions = {},
)

Source from the content-addressed store, hash-verified

55 * @returns the created file record
56 */
57export const uploadLocalFile = async (
58 client: TrpcClient,
59 filePath: string,
60 options: UploadLocalFileOptions = {},
61) => {
62 const resolved = path.resolve(filePath);
63 if (!fs.existsSync(resolved)) {
64 throw new Error(`File not found: ${resolved}`);
65 }
66
67 const stat = fs.statSync(resolved);
68 if (!stat.isFile()) {
69 throw new Error(`Not a file: ${resolved}`);
70 }
71
72 const fileName = path.basename(resolved);
73 const fileBuffer = fs.readFileSync(resolved);
74
75 // Compute SHA-256 hash for deduplication
76 const hash = crypto.createHash('sha256').update(fileBuffer).digest('hex');
77
78 const ext = path.extname(fileName).toLowerCase().slice(1);
79 const fileType = detectMimeType(fileName);
80
81 const date = new Date().toLocaleDateString('en-CA'); // YYYY-MM-DD
82
83 // 1. Dedup: if the same bytes are already stored (and the object still
84 // exists), skip the S3 upload entirely and reuse the existing url.
85 const existing = (await client.file.checkFileHash.mutate({ hash })) as {
86 isExist?: boolean;
87 url?: string;
88 };
89
90 let pathname: string;
91 if (existing?.isExist && existing.url) {
92 pathname = existing.url;
93 } else {
94 // 2. Get a pre-signed upload URL and PUT the bytes to S3
95 pathname = ext ? `files/${date}/${hash}.${ext}` : `files/${date}/${hash}`;
96 const presigned = await client.upload.createS3PreSignedUrl.mutate({ pathname });
97
98 const presignedUrl = typeof presigned === 'string' ? presigned : (presigned as any).url;
99 const uploadRes = await fetch(presignedUrl, {
100 body: fileBuffer,
101 headers: { 'Content-Type': fileType },
102 method: 'PUT',
103 });
104 if (!uploadRes.ok) {
105 throw new Error(`Upload failed: ${uploadRes.status} ${uploadRes.statusText}`);
106 }
107 }
108
109 // 3. Create the file record
110 return await client.file.createFile.mutate({
111 fileType,
112 hash,
113 knowledgeBaseId: options.knowledgeBaseId,
114 metadata: {

Callers 4

registerVerifyCommandFunction · 0.90
registerKbCommandFunction · 0.90
registerFileCommandFunction · 0.90
registerAsrCommandFunction · 0.90

Calls 3

detectMimeTypeFunction · 0.85
resolveMethod · 0.45
updateMethod · 0.45

Tested by

no test coverage detected