@jk3labs/paperclip-plugin-file-browser 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -80
- package/dist/manifest.js +89 -0
- package/dist/manifest.js.map +7 -0
- package/dist/ui/index.js +198 -0
- package/dist/ui/index.js.map +7 -0
- package/dist/worker.js +9268 -0
- package/dist/worker.js.map +7 -0
- package/package.json +48 -34
- package/IMPLEMENTATION_NOTES.md +0 -0
- package/dist/__tests__/file-browser.spec.js +0 -140
- package/dist/index.js +0 -110
- package/index.js +0 -82
- package/jest.config.js +0 -6
- package/manifest.ts +0 -15
- package/src/__tests__/file-browser.spec.ts +0 -161
- package/src/index.ts +0 -128
- package/tsconfig.json +0 -15
package/src/index.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import express from 'express';
|
|
2
|
-
import fs from 'fs-extra';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import archiver from 'archiver';
|
|
5
|
-
|
|
6
|
-
interface PluginContext {
|
|
7
|
-
addRouter: (basePath: string, router: express.Router) => void;
|
|
8
|
-
environment: {
|
|
9
|
-
rootDir: string;
|
|
10
|
-
};
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
const plugin = {
|
|
14
|
-
id: 'file-browser',
|
|
15
|
-
name: 'File Browser Plugin',
|
|
16
|
-
description: 'A plugin to browse, download, and zip files in the Paperclip workspace.',
|
|
17
|
-
register: (context: PluginContext) => {
|
|
18
|
-
const router = express.Router();
|
|
19
|
-
const rootDir = context.environment.rootDir;
|
|
20
|
-
|
|
21
|
-
// Validate rootDir exists
|
|
22
|
-
if (!rootDir || !(fs.existsSync(rootDir))) {
|
|
23
|
-
throw new Error(`Invalid root directory: ${rootDir}`);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
router.get('/list', async (req, res) => {
|
|
27
|
-
try {
|
|
28
|
-
const relativePath = req.query.path as string || '';
|
|
29
|
-
const targetPath = path.join(rootDir, relativePath);
|
|
30
|
-
|
|
31
|
-
// Security: Ensure targetPath is within rootDir
|
|
32
|
-
if (!targetPath.startsWith(rootDir)) {
|
|
33
|
-
return res.status(403).json({ error: 'Access denied' });
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const entries = await fs.readdir(targetPath, { withFileTypes: true });
|
|
37
|
-
const files = entries
|
|
38
|
-
.filter(dirent => dirent.isFile())
|
|
39
|
-
.map(dirent => dirent.name);
|
|
40
|
-
const directories = entries
|
|
41
|
-
.filter(dirent => dirent.isDirectory())
|
|
42
|
-
.map(dirent => dirent.name);
|
|
43
|
-
|
|
44
|
-
res.json({
|
|
45
|
-
files,
|
|
46
|
-
directories,
|
|
47
|
-
currentPath: path.relative(rootDir, targetPath),
|
|
48
|
-
rootDir
|
|
49
|
-
});
|
|
50
|
-
} catch (error) {
|
|
51
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
52
|
-
const statusCode = (error as NodeJS.ErrnoException).code === 'ENOENT' ? 404 : 500;
|
|
53
|
-
res.status(statusCode).json({ error: message });
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
router.get('/download', async (req, res) => {
|
|
58
|
-
try {
|
|
59
|
-
const relativePath = req.query.path as string;
|
|
60
|
-
if (!relativePath) {
|
|
61
|
-
return res.status(400).json({ error: 'Path parameter is required' });
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const targetPath = path.join(rootDir, relativePath);
|
|
65
|
-
|
|
66
|
-
// Security: Ensure targetPath is within rootDir
|
|
67
|
-
if (!targetPath.startsWith(rootDir)) {
|
|
68
|
-
return res.status(403).json({ error: 'Access denied' });
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Check if path exists and is a file
|
|
72
|
-
const stats = await fs.stat(targetPath);
|
|
73
|
-
if (!stats.isFile()) {
|
|
74
|
-
return res.status(404).json({ error: 'File not found' });
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Stream file for download
|
|
78
|
-
res.download(targetPath, path.basename(targetPath));
|
|
79
|
-
} catch (error) {
|
|
80
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
81
|
-
const statusCode = (error as NodeJS.ErrnoException).code === 'ENOENT' ? 404 : 500;
|
|
82
|
-
res.status(statusCode).json({ error: message });
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
router.get('/zip', async (req, res) => {
|
|
87
|
-
try {
|
|
88
|
-
const relativePath = req.query.path as string;
|
|
89
|
-
if (!relativePath) {
|
|
90
|
-
return res.status(400).json({ error: 'Path parameter is required' });
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const targetPath = path.join(rootDir, relativePath);
|
|
94
|
-
|
|
95
|
-
// Security: Ensure targetPath is within rootDir
|
|
96
|
-
if (!targetPath.startsWith(rootDir)) {
|
|
97
|
-
return res.status(403).json({ error: 'Access denied' });
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Check if path exists and is a directory
|
|
101
|
-
const stats = await fs.stat(targetPath);
|
|
102
|
-
if (!stats.isDirectory()) {
|
|
103
|
-
return res.status(404).json({ error: 'Directory not found' });
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Set headers for ZIP download
|
|
107
|
-
res.attachment(`${path.basename(targetPath)}.zip`);
|
|
108
|
-
|
|
109
|
-
// Create ZIP stream
|
|
110
|
-
const archive = archiver('zip', {
|
|
111
|
-
zlib: { level: 9 } // Maximum compression
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
archive.pipe(res);
|
|
115
|
-
archive.directory(targetPath, false);
|
|
116
|
-
await archive.finalize();
|
|
117
|
-
} catch (error) {
|
|
118
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
119
|
-
const statusCode = (error as NodeJS.ErrnoException).code === 'ENOENT' ? 404 : 500;
|
|
120
|
-
res.status(statusCode).json({ error: message });
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
context.addRouter('/files', router);
|
|
125
|
-
},
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
export default plugin;
|
package/tsconfig.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"module": "commonjs",
|
|
5
|
-
"outDir": "./dist",
|
|
6
|
-
"rootDir": "./src",
|
|
7
|
-
"strict": true,
|
|
8
|
-
"esModuleInterop": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"forceConsistentCasingInFileNames": true,
|
|
11
|
-
"types": ["jest", "node"]
|
|
12
|
-
},
|
|
13
|
-
"include": ["src/**/*", "src/__tests__/**/*"],
|
|
14
|
-
"exclude": ["node_modules"]
|
|
15
|
-
}
|