feat: add CORS support, dynamic API_BASE for Netlify frontend, and netlify.toml
This commit is contained in:
parent
9fc9709f69
commit
55015d94d1
4 changed files with 39 additions and 4 deletions
8
netlify.toml
Normal file
8
netlify.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[build]
|
||||
publish = "public"
|
||||
|
||||
[[headers]]
|
||||
for = "/*"
|
||||
[headers.values]
|
||||
X-Frame-Options = "DENY"
|
||||
X-Content-Type-Options = "nosniff"
|
||||
10
public/_redirects
Normal file
10
public/_redirects
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Netlify redirects file
|
||||
# To proxy API requests through Netlify (bypassing mixed content & CORS),
|
||||
# replace YOUR_BACKEND_URL with your Termux backend URL (e.g., Cloudflare Tunnel / ngrok URL):
|
||||
# /files https://YOUR_BACKEND_URL/files 200
|
||||
# /upload https://YOUR_BACKEND_URL/upload 200
|
||||
# /uploads/* https://YOUR_BACKEND_URL/uploads/:splat 200
|
||||
# /delete/* https://YOUR_BACKEND_URL/delete/:splat 200
|
||||
|
||||
# SPA fallback rule
|
||||
/* /index.html 200
|
||||
|
|
@ -17,6 +17,14 @@
|
|||
|
||||
let selectedFiles = [];
|
||||
|
||||
// API Base configuration for remote frontend (Netlify) or local hosting
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
if (urlParams.has('api')) {
|
||||
const customApi = urlParams.get('api').replace(/\/+$/, '');
|
||||
localStorage.setItem('katdrop_api', customApi);
|
||||
}
|
||||
const API_BASE = window.KATDROP_API || localStorage.getItem('katdrop_api') || '';
|
||||
|
||||
// Toast
|
||||
let toastTimeout;
|
||||
function showToast(msg) {
|
||||
|
|
@ -221,7 +229,7 @@
|
|||
// Fetch and display files
|
||||
async function fetchFiles() {
|
||||
try {
|
||||
const res = await fetch('/files');
|
||||
const res = await fetch(`${API_BASE}/files`);
|
||||
const files = await res.json();
|
||||
fileList.innerHTML = '';
|
||||
|
||||
|
|
@ -252,7 +260,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="file-actions">
|
||||
<a href="/uploads/${encodeURIComponent(name)}" class="action-btn action-download" download>download</a>
|
||||
<a href="${API_BASE}/uploads/${encodeURIComponent(name)}" class="action-btn action-download" download>download</a>
|
||||
<button class="action-btn action-delete" onclick="deleteFile('${escapeHtml(name)}', this.closest('li'))">delete</button>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -271,7 +279,7 @@
|
|||
if (cardElement) cardElement.classList.add('deleting');
|
||||
|
||||
try {
|
||||
const res = await fetch(`/delete/${encodeURIComponent(filename)}`, { method: 'DELETE' });
|
||||
const res = await fetch(`${API_BASE}/delete/${encodeURIComponent(filename)}`, { method: 'DELETE' });
|
||||
if (res.ok) {
|
||||
showToast('file deleted');
|
||||
setTimeout(() => {
|
||||
|
|
@ -343,7 +351,7 @@
|
|||
showToast('upload failed');
|
||||
};
|
||||
|
||||
xhr.open('POST', '/upload');
|
||||
xhr.open('POST', `${API_BASE}/upload`);
|
||||
xhr.send(formData);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,6 +92,15 @@ const upload = multer({
|
|||
});
|
||||
|
||||
// Middlewares
|
||||
app.use((req, res, next) => {
|
||||
res.header('Access-Control-Allow-Origin', '*');
|
||||
res.header('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
|
||||
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
|
||||
if (req.method === 'OPTIONS') {
|
||||
return res.sendStatus(200);
|
||||
}
|
||||
next();
|
||||
});
|
||||
app.use(express.json());
|
||||
app.use(express.static(publicDir));
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue