r2-explorer 0.6.0 → 1.0.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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +9 -90
  3. package/bin/cli.js +29970 -0
  4. package/dist/index.js +1 -0
  5. package/dist/index.mjs +1 -0
  6. package/dist/src/authentication/api/access.d.ts +4 -0
  7. package/dist/src/buckets/api/createFolder.d.ts +8 -0
  8. package/dist/src/buckets/api/deleteObject.d.ts +8 -0
  9. package/dist/src/buckets/api/downloadObject.d.ts +8 -0
  10. package/dist/src/buckets/api/getObject.d.ts +8 -0
  11. package/dist/src/buckets/api/headObject.d.ts +8 -0
  12. package/dist/src/buckets/api/listBuckets.d.ts +10 -0
  13. package/dist/src/buckets/api/listObjects.d.ts +8 -0
  14. package/dist/src/buckets/api/moveObject.d.ts +8 -0
  15. package/dist/src/buckets/api/multipart/completeUpload.d.ts +11 -0
  16. package/dist/src/buckets/api/multipart/createUpload.d.ts +11 -0
  17. package/dist/src/buckets/api/multipart/partUpload.d.ts +8 -0
  18. package/dist/src/buckets/api/putMetadata.d.ts +8 -0
  19. package/dist/src/buckets/api/putObject.d.ts +8 -0
  20. package/dist/src/buckets/api/renameObject.d.ts +8 -0
  21. package/dist/src/buckets/api/uploadObject.d.ts +10 -0
  22. package/dist/src/buckets/router.d.ts +1 -0
  23. package/dist/src/dashbord.d.ts +2 -0
  24. package/dist/src/dates.d.ts +2 -0
  25. package/dist/src/emails/receiveEmail.d.ts +2 -0
  26. package/dist/src/index.d.ts +5 -0
  27. package/dist/src/interfaces.d.ts +21 -0
  28. package/dist/src/server/api/createFolder.d.ts +8 -0
  29. package/dist/src/server/api/deleteObject.d.ts +10 -0
  30. package/dist/src/server/api/downloadObject.d.ts +8 -0
  31. package/dist/src/server/api/getInfo.d.ts +14 -0
  32. package/dist/src/server/api/listBuckets.d.ts +14 -0
  33. package/dist/src/server/api/listObjects.d.ts +11 -0
  34. package/dist/src/server/api/multipart/completeUpload.d.ts +11 -0
  35. package/dist/src/server/api/multipart/createUpload.d.ts +11 -0
  36. package/dist/src/server/api/multipart/partUpload.d.ts +8 -0
  37. package/dist/src/server/api/renameObject.d.ts +10 -0
  38. package/dist/src/server/api/uploadObject.d.ts +10 -0
  39. package/dist/src/server/router.d.ts +1 -0
  40. package/dist/src/settings.d.ts +5 -0
  41. package/package.json +48 -29
  42. package/bin/r2-explorer.js +0 -70
  43. package/dist/umd/index.js +0 -679
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("itty-router"),t=require("@cloudflare/itty-router-openapi"),a=require("zod");const s=!0,o=!1,n="1.0.0";class r extends t.OpenAPIRoute{static schema={operationId:"get-bucket-list",tags:["Buckets"],summary:"List buckets"};async handle(e,t,a,s){const o=[];for(const[e,a]of Object.entries(t))a.get&&a.put&&o.push({name:e});return{buckets:o}}}class c extends t.OpenAPIRoute{static schema={operationId:"get-bucket-list-objects",tags:["Buckets"],summary:"List objects",parameters:{bucket:t.Path(String),limit:t.Query(a.z.number().optional()),prefix:t.Query(a.z.string().optional().describe("base64 encoded prefix")),cursor:t.Query(a.z.string().optional()),delimiter:t.Query(a.z.string().optional()),include:t.Query(a.z.string().array().optional())}};async handle(e,t,a,s){const o=t[s.params.bucket];return await o.list({limit:s.query.limit,prefix:s.query.prefix?decodeURIComponent(escape(atob(s.query.prefix))):void 0,cursor:s.query.cursor,delimiter:s.query.delimiter,include:s.query.include})}}class i extends t.OpenAPIRoute{static schema={operationId:"post-bucket-move-object",tags:["Buckets"],summary:"Move object",parameters:{bucket:t.Path(String)},requestBody:{oldKey:a.z.string().optional().describe("base64 encoded file key"),newKey:a.z.string().optional().describe("base64 encoded file key")}};async handle(e,t,a,s){if(!0===a.config.readonly)return Response.json({msg:"unauthorized"},{status:401});const o=t[s.params.bucket],n=decodeURIComponent(escape(atob(s.body.oldKey))),r=decodeURIComponent(escape(atob(s.body.newKey))),c=await o.get(n),i=await o.put(r,c.body,{customMetadata:c.customMetadata,httpMetadata:c.httpMetadata});return await o.delete(n),i}}class u extends t.OpenAPIRoute{static schema={operationId:"post-bucket-create-folder",tags:["Buckets"],summary:"Create folder",parameters:{bucket:t.Path(String)},requestBody:{key:a.z.string().optional().describe("base64 encoded file key")}};async handle(e,t,a,s){if(!0===a.config.readonly)return Response.json({msg:"unauthorized"},{status:401});const o=t[s.params.bucket],n=decodeURIComponent(escape(atob(s.body.key)));return await o.put(n,"R2 Explorer Folder")}}class d extends t.OpenAPIRoute{static schema={operationId:"post-bucket-upload-object",tags:["Buckets"],summary:"Upload object",parameters:{bucket:t.Path(String),key:t.Query(a.z.string().optional().describe("base64 encoded file key")),customMetadata:t.Query(a.z.string().optional().describe("base64 encoded json string")),httpMetadata:t.Query(a.z.string().optional().describe("base64 encoded json string"))}};async handle(e,t,a,s){if(!0===a.config.readonly)return Response.json({msg:"unauthorized"},{status:401});const o=t[s.params.bucket];let n,r,c=decodeURIComponent(escape(atob(s.query.key)));return s.query.customMetadata&&(n=JSON.parse(decodeURIComponent(escape(atob(s.query.customMetadata))))),s.query.httpMetadata&&(r=JSON.parse(decodeURIComponent(escape(atob(s.query.httpMetadata))))),await o.put(c,e.body,{customMetadata:n,httpMetadata:r})}}class p extends t.OpenAPIRoute{static schema={operationId:"post-bucket-delete-object",tags:["Buckets"],summary:"Delete object",parameters:{bucket:t.Path(String)},requestBody:{key:a.z.string().optional().describe("base64 encoded file key")}};async handle(e,t,a,s){if(!0===a.config.readonly)return Response.json({msg:"unauthorized"},{status:401});const o=t[s.params.bucket],n=decodeURIComponent(escape(atob(s.body.key)));return await o.delete(n)}}class l extends t.OpenAPIRoute{static schema={operationId:"post-multipart-create-upload",tags:["Multipart"],summary:"Create upload",parameters:{bucket:t.Path(String),key:t.Query(a.z.string().optional().describe("base64 encoded file key")),customMetadata:t.Query(a.z.string().optional().describe("base64 encoded json string")),httpMetadata:t.Query(a.z.string().optional().describe("base64 encoded json string"))}};async handle(e,t,a,s){if(!0===a.config.readonly)return Response.json({msg:"unauthorized"},{status:401});const o=t[s.params.bucket],n=decodeURIComponent(escape(atob(s.query.key)));let r,c;s.query.customMetadata&&(r=JSON.parse(decodeURIComponent(escape(atob(s.query.customMetadata))))),s.query.httpMetadata&&(c=JSON.parse(decodeURIComponent(escape(atob(s.query.httpMetadata)))));const i=await o.createMultipartUpload(n,{customMetadata:r,httpMetadata:c});return{uploadId:i.uploadId,key:i.key}}}class m extends t.OpenAPIRoute{static schema={operationId:"post-multipart-part-upload",tags:["Multipart"],summary:"Part upload",parameters:{bucket:t.Path(String),key:t.Query(a.z.string().optional().describe("base64 encoded file key")),uploadId:t.Query(String),partNumber:t.Query(t.Int)}};async handle(e,t,a,s){if(!0===a.config.readonly)return Response.json({msg:"unauthorized"},{status:401});const o=t[s.params.bucket],n=decodeURIComponent(escape(atob(s.query.key))),r=o.resumeMultipartUpload(n,s.query.uploadId);try{return await r.uploadPart(s.query.partNumber,e.body)}catch(e){return new Response(e.message,{status:400})}}}class y extends t.OpenAPIRoute{static schema={operationId:"post-multipart-complete-upload",tags:["Multipart"],summary:"Complete upload",parameters:{bucket:t.Path(String)},requestBody:{uploadId:String,key:a.z.string().optional().describe("base64 encoded file key"),parts:[{etag:String,partNumber:t.Int}]}};async handle(e,t,a,s){if(!0===a.config.readonly)return Response.json({msg:"unauthorized"},{status:401});const o=t[s.params.bucket],n=s.body.uploadId,r=decodeURIComponent(escape(atob(s.body.key))),c=s.body.parts,i=await o.resumeMultipartUpload(r,n);try{return{success:!0,str:await i.complete(c)}}catch(e){return Response.json({msg:e.message},{status:400})}}}class b extends t.OpenAPIRoute{static schema={operationId:"get-bucket-object",tags:["Buckets"],summary:"Get Object",parameters:{bucket:t.Path(String),key:t.Path(a.z.string().optional().describe("base64 encoded file key"))},responses:{200:{description:"File binary",schema:a.z.string().openapi({format:"binary"})}}};async handle(e,t,a,s){const o=t[s.params.bucket],n=decodeURIComponent(escape(atob(s.params.key))),r=await o.get(n);if(null===r)return Response.json({msg:"Object Not Found"},{status:404});const c=new Headers;return r.writeHttpMetadata(c),c.set("etag",r.httpEtag),c.set("Content-Disposition",`attachment; filename="${n.split("/").pop()}"`),new Response(r.body,{headers:c})}}class g extends t.OpenAPIRoute{static schema={operationId:"Head-bucket-object",tags:["Buckets"],summary:"Get Object",parameters:{bucket:t.Path(String),key:t.Query(a.z.string().optional().describe("base64 encoded file key"))}};async handle(e,t,a,s){const o=t[s.params.bucket],n=decodeURIComponent(escape(atob(s.params.key))),r=await o.head(n);return null===r?Response.json({msg:"Object Not Found"},{status:404}):r}}class f extends t.OpenAPIRoute{static schema={operationId:"post-bucket-put-object-metadata",tags:["Buckets"],summary:"Update object metadata",parameters:{bucket:t.Path(String),key:t.Query(a.z.string().describe("base64 encoded file key")),customMetadata:t.Query(a.z.string().describe("base64 encoded json string"))}};async handle(e,t,a,s){if(!0===a.config.readonly)return Response.json({msg:"unauthorized"},{status:401});const o=t[s.params.bucket],n=decodeURIComponent(escape(atob(s.query.key))),r=decodeURIComponent(escape(atob(s.query.key))),c=await o.get(n);return await o.put(n,c.body,{customMetadata:r})}}const h=t.OpenAPIRouter({base:"/api/buckets",raiseUnknownParameters:s,generateOperationIds:o});h.get("",r),h.get("/:bucket",c),h.post("/:bucket/move",i),h.post("/:bucket/folder",u),h.post("/:bucket/upload",d),h.post("/:bucket/multipart/create",l),h.post("/:bucket/multipart/upload",m),h.post("/:bucket/multipart/complete",y),h.post("/:bucket/delete",p),h.head("/:bucket/:key",g),h.get("/:bucket/:key",b),h.post("/:bucket/:key",f);let k={},w=0;function R(e){return`https://${e}.cloudflareaccess.com`}async function I(e,t,a){let s=!1;try{s=await async function(e,t){const a=function(e){const t=e.headers.get("cf-access-jwt-assertion");if(!t)return null;return t.trim()}(e);if(null===a)return!1;(0===Object.keys(k).length||Math.floor(Date.now()/1e3)<w)&&(k=await async function(e){let t=`${R(e.cfAccessTeamName)}/cdn-cgi/access/certs`;const a=await fetch(t,{method:"GET",cf:{cacheTtlByStatus:{"200-299":30,"300-599":0}},headers:{"Content-Type":"application/json; charset=UTF-8"}}),s=await a.json();w=Math.floor(Date.now()/1e3)+3600;const o={};for(const e of s.keys)o[e.kid]=await crypto.subtle.importKey("jwk",e,{name:"RSASSA-PKCS1-v1_5",hash:"SHA-256"},!1,["verify"]);return o}(t));let s;try{s=function(e){const t=e.split("."),a=JSON.parse(atob(t[0])),s=JSON.parse(atob(t[1])),o=atob(t[2].replace(/_/g,"/").replace(/-/g,"+"));return{header:a,payload:s,signature:o,raw:{header:t[0],payload:t[1],signature:t[2]}}}(a)}catch(e){return!1}const o=new Date(1e3*s.payload.exp),n=new Date(Date.now());if(o<=n)return console.log("expired token"),!1;if(s.payload?.iss!==R(t.cfAccessTeamName))return console.log("invalid access signer"),!1;if(!async function(e){const t=(new TextEncoder).encode([e.raw.header,e.raw.payload].join(".")),a=new Uint8Array(Array.from(e.signature).map((e=>e.charCodeAt(0))));for(const e of Object.values(k)){if(await j(e,a,t))return!0}return!1}(s))return!1;return s}(e,a.config)}catch(e){}if(!1===s)return Response.json({success:!1,errors:[{code:1e4,message:"Authentication error! Verify that the Cloudflare Access Team name is correct"}]},{status:401});a.username=s.payload.email}async function j(e,t,a){return crypto.subtle.verify("RSASSA-PKCS1-v1_5",e,t,a)}async function x(e,t,a){const s=caches.default;let o,n=new URL(e.url).pathname;if(n.includes(".")||(n="/"),!1!==a.config.cacheAssets&&(o=await s.match(e),o))return o;let r="https://demo.r2explorer.dev";a.config?.dashboardUrl&&(r=a.config.dashboardUrl.endsWith("/")?a.config.dashboardUrl.slice(0,-1):a.config.dashboardUrl);const c=await fetch(`${r}${n}`);return o=new Response(await c.text(),{status:c.status,headers:{"Content-Type":c.headers.get("Content-Type"),"Access-Control-Allow-Origin":"*","Cache-Control":"max-age: 300"}}),200===c.status&&!1!==a.config.cacheAssets&&a.executionContext.waitUntil(s.put(e,o.clone())),o}const M=require("postal-mime/dist/node").postalMime.default;async function P(e,t,a){let s;if(a.config?.emailRouting?.targetBucket&&t[a.config.emailRouting.targetBucket]&&(s=t[a.config.emailRouting.targetBucket]),!s)for(const[e,a]of Object.entries(t))if(a.get&&a.put){s=a;break}const o=await async function(e,t){let a=new Uint8Array(t),s=0;const o=e.getReader();for(;;){const{done:e,value:t}=await o.read();if(e)break;a.set(t,s),s+=t.length}return a}(e.raw,e.rawSize),n=new M,r=await n.parse(o),c=`${Math.floor(Date.now())}-${crypto.randomUUID()}`;await s.put(`.r2-explorer/emails/inbox/${c}.json`,JSON.stringify(r),{customMetadata:{subject:r.subject,from_address:r.from?.address,from_name:r.from?.name,to_address:r.to.length>0?r.to[0].address:null,to_name:r.to.length>0?r.to[0].name:null,has_attachments:r.attachments.length>0,read:!1}});for(const e of r.attachments)await s.put(`.r2-explorer/emails/inbox/${c}/${e.filename}`,e.content)}class A extends t.OpenAPIRoute{static schema={operationId:"get-server-info",tags:["Server"],summary:"Get server info"};async handle(e,t,a,s){return{version:n,config:a.config,user:{username:a.username}}}}const C=t.OpenAPIRouter({base:"/api/server",raiseUnknownParameters:s,generateOperationIds:o});C.get("/config",A),exports.R2Explorer=function(a){!1!==(a=a||{}).readonly&&(a.readonly=!0);const s=t.OpenAPIRouter({schema:{info:{title:"R2 Explorer API",version:n}}}),{preflight:o,corsify:r}=e.createCors();return a.cfAccessTeamName&&s.all("*",I),!0===a.cors&&s.all("*",o),s.all("/api/server/*",C),s.all("/api/buckets/*",h),s.original.get("*",x),s.all("*",(()=>Response.json({msg:"404, not found!"},{status:404}))),{async email(e,t,s){await P(e,t,{executionContext:s,config:a})},async fetch(e,t,o){let n=await s.handle(e,t,{executionContext:o,config:a});return!0===a.cors&&(n=r(n)),n}}};
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ import{createCors as e}from"itty-router";import{OpenAPIRoute as t,Path as a,Query as s,Int as o,OpenAPIRouter as n}from"@cloudflare/itty-router-openapi";import{z as r}from"zod";const c=!0,i=!1,d="1.0.0";class u extends t{static schema={operationId:"get-bucket-list-objects",tags:["Buckets"],summary:"List objects",parameters:{bucket:a(String),limit:s(r.number().optional()),prefix:s(r.string().optional().describe("base64 encoded prefix")),cursor:s(r.string().optional()),delimiter:s(r.string().optional()),include:s(r.string().array().optional())}};async handle(e,t,a,s){const o=t[s.params.bucket];return await o.list({limit:s.query.limit,prefix:s.query.prefix?decodeURIComponent(escape(atob(s.query.prefix))):void 0,cursor:s.query.cursor,delimiter:s.query.delimiter,include:s.query.include})}}class p extends t{static schema={operationId:"post-bucket-move-object",tags:["Buckets"],summary:"Move object",parameters:{bucket:a(String)},requestBody:{oldKey:r.string().optional().describe("base64 encoded file key"),newKey:r.string().optional().describe("base64 encoded file key")}};async handle(e,t,a,s){if(!0===a.config.readonly)return Response.json({msg:"unauthorized"},{status:401});const o=t[s.params.bucket],n=decodeURIComponent(escape(atob(s.body.oldKey))),r=decodeURIComponent(escape(atob(s.body.newKey))),c=await o.get(n),i=await o.put(r,c.body,{customMetadata:c.customMetadata,httpMetadata:c.httpMetadata});return await o.delete(n),i}}class l extends t{static schema={operationId:"post-bucket-create-folder",tags:["Buckets"],summary:"Create folder",parameters:{bucket:a(String)},requestBody:{key:r.string().optional().describe("base64 encoded file key")}};async handle(e,t,a,s){if(!0===a.config.readonly)return Response.json({msg:"unauthorized"},{status:401});const o=t[s.params.bucket],n=decodeURIComponent(escape(atob(s.body.key)));return await o.put(n,"R2 Explorer Folder")}}class m extends t{static schema={operationId:"post-bucket-upload-object",tags:["Buckets"],summary:"Upload object",parameters:{bucket:a(String),key:s(r.string().optional().describe("base64 encoded file key")),customMetadata:s(r.string().optional().describe("base64 encoded json string")),httpMetadata:s(r.string().optional().describe("base64 encoded json string"))}};async handle(e,t,a,s){if(!0===a.config.readonly)return Response.json({msg:"unauthorized"},{status:401});const o=t[s.params.bucket];let n,r,c=decodeURIComponent(escape(atob(s.query.key)));return s.query.customMetadata&&(n=JSON.parse(decodeURIComponent(escape(atob(s.query.customMetadata))))),s.query.httpMetadata&&(r=JSON.parse(decodeURIComponent(escape(atob(s.query.httpMetadata))))),await o.put(c,e.body,{customMetadata:n,httpMetadata:r})}}class y extends t{static schema={operationId:"post-bucket-delete-object",tags:["Buckets"],summary:"Delete object",parameters:{bucket:a(String)},requestBody:{key:r.string().optional().describe("base64 encoded file key")}};async handle(e,t,a,s){if(!0===a.config.readonly)return Response.json({msg:"unauthorized"},{status:401});const o=t[s.params.bucket],n=decodeURIComponent(escape(atob(s.body.key)));return await o.delete(n)}}class b extends t{static schema={operationId:"post-multipart-create-upload",tags:["Multipart"],summary:"Create upload",parameters:{bucket:a(String),key:s(r.string().optional().describe("base64 encoded file key")),customMetadata:s(r.string().optional().describe("base64 encoded json string")),httpMetadata:s(r.string().optional().describe("base64 encoded json string"))}};async handle(e,t,a,s){if(!0===a.config.readonly)return Response.json({msg:"unauthorized"},{status:401});const o=t[s.params.bucket],n=decodeURIComponent(escape(atob(s.query.key)));let r,c;s.query.customMetadata&&(r=JSON.parse(decodeURIComponent(escape(atob(s.query.customMetadata))))),s.query.httpMetadata&&(c=JSON.parse(decodeURIComponent(escape(atob(s.query.httpMetadata)))));const i=await o.createMultipartUpload(n,{customMetadata:r,httpMetadata:c});return{uploadId:i.uploadId,key:i.key}}}class g extends t{static schema={operationId:"post-multipart-part-upload",tags:["Multipart"],summary:"Part upload",parameters:{bucket:a(String),key:s(r.string().optional().describe("base64 encoded file key")),uploadId:s(String),partNumber:s(o)}};async handle(e,t,a,s){if(!0===a.config.readonly)return Response.json({msg:"unauthorized"},{status:401});const o=t[s.params.bucket],n=decodeURIComponent(escape(atob(s.query.key))),r=o.resumeMultipartUpload(n,s.query.uploadId);try{return await r.uploadPart(s.query.partNumber,e.body)}catch(e){return new Response(e.message,{status:400})}}}class f extends t{static schema={operationId:"post-multipart-complete-upload",tags:["Multipart"],summary:"Complete upload",parameters:{bucket:a(String)},requestBody:{uploadId:String,key:r.string().optional().describe("base64 encoded file key"),parts:[{etag:String,partNumber:o}]}};async handle(e,t,a,s){if(!0===a.config.readonly)return Response.json({msg:"unauthorized"},{status:401});const o=t[s.params.bucket],n=s.body.uploadId,r=decodeURIComponent(escape(atob(s.body.key))),c=s.body.parts,i=await o.resumeMultipartUpload(r,n);try{return{success:!0,str:await i.complete(c)}}catch(e){return Response.json({msg:e.message},{status:400})}}}class h extends t{static schema={operationId:"get-bucket-object",tags:["Buckets"],summary:"Get Object",parameters:{bucket:a(String),key:a(r.string().optional().describe("base64 encoded file key"))},responses:{200:{description:"File binary",schema:r.string().openapi({format:"binary"})}}};async handle(e,t,a,s){const o=t[s.params.bucket],n=decodeURIComponent(escape(atob(s.params.key))),r=await o.get(n);if(null===r)return Response.json({msg:"Object Not Found"},{status:404});const c=new Headers;return r.writeHttpMetadata(c),c.set("etag",r.httpEtag),c.set("Content-Disposition",`attachment; filename="${n.split("/").pop()}"`),new Response(r.body,{headers:c})}}class k extends t{static schema={operationId:"Head-bucket-object",tags:["Buckets"],summary:"Get Object",parameters:{bucket:a(String),key:s(r.string().optional().describe("base64 encoded file key"))}};async handle(e,t,a,s){const o=t[s.params.bucket],n=decodeURIComponent(escape(atob(s.params.key))),r=await o.head(n);return null===r?Response.json({msg:"Object Not Found"},{status:404}):r}}class w extends t{static schema={operationId:"post-bucket-put-object-metadata",tags:["Buckets"],summary:"Update object metadata",parameters:{bucket:a(String),key:s(r.string().describe("base64 encoded file key")),customMetadata:s(r.string().describe("base64 encoded json string"))}};async handle(e,t,a,s){if(!0===a.config.readonly)return Response.json({msg:"unauthorized"},{status:401});const o=t[s.params.bucket],n=decodeURIComponent(escape(atob(s.query.key))),r=decodeURIComponent(escape(atob(s.query.key))),c=await o.get(n);return await o.put(n,c.body,{customMetadata:r})}}const j=n({base:"/api/buckets",raiseUnknownParameters:c,generateOperationIds:i});j.get("",class extends t{static schema={operationId:"get-bucket-list",tags:["Buckets"],summary:"List buckets"};async handle(e,t,a,s){const o=[];for(const[e,a]of Object.entries(t))a.get&&a.put&&o.push({name:e});return{buckets:o}}}),j.get("/:bucket",u),j.post("/:bucket/move",p),j.post("/:bucket/folder",l),j.post("/:bucket/upload",m),j.post("/:bucket/multipart/create",b),j.post("/:bucket/multipart/upload",g),j.post("/:bucket/multipart/complete",f),j.post("/:bucket/delete",y),j.head("/:bucket/:key",k),j.get("/:bucket/:key",h),j.post("/:bucket/:key",w);let R={},I=0;function x(e){return`https://${e}.cloudflareaccess.com`}async function M(e,t,a){let s=!1;try{s=await async function(e,t){const a=function(e){const t=e.headers.get("cf-access-jwt-assertion");if(!t)return null;return t.trim()}(e);if(null===a)return!1;(0===Object.keys(R).length||Math.floor(Date.now()/1e3)<I)&&(R=await async function(e){let t=`${x(e.cfAccessTeamName)}/cdn-cgi/access/certs`;const a=await fetch(t,{method:"GET",cf:{cacheTtlByStatus:{"200-299":30,"300-599":0}},headers:{"Content-Type":"application/json; charset=UTF-8"}}),s=await a.json();I=Math.floor(Date.now()/1e3)+3600;const o={};for(const e of s.keys)o[e.kid]=await crypto.subtle.importKey("jwk",e,{name:"RSASSA-PKCS1-v1_5",hash:"SHA-256"},!1,["verify"]);return o}(t));let s;try{s=function(e){const t=e.split("."),a=JSON.parse(atob(t[0])),s=JSON.parse(atob(t[1])),o=atob(t[2].replace(/_/g,"/").replace(/-/g,"+"));return{header:a,payload:s,signature:o,raw:{header:t[0],payload:t[1],signature:t[2]}}}(a)}catch(e){return!1}const o=new Date(1e3*s.payload.exp),n=new Date(Date.now());if(o<=n)return console.log("expired token"),!1;if(s.payload?.iss!==x(t.cfAccessTeamName))return console.log("invalid access signer"),!1;if(!async function(e){const t=(new TextEncoder).encode([e.raw.header,e.raw.payload].join(".")),a=new Uint8Array(Array.from(e.signature).map((e=>e.charCodeAt(0))));for(const e of Object.values(R)){if(await U(e,a,t))return!0}return!1}(s))return!1;return s}(e,a.config)}catch(e){}if(!1===s)return Response.json({success:!1,errors:[{code:1e4,message:"Authentication error! Verify that the Cloudflare Access Team name is correct"}]},{status:401});a.username=s.payload.email}async function U(e,t,a){return crypto.subtle.verify("RSASSA-PKCS1-v1_5",e,t,a)}async function C(e,t,a){const s=caches.default;let o,n=new URL(e.url).pathname;if(n.includes(".")||(n="/"),!1!==a.config.cacheAssets&&(o=await s.match(e),o))return o;let r="https://demo.r2explorer.dev";a.config?.dashboardUrl&&(r=a.config.dashboardUrl.endsWith("/")?a.config.dashboardUrl.slice(0,-1):a.config.dashboardUrl);const c=await fetch(`${r}${n}`);return o=new Response(await c.text(),{status:c.status,headers:{"Content-Type":c.headers.get("Content-Type"),"Access-Control-Allow-Origin":"*","Cache-Control":"max-age: 300"}}),200===c.status&&!1!==a.config.cacheAssets&&a.executionContext.waitUntil(s.put(e,o.clone())),o}const S=require("postal-mime/dist/node").postalMime.default;async function q(e,t,a){let s;if(a.config?.emailRouting?.targetBucket&&t[a.config.emailRouting.targetBucket]&&(s=t[a.config.emailRouting.targetBucket]),!s)for(const[e,a]of Object.entries(t))if(a.get&&a.put){s=a;break}const o=await async function(e,t){let a=new Uint8Array(t),s=0;const o=e.getReader();for(;;){const{done:e,value:t}=await o.read();if(e)break;a.set(t,s),s+=t.length}return a}(e.raw,e.rawSize),n=new S,r=await n.parse(o),c=`${Math.floor(Date.now())}-${crypto.randomUUID()}`;await s.put(`.r2-explorer/emails/inbox/${c}.json`,JSON.stringify(r),{customMetadata:{subject:r.subject,from_address:r.from?.address,from_name:r.from?.name,to_address:r.to.length>0?r.to[0].address:null,to_name:r.to.length>0?r.to[0].name:null,has_attachments:r.attachments.length>0,read:!1}});for(const e of r.attachments)await s.put(`.r2-explorer/emails/inbox/${c}/${e.filename}`,e.content)}const v=n({base:"/api/server",raiseUnknownParameters:c,generateOperationIds:i});function A(t){!1!==(t=t||{}).readonly&&(t.readonly=!0);const a=n({schema:{info:{title:"R2 Explorer API",version:d}}}),{preflight:s,corsify:o}=e();return t.cfAccessTeamName&&a.all("*",M),!0===t.cors&&a.all("*",s),a.all("/api/server/*",v),a.all("/api/buckets/*",j),a.original.get("*",C),a.all("*",(()=>Response.json({msg:"404, not found!"},{status:404}))),{async email(e,a,s){await q(e,a,{executionContext:s,config:t})},async fetch(e,s,n){let r=await a.handle(e,s,{executionContext:n,config:t});return!0===t.cors&&(r=o(r)),r}}}v.get("/config",class extends t{static schema={operationId:"get-server-info",tags:["Server"],summary:"Get server info"};async handle(e,t,a,s){return{version:d,config:a.config,user:{username:a.username}}}});export{A as R2Explorer};
@@ -0,0 +1,4 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { Context, R2ExplorerConfig } from "../../interfaces";
3
+ export declare function authenticateUser(request: any, env: any, context: Context): Promise<Response>;
4
+ export declare function isValidJwt(request: any, config: R2ExplorerConfig): Promise<any>;
@@ -0,0 +1,8 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class CreateFolder extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<any>;
8
+ }
@@ -0,0 +1,8 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class DeleteObject extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<any>;
8
+ }
@@ -0,0 +1,8 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class DownloadObject extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<Response>;
8
+ }
@@ -0,0 +1,8 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class GetObject extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<Response>;
8
+ }
@@ -0,0 +1,8 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class HeadObject extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<any>;
8
+ }
@@ -0,0 +1,10 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class ListBuckets extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<{
8
+ buckets: any[];
9
+ }>;
10
+ }
@@ -0,0 +1,8 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class ListObjects extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<any>;
8
+ }
@@ -0,0 +1,8 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class MoveObject extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<any>;
8
+ }
@@ -0,0 +1,11 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class CompleteUpload extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<Response | {
8
+ success: boolean;
9
+ str: any;
10
+ }>;
11
+ }
@@ -0,0 +1,11 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class CreateUpload extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<Response | {
8
+ uploadId: any;
9
+ key: any;
10
+ }>;
11
+ }
@@ -0,0 +1,8 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class PartUpload extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<any>;
8
+ }
@@ -0,0 +1,8 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class PutMetadata extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<any>;
8
+ }
@@ -0,0 +1,8 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class PutObject extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<any>;
8
+ }
@@ -0,0 +1,8 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class RenameObject extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<any>;
8
+ }
@@ -0,0 +1,10 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class UploadObject extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<Response | {
8
+ success: boolean;
9
+ }>;
10
+ }
@@ -0,0 +1 @@
1
+ export declare const bucketsRouter: import("@cloudflare/itty-router-openapi").OpenAPIRouterType<import("@cloudflare/itty-router-openapi").Route, any[]>;
@@ -0,0 +1,2 @@
1
+ import { Context } from "./interfaces";
2
+ export declare function dashboardProxy(request: any, env: any, context: Context): Promise<any>;
@@ -0,0 +1,2 @@
1
+ export declare function getCurrentTimestampSeconds(): number;
2
+ export declare function getCurrentTimestampMilliseconds(): number;
@@ -0,0 +1,2 @@
1
+ import { Context } from "../interfaces";
2
+ export declare function receiveEmail(event: any, env: any, ctx: Context): Promise<void>;
@@ -0,0 +1,5 @@
1
+ import { R2ExplorerConfig } from "./interfaces";
2
+ export declare function R2Explorer(config?: R2ExplorerConfig): {
3
+ email(event: any, env: any, context: any): Promise<void>;
4
+ fetch(request: any, env: any, context: any): Promise<any>;
5
+ };
@@ -0,0 +1,21 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ export interface BasicAuth {
3
+ username: string;
4
+ password: string;
5
+ }
6
+ export interface R2ExplorerConfig {
7
+ readonly?: boolean;
8
+ cors?: boolean;
9
+ cfAccessTeamName?: string;
10
+ dashboardUrl?: string;
11
+ emailRouting?: {
12
+ targetBucket: string;
13
+ };
14
+ showHiddenFiles?: string;
15
+ cacheAssets?: boolean;
16
+ }
17
+ export interface Context {
18
+ config: R2ExplorerConfig;
19
+ username?: string;
20
+ executionContext: ExecutionContext;
21
+ }
@@ -0,0 +1,8 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class CreateFolder extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<any>;
8
+ }
@@ -0,0 +1,10 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class DeleteObject extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<Response | {
8
+ success: boolean;
9
+ }>;
10
+ }
@@ -0,0 +1,8 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class DownloadObject extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<Response>;
8
+ }
@@ -0,0 +1,14 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class GetInfo extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<{
8
+ version: string;
9
+ config: import("../../interfaces").R2ExplorerConfig;
10
+ user: {
11
+ username: string;
12
+ };
13
+ }>;
14
+ }
@@ -0,0 +1,14 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class ListBuckets extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<{
8
+ Buckets: any[];
9
+ config: import("../../interfaces").R2ExplorerConfig;
10
+ user: {
11
+ email: string;
12
+ };
13
+ }>;
14
+ }
@@ -0,0 +1,11 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class ListObjects extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<{
8
+ Contents: any[];
9
+ CommonPrefixes: any[];
10
+ }>;
11
+ }
@@ -0,0 +1,11 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class CompleteUpload extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<Response | {
8
+ success: boolean;
9
+ str: any;
10
+ }>;
11
+ }
@@ -0,0 +1,11 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class CreateUpload extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<Response | {
8
+ uploadId: any;
9
+ key: any;
10
+ }>;
11
+ }
@@ -0,0 +1,8 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class PartUpload extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<any>;
8
+ }
@@ -0,0 +1,10 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class RenameObject extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<Response | {
8
+ success: boolean;
9
+ }>;
10
+ }
@@ -0,0 +1,10 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { OpenAPIRoute } from "@cloudflare/itty-router-openapi";
3
+ import { Context } from "../../interfaces";
4
+ import { OpenAPIRouteSchema } from "@cloudflare/itty-router-openapi/dist/src/types";
5
+ export declare class UploadObject extends OpenAPIRoute {
6
+ static schema: OpenAPIRouteSchema;
7
+ handle(request: Request, env: any, context: Context, data: any): Promise<Response | {
8
+ success: boolean;
9
+ }>;
10
+ }
@@ -0,0 +1 @@
1
+ export declare const serverRouter: import("@cloudflare/itty-router-openapi").OpenAPIRouterType<import("@cloudflare/itty-router-openapi").Route, any[]>;
@@ -0,0 +1,5 @@
1
+ export declare const config: {
2
+ raiseUnknownParameters: boolean;
3
+ generateOperationIds: boolean;
4
+ version: string;
5
+ };
package/package.json CHANGED
@@ -1,28 +1,48 @@
1
1
  {
2
2
  "name": "r2-explorer",
3
- "version": "0.6.0",
3
+ "version": "1.0.0",
4
4
  "description": "A Google Drive Interface for your Cloudflare R2 Buckets",
5
- "main": "dist/umd/index.js",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/src/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/src/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "bin",
17
+ "dist"
18
+ ],
6
19
  "scripts": {
7
20
  "postinstallDisabled": "husky install",
8
21
  "prepublishOnly": "pinst --disable",
9
22
  "postpublish": "pinst --enable",
10
- "build": "npm run build:umd",
11
- "build:umd": "node tools/cleanup umd && rollup --config config/rollup.config.js",
23
+ "build": "node tools/cleanup umd && rollup --config rollup.config.js",
12
24
  "clean": "node tools/cleanup",
13
25
  "package": "npm run build && npm pack",
14
26
  "test": "jest --no-cache --runInBand",
15
27
  "test:cov": "jest --coverage --no-cache --runInBand",
16
28
  "addscope": "node tools/packagejson name @g4brym/r2-explorer",
17
29
  "prettify": "prettier . --write --ignore-unknown",
18
- "prepareDisabled": "husky install"
30
+ "prepareDisabled": "husky install",
31
+ "watch": "npm-watch build"
32
+ },
33
+ "watch": {
34
+ "build": {
35
+ "patterns": [
36
+ "src"
37
+ ],
38
+ "extensions": "js,ts",
39
+ "legacyWatch": true,
40
+ "runOnChangeOnly": false
41
+ }
19
42
  },
20
43
  "publishConfig": {
21
44
  "access": "public"
22
45
  },
23
- "files": [
24
- "dist"
25
- ],
26
46
  "keywords": [
27
47
  "cloudflare",
28
48
  "worker",
@@ -45,7 +65,7 @@
45
65
  ],
46
66
  "author": "Gabriel Massadas",
47
67
  "license": "MIT",
48
- "homepage": "https://github.com/G4brym/R2-Explorer",
68
+ "homepage": "https://r2explorer.dev",
49
69
  "repository": {
50
70
  "type": "git",
51
71
  "url": "git@github.com:G4brym/R2-Explorer.git"
@@ -54,30 +74,29 @@
54
74
  "url": "https://github.com/G4brym/R2-Explorer/issues"
55
75
  },
56
76
  "devDependencies": {
57
- "@commitlint/cli": "^13.1.0",
58
- "@commitlint/config-conventional": "^13.1.0",
59
- "@rollup/plugin-commonjs": "^17.0.0",
60
- "@rollup/plugin-json": "^5.0.1",
61
- "@rollup/plugin-node-resolve": "^11.1.0",
62
- "@types/jest": "^27.0.1",
63
- "@typescript-eslint/eslint-plugin": "^4.31.1",
64
- "@typescript-eslint/parser": "^4.31.1",
65
- "eslint": "^7.32.0",
66
- "eslint-config-prettier": "^8.3.0",
67
- "eslint-plugin-prettier": "^4.0.0",
68
- "husky": "^7.0.2",
69
- "jest": "^28.1.2",
77
+ "@cloudflare/workers-types": "^4.20230518.0",
78
+ "@rollup/plugin-terser": "^0.4.3",
79
+ "@rollup/plugin-typescript": "^11.1.2",
80
+ "@types/node": "^18.11.18",
81
+ "@types/service-worker-mock": "^2.0.1",
82
+ "eslint": "^8.18.0",
83
+ "eslint-config-prettier": "^8.5.0",
84
+ "eslint-config-typescript": "^3.0.0",
85
+ "husky": "^8.0.0",
86
+ "npm-watch": "^0.11.0",
70
87
  "pinst": "^2.1.6",
71
- "prettier": "^2.4.0",
88
+ "prettier": "^2.7.1",
72
89
  "rollup": "^2.36.1",
73
- "rollup-plugin-ts": "^3.0.2",
74
- "ts-jest": "^28.0.5",
75
- "ts-loader": "^9.2.5",
76
- "typescript": "^4.4.3",
77
- "wrangler": "^3.1.1"
90
+ "rollup-plugin-bundle-size": "^1.0.3",
91
+ "rollup-plugin-copy": "^3.4.0",
92
+ "service-worker-mock": "^2.0.5",
93
+ "ts-node": "^10.9.1",
94
+ "typescript": "^4.7.4",
95
+ "wrangler": "^3.6.0"
78
96
  },
79
97
  "dependencies": {
80
- "itty-router": "^2.6.1"
98
+ "@cloudflare/itty-router-openapi": "https://prerelease-registry.devprod.cloudflare.dev/itty-router-openapi/runs/5881739194/npm-package-itty-router-openapi-83",
99
+ "postal-mime": "^1.0.16"
81
100
  },
82
101
  "bin": {
83
102
  "r2-explorer": "bin/r2-explorer.js"
@@ -1,70 +0,0 @@
1
- #! /usr/bin/env node
2
- var fs = require('fs')
3
-
4
- const args = process.argv.slice(2)
5
- const projectName = args[0] || 'r2-explorer'
6
-
7
- const dir = `./${projectName}`
8
- if (!fs.existsSync(dir)) {
9
- fs.mkdirSync(dir)
10
- }
11
-
12
- fs.writeFileSync(
13
- `${dir}/wrangler.toml`,
14
- `name = "${projectName}"
15
- compatibility_date = "2022-08-09"
16
- main = "src/index.js"
17
-
18
- [[r2_buckets]]
19
- binding = 'my-bucket-name'
20
- bucket_name = 'my-bucket-name'
21
- preview_bucket_name = 'my-bucket-name'
22
- `
23
- )
24
- fs.writeFileSync(
25
- `${dir}/package.json`,
26
- `{
27
- "name": "${projectName}",
28
- "version": "0.1.0",
29
- "private": true,
30
- "devDependencies": {
31
- "wrangler": "^2.4.2"
32
- },
33
- "scripts": {
34
- "publish": "wrangler publish"
35
- },
36
- "dependencies": {
37
- "r2-explorer": "^0.6.0"
38
- }
39
- }
40
-
41
- `
42
- )
43
-
44
- const srcDir = `${dir}/src`
45
- if (!fs.existsSync(srcDir)) {
46
- fs.mkdirSync(srcDir)
47
- }
48
-
49
- fs.writeFileSync(
50
- `${srcDir}/index.js`,
51
- `import { R2Explorer } from 'r2-explorer';
52
-
53
- const explorer = R2Explorer({ readonly: true })
54
-
55
- export default {
56
- async fetch(request, env, context) {
57
- return explorer(request, env, context)
58
- }
59
- };
60
- `
61
- )
62
-
63
- console.log(`Project ${projectName} successfully created!`)
64
- console.log('----------------------------')
65
- console.log('Next steps:')
66
- console.log(` 1. Run 'cd ${projectName} && npm install'`)
67
- console.log(" 2. Update the 'wrangler.toml' file with your R2 Buckets")
68
- console.log(" 3. Run 'wrangler publish' to deploy your own R2-Explorer!")
69
-
70
- process.exit(0) //no errors occurred