@rmdes/indiekit-endpoint-rss 1.2.2 → 1.2.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
@@ -20,6 +20,9 @@ const defaults = {
20
20
  retentionDays: 30,
21
21
  minItemsPerFeed: 10,
22
22
  maxPostsPerCycle: 10,
23
+ // Eleventy's watcher settles a new file in stabilityThreshold (2s) + watch
24
+ // throttle (3s); posting faster than that loses builds.
25
+ postIntervalMs: 5000,
23
26
  };
24
27
 
25
28
  export default class RssEndpoint {
@@ -3,6 +3,7 @@ import {
3
3
  resetPublishState,
4
4
  rewindWatermark,
5
5
  } from "../feed-settings.js";
6
+ import { defaultContent } from "../jf2-builder.js";
6
7
  import { getSyncState, runSync } from "../sync.js";
7
8
  import { formatFeed, formatItem } from "../utils.js";
8
9
 
@@ -93,7 +94,16 @@ export const dashboardController = {
93
94
 
94
95
  response.render("rss", {
95
96
  title: response.__("rss.title"),
96
- feeds: feeds.map(formatFeed),
97
+ feeds: feeds.map((feed) => {
98
+ const formatted = formatFeed(feed);
99
+ return {
100
+ ...formatted,
101
+ // Shown as the content field's placeholder. Leaving the field
102
+ // empty makes applyFeedSettings apply this same default, derived
103
+ // from the post type actually submitted.
104
+ contentDefault: defaultContent(formatted.publish?.postType),
105
+ };
106
+ }),
97
107
  recentItems: recentItems.map((item) => formatItem(item)),
98
108
  totalFeeds: feeds.length,
99
109
  totalItems,
package/lib/publisher.js CHANGED
@@ -4,6 +4,14 @@ import { buildJf2 } from "./jf2-builder.js";
4
4
 
5
5
  const TOKEN_TTL = "5m";
6
6
 
7
+ /**
8
+ * Pause between posts
9
+ * @param {number} ms - Milliseconds
10
+ * @returns {Promise<void>} Resolves after the delay
11
+ */
12
+ const sleep = (ms) =>
13
+ ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();
14
+
7
15
  /**
8
16
  * Mint a short-lived token for background publishing.
9
17
  *
@@ -163,8 +171,10 @@ export function pendingQuery(feed) {
163
171
  * @param {string} options.micropubEndpoint - Micropub endpoint URL
164
172
  * @param {string} options.me - Publication URL
165
173
  * @param {number} options.maxPostsPerCycle - Cap per cycle
174
+ * @param {number} [options.postIntervalMs] - Pause between posts
166
175
  * @param {Function} [options.postImpl] - Post implementation, for tests
167
176
  * @param {Function} [options.mintImpl] - Token minter, for tests
177
+ * @param {Function} [options.sleepImpl] - Sleep implementation, for tests
168
178
  * @returns {Promise<object>} Counts for this feed
169
179
  */
170
180
  export async function publishPending(feed, itemsCollection, options) {
@@ -178,6 +188,8 @@ export async function publishPending(feed, itemsCollection, options) {
178
188
  maxPostsPerCycle,
179
189
  postImpl = postToMicropub,
180
190
  mintImpl = mintToken,
191
+ postIntervalMs = 0,
192
+ sleepImpl = sleep,
181
193
  } = options;
182
194
 
183
195
  const query = pendingQuery(feed);
@@ -199,7 +211,7 @@ export async function publishPending(feed, itemsCollection, options) {
199
211
  // postData.create replaceOne's on the same URL, so it overwrites rather
200
212
  // than duplicates. Add a q=source reconciliation if a feed ever produces
201
213
  // non-deterministic slugs.
202
- for (const item of items) {
214
+ for (const [index, item] of items.entries()) {
203
215
  try {
204
216
  // Minted per item, not once for the batch: signing is a cheap HMAC, and
205
217
  // a single batch token can expire mid-cycle on a slow endpoint. The
@@ -243,6 +255,14 @@ export async function publishPending(feed, itemsCollection, options) {
243
255
 
244
256
  console.error(`[RSS] Publish failed for ${item.guid}: ${error.message}`);
245
257
  }
258
+
259
+ // Space the posts out. Each one writes a markdown file, and Eleventy's
260
+ // watcher needs chokidar's stabilityThreshold (2s) plus its own watch
261
+ // throttle (3s) to absorb one before the next lands. A burst arriving
262
+ // faster makes it log "Wrote 0 files" and leave the posts unbuilt.
263
+ if (index < items.length - 1) {
264
+ await sleepImpl(postIntervalMs);
265
+ }
246
266
  }
247
267
 
248
268
  console.log(
package/lib/sync.js CHANGED
@@ -154,6 +154,7 @@ export async function runSync(dbOrIndiekit, options, publishContext) {
154
154
  const result = await publishPending(feed, itemsCollection, {
155
155
  ...publishContext,
156
156
  maxPostsPerCycle: options.maxPostsPerCycle || 10,
157
+ postIntervalMs: options.postIntervalMs ?? 5000,
157
158
  });
158
159
  itemsPublished += result.published;
159
160
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmdes/indiekit-endpoint-rss",
3
- "version": "1.2.2",
3
+ "version": "1.2.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
@@ -145,7 +145,8 @@
145
145
  name: "content",
146
146
  label: __("rss.publish.content"),
147
147
  hint: __("rss.publish.contentHint"),
148
- value: feed.publish.content or "{{description}}"
148
+ value: feed.publish.content,
149
+ attributes: { placeholder: feed.contentDefault }
149
150
  }) }}
150
151
 
151
152
  {{ input({