diff --git a/README.md b/README.md index 87885ba..c17e810 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,8 @@ USERNAME = "USERNAME" PASSWORD = "PASSWORD" ``` -* USERNAME: The username of WebDav. -* PASSWORD: The password of WebDav. +- USERNAME: The username of WebDav. +- PASSWORD: The password of WebDav. ## Development diff --git a/package-lock.json b/package-lock.json index 05fc3c1..f692944 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "devDependencies": { "@cloudflare/workers-types": "^4.20231121.0", + "prettier": "3.1.1", "typescript": "^5.0.4", "wrangler": "^3.0.0" } @@ -970,6 +971,21 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/prettier": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz", + "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/printable-characters": { "version": "1.0.42", "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", diff --git a/package.json b/package.json index 88eba47..73171b8 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,13 @@ "scripts": { "deploy": "wrangler deploy", "dev": "wrangler dev", - "start": "wrangler dev" + "start": "wrangler dev", + "lint-perttier": "prettier . --write", + "check-perttier": "prettier . --check" }, "devDependencies": { "@cloudflare/workers-types": "^4.20231121.0", + "prettier": "3.1.1", "typescript": "^5.0.4", "wrangler": "^3.0.0" }, diff --git a/src/index.ts b/src/index.ts index 020d50c..6f47fd6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -46,21 +46,11 @@ async function* listAll(bucket: R2Bucket, prefix: string, isRecursive: boolean = if (r2_objects.truncated) { cursor = r2_objects.cursor; } - } while (r2_objects.truncated) + } while (r2_objects.truncated); } - -const DAV_CLASS = "1"; -const SUPPORT_METHODS = [ - "OPTIONS", - "PROPFIND", - "MKCOL", - "GET", - "HEAD", - "PUT", - "COPY", - "MOVE", -]; +const DAV_CLASS = '1'; +const SUPPORT_METHODS = ['OPTIONS', 'PROPFIND', 'MKCOL', 'GET', 'HEAD', 'PUT', 'COPY', 'MOVE']; type DavProperties = { creationdate: string | undefined; @@ -71,7 +61,7 @@ type DavProperties = { getetag: string | undefined; getlastmodified: string | undefined; resourcetype: string; -} +}; function fromR2Object(object: R2Object | null | undefined): DavProperties { if (object === null || object === undefined) { @@ -79,11 +69,11 @@ function fromR2Object(object: R2Object | null | undefined): DavProperties { creationdate: new Date().toUTCString(), displayname: undefined, getcontentlanguage: undefined, - getcontentlength: "0", + getcontentlength: '0', getcontenttype: undefined, getetag: undefined, getlastmodified: new Date().toUTCString(), - resourcetype: "", + resourcetype: '', }; } @@ -99,7 +89,6 @@ function fromR2Object(object: R2Object | null | undefined): DavProperties { }; } - function make_resource_path(request: Request): string { let path = new URL(request.url).pathname.slice(1); path = path.endsWith('/') ? path.slice(0, -1) : path; @@ -110,9 +99,9 @@ async function handle_options(request: Request, bucket: R2Bucket): Promise if (resource_path !== '') page += `..
`; for await (const object of listAll(bucket, resource_path)) { if (object.key === resource_path) { - continue + continue; } let href = `/${object.key + (object.customMetadata?.resourcetype === '' ? '/' : '')}`; page += `${object.httpMetadata?.contentDisposition ?? object.key}
`; @@ -147,12 +136,12 @@ async function handle_get(request: Request, bucket: R2Bucket): Promise let isR2ObjectBody = (object: R2Object | R2ObjectBody): object is R2ObjectBody => { return 'body' in object; - } + }; if (object === null) { return new Response('Not Found', { status: 404 }); } else if (!isR2ObjectBody(object)) { - return new Response("Precondition Failed", { status: 412 }); + return new Response('Precondition Failed', { status: 412 }); } else { return new Response(object.body, { status: object.range ? 206 : 200, @@ -160,22 +149,32 @@ async function handle_get(request: Request, bucket: R2Bucket): Promise 'Content-Type': object.httpMetadata?.contentType ?? 'application/octet-stream', // TODO: Content-Length, Content-Range - ...(object.httpMetadata?.contentDisposition ? { - 'Content-Disposition': object.httpMetadata.contentDisposition, - } : {}), - ...(object.httpMetadata?.contentEncoding ? { - 'Content-Encoding': object.httpMetadata.contentEncoding, - } : {}), - ...(object.httpMetadata?.contentLanguage ? { - 'Content-Language': object.httpMetadata.contentLanguage, - } : {}), - ...(object.httpMetadata?.cacheControl ? { - 'Cache-Control': object.httpMetadata.cacheControl, - } : {}), - ...(object.httpMetadata?.cacheExpiry ? { - 'Cache-Expiry': object.httpMetadata.cacheExpiry.toISOString(), - } : {}), - } + ...(object.httpMetadata?.contentDisposition + ? { + 'Content-Disposition': object.httpMetadata.contentDisposition, + } + : {}), + ...(object.httpMetadata?.contentEncoding + ? { + 'Content-Encoding': object.httpMetadata.contentEncoding, + } + : {}), + ...(object.httpMetadata?.contentLanguage + ? { + 'Content-Language': object.httpMetadata.contentLanguage, + } + : {}), + ...(object.httpMetadata?.cacheControl + ? { + 'Cache-Control': object.httpMetadata.cacheControl, + } + : {}), + ...(object.httpMetadata?.cacheExpiry + ? { + 'Cache-Expiry': object.httpMetadata.cacheExpiry.toISOString(), + } + : {}), + }, }); } } @@ -209,10 +208,11 @@ async function handle_delete(request: Request, bucket: R2Bucket): Promise object.key); + let keys = r2_objects.objects.map((object) => object.key); if (keys.length > 0) { await bucket.delete(keys); } @@ -234,13 +234,14 @@ async function handle_delete(request: Request, bucket: R2Bucket): Promise object.key); + let keys = r2_objects.objects.map((object) => object.key); if (keys.length > 0) { await bucket.delete(keys); } @@ -267,15 +268,15 @@ async function handle_mkcol(request: Request, bucket: R2Bucket): Promise' } + customMetadata: { resourcetype: '' }, }); return new Response('', { status: 201 }); } @@ -287,7 +288,7 @@ async function handle_propfind(request: Request, bucket: R2Bucket): Promise `; - if (resource_path === "") { + if (resource_path === '') { page += ` / @@ -321,53 +322,55 @@ async function handle_propfind(request: Request, bucket: R2Bucket): Promise HTTP/1.1 200 OK - ` - }; + `; + } if (is_collection) { let depth = request.headers.get('Depth') ?? 'infinity'; switch (depth) { - case '0': break; - case '1': { - let prefix = resource_path === "" ? resource_path : resource_path + '/'; - for await (let object of listAll(bucket, prefix)) { - let href = `/${object.key + (object.customMetadata?.resourcetype === '' ? '/' : '')}`; - page += ` - - ${href} - - - ${Object.entries(fromR2Object(object)) - .filter(([_, value]) => value !== undefined) - .map(([key, value]) => `<${key}>${value}`) - .join('\n ')} - - HTTP/1.1 200 OK - - `; - } - } + case '0': break; - case 'infinity': { - let prefix = resource_path === "" ? resource_path : resource_path + '/'; - for await (let object of listAll(bucket, prefix, true)) { - let href = `/${object.key + (object.customMetadata?.resourcetype === '' ? '/' : '')}`; - page += ` + case '1': + { + let prefix = resource_path === '' ? resource_path : resource_path + '/'; + for await (let object of listAll(bucket, prefix)) { + let href = `/${object.key + (object.customMetadata?.resourcetype === '' ? '/' : '')}`; + page += ` ${href} ${Object.entries(fromR2Object(object)) - .filter(([_, value]) => value !== undefined) - .map(([key, value]) => `<${key}>${value}`) - .join('\n ') - } + .filter(([_, value]) => value !== undefined) + .map(([key, value]) => `<${key}>${value}`) + .join('\n ')} HTTP/1.1 200 OK `; + } + } + break; + case 'infinity': + { + let prefix = resource_path === '' ? resource_path : resource_path + '/'; + for await (let object of listAll(bucket, prefix, true)) { + let href = `/${object.key + (object.customMetadata?.resourcetype === '' ? '/' : '')}`; + page += ` + + ${href} + + + ${Object.entries(fromR2Object(object)) + .filter(([_, value]) => value !== undefined) + .map(([key, value]) => `<${key}>${value}`) + .join('\n ')} + + HTTP/1.1 200 OK + + `; + } } - } break; default: { return new Response('Forbidden', { status: 403 }); @@ -395,8 +398,11 @@ async function handle_copy(request: Request, bucket: R2Bucket): Promise { - let target = destination + "/" + object.key.slice(prefix.length); - target = target.endsWith("/") ? target.slice(0, -1) : target; + let target = destination + '/' + object.key.slice(prefix.length); + target = target.endsWith('/') ? target.slice(0, -1) : target; let src = await bucket.get(object.key); if (src !== null) { await bucket.put(target, src.body, { @@ -487,8 +493,11 @@ async function handle_move(request: Request, bucket: R2Bucket): Promise { - let target = destination + "/" + object.key.slice(prefix.length); - target = target.endsWith("/") ? target.slice(0, -1) : target; + let target = destination + '/' + object.key.slice(prefix.length); + target = target.endsWith('/') ? target.slice(0, -1) : target; let src = await bucket.get(object.key); if (src !== null) { await bucket.put(target, src.body, { @@ -611,9 +621,9 @@ async function dispatch_handler(request: Request, bucket: R2Bucket): Promise