clawvault 3.0.0 → 3.1.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.
Files changed (60) hide show
  1. package/README.md +156 -105
  2. package/bin/clawvault.js +0 -2
  3. package/bin/register-core-commands.js +20 -2
  4. package/dist/{chunk-3D6BCTP6.js → chunk-33UGEQRT.js} +70 -145
  5. package/dist/{chunk-ZVVFWOLW.js → chunk-3WRJEKN4.js} +1 -1
  6. package/dist/{chunk-DEFFDRVP.js → chunk-3ZIH425O.js} +3 -70
  7. package/dist/{chunk-K234IDRJ.js → chunk-D2H45LON.js} +1 -0
  8. package/dist/{chunk-YKTA5JOJ.js → chunk-H62BP7RI.js} +3 -3
  9. package/dist/{chunk-WGRQ6HDV.js → chunk-LI4O6NVK.js} +1 -1
  10. package/dist/{chunk-7R7O6STJ.js → chunk-OCGVIN3L.js} +1 -1
  11. package/dist/{chunk-GAJV4IGR.js → chunk-YCUNCH2I.js} +3 -7
  12. package/dist/cli/index.cjs +10 -1459
  13. package/dist/cli/index.js +5 -8
  14. package/dist/commands/compat.cjs +70 -145
  15. package/dist/commands/compat.js +1 -1
  16. package/dist/commands/context.cjs +1 -0
  17. package/dist/commands/context.js +3 -3
  18. package/dist/commands/doctor.cjs +68 -144
  19. package/dist/commands/doctor.js +4 -4
  20. package/dist/commands/embed.js +2 -2
  21. package/dist/commands/setup.cjs +2 -69
  22. package/dist/commands/setup.d.cts +0 -1
  23. package/dist/commands/setup.d.ts +0 -1
  24. package/dist/commands/setup.js +2 -2
  25. package/dist/commands/sleep.cjs +1 -0
  26. package/dist/commands/sleep.js +2 -2
  27. package/dist/commands/status.cjs +1 -0
  28. package/dist/commands/status.js +2 -2
  29. package/dist/commands/wake.cjs +1 -0
  30. package/dist/commands/wake.js +2 -2
  31. package/dist/index.cjs +447 -2600
  32. package/dist/index.d.cts +0 -4
  33. package/dist/index.d.ts +0 -4
  34. package/dist/index.js +8 -69
  35. package/dist/plugin/index.cjs +3 -3
  36. package/dist/plugin/index.js +10 -10
  37. package/package.json +11 -17
  38. package/bin/register-tailscale-commands.js +0 -106
  39. package/dist/chunk-IVRIKYFE.js +0 -520
  40. package/dist/chunk-THRJVD4L.js +0 -373
  41. package/dist/chunk-TIGW564L.js +0 -628
  42. package/dist/commands/tailscale.cjs +0 -1532
  43. package/dist/commands/tailscale.d.cts +0 -52
  44. package/dist/commands/tailscale.d.ts +0 -52
  45. package/dist/commands/tailscale.js +0 -26
  46. package/dist/lib/canvas-layout.cjs +0 -136
  47. package/dist/lib/canvas-layout.d.cts +0 -31
  48. package/dist/lib/canvas-layout.d.ts +0 -31
  49. package/dist/lib/canvas-layout.js +0 -92
  50. package/dist/lib/tailscale.cjs +0 -1183
  51. package/dist/lib/tailscale.d.cts +0 -225
  52. package/dist/lib/tailscale.d.ts +0 -225
  53. package/dist/lib/tailscale.js +0 -50
  54. package/dist/lib/webdav.cjs +0 -568
  55. package/dist/lib/webdav.d.cts +0 -109
  56. package/dist/lib/webdav.d.ts +0 -109
  57. package/dist/lib/webdav.js +0 -35
  58. package/hooks/clawvault/HOOK.md +0 -83
  59. package/hooks/clawvault/handler.js +0 -879
  60. package/hooks/clawvault/handler.test.js +0 -354
@@ -1,520 +0,0 @@
1
- // src/lib/webdav.ts
2
- import * as fs from "fs";
3
- import * as path from "path";
4
- var WEBDAV_PREFIX = "/webdav";
5
- var BLOCKED_PATHS = [
6
- ".clawvault",
7
- ".git",
8
- ".obsidian",
9
- "node_modules"
10
- ];
11
- var SUPPORTED_METHODS = ["GET", "PUT", "DELETE", "MKCOL", "PROPFIND", "OPTIONS", "HEAD", "MOVE", "COPY"];
12
- function toRequestSegments(requestPath) {
13
- return requestPath.replace(/\\/g, "/").split("/").filter(Boolean);
14
- }
15
- function isWithinRoot(fullPath, rootPath) {
16
- const resolvedRoot = path.resolve(rootPath);
17
- const relative2 = path.relative(resolvedRoot, fullPath);
18
- return !(relative2.startsWith("..") || path.isAbsolute(relative2));
19
- }
20
- function isPathSafe(requestPath, rootPath) {
21
- const pathParts = toRequestSegments(requestPath);
22
- if (pathParts.includes("..")) {
23
- return false;
24
- }
25
- const normalizedRelativePath = path.normalize(pathParts.join(path.sep));
26
- const fullPath = path.resolve(rootPath, normalizedRelativePath);
27
- if (!isWithinRoot(fullPath, rootPath)) {
28
- return false;
29
- }
30
- for (const part of pathParts) {
31
- if (BLOCKED_PATHS.includes(part)) {
32
- return false;
33
- }
34
- }
35
- return true;
36
- }
37
- function resolveWebDAVPath(requestPath, rootPath) {
38
- const pathParts = toRequestSegments(requestPath);
39
- if (pathParts.includes("..")) {
40
- return null;
41
- }
42
- const normalizedRelativePath = path.normalize(pathParts.join(path.sep));
43
- const fullPath = path.resolve(rootPath, normalizedRelativePath);
44
- if (!isWithinRoot(fullPath, rootPath)) {
45
- return null;
46
- }
47
- return fullPath;
48
- }
49
- function checkAuth(req, auth) {
50
- if (!auth) {
51
- return true;
52
- }
53
- const authHeader = req.headers.authorization;
54
- if (!authHeader || !authHeader.startsWith("Basic ")) {
55
- return false;
56
- }
57
- const base64Credentials = authHeader.slice(6);
58
- const credentials = Buffer.from(base64Credentials, "base64").toString("utf-8");
59
- const [username, password] = credentials.split(":");
60
- return username === auth.username && password === auth.password;
61
- }
62
- function escapeXml(str) {
63
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
64
- }
65
- function formatWebDAVDate(date) {
66
- return date.toUTCString();
67
- }
68
- function generatePropfindEntry(href, stats, isCollection) {
69
- const resourceType = isCollection ? "<D:resourcetype><D:collection/></D:resourcetype>" : "<D:resourcetype/>";
70
- const contentLength = stats && !isCollection ? `<D:getcontentlength>${stats.size}</D:getcontentlength>` : "";
71
- const lastModified = stats ? `<D:getlastmodified>${formatWebDAVDate(stats.mtime)}</D:getlastmodified>` : "";
72
- const etag = stats ? `<D:getetag>"${stats.mtime.getTime().toString(16)}-${stats.size.toString(16)}"</D:getetag>` : "";
73
- const contentType = !isCollection ? "<D:getcontenttype>application/octet-stream</D:getcontenttype>" : "";
74
- return ` <D:response>
75
- <D:href>${escapeXml(href)}</D:href>
76
- <D:propstat>
77
- <D:prop>
78
- ${resourceType}
79
- ${contentLength}
80
- ${lastModified}
81
- ${etag}
82
- ${contentType}
83
- </D:prop>
84
- <D:status>HTTP/1.1 200 OK</D:status>
85
- </D:propstat>
86
- </D:response>`;
87
- }
88
- function generatePropfindResponse(entries) {
89
- const responseEntries = entries.map(
90
- (e) => generatePropfindEntry(e.href, e.stats, e.isCollection)
91
- ).join("\n");
92
- return `<?xml version="1.0" encoding="utf-8"?>
93
- <D:multistatus xmlns:D="DAV:">
94
- ${responseEntries}
95
- </D:multistatus>`;
96
- }
97
- function handleOptions(res, prefix) {
98
- res.writeHead(200, {
99
- "Allow": SUPPORTED_METHODS.join(", "),
100
- "DAV": "1, 2",
101
- "Content-Length": "0",
102
- "Access-Control-Allow-Origin": "*",
103
- "Access-Control-Allow-Methods": SUPPORTED_METHODS.join(", "),
104
- "Access-Control-Allow-Headers": "Content-Type, Depth, Destination, Overwrite, Authorization",
105
- "MS-Author-Via": "DAV"
106
- });
107
- res.end();
108
- }
109
- function handleHead(res, filePath) {
110
- try {
111
- const stats = fs.statSync(filePath);
112
- if (stats.isDirectory()) {
113
- res.writeHead(200, {
114
- "Content-Type": "httpd/unix-directory",
115
- "Last-Modified": formatWebDAVDate(stats.mtime),
116
- "ETag": `"${stats.mtime.getTime().toString(16)}"`,
117
- "Access-Control-Allow-Origin": "*"
118
- });
119
- } else {
120
- res.writeHead(200, {
121
- "Content-Type": "application/octet-stream",
122
- "Content-Length": stats.size.toString(),
123
- "Last-Modified": formatWebDAVDate(stats.mtime),
124
- "ETag": `"${stats.mtime.getTime().toString(16)}-${stats.size.toString(16)}"`,
125
- "Access-Control-Allow-Origin": "*"
126
- });
127
- }
128
- res.end();
129
- } catch (err) {
130
- res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
131
- res.end("Not Found");
132
- }
133
- }
134
- function handleGet(res, filePath) {
135
- try {
136
- const stats = fs.statSync(filePath);
137
- if (stats.isDirectory()) {
138
- const entries = fs.readdirSync(filePath);
139
- const listing = entries.join("\n");
140
- res.writeHead(200, {
141
- "Content-Type": "text/plain",
142
- "Content-Length": Buffer.byteLength(listing).toString(),
143
- "Access-Control-Allow-Origin": "*"
144
- });
145
- res.end(listing);
146
- } else {
147
- const content = fs.readFileSync(filePath);
148
- res.writeHead(200, {
149
- "Content-Type": "application/octet-stream",
150
- "Content-Length": content.length.toString(),
151
- "Last-Modified": formatWebDAVDate(stats.mtime),
152
- "ETag": `"${stats.mtime.getTime().toString(16)}-${stats.size.toString(16)}"`,
153
- "Access-Control-Allow-Origin": "*"
154
- });
155
- res.end(content);
156
- }
157
- } catch (err) {
158
- res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
159
- res.end("Not Found");
160
- }
161
- }
162
- function handlePut(res, filePath, body) {
163
- try {
164
- const exists = fs.existsSync(filePath);
165
- const dir = path.dirname(filePath);
166
- if (!fs.existsSync(dir)) {
167
- fs.mkdirSync(dir, { recursive: true });
168
- }
169
- fs.writeFileSync(filePath, body);
170
- const status = exists ? 204 : 201;
171
- res.writeHead(status, {
172
- "Content-Length": "0",
173
- "Access-Control-Allow-Origin": "*"
174
- });
175
- res.end();
176
- } catch (err) {
177
- res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
178
- res.end(`Error: ${err}`);
179
- }
180
- }
181
- function handleDelete(res, filePath) {
182
- try {
183
- if (!fs.existsSync(filePath)) {
184
- res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
185
- res.end("Not Found");
186
- return;
187
- }
188
- const stats = fs.statSync(filePath);
189
- if (stats.isDirectory()) {
190
- fs.rmSync(filePath, { recursive: true });
191
- } else {
192
- fs.unlinkSync(filePath);
193
- }
194
- res.writeHead(204, {
195
- "Content-Length": "0",
196
- "Access-Control-Allow-Origin": "*"
197
- });
198
- res.end();
199
- } catch (err) {
200
- res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
201
- res.end(`Error: ${err}`);
202
- }
203
- }
204
- function handleMkcol(res, filePath) {
205
- try {
206
- if (fs.existsSync(filePath)) {
207
- res.writeHead(405, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
208
- res.end("Resource already exists");
209
- return;
210
- }
211
- const parent = path.dirname(filePath);
212
- if (!fs.existsSync(parent)) {
213
- res.writeHead(409, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
214
- res.end("Parent directory does not exist");
215
- return;
216
- }
217
- fs.mkdirSync(filePath);
218
- res.writeHead(201, {
219
- "Content-Length": "0",
220
- "Access-Control-Allow-Origin": "*"
221
- });
222
- res.end();
223
- } catch (err) {
224
- res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
225
- res.end(`Error: ${err}`);
226
- }
227
- }
228
- function handlePropfind(res, filePath, webdavPath, prefix, depth) {
229
- try {
230
- if (!fs.existsSync(filePath)) {
231
- res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
232
- res.end("Not Found");
233
- return;
234
- }
235
- const stats = fs.statSync(filePath);
236
- const entries = [];
237
- const normalizedWebdavPath = webdavPath.startsWith("/") ? webdavPath : "/" + webdavPath;
238
- const href = prefix + normalizedWebdavPath;
239
- entries.push({
240
- href: href.endsWith("/") || stats.isDirectory() ? href : href,
241
- stats,
242
- isCollection: stats.isDirectory()
243
- });
244
- if (stats.isDirectory() && depth !== "0") {
245
- try {
246
- const children = fs.readdirSync(filePath);
247
- for (const child of children) {
248
- if (BLOCKED_PATHS.includes(child)) {
249
- continue;
250
- }
251
- const childPath = path.join(filePath, child);
252
- const childWebdavPath = normalizedWebdavPath.endsWith("/") ? normalizedWebdavPath + child : normalizedWebdavPath + "/" + child;
253
- try {
254
- const childStats = fs.statSync(childPath);
255
- entries.push({
256
- href: prefix + childWebdavPath,
257
- stats: childStats,
258
- isCollection: childStats.isDirectory()
259
- });
260
- } catch {
261
- }
262
- }
263
- } catch {
264
- }
265
- }
266
- const xml = generatePropfindResponse(entries);
267
- res.writeHead(207, {
268
- "Content-Type": "application/xml; charset=utf-8",
269
- "Content-Length": Buffer.byteLength(xml).toString(),
270
- "Access-Control-Allow-Origin": "*"
271
- });
272
- res.end(xml);
273
- } catch (err) {
274
- res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
275
- res.end(`Error: ${err}`);
276
- }
277
- }
278
- function handleMove(res, sourcePath, destinationPath, overwrite) {
279
- try {
280
- if (!fs.existsSync(sourcePath)) {
281
- res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
282
- res.end("Source not found");
283
- return;
284
- }
285
- if (!destinationPath) {
286
- res.writeHead(400, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
287
- res.end("Destination header required");
288
- return;
289
- }
290
- const destExists = fs.existsSync(destinationPath);
291
- if (destExists && !overwrite) {
292
- res.writeHead(412, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
293
- res.end("Destination exists and Overwrite is F");
294
- return;
295
- }
296
- const destDir = path.dirname(destinationPath);
297
- if (!fs.existsSync(destDir)) {
298
- fs.mkdirSync(destDir, { recursive: true });
299
- }
300
- if (destExists) {
301
- const destStats = fs.statSync(destinationPath);
302
- if (destStats.isDirectory()) {
303
- fs.rmSync(destinationPath, { recursive: true });
304
- } else {
305
- fs.unlinkSync(destinationPath);
306
- }
307
- }
308
- fs.renameSync(sourcePath, destinationPath);
309
- const status = destExists ? 204 : 201;
310
- res.writeHead(status, {
311
- "Content-Length": "0",
312
- "Access-Control-Allow-Origin": "*"
313
- });
314
- res.end();
315
- } catch (err) {
316
- res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
317
- res.end(`Error: ${err}`);
318
- }
319
- }
320
- function handleCopy(res, sourcePath, destinationPath, overwrite) {
321
- try {
322
- if (!fs.existsSync(sourcePath)) {
323
- res.writeHead(404, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
324
- res.end("Source not found");
325
- return;
326
- }
327
- if (!destinationPath) {
328
- res.writeHead(400, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
329
- res.end("Destination header required");
330
- return;
331
- }
332
- const destExists = fs.existsSync(destinationPath);
333
- if (destExists && !overwrite) {
334
- res.writeHead(412, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
335
- res.end("Destination exists and Overwrite is F");
336
- return;
337
- }
338
- const destDir = path.dirname(destinationPath);
339
- if (!fs.existsSync(destDir)) {
340
- fs.mkdirSync(destDir, { recursive: true });
341
- }
342
- const sourceStats = fs.statSync(sourcePath);
343
- if (sourceStats.isDirectory()) {
344
- copyDirRecursive(sourcePath, destinationPath);
345
- } else {
346
- fs.copyFileSync(sourcePath, destinationPath);
347
- }
348
- const status = destExists ? 204 : 201;
349
- res.writeHead(status, {
350
- "Content-Length": "0",
351
- "Access-Control-Allow-Origin": "*"
352
- });
353
- res.end();
354
- } catch (err) {
355
- res.writeHead(500, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
356
- res.end(`Error: ${err}`);
357
- }
358
- }
359
- function copyDirRecursive(src, dest) {
360
- if (!fs.existsSync(dest)) {
361
- fs.mkdirSync(dest, { recursive: true });
362
- }
363
- const entries = fs.readdirSync(src, { withFileTypes: true });
364
- for (const entry of entries) {
365
- const srcPath = path.join(src, entry.name);
366
- const destPath = path.join(dest, entry.name);
367
- if (entry.isDirectory()) {
368
- copyDirRecursive(srcPath, destPath);
369
- } else {
370
- fs.copyFileSync(srcPath, destPath);
371
- }
372
- }
373
- }
374
- function parseDestinationHeader(destinationHeader, prefix, rootPath) {
375
- if (!destinationHeader) {
376
- return null;
377
- }
378
- try {
379
- let destPath;
380
- if (destinationHeader.startsWith("http://") || destinationHeader.startsWith("https://")) {
381
- const url = new URL(destinationHeader);
382
- destPath = decodeURIComponent(url.pathname);
383
- } else {
384
- destPath = decodeURIComponent(destinationHeader);
385
- }
386
- if (destPath.startsWith(prefix)) {
387
- destPath = destPath.slice(prefix.length);
388
- }
389
- return resolveWebDAVPath(destPath, rootPath);
390
- } catch {
391
- return null;
392
- }
393
- }
394
- function createWebDAVHandler(config) {
395
- const { rootPath, prefix = WEBDAV_PREFIX, auth } = config;
396
- return async (req, res) => {
397
- const rawUrl = req.url || "/";
398
- if (rawUrl.includes("..")) {
399
- if (rawUrl.startsWith(prefix)) {
400
- res.writeHead(403, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
401
- res.end("Forbidden");
402
- return true;
403
- }
404
- }
405
- const url = new URL(rawUrl, `http://${req.headers.host || "localhost"}`);
406
- const pathname = decodeURIComponent(url.pathname);
407
- if (!pathname.startsWith(prefix)) {
408
- return false;
409
- }
410
- let webdavPath = pathname.slice(prefix.length);
411
- if (!webdavPath.startsWith("/")) {
412
- webdavPath = "/" + webdavPath;
413
- }
414
- if (req.method === "OPTIONS") {
415
- handleOptions(res, prefix);
416
- return true;
417
- }
418
- if (!checkAuth(req, auth)) {
419
- res.writeHead(401, {
420
- "WWW-Authenticate": 'Basic realm="ClawVault WebDAV"',
421
- "Content-Type": "text/plain",
422
- "Access-Control-Allow-Origin": "*"
423
- });
424
- res.end("Unauthorized");
425
- return true;
426
- }
427
- if (!isPathSafe(webdavPath, rootPath)) {
428
- res.writeHead(403, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
429
- res.end("Forbidden");
430
- return true;
431
- }
432
- const filePath = resolveWebDAVPath(webdavPath, rootPath);
433
- if (!filePath) {
434
- res.writeHead(403, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
435
- res.end("Forbidden");
436
- return true;
437
- }
438
- const depth = req.headers.depth || "infinity";
439
- const overwrite = req.headers.overwrite?.toUpperCase() !== "F";
440
- const destinationHeader = req.headers.destination;
441
- switch (req.method) {
442
- case "HEAD":
443
- handleHead(res, filePath);
444
- return true;
445
- case "GET":
446
- handleGet(res, filePath);
447
- return true;
448
- case "PUT": {
449
- const chunks = [];
450
- for await (const chunk of req) {
451
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
452
- }
453
- const body = Buffer.concat(chunks);
454
- handlePut(res, filePath, body);
455
- return true;
456
- }
457
- case "DELETE":
458
- handleDelete(res, filePath);
459
- return true;
460
- case "MKCOL":
461
- handleMkcol(res, filePath);
462
- return true;
463
- case "PROPFIND":
464
- handlePropfind(res, filePath, webdavPath, prefix, depth);
465
- return true;
466
- case "MOVE": {
467
- const destPath = parseDestinationHeader(destinationHeader, prefix, rootPath);
468
- if (destPath && destinationHeader) {
469
- const destWebdavPath = destinationHeader.includes(prefix) ? destinationHeader.slice(destinationHeader.indexOf(prefix) + prefix.length) : destinationHeader;
470
- if (!isPathSafe(destWebdavPath, rootPath)) {
471
- res.writeHead(403, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
472
- res.end("Forbidden");
473
- return true;
474
- }
475
- }
476
- handleMove(res, filePath, destPath, overwrite);
477
- return true;
478
- }
479
- case "COPY": {
480
- const destPath = parseDestinationHeader(destinationHeader, prefix, rootPath);
481
- if (destPath && destinationHeader) {
482
- const destWebdavPath = destinationHeader.includes(prefix) ? destinationHeader.slice(destinationHeader.indexOf(prefix) + prefix.length) : destinationHeader;
483
- if (!isPathSafe(destWebdavPath, rootPath)) {
484
- res.writeHead(403, { "Content-Type": "text/plain", "Access-Control-Allow-Origin": "*" });
485
- res.end("Forbidden");
486
- return true;
487
- }
488
- }
489
- handleCopy(res, filePath, destPath, overwrite);
490
- return true;
491
- }
492
- default:
493
- res.writeHead(405, {
494
- "Allow": SUPPORTED_METHODS.join(", "),
495
- "Content-Type": "text/plain",
496
- "Access-Control-Allow-Origin": "*"
497
- });
498
- res.end("Method Not Allowed");
499
- return true;
500
- }
501
- };
502
- }
503
-
504
- export {
505
- WEBDAV_PREFIX,
506
- isPathSafe,
507
- resolveWebDAVPath,
508
- checkAuth,
509
- generatePropfindResponse,
510
- handleOptions,
511
- handleHead,
512
- handleGet,
513
- handlePut,
514
- handleDelete,
515
- handleMkcol,
516
- handlePropfind,
517
- handleMove,
518
- handleCopy,
519
- createWebDAVHandler
520
- };