← back to NEW SKU Viewer
server: 404-guard snapshot paths + server-side sort on /api/vendors
b85fbce2e7e8bdc93875715ba1dfedd24d92cba8 · 2026-05-19 21:19:12 -0700 · Steve Abrams
- Middleware before express.static returns 404 for any request whose
path matches *.bak / *.bak.* / *.pre-* / *.orig / *.rej / *.swp / ~,
so stray editor snapshots never serve from public/.
- /api/vendors now honors a ?sort= query param (products|newest|vendor|
series|sku|title|status) so the grid can be sorted server-side per
the standing "every grid gets sort + density" rule. Frontend wiring
in a follow-up commit.
node -c server.js passes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Files touched
Diff
commit b85fbce2e7e8bdc93875715ba1dfedd24d92cba8
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue May 19 21:19:12 2026 -0700
server: 404-guard snapshot paths + server-side sort on /api/vendors
- Middleware before express.static returns 404 for any request whose
path matches *.bak / *.bak.* / *.pre-* / *.orig / *.rej / *.swp / ~,
so stray editor snapshots never serve from public/.
- /api/vendors now honors a ?sort= query param (products|newest|vendor|
series|sku|title|status) so the grid can be sorted server-side per
the standing "every grid gets sort + density" rule. Frontend wiring
in a follow-up commit.
node -c server.js passes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
server.js | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 50 insertions(+), 2 deletions(-)
diff --git a/server.js b/server.js
index 7ccc4e2..23ee108 100644
--- a/server.js
+++ b/server.js
@@ -13,6 +13,15 @@ const PORT = 3030;
// Middleware
app.use(cors());
app.use(express.json());
+
+// Snapshot-file 404 guard — never serve .bak/.bak.*/.pre-*/.orig/.rej/.swp/~ from static root
+app.use((req, res, next) => {
+ if (/\.(bak|orig|rej|swp)(\.|$)|\.pre-|~$/i.test(req.path)) {
+ return res.status(404).send('Not Found');
+ }
+ next();
+});
+
app.use(express.static('public'));
// In-memory cache for vendor results - Load from file if exists
@@ -270,12 +279,51 @@ async function scanAllVendors() {
}
}
+// Server-side sort for vendor list. Sort modes:
+// products (default) — most products first
+// newest — most recently tested first
+// vendor — vendor id A→Z
+// series — vendor name A→Z (series-style display label)
+// sku — sku-prefix A→Z (same as vendor id)
+// title — vendor display name A→Z
+// status — working first, then errors
+function sortVendorEntries(entries, mode) {
+ const m = (mode || 'products').toLowerCase();
+ const arr = entries.slice();
+ const nameOf = ([id, v]) => (v.vendorName || id || '').toString().toLowerCase();
+ const idOf = ([id]) => (id || '').toString().toLowerCase();
+ const tsOf = ([, v]) => Date.parse(v.lastTested || '') || 0;
+ switch (m) {
+ case 'newest':
+ arr.sort((a, b) => tsOf(b) - tsOf(a));
+ break;
+ case 'vendor':
+ case 'sku':
+ arr.sort((a, b) => idOf(a).localeCompare(idOf(b)));
+ break;
+ case 'series':
+ case 'title':
+ arr.sort((a, b) => nameOf(a).localeCompare(nameOf(b)));
+ break;
+ case 'status':
+ arr.sort((a, b) => Number(!!b[1].success) - Number(!!a[1].success));
+ break;
+ case 'products':
+ default:
+ arr.sort((a, b) => (b[1].products || 0) - (a[1].products || 0));
+ }
+ return arr;
+}
+
// API Routes
app.get('/api/vendors', (req, res) => {
+ const sortedEntries = sortVendorEntries(Object.entries(vendorCache), req.query.sort);
+ const sortedVendors = Object.fromEntries(sortedEntries);
const summary = {
- vendors: vendorCache,
+ vendors: sortedVendors,
lastUpdate,
isScanning,
+ sort: (req.query.sort || 'products').toString(),
stats: {
total: Object.keys(vendorCache).length,
successful: Object.values(vendorCache).filter(v => v.success).length,
@@ -283,7 +331,7 @@ app.get('/api/vendors', (req, res) => {
totalProducts: Object.values(vendorCache).reduce((sum, v) => sum + v.products, 0)
}
};
-
+
res.json(summary);
});
← de911b9 public: add rel=noopener noreferrer to product-modal externa
·
back to NEW SKU Viewer
·
public: wire sort <select> + density slider with localStorag 098e8b6 →