@aikeytake/social-automation 2.0.5 → 2.0.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.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/src/index.js +92 -69
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aikeytake/social-automation",
3
- "version": "2.0.5",
3
+ "version": "2.0.6",
4
4
  "description": "Content research and aggregation tool for AI agents",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -24,7 +24,7 @@
24
24
  "author": "aikeytake",
25
25
  "license": "MIT",
26
26
  "dependencies": {
27
- "@aikeytake/social-automation": "2.0.4",
27
+ "@aikeytake/social-automation": "2.0.5",
28
28
  "@supabase/supabase-js": "^2.47.0",
29
29
  "axios": "^1.7.9",
30
30
  "cheerio": "^1.0.0",
package/src/index.js CHANGED
@@ -133,20 +133,26 @@ function getDateString() {
133
133
  }
134
134
 
135
135
  async function saveSourceData(source, items, today) {
136
- const todayFolder = path.join(__dirname, '../data', today);
137
- if (!fs.existsSync(todayFolder)) {
138
- fs.mkdirSync(todayFolder, { recursive: true });
136
+ try {
137
+ const todayFolder = path.join(__dirname, '../data', today);
138
+ if (!fs.existsSync(todayFolder)) {
139
+ fs.mkdirSync(todayFolder, { recursive: true });
140
+ }
141
+ const filePath = path.join(todayFolder, `${source}.json`);
142
+ const data = {
143
+ date: today,
144
+ source: source,
145
+ total_items: items.length,
146
+ scraped_at: new Date().toISOString(),
147
+ items: items
148
+ };
149
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
150
+ } catch (err) {
151
+ // Vercel ephemeral filesystem - ignore write errors when saving to filesystem
152
+ if (err.code !== 'ENOENT' && err.code !== 'EACCES') {
153
+ logger.warn(`saveSourceData skipped: ${err.message}`);
154
+ }
139
155
  }
140
-
141
- const filePath = path.join(todayFolder, `${source}.json`);
142
- const data = {
143
- date: today,
144
- source: source,
145
- total_items: items.length,
146
- scraped_at: new Date().toISOString(),
147
- items: items
148
- };
149
- fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
150
156
  }
151
157
 
152
158
  async function saveToSupabase(supabase, items, date) {
@@ -177,66 +183,83 @@ async function saveToSupabase(supabase, items, date) {
177
183
  }
178
184
 
179
185
  async function generateCombinedFiles(results, today) {
180
- const todayFolder = path.join(__dirname, '../data', today);
181
-
182
- // Load all source files
183
- const allItems = [];
184
- const sourceFiles = fs.readdirSync(todayFolder)
185
- .filter(f => f.endsWith('.json') && f !== 'all.json' && f !== 'trending.json');
186
- for (const file of sourceFiles) {
187
- const filePath = path.join(todayFolder, file);
188
- const content = fs.readFileSync(filePath, 'utf-8');
189
- const data = JSON.parse(content);
190
- allItems.push(...(data.items || []));
191
- }
186
+ try {
187
+ const todayFolder = path.join(__dirname, '../data', today);
192
188
 
193
- // Save all.json
194
- const allData = {
195
- date: today,
196
- generated_at: new Date().toISOString(),
197
- total_items: allItems.length,
198
- sources: results.sources,
199
- items: allItems
200
- };
201
- fs.writeFileSync(path.join(todayFolder, 'all.json'), JSON.stringify(allData, null, 2));
202
-
203
- // Generate trending.json (top 20 by score with source diversity)
204
- const scoredItems = allItems
205
- .filter(item => item.metadata?.score || item.engagement?.upvotes || item.engagement?.points || 0)
206
- .map(item => ({ ...item, combined_score: calculateScore(item) }))
207
- .sort((a, b) => b.combined_score - a.combined_score);
208
-
209
- // Apply source diversity: max 5 items per source
210
- const trendingBySource = {};
211
- const finalTrending = [];
212
- for (const item of scoredItems) {
213
- const source = item.source || 'unknown';
214
- if (!trendingBySource[source]) trendingBySource[source] = 0;
215
- if (trendingBySource[source] < 5) {
216
- trendingBySource[source]++;
217
- finalTrending.push(item);
189
+ // Load all source files
190
+ const allItems = [];
191
+ let sourceFiles = [];
192
+ try {
193
+ sourceFiles = fs.readdirSync(todayFolder)
194
+ .filter(f => f.endsWith('.json') && f !== 'all.json' && f !== 'trending.json');
195
+ } catch {
196
+ // Folder may not exist - skip loading
197
+ sourceFiles = [];
198
+ }
199
+ for (const file of sourceFiles) {
200
+ try {
201
+ const filePath = path.join(todayFolder, file);
202
+ const content = fs.readFileSync(filePath, 'utf-8');
203
+ const data = JSON.parse(content);
204
+ allItems.push(...(data.items || []));
205
+ } catch {
206
+ // Skip unreadable files
207
+ }
218
208
  }
219
- if (finalTrending.length >= 20) break;
220
- }
221
209
 
222
- const trendingData = {
223
- date: today,
224
- generated_at: new Date().toISOString(),
225
- total_items: finalTrending.length,
226
- items: finalTrending.map((item, index) => ({
227
- rank: index + 1,
228
- score: item.combined_score,
229
- sources: getItemSources(item),
230
- title: item.title,
231
- url: item.url || item.link,
232
- summary: extractSummary(item),
233
- keywords: extractKeywords(item),
234
- engagement: item.engagement || item.metadata || {}
235
- }))
236
- };
210
+ // Save all.json
211
+ const allData = {
212
+ date: today,
213
+ generated_at: new Date().toISOString(),
214
+ total_items: allItems.length,
215
+ sources: results.sources,
216
+ items: allItems
217
+ };
218
+ fs.writeFileSync(path.join(todayFolder, 'all.json'), JSON.stringify(allData, null, 2));
219
+
220
+ // Generate trending.json (top 20 by score with source diversity)
221
+ const scoredItems = allItems
222
+ .filter(item => item.metadata?.score || item.engagement?.upvotes || item.engagement?.points || 0)
223
+ .map(item => ({ ...item, combined_score: calculateScore(item) }))
224
+ .sort((a, b) => b.combined_score - a.combined_score);
225
+
226
+ // Apply source diversity: max 5 items per source
227
+ const trendingBySource = {};
228
+ const finalTrending = [];
229
+ for (const item of scoredItems) {
230
+ const source = item.source || 'unknown';
231
+ if (!trendingBySource[source]) trendingBySource[source] = 0;
232
+ if (trendingBySource[source] < 5) {
233
+ trendingBySource[source]++;
234
+ finalTrending.push(item);
235
+ }
236
+ if (finalTrending.length >= 20) break;
237
+ }
237
238
 
238
- fs.writeFileSync(path.join(todayFolder, 'trending.json'), JSON.stringify(trendingData, null, 2));
239
- logger.success(`✅ Generated: trending.json (${finalTrending.length} items)`);
239
+ const trendingData = {
240
+ date: today,
241
+ generated_at: new Date().toISOString(),
242
+ total_items: finalTrending.length,
243
+ items: finalTrending.map((item, index) => ({
244
+ rank: index + 1,
245
+ score: item.combined_score,
246
+ sources: getItemSources(item),
247
+ title: item.title,
248
+ url: item.url || item.link,
249
+ summary: extractSummary(item),
250
+ keywords: extractKeywords(item),
251
+ engagement: item.engagement || item.metadata || {}
252
+ }))
253
+ };
254
+
255
+ fs.writeFileSync(path.join(todayFolder, 'trending.json'), JSON.stringify(trendingData, null, 2));
256
+ logger.success(`✅ Generated: trending.json (${finalTrending.length} items)`);
257
+ } catch (err) {
258
+ // Vercel ephemeral filesystem - ignore write errors
259
+ if (err.code !== 'ENOENT' && err.code !== 'EACCES') {
260
+ logger.warn(`generateCombinedFiles skipped: ${err.message}`);
261
+ }
262
+ }
240
263
  }
241
264
 
242
265
  function calculateScore(item) {