heyio 0.20.0 → 0.21.0

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.
@@ -14,12 +14,25 @@ import { requireAuth } from "./auth.js";
14
14
  import { listSchedules, getSchedule, deleteSchedule, setScheduleEnabled } from "../store/schedules.js";
15
15
  import { listIoSchedules, getIoSchedule, deleteIoSchedule, setIoScheduleEnabled } from "../store/io-schedules.js";
16
16
  import { getScheduleRuns } from "../store/schedule-runs.js";
17
- import { createFeedEntry, listFeedEntries, countUnreadFeedEntries, markFeedEntryRead, markAllFeedEntriesRead, deleteFeedEntry } from "../store/feed.js";
17
+ import { createFeedEntry, listFeedEntries, countUnreadFeedEntries, markFeedEntryRead, markAllFeedEntriesRead, deleteFeedEntry, markFeedEntriesRead, deleteFeedEntries } from "../store/feed.js";
18
18
  import { listPages, readPage } from "../wiki/fs.js";
19
19
  import { runScheduleNow } from "../copilot/scheduler.js";
20
20
  import { runIoScheduleNow } from "../copilot/io-scheduler.js";
21
21
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
22
22
  const WEB_DIST = path.resolve(__dirname, "../../web-dist");
23
+ let releasesCache = null;
24
+ function loadReleases() {
25
+ if (releasesCache)
26
+ return releasesCache;
27
+ try {
28
+ const raw = readFileSync(path.join(__dirname, "../releases.json"), "utf-8");
29
+ releasesCache = JSON.parse(raw);
30
+ return releasesCache;
31
+ }
32
+ catch {
33
+ return [];
34
+ }
35
+ }
23
36
  let messageHandler;
24
37
  const sseConnections = new Set();
25
38
  export function setMessageHandler(handler) {
@@ -152,6 +165,10 @@ export async function startApiServer() {
152
165
  api.get("/status", (_req, res) => {
153
166
  res.json({ version: IO_VERSION, uptime: process.uptime() });
154
167
  });
168
+ // Releases endpoint — serves build-time bundled GitHub release notes
169
+ api.get("/releases", (_req, res) => {
170
+ res.json({ releases: loadReleases() });
171
+ });
155
172
  // SSE events endpoint
156
173
  api.get("/events", (req, res) => {
157
174
  res.setHeader("Content-Type", "text/event-stream");
@@ -249,6 +266,36 @@ export async function startApiServer() {
249
266
  res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
250
267
  }
251
268
  });
269
+ api.post("/feed/batch-read", (req, res) => {
270
+ const { ids } = req.body;
271
+ if (!Array.isArray(ids) || ids.length === 0 || !ids.every((x) => typeof x === "number")) {
272
+ res.status(400).json({ error: "ids must be a non-empty array of numbers" });
273
+ return;
274
+ }
275
+ try {
276
+ const marked = markFeedEntriesRead(ids);
277
+ res.json({ marked });
278
+ }
279
+ catch (e) {
280
+ console.error("Error batch-marking feed entries read:", e);
281
+ res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
282
+ }
283
+ });
284
+ api.post("/feed/batch-delete", (req, res) => {
285
+ const { ids } = req.body;
286
+ if (!Array.isArray(ids) || ids.length === 0 || !ids.every((x) => typeof x === "number")) {
287
+ res.status(400).json({ error: "ids must be a non-empty array of numbers" });
288
+ return;
289
+ }
290
+ try {
291
+ const deleted = deleteFeedEntries(ids);
292
+ res.json({ deleted });
293
+ }
294
+ catch (e) {
295
+ console.error("Error batch-deleting feed entries:", e);
296
+ res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
297
+ }
298
+ });
252
299
  api.post("/feed/:id/read", (req, res) => {
253
300
  const raw = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
254
301
  const id = Number.parseInt(raw, 10);
@@ -73,4 +73,22 @@ export function pruneOldFeedEntries(olderThanDays) {
73
73
  .run(olderThanDays);
74
74
  return info.changes;
75
75
  }
76
+ export function markFeedEntriesRead(ids) {
77
+ if (ids.length === 0)
78
+ return 0;
79
+ const placeholders = ids.map(() => "?").join(", ");
80
+ const info = getDb()
81
+ .prepare(`UPDATE unified_feed SET read_at = CURRENT_TIMESTAMP WHERE id IN (${placeholders}) AND read_at IS NULL`)
82
+ .run(...ids);
83
+ return info.changes;
84
+ }
85
+ export function deleteFeedEntries(ids) {
86
+ if (ids.length === 0)
87
+ return 0;
88
+ const placeholders = ids.map(() => "?").join(", ");
89
+ const info = getDb()
90
+ .prepare(`DELETE FROM unified_feed WHERE id IN (${placeholders})`)
91
+ .run(...ids);
92
+ return info.changes;
93
+ }
76
94
  //# sourceMappingURL=feed.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "heyio",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "IO — a personal AI assistant built on the GitHub Copilot SDK",
5
5
  "bin": {
6
6
  "io": "dist/index.js"