@seedvault/server 0.2.1 → 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 +18 -14
- package/dist/seedvault-events.js +57 -0
- package/dist/server.js +18 -1
- package/package.json +3 -2
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
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
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
|
|
1477
|
-
|
|
1478
|
-
|
|
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
|
-
|
|
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(
|
|
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.
|
|
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,6 +22,7 @@
|
|
|
22
22
|
"directory": "server"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
+
"@seedvault/sdk": "0.2.0",
|
|
25
26
|
"hono": "^4"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|