Readme

Webdav

Manage your vals from a webdav client (ex: https://cyberduck.io/)

image.png

⚠️ some webdav operations are not supported, so support can vary between clients.

Installation

Click "Create Val" on the code block, and change it's type to http.

import { basicAuth } from "https://esm.town/v/pomdtr/basicAuth"; import { verifyToken } from "https://esm.town/v/pomdtr/verifyToken"; import { serveVals } from "https://esm.town/v/pomdtr/webdavServer"; export default basicAuth(serveVals, { verifyUser: (user) => { return verifyToken(user); }, });

Use a val town token as the username, and keep the password blank to authenticate.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { ValTown } from "npm:@valtown/sdk";
import { Hono } from "npm:hono";
import { logger } from "npm:hono/logger";
type WebdavOptions = {
token?: string;
};
export function serveVals(
req: Request,
options?: WebdavOptions,
): Response | Promise<Response> {
const app = new Hono();
const vt = new ValTown({
bearerToken: options?.token,
});
app.use(logger());
app.on("PROPFIND", "/", async () => {
try {
const me = await vt.me.profile.retrieve();
const vals: ValTown.BasicVal[] = [];
while (true) {
const { data, links } = await vt.users.vals.list(me.id, {
offset: vals.length,
limit: 100,
});
vals.push(...data);
if (!links.next) {
break;
}
}
const body = `<?xml version="1.0" encoding="utf-8"?>
<multistatus xmlns="DAV:">
${
vals.map((val) => `
<response>
<href>${xmlEscape(val.name + ".tsx")}</href>
<propstat>
<prop>
<displayname>${xmlEscape(val.name + ".tsx")}</displayname>
<resourcetype></resourcetype>
<getcontentlength>${val.code ? getByteLength(val.code) : 0}</getcontentlength>
<getcontenttype>text/plain</getcontenttype>
<getlastmodified>${val.createdAt}</getlastmodified>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
`).join("")
}
</multistatus>`;
return new Response(body, {
status: 207,
headers: {
"content-type": "application/xml",
},
});
} catch (error) {
return new Response(
`Internal Server Error: ${xmlEscape(error.message)}`,
{
status: 500,
headers: {
"content-type": "text/plain",
},
},
);
}
});
app.on("PROPFIND", "/:val", async (c) => {
const valName = c.req.param("val").slice(0, -4);
const me = await vt.me.profile.retrieve();
if (!me.username) {
return c.text("You must set a username to use this feature", 400);
}
try {
const val = await vt.alias.username.valName.retrieve(
me.username,
valName,
);
const body = `<?xml version="1.0" encoding="utf-8"?>
<multistatus xmlns="DAV:">
<response>
<href>${xmlEscape(val.name + ".tsx")}</href>
<propstat>
<prop>
<displayname>${xmlEscape(val.name + ".tsx")}</displayname>
<resourcetype></resourcetype>
<getcontentlength>${val.code ? getByteLength(val.code) : 0}</getcontentlength>
<getcontenttype>text/plain</getcontenttype>
<getlastmodified>${val.createdAt}</getlastmodified>
Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Comments
1
August 30, 2024