@seedvault/server 0.2.2 → 0.2.3

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/dist/index.html CHANGED
@@ -1073,6 +1073,7 @@
1073
1073
  Activity</button>
1074
1074
  </footer>
1075
1075
  <script type="module">
1076
+ import { parseVaultEvent } from "/seedvault-events.js";
1076
1077
  const { marked } = await import("https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js");
1077
1078
  const matter = (await import("https://cdn.jsdelivr.net/npm/gray-matter@4.0.3/+esm")).default;
1078
1079
  const DOMPurify = (await import("https://cdn.jsdelivr.net/npm/dompurify@3.0.9/+esm")).default;
@@ -1454,17 +1455,18 @@
1454
1455
  evtSource = new EventSource("/v1/events?token=" + encodeURIComponent(token));
1455
1456
 
1456
1457
  evtSource.addEventListener("file_updated", (e) => {
1457
- const { contributor, path } = JSON.parse(e.data);
1458
- scheduleContributorReload(contributor);
1459
- if (localStorage.getItem("sv-file") === path && localStorage.getItem("sv-contributor") === contributor) {
1460
- const encodedPath = path.split("/").map(encodeURIComponent).join("/");
1461
- api("/v1/files/" + encodeURIComponent(contributor) + "/" + encodedPath)
1458
+ const event = parseVaultEvent(e.type, e.data);
1459
+ if (!event || event.type !== "file_updated") return;
1460
+ scheduleContributorReload(event.contributor);
1461
+ if (localStorage.getItem("sv-file") === event.path && localStorage.getItem("sv-contributor") === event.contributor) {
1462
+ const encodedPath = event.path.split("/").map(encodeURIComponent).join("/");
1463
+ api("/v1/files/" + encodeURIComponent(event.contributor) + "/" + encodedPath)
1462
1464
  .then((res) => res.text())
1463
1465
  .then((text) => {
1464
1466
  const { html, meta } = renderMarkdown(text);
1465
- const fileName = path.split("/").pop().replace(/\.md$/, "");
1467
+ const fileName = event.path.split("/").pop().replace(/\.md$/, "");
1466
1468
  $("item-title").textContent = meta.title || fileName;
1467
- $("item-path").textContent = contributor + ":" + path;
1469
+ $("item-path").textContent = event.contributor + ":" + event.path;
1468
1470
  $("item-meta").innerHTML = renderMeta(meta);
1469
1471
  $("item-header").hidden = false;
1470
1472
  contentEl.innerHTML = html;
@@ -1473,17 +1475,20 @@
1473
1475
  });
1474
1476
 
1475
1477
  evtSource.addEventListener("file_deleted", (e) => {
1476
- const { contributor, path } = JSON.parse(e.data);
1477
- scheduleContributorReload(contributor);
1478
- if (localStorage.getItem("sv-file") === path && localStorage.getItem("sv-contributor") === contributor) {
1478
+ const event = parseVaultEvent(e.type, e.data);
1479
+ if (!event || event.type !== "file_deleted") return;
1480
+ scheduleContributorReload(event.contributor);
1481
+ if (localStorage.getItem("sv-file") === event.path && localStorage.getItem("sv-contributor") === event.contributor) {
1479
1482
  $("item-header").hidden = true;
1480
1483
  contentEl.innerHTML = emptyStateHTML;
1481
- status("File deleted: " + path);
1484
+ status("File deleted: " + event.path);
1482
1485
  }
1483
1486
  });
1484
1487
 
1485
1488
  evtSource.addEventListener("activity", (e) => {
1486
- handleActivitySSE(e);
1489
+ const event = parseVaultEvent(e.type, e.data);
1490
+ if (!event || event.type !== "activity") return;
1491
+ handleActivitySSE(event);
1487
1492
  });
1488
1493
 
1489
1494
  evtSource.onerror = () => {
@@ -1549,9 +1554,8 @@
1549
1554
  activityModal.classList.remove("open");
1550
1555
  }
1551
1556
 
1552
- function handleActivitySSE(ev) {
1557
+ function handleActivitySSE(event) {
1553
1558
  if (!activityModal.classList.contains("open")) return;
1554
- const event = JSON.parse(ev.detail || ev.data);
1555
1559
  if (activitySeenIds.has(event.id)) return;
1556
1560
  activitySeenIds.add(event.id);
1557
1561
  activityOffset++;
@@ -0,0 +1,57 @@
1
+ // src/events.ts
2
+ function str(value) {
3
+ return typeof value === "string" ? value : "";
4
+ }
5
+ function num(value) {
6
+ return typeof value === "number" ? value : 0;
7
+ }
8
+ function parseVaultEvent(eventType, jsonData) {
9
+ let data;
10
+ try {
11
+ data = JSON.parse(jsonData);
12
+ } catch {
13
+ return null;
14
+ }
15
+ switch (eventType) {
16
+ case "file_updated":
17
+ return {
18
+ type: "file_updated",
19
+ id: str(data.id),
20
+ contributor: str(data.contributor),
21
+ path: str(data.path),
22
+ size: num(data.size),
23
+ modifiedAt: str(data.modifiedAt)
24
+ };
25
+ case "file_deleted":
26
+ return {
27
+ type: "file_deleted",
28
+ id: str(data.id),
29
+ contributor: str(data.contributor),
30
+ path: str(data.path)
31
+ };
32
+ case "activity":
33
+ return {
34
+ type: "activity",
35
+ id: str(data.id),
36
+ contributor: str(data.contributor),
37
+ action: str(data.action),
38
+ detail: typeof data.detail === "string" ? data.detail : null,
39
+ created_at: str(data.created_at)
40
+ };
41
+ default:
42
+ return null;
43
+ }
44
+ }
45
+ function matchesFilter(event, opts) {
46
+ if (opts?.contributor && event.contributor !== opts.contributor) {
47
+ return false;
48
+ }
49
+ if (opts?.eventTypes && !opts.eventTypes.includes(event.type)) {
50
+ return false;
51
+ }
52
+ return true;
53
+ }
54
+ export {
55
+ parseVaultEvent,
56
+ matchesFilter
57
+ };
package/dist/server.js CHANGED
@@ -1828,8 +1828,9 @@ var Hono2 = class extends Hono {
1828
1828
  };
1829
1829
 
1830
1830
  // src/routes.ts
1831
+ import { randomUUID as randomUUID2 } from "crypto";
1831
1832
  import { readFileSync } from "fs";
1832
- import { resolve } from "path";
1833
+ import { dirname, resolve } from "path";
1833
1834
 
1834
1835
  // src/auth.ts
1835
1836
  import { createHash, randomBytes as randomBytes2 } from "crypto";
@@ -2044,11 +2045,20 @@ function buildHunks(edits, oldLines, newLines, context) {
2044
2045
  // src/routes.ts
2045
2046
  var uiPath = resolve(import.meta.dirname, "index.html");
2046
2047
  var isDev = true;
2048
+ var sdkDir = dirname(Bun.resolveSync("@seedvault/sdk", import.meta.dirname));
2049
+ var eventsModulePath = resolve(sdkDir, "seedvault-events.js");
2047
2050
  function logActivity(contributor, action, detail) {
2048
2051
  const event = createActivityEvent(contributor, action, detail);
2049
2052
  broadcast("activity", event);
2050
2053
  }
2051
2054
  var uiHtmlCached = readFileSync(uiPath, "utf-8");
2055
+ var eventsModuleCached;
2056
+ function getEventsModule() {
2057
+ if (isDev)
2058
+ return readFileSync(eventsModulePath, "utf-8");
2059
+ eventsModuleCached ??= readFileSync(eventsModulePath, "utf-8");
2060
+ return eventsModuleCached;
2061
+ }
2052
2062
  function extractFileInfo(reqPath) {
2053
2063
  const raw2 = reqPath.replace("/v1/files/", "");
2054
2064
  let decoded;
@@ -2073,6 +2083,11 @@ function createApp() {
2073
2083
  app.get("/health", (c) => {
2074
2084
  return c.json({ status: "ok" });
2075
2085
  });
2086
+ app.get("/seedvault-events.js", (c) => {
2087
+ return c.body(getEventsModule(), 200, {
2088
+ "Content-Type": "application/javascript"
2089
+ });
2090
+ });
2076
2091
  app.post("/v1/signup", async (c) => {
2077
2092
  const body = await c.req.json();
2078
2093
  if (!body.name || typeof body.name !== "string" || body.name.trim().length === 0) {
@@ -2200,6 +2215,7 @@ function createApp() {
2200
2215
  }
2201
2216
  logActivity(contributor.username, "file_upserted", detail);
2202
2217
  broadcast("file_updated", {
2218
+ id: randomUUID2(),
2203
2219
  contributor: parsed.username,
2204
2220
  path: item.path,
2205
2221
  size: Buffer.byteLength(item.content),
@@ -2239,6 +2255,7 @@ function createApp() {
2239
2255
  path: parsed.filePath
2240
2256
  });
2241
2257
  broadcast("file_deleted", {
2258
+ id: randomUUID2(),
2242
2259
  contributor: parsed.username,
2243
2260
  path: parsed.filePath
2244
2261
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seedvault/server",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "seedvault-server": "bin/seedvault-server.mjs"
@@ -10,7 +10,7 @@
10
10
  "bin"
11
11
  ],
12
12
  "scripts": {
13
- "build": "bun build src/index.ts --outfile dist/server.js --target bun && cp src/index.html dist/",
13
+ "build": "bun build src/index.ts --outfile dist/server.js --target bun && cp src/index.html dist/ && cp ../sdk/dist/seedvault-events.js dist/",
14
14
  "dev": "DATA_DIR=./data bun run --watch src/index.ts",
15
15
  "start": "bun run src/index.ts",
16
16
  "check": "tsc --noEmit",
@@ -22,10 +22,10 @@
22
22
  "directory": "server"
23
23
  },
24
24
  "dependencies": {
25
+ "@seedvault/sdk": "0.2.0",
25
26
  "hono": "^4"
26
27
  },
27
28
  "devDependencies": {
28
- "@seedvault/sdk": "workspace:*",
29
29
  "@types/bun": "latest",
30
30
  "typescript": "^5"
31
31
  }