@rmdes/indiekit-endpoint-rss 1.0.3 → 1.0.4

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/index.js CHANGED
@@ -61,6 +61,9 @@ export default class RssEndpoint {
61
61
  // Manual sync trigger
62
62
  protectedRouter.post("/sync", dashboardController.sync);
63
63
 
64
+ // Clear items and re-sync
65
+ protectedRouter.post("/clear-resync", dashboardController.clearResync);
66
+
64
67
  // Feed management (protected - requires auth)
65
68
  protectedRouter.post("/api/feeds", express.json(), feedsController.add);
66
69
  protectedRouter.delete("/api/feeds/:id", feedsController.remove);
@@ -59,6 +59,59 @@ export const dashboardController = {
59
59
  }
60
60
  },
61
61
 
62
+ /**
63
+ * Clear all items and re-sync
64
+ * POST /clear-resync
65
+ */
66
+ async clearResync(request, response) {
67
+ try {
68
+ const { rssConfig, getRssDb } = request.app.locals.application;
69
+
70
+ if (!rssConfig) {
71
+ return response.status(500).json({
72
+ error: response.locals.__("rss.error.noConfig"),
73
+ });
74
+ }
75
+
76
+ const db = getRssDb?.();
77
+ if (!db) {
78
+ return response.status(500).json({
79
+ error: response.locals.__("rss.error.noDatabase"),
80
+ });
81
+ }
82
+
83
+ // Drop all items
84
+ const itemsCollection = db.collection("rssItems");
85
+ const deleteResult = await itemsCollection.deleteMany({});
86
+ console.log(`[RSS] Cleared ${deleteResult.deletedCount} items`);
87
+
88
+ // Reset feed item counts
89
+ const feedsCollection = db.collection("rssFeeds");
90
+ await feedsCollection.updateMany({}, { $set: { itemCount: 0 } });
91
+
92
+ // Trigger sync
93
+ const result = await runSync(db, rssConfig);
94
+
95
+ if (result.error) {
96
+ return response.status(500).json({
97
+ success: false,
98
+ error: result.error,
99
+ });
100
+ }
101
+
102
+ response.json({
103
+ success: true,
104
+ message: response.locals.__("rss.success.clearResync"),
105
+ itemsCleared: deleteResult.deletedCount,
106
+ feedsProcessed: result.feedsProcessed,
107
+ itemsAdded: result.itemsAdded,
108
+ });
109
+ } catch (error) {
110
+ console.error("[RSS] Clear & re-sync error:", error.message);
111
+ response.status(500).json({ error: error.message });
112
+ }
113
+ },
114
+
62
115
  /**
63
116
  * Trigger manual sync
64
117
  * POST /sync
package/locales/en.json CHANGED
@@ -8,6 +8,7 @@
8
8
  "enableFeed": "Enable",
9
9
  "disableFeed": "Disable",
10
10
  "syncNow": "Sync Now",
11
+ "clearResync": "Clear & Re-sync",
11
12
  "syncing": "Syncing...",
12
13
  "lastSynced": "Last synced",
13
14
  "noFeeds": "No feeds configured. Add a feed URL to get started.",
@@ -40,7 +41,8 @@
40
41
  "feedRemoved": "Feed removed",
41
42
  "feedEnabled": "Feed enabled",
42
43
  "feedDisabled": "Feed disabled",
43
- "syncComplete": "Sync complete"
44
+ "syncComplete": "Sync complete",
45
+ "clearResync": "Items cleared and re-synced"
44
46
  },
45
47
  "widget": {
46
48
  "description": "View aggregated RSS feeds on the public page",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmdes/indiekit-endpoint-rss",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "RSS feed reader endpoint for Indiekit. Aggregates multiple feeds, caches in MongoDB, displays on frontend.",
5
5
  "keywords": [
6
6
  "indiekit",
package/views/rss.njk CHANGED
@@ -284,13 +284,22 @@
284
284
  <span class="rss-feed-error">{{ syncState.lastError }}</span>
285
285
  {% endif %}
286
286
  </div>
287
- <form action="{{ publicUrl }}/sync" method="post">
288
- {{ button({
289
- type: "submit",
290
- text: __("rss.syncNow"),
291
- disabled: syncState.syncing
292
- }) }}
293
- </form>
287
+ <div style="display: flex; gap: 0.5rem;">
288
+ <form action="{{ publicUrl }}/sync" method="post" style="margin: 0;">
289
+ {{ button({
290
+ type: "submit",
291
+ text: __("rss.syncNow"),
292
+ disabled: syncState.syncing
293
+ }) }}
294
+ </form>
295
+ <form action="{{ publicUrl }}/clear-resync" method="post" style="margin: 0;" id="clear-resync-form">
296
+ {{ button({
297
+ type: "submit",
298
+ text: __("rss.clearResync"),
299
+ disabled: syncState.syncing
300
+ }) }}
301
+ </form>
302
+ </div>
294
303
  </div>
295
304
 
296
305
  {# Stats #}
@@ -471,6 +480,45 @@
471
480
  });
472
481
  });
473
482
 
483
+ // Handle clear & re-sync
484
+ document.getElementById('clear-resync-form')?.addEventListener('submit', async (e) => {
485
+ e.preventDefault();
486
+ if (!confirm('This will delete all cached items and re-fetch them from feeds. Continue?')) return;
487
+
488
+ const form = e.target;
489
+ const submitBtn = form.querySelector('button[type="submit"]');
490
+ const originalText = submitBtn?.textContent;
491
+ if (submitBtn) {
492
+ submitBtn.disabled = true;
493
+ submitBtn.textContent = 'Clearing...';
494
+ }
495
+
496
+ try {
497
+ const response = await fetch(form.action, {
498
+ method: 'POST',
499
+ headers: { 'Content-Type': 'application/json' }
500
+ });
501
+
502
+ const data = await response.json();
503
+ if (response.ok) {
504
+ alert(`Cleared ${data.itemsCleared} items, re-fetched ${data.itemsAdded} items from ${data.feedsProcessed} feeds.`);
505
+ location.reload();
506
+ } else {
507
+ alert(data.error || 'Failed to clear & re-sync');
508
+ if (submitBtn) {
509
+ submitBtn.disabled = false;
510
+ submitBtn.textContent = originalText;
511
+ }
512
+ }
513
+ } catch (err) {
514
+ alert('Failed to clear & re-sync: ' + err.message);
515
+ if (submitBtn) {
516
+ submitBtn.disabled = false;
517
+ submitBtn.textContent = originalText;
518
+ }
519
+ }
520
+ });
521
+
474
522
  // Handle delete feed
475
523
  document.querySelectorAll('[data-delete-feed]').forEach(btn => {
476
524
  btn.addEventListener('click', async (e) => {