From a3d2e06fb45747d99c1cb551178101709d75213f Mon Sep 17 00:00:00 2001 From: Siyu Long Date: Tue, 20 Aug 2024 16:05:00 +0800 Subject: [PATCH 01/19] Add Cx File Explorer --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ce92b5..1f95123 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ npx wrangler pages deploy build ### WebDAV endpoint -You can use any client (such as [BD File Manager](https://play.google.com/store/apps/details?id=com.liuzho.file.explorer)) +You can use any client (such as [Cx File Explorer](https://play.google.com/store/apps/details?id=com.cxinventor.file.explorer), [BD File Manager](https://play.google.com/store/apps/details?id=com.liuzho.file.explorer)) that supports the WebDAV protocol to access your files. Fill the endpoint URL as `https:///webdav` and use the username and password you set. From 401ba35363850adca6c6f3ca5b04a26c4154402f Mon Sep 17 00:00:00 2001 From: longern Date: Tue, 3 Sep 2024 15:27:08 +0800 Subject: [PATCH 02/19] Fix context menu --- src/FileGrid.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/FileGrid.tsx b/src/FileGrid.tsx index 755031a..c48a8d0 100644 --- a/src/FileGrid.tsx +++ b/src/FileGrid.tsx @@ -49,24 +49,24 @@ function FileGrid({ {files.map((file) => ( { + onClick={() => { if (multiSelected !== null) { onMultiSelect(file.key); - event.preventDefault(); } else if (isDirectory(file)) { onCwdChange(file.key + "/"); - event.preventDefault(); - } + } else + window.open( + `/webdav/${encodeKey(file.key)}`, + "_blank", + "noopener,noreferrer" + ); }} onContextMenu={(e) => { e.preventDefault(); onMultiSelect(file.key); }} + sx={{ userSelect: "none" }} > {file.customMetadata?.thumbnail ? ( From 034bd483024e1401499c7080aad39688c2cdb5a8 Mon Sep 17 00:00:00 2001 From: Siyu Long Date: Wed, 11 Dec 2024 17:48:30 +0800 Subject: [PATCH 03/19] Update framework preset in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1f95123..261b076 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Before starting, you should make sure that Steps: 1. Fork this project and connect your fork with Cloudflare Pages - - Select `Create React App` framework preset + - Select `Docusaurus` framework preset - Set `WEBDAV_USERNAME` and `WEBDAV_PASSWORD` - (Optional) Set `WEBDAV_PUBLIC_READ` to `1` to enable public read 2. After initial deployment, bind your R2 bucket to `BUCKET` variable From cccc5a86ec8885297536cc53d2f2bd8eef5be6fc Mon Sep 17 00:00:00 2001 From: longern Date: Tue, 17 Dec 2024 14:52:38 +0800 Subject: [PATCH 04/19] Add share feature --- src/Main.tsx | 8 ++++++++ src/MultiSelectToolbar.tsx | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Main.tsx b/src/Main.tsx index 19a3f1e..aad296f 100644 --- a/src/Main.tsx +++ b/src/Main.tsx @@ -237,6 +237,14 @@ function Main({ await fetch(`/webdav/${encodeKey(key)}`, { method: "DELETE" }); fetchFiles(); }} + onShare={() => { + if (multiSelected?.length !== 1) return; + const url = new URL( + `/webdav/${encodeKey(multiSelected[0])}`, + window.location.href + ); + navigator.share({ url: url.toString() }); + }} /> ); diff --git a/src/MultiSelectToolbar.tsx b/src/MultiSelectToolbar.tsx index 186419a..324b37b 100644 --- a/src/MultiSelectToolbar.tsx +++ b/src/MultiSelectToolbar.tsx @@ -13,12 +13,14 @@ function MultiSelectToolbar({ onDownload, onRename, onDelete, + onShare, }: { multiSelected: string[] | null; onClose: () => void; onDownload: () => void; onRename: () => void; onDelete: () => void; + onShare: () => void; }) { const [anchorEl, setAnchorEl] = useState(null); @@ -69,7 +71,7 @@ function MultiSelectToolbar({ {multiSelected.length === 1 && ( Rename - Share + Share )} From c78030e823a49b8ced7f50c1e8c2fc4642ebd5ea Mon Sep 17 00:00:00 2001 From: Sujal Patel <76617735+SujalPatel75@users.noreply.github.com> Date: Mon, 17 Mar 2025 23:45:21 +0530 Subject: [PATCH 05/19] Add files via upload --- src/Main.tsx | 77 +++++++++++++++++++++++++------------ src/TextPadDrawer.tsx | 88 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 25 deletions(-) create mode 100644 src/TextPadDrawer.tsx diff --git a/src/Main.tsx b/src/Main.tsx index aad296f..6c8c52e 100644 --- a/src/Main.tsx +++ b/src/Main.tsx @@ -1,4 +1,4 @@ -import { Home as HomeIcon } from "@mui/icons-material"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import { Box, Breadcrumbs, @@ -7,14 +7,16 @@ import { Link, Typography, } from "@mui/material"; -import React, { useCallback, useEffect, useMemo, useState } from "react"; +import { Home as HomeIcon, NoteAdd as NoteAddIcon } from "@mui/icons-material"; import FileGrid, { encodeKey, FileItem, isDirectory } from "./FileGrid"; import MultiSelectToolbar from "./MultiSelectToolbar"; import UploadDrawer, { UploadFab } from "./UploadDrawer"; +import TextPadDrawer from "./TextPadDrawer"; import { copyPaste, fetchPath } from "./app/transfer"; import { useTransferQueue, useUploadEnqueue } from "./app/transferQueue"; +// Centered helper function Centered({ children }: { children: React.ReactNode }) { return ( @@ -71,6 +71,7 @@ function PathBreadcrumb({ ); } +// DropZone wrapper function DropZone({ children, onDrop, @@ -89,18 +90,18 @@ function DropZone({ filter: dragging ? "brightness(0.9)" : "none", transition: "filter 0.2s", }} - onDragEnter={(event) => { - event.preventDefault(); + onDragEnter={(e) => { + e.preventDefault(); setDragging(true); }} - onDragOver={(event) => { - event.preventDefault(); - event.dataTransfer.dropEffect = "copy"; + onDragOver={(e) => { + e.preventDefault(); + e.dataTransfer.dropEffect = "copy"; }} onDragLeave={() => setDragging(false)} - onDrop={(event) => { - event.preventDefault(); - onDrop(event.dataTransfer.files); + onDrop={(e) => { + e.preventDefault(); + onDrop(e.dataTransfer.files); setDragging(false); }} > @@ -109,6 +110,7 @@ function DropZone({ ); } +// Main Component function Main({ search, onError, @@ -116,11 +118,12 @@ function Main({ search: string; onError: (error: Error) => void; }) { - const [cwd, setCwd] = React.useState(""); + const [cwd, setCwd] = useState(""); const [files, setFiles] = useState([]); const [loading, setLoading] = useState(true); const [multiSelected, setMultiSelected] = useState(null); const [showUploadDrawer, setShowUploadDrawer] = useState(false); + const [showTextPadDrawer, setShowTextPadDrawer] = useState(false); const [lastUploadKey, setLastUploadKey] = useState(null); const transferQueue = useTransferQueue(); @@ -165,20 +168,20 @@ function Main({ ); const handleMultiSelect = useCallback((key: string) => { - setMultiSelected((multiSelected) => { - if (multiSelected === null) { - return [key]; - } else if (multiSelected.includes(key)) { - const newSelected = multiSelected.filter((k) => k !== key); - return newSelected.length ? newSelected : null; + setMultiSelected((prev) => { + if (prev === null) return [key]; + if (prev.includes(key)) { + const updated = prev.filter((k) => k !== key); + return updated.length ? updated : null; } - return [...multiSelected, key]; + return [...prev, key]; }); }, []); return ( - + <> {cwd && } + {loading ? ( @@ -200,15 +203,39 @@ function Main({ /> )} + {multiSelected === null && ( - setShowUploadDrawer(true)} /> + <> + setShowUploadDrawer(true)} /> + + )} + + + + setMultiSelected(null)} @@ -246,7 +273,7 @@ function Main({ navigator.share({ url: url.toString() }); }} /> - + ); } diff --git a/src/TextPadDrawer.tsx b/src/TextPadDrawer.tsx new file mode 100644 index 0000000..d042e4d --- /dev/null +++ b/src/TextPadDrawer.tsx @@ -0,0 +1,88 @@ +// TextPadDrawer.tsx +import React, { useState } from "react"; +import { + Drawer, + IconButton, + TextField, + Box, + Typography, + Button, +} from "@mui/material"; +import { Close as CloseIcon, Save as SaveIcon } from "@mui/icons-material"; +import { useUploadEnqueue } from "./app/transferQueue"; + +const TextPadDrawer = ({ + open, + setOpen, + cwd, + onUpload, +}: { + open: boolean; + setOpen: (open: boolean) => void; + cwd: string; + onUpload: () => void; +}) => { + const [noteTitle, setNoteTitle] = useState(""); + const [noteContent, setNoteContent] = useState(""); + + const uploadEnqueue = useUploadEnqueue(); + + const handleSaveAndUpload = async () => { + if (!noteTitle || !noteContent) return; + + const file = new File([noteContent], `${noteTitle}.txt`, { + type: "text/plain", + }); + + uploadEnqueue({ file, basedir: cwd }); + setOpen(false); + setNoteTitle(""); + setNoteContent(""); + onUpload(); + }; + + return ( + setOpen(false)}> + + + TextPad + setOpen(false)}> + + + + + setNoteTitle(e.target.value)} + /> + + setNoteContent(e.target.value)} + /> + + + + + ); +}; + +export default TextPadDrawer; From aa5da56233d88cb34ddd97a3b1bca74db656d5d7 Mon Sep 17 00:00:00 2001 From: Sujal Patel <76617735+SujalPatel75@users.noreply.github.com> Date: Mon, 17 Mar 2025 23:52:38 +0530 Subject: [PATCH 06/19] Add files via upload --- Main.tsx | 279 ++++++++++++++++++++++++++++++++++++++++++++++ TextPadDrawer.tsx | 87 +++++++++++++++ 2 files changed, 366 insertions(+) create mode 100644 Main.tsx create mode 100644 TextPadDrawer.tsx diff --git a/Main.tsx b/Main.tsx new file mode 100644 index 0000000..ab10f01 --- /dev/null +++ b/Main.tsx @@ -0,0 +1,279 @@ +// Main.tsx +import React, { useCallback, useEffect, useMemo, useState } from "react"; +import { + Box, + Breadcrumbs, + Button, + CircularProgress, + Link, + Typography, +} from "@mui/material"; +import { Home as HomeIcon, NoteAdd as NoteAddIcon } from "@mui/icons-material"; + +import FileGrid, { encodeKey, FileItem, isDirectory } from "./FileGrid"; +import MultiSelectToolbar from "./MultiSelectToolbar"; +import UploadDrawer, { UploadFab } from "./UploadDrawer"; +import TextPadDrawer from "./TextPadDrawer"; +import { copyPaste, fetchPath } from "./app/transfer"; +import { useTransferQueue, useUploadEnqueue } from "./app/transferQueue"; + +// Centered helper +function Centered({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} + +// Breadcrumb component +function PathBreadcrumb({ + path, + onCwdChange, +}: { + path: string; + onCwdChange: (newCwd: string) => void; +}) { + const parts = path.replace(/\/$/, "").split("/"); + + return ( + + + {parts.map((part, index) => + index === parts.length - 1 ? ( + + {part} + + ) : ( + { + onCwdChange(parts.slice(0, index + 1).join("/") + "/"); + }} + > + {part} + + ) + )} + + ); +} + +// DropZone wrapper +function DropZone({ + children, + onDrop, +}: { + children: React.ReactNode; + onDrop: (files: FileList) => void; +}) { + const [dragging, setDragging] = useState(false); + + return ( + theme.palette.background.default, + filter: dragging ? "brightness(0.9)" : "none", + transition: "filter 0.2s", + }} + onDragEnter={(e) => { + e.preventDefault(); + setDragging(true); + }} + onDragOver={(e) => { + e.preventDefault(); + e.dataTransfer.dropEffect = "copy"; + }} + onDragLeave={() => setDragging(false)} + onDrop={(e) => { + e.preventDefault(); + onDrop(e.dataTransfer.files); + setDragging(false); + }} + > + {children} + + ); +} + +// Main Component +function Main({ + search, + onError, +}: { + search: string; + onError: (error: Error) => void; +}) { + const [cwd, setCwd] = useState(""); + const [files, setFiles] = useState([]); + const [loading, setLoading] = useState(true); + const [multiSelected, setMultiSelected] = useState(null); + const [showUploadDrawer, setShowUploadDrawer] = useState(false); + const [showTextPadDrawer, setShowTextPadDrawer] = useState(false); + const [lastUploadKey, setLastUploadKey] = useState(null); + + const transferQueue = useTransferQueue(); + const uploadEnqueue = useUploadEnqueue(); + + const fetchFiles = useCallback(() => { + fetchPath(cwd) + .then((files) => { + setFiles(files); + setMultiSelected(null); + }) + .catch(onError) + .finally(() => setLoading(false)); + }, [cwd, onError]); + + useEffect(() => setLoading(true), [cwd]); + + useEffect(() => { + fetchFiles(); + }, [fetchFiles]); + + useEffect(() => { + if (!transferQueue.length) return; + const lastFile = transferQueue[transferQueue.length - 1]; + if (["pending", "in-progress"].includes(lastFile.status)) { + setLastUploadKey(lastFile.remoteKey); + } else if (lastUploadKey) { + fetchFiles(); + setLastUploadKey(null); + } + }, [cwd, fetchFiles, lastUploadKey, transferQueue]); + + const filteredFiles = useMemo( + () => + (search + ? files.filter((file) => + file.key.toLowerCase().includes(search.toLowerCase()) + ) + : files + ).sort((a, b) => (isDirectory(a) ? -1 : isDirectory(b) ? 1 : 0)), + [files, search] + ); + + const handleMultiSelect = useCallback((key: string) => { + setMultiSelected((prev) => { + if (prev === null) return [key]; + if (prev.includes(key)) { + const updated = prev.filter((k) => k !== key); + return updated.length ? updated : null; + } + return [...prev, key]; + }); + }, []); + + return ( + <> + {cwd && } + + {loading ? ( + + + + ) : ( + { + uploadEnqueue( + ...Array.from(files).map((file) => ({ file, basedir: cwd })) + ); + }} + > + setCwd(newCwd)} + multiSelected={multiSelected} + onMultiSelect={handleMultiSelect} + emptyMessage={No files or folders} + /> + + )} + + {multiSelected === null && ( + <> + setShowUploadDrawer(true)} /> + + + )} + + + + + + setMultiSelected(null)} + onDownload={() => { + if (multiSelected?.length !== 1) return; + const a = document.createElement("a"); + a.href = `/webdav/${encodeKey(multiSelected[0])}`; + a.download = multiSelected[0].split("/").pop()!; + a.click(); + }} + onRename={async () => { + if (multiSelected?.length !== 1) return; + const newName = window.prompt("Rename to:"); + if (!newName) return; + await copyPaste(multiSelected[0], cwd + newName, true); + fetchFiles(); + }} + onDelete={async () => { + if (!multiSelected?.length) return; + const filenames = multiSelected + .map((key) => key.replace(/\/$/, "").split("/").pop()) + .join("\n"); + const confirmMessage = "Delete the following file(s) permanently?"; + if (!window.confirm(`${confirmMessage}\n${filenames}`)) return; + for (const key of multiSelected) + await fetch(`/webdav/${encodeKey(key)}`, { method: "DELETE" }); + fetchFiles(); + }} + onShare={() => { + if (multiSelected?.length !== 1) return; + const url = new URL( + `/webdav/${encodeKey(multiSelected[0])}`, + window.location.href + ); + navigator.share({ url: url.toString() }); + }} + /> + + ); +} + +export default Main; diff --git a/TextPadDrawer.tsx b/TextPadDrawer.tsx new file mode 100644 index 0000000..d3586c4 --- /dev/null +++ b/TextPadDrawer.tsx @@ -0,0 +1,87 @@ +// TextPadDrawer.tsx +import React, { useState } from "react"; +import { + Drawer, + IconButton, + TextField, + Box, + Typography, + Button, +} from "@mui/material"; +import { Close as CloseIcon, Save as SaveIcon } from "@mui/icons-material"; +import { useUploadEnqueue } from "./app/transferQueue"; + +type TextPadDrawerProps = { + open: boolean; + setOpen: (open: boolean) => void; + cwd: string; + onUpload: () => void; +}; + +const TextPadDrawer = ({ open, setOpen, cwd, onUpload }: TextPadDrawerProps) => { + const [noteTitle, setNoteTitle] = useState(""); + const [noteContent, setNoteContent] = useState(""); + + const uploadEnqueue = useUploadEnqueue(); + + const handleSaveAndUpload = async () => { + if (!noteTitle.trim() || !noteContent.trim()) return; + + const file = new File([noteContent], `${noteTitle}.txt`, { + type: "text/plain", + }); + + uploadEnqueue({ file, basedir: cwd }); + + // Reset fields and close drawer + setNoteTitle(""); + setNoteContent(""); + setOpen(false); + onUpload(); // Refresh file list + }; + + return ( + setOpen(false)}> + + + TextPad + setOpen(false)}> + + + + + setNoteTitle(e.target.value)} + /> + + setNoteContent(e.target.value)} + /> + + + + + ); +}; + +export default TextPadDrawer; From 31506bc02eb37fd62e4b3bb7137ff820c5139f35 Mon Sep 17 00:00:00 2001 From: Sujal Patel <76617735+SujalPatel75@users.noreply.github.com> Date: Mon, 17 Mar 2025 23:55:10 +0530 Subject: [PATCH 07/19] Add files via upload --- src/Main.tsx | 13 ++++---- src/TextPadDrawer.tsx | 76 ++++++++++++++++++++----------------------- 2 files changed, 41 insertions(+), 48 deletions(-) diff --git a/src/Main.tsx b/src/Main.tsx index 6c8c52e..ab10f01 100644 --- a/src/Main.tsx +++ b/src/Main.tsx @@ -1,3 +1,4 @@ +// Main.tsx import React, { useCallback, useEffect, useMemo, useState } from "react"; import { Box, @@ -44,10 +45,7 @@ function PathBreadcrumb({ return ( - {parts.map((part, index) => @@ -148,9 +146,9 @@ function Main({ useEffect(() => { if (!transferQueue.length) return; const lastFile = transferQueue[transferQueue.length - 1]; - if (["pending", "in-progress"].includes(lastFile.status)) + if (["pending", "in-progress"].includes(lastFile.status)) { setLastUploadKey(lastFile.remoteKey); - else if (lastUploadKey) { + } else if (lastUploadKey) { fetchFiles(); setLastUploadKey(null); } @@ -188,7 +186,7 @@ function Main({ ) : ( { + onDrop={(files) => { uploadEnqueue( ...Array.from(files).map((file) => ({ file, basedir: cwd })) ); @@ -234,6 +232,7 @@ function Main({ open={showTextPadDrawer} setOpen={setShowTextPadDrawer} cwd={cwd} + onUpload={fetchFiles} /> void; cwd: string; onUpload: () => void; -}) => { - const [noteTitle, setNoteTitle] = useState(""); - const [noteContent, setNoteContent] = useState(""); +} +const TextPadDrawer: React.FC = ({ + open, + setOpen, + cwd, + onUpload, +}) => { + const [noteText, setNoteText] = useState(""); + const [noteName, setNoteName] = useState("note.txt"); const uploadEnqueue = useUploadEnqueue(); - const handleSaveAndUpload = async () => { - if (!noteTitle || !noteContent) return; - - const file = new File([noteContent], `${noteTitle}.txt`, { - type: "text/plain", - }); - + const handleSaveNote = () => { + const fileBlob = new Blob([noteText], { type: "text/plain" }); + const file = new File([fileBlob], noteName, { type: "text/plain" }); uploadEnqueue({ file, basedir: cwd }); - setOpen(false); - setNoteTitle(""); - setNoteContent(""); - onUpload(); + onUpload(); // Refresh file list after upload + setOpen(false); // Close drawer + setNoteText(""); // Reset + setNoteName("note.txt"); }; return ( setOpen(false)}> - - + + TextPad setOpen(false)}> @@ -52,33 +49,30 @@ const TextPadDrawer = ({ setNoteName(e.target.value)} fullWidth - variant="outlined" - margin="normal" - value={noteTitle} - onChange={(e) => setNoteTitle(e.target.value)} + sx={{ mb: 2 }} /> setNoteContent(e.target.value)} + value={noteText} + onChange={(e) => setNoteText(e.target.value)} + fullWidth /> From 6a351a3d9e3cc5e74bb8302ce2d8881f71894d6c Mon Sep 17 00:00:00 2001 From: "(Moai Emoji)" <25407129+SandiyosDev@users.noreply.github.com> Date: Mon, 9 Jun 2025 00:33:36 -0500 Subject: [PATCH 08/19] fix incorrect WEBDAV_PUBLIC_READ logic --- functions/webdav/[[path]].ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/webdav/[[path]].ts b/functions/webdav/[[path]].ts index f9077e8..16a6340 100644 --- a/functions/webdav/[[path]].ts +++ b/functions/webdav/[[path]].ts @@ -45,7 +45,7 @@ export const onRequest: PagesFunction<{ if (request.method === "OPTIONS") return handleRequestOptions(); const skipAuth = - env.WEBDAV_PUBLIC_READ && + env.WEBDAV_PUBLIC_READ === "1" && ["GET", "HEAD", "PROPFIND"].includes(request.method); if (!skipAuth) { From a0d55a39df41e427011916829e18e4cc65c3f32e Mon Sep 17 00:00:00 2001 From: Siyu Long Date: Mon, 13 Oct 2025 14:04:25 +0800 Subject: [PATCH 09/19] Add DAV header --- functions/webdav/[[path]].ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/functions/webdav/[[path]].ts b/functions/webdav/[[path]].ts index 16a6340..fbc3e42 100644 --- a/functions/webdav/[[path]].ts +++ b/functions/webdav/[[path]].ts @@ -12,7 +12,10 @@ import { handleRequestPost } from "./post"; async function handleRequestOptions() { return new Response(null, { - headers: { Allow: Object.keys(HANDLERS).join(", ") }, + headers: { + Allow: Object.keys(HANDLERS).join(", "), + DAV: "1", + }, }); } From 41ba825e7ada24f95c9e6b4f524838cdc9066710 Mon Sep 17 00:00:00 2001 From: boy86001 <103086198+boy86001@users.noreply.github.com> Date: Sun, 30 Nov 2025 11:48:52 +0800 Subject: [PATCH 10/19] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20robots.txt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/robots.txt | 59 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/public/robots.txt b/public/robots.txt index e9e57dc..3dad881 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -1,3 +1,56 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * -Disallow: +# As a condition of accessing this website, you agree to abide by the following +# content signals: + +# (a) If a content-signal = yes, you may collect content for the corresponding +# use. +# (b) If a content-signal = no, you may not collect content for the +# corresponding use. +# (c) If the website operator does not include a content signal for a +# corresponding use, the website operator neither grants nor restricts +# permission via content signal with respect to the corresponding use. + +# The content signals and their meanings are: + +# search: building a search index and providing search results (e.g., returning +# hyperlinks and short excerpts from your website's contents). Search does not +# include providing AI-generated search summaries. +# ai-input: inputting content into one or more AI models (e.g., retrieval +# augmented generation, grounding, or other real-time taking of content for +# generative AI search answers). +# ai-train: training or fine-tuning AI models. + +# ANY RESTRICTIONS EXPRESSED VIA CONTENT SIGNALS ARE EXPRESS RESERVATIONS OF +# RIGHTS UNDER ARTICLE 4 OF THE EUROPEAN UNION DIRECTIVE 2019/790 ON COPYRIGHT +# AND RELATED RIGHTS IN THE DIGITAL SINGLE MARKET. + +# BEGIN Cloudflare Managed content + +User-Agent: * +Content-signal: search=yes,ai-train=no +Allow: / + +User-agent: Amazonbot +Disallow: / + +User-agent: Applebot-Extended +Disallow: / + +User-agent: Bytespider +Disallow: / + +User-agent: CCBot +Disallow: / + +User-agent: ClaudeBot +Disallow: / + +User-agent: Google-Extended +Disallow: / + +User-agent: GPTBot +Disallow: / + +User-agent: meta-externalagent +Disallow: / + +# END Cloudflare Managed Content From ef07983ac4849d75efb6c749b0363f0d6cb5ebfb Mon Sep 17 00:00:00 2001 From: boy86001 <103086198+boy86001@users.noreply.github.com> Date: Sun, 30 Nov 2025 11:49:46 +0800 Subject: [PATCH 11/19] Add files via upload --- public/sitemap.xml | 165 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 public/sitemap.xml diff --git a/public/sitemap.xml b/public/sitemap.xml new file mode 100644 index 0000000..b473888 --- /dev/null +++ b/public/sitemap.xml @@ -0,0 +1,165 @@ + + + + + https://zero001.icu/webdav/index.html + 2025-11-26 + weekly + 1.0 + + + + + https://zero001.icu/webdav/index.html?post=2024-06-25 + 2024-06-25 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2024-09-19 + 2024-09-19 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2024-09-25 + 2024-09-25 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2024-10-19 + 2024-10-19 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2024-10-21 + 2024-10-21 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2024-10-24 + 2024-10-24 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2024-10-31 + 2024-10-31 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2024-11-07 + 2024-11-07 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2024-11-19 + 2024-11-19 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2025-01-05 + 2025-01-05 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2025-01-22 + 2025-01-22 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2025-03-19 + 2025-03-19 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2025-04-10 + 2025-04-10 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2025-04-17 + 2025-04-17 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2025-05-30 + 2025-05-30 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2025-05-31 + 2025-05-31 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2025-07-14 + 2025-07-14 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2025-08-18 + 2025-08-18 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2025-08-23 + 2025-08-23 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2025-08-26 + 2025-08-26 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2025-11-26 + 2025-11-26 + monthly + 0.8 + + + + https://zero001.icu/webdav/index.html?post=2025-11-29 + 2025-11-29 + monthly + 0.8 + + \ No newline at end of file From 5e93cec4efbd7c304fd205a4a577608fb12bd974 Mon Sep 17 00:00:00 2001 From: boy86001 <103086198+boy86001@users.noreply.github.com> Date: Sun, 30 Nov 2025 12:04:12 +0800 Subject: [PATCH 12/19] Add workflow for manual branch synchronization --- .github/workflows/Modify.yml | 42 ++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/workflows/Modify.yml diff --git a/.github/workflows/Modify.yml b/.github/workflows/Modify.yml new file mode 100644 index 0000000..6e7b1ce --- /dev/null +++ b/.github/workflows/Modify.yml @@ -0,0 +1,42 @@ +name: 手动同步分支 + +on: + workflow_dispatch: + inputs: + source_branch: + description: 'Modify' + required: true + default: 'Original' + type: string + target_branch: + description: 'main' + required: true + default: 'Modify' + type: string + +jobs: + sync-branches: + runs-on: ubuntu-latest + + steps: + - name: 检出代码 + uses: actions/checkout@v4 + with: + fetch-depth: 0 # 获取完整历史记录 + + - name: 配置 Git + run: | + git config user.name "GitHub Actions Bot" + git config user.email "actions@github.com" + + - name: 同步分支 + run: | + echo "从 ${{ inputs.source_branch }} 同步到 ${{ inputs.target_branch }}" + git fetch origin ${{ inputs.source_branch }} + git checkout ${{ inputs.target_branch }} + git merge origin/${{ inputs.source_branch }} --no-ff -m "Merge ${{ inputs.source_branch }} into ${{ inputs.target_branch }}" + git push origin ${{ inputs.target_branch }} + + - name: 完成提示 + run: | + echo "✅ 成功将 ${{ inputs.source_branch }} 同步到 ${{ inputs.target_branch }}" From 0f77371b2ae252b7d46baeb1ab0cec168ca77696 Mon Sep 17 00:00:00 2001 From: boy86001 <103086198+boy86001@users.noreply.github.com> Date: Sun, 30 Nov 2025 12:14:50 +0800 Subject: [PATCH 13/19] Create workflow to sync Original branch to main --- .github/workflows/Modify.yml | 42 --------------------- .github/workflows/sync-original-to-main.yml | 36 ++++++++++++++++++ 2 files changed, 36 insertions(+), 42 deletions(-) delete mode 100644 .github/workflows/Modify.yml create mode 100644 .github/workflows/sync-original-to-main.yml diff --git a/.github/workflows/Modify.yml b/.github/workflows/Modify.yml deleted file mode 100644 index 6e7b1ce..0000000 --- a/.github/workflows/Modify.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: 手动同步分支 - -on: - workflow_dispatch: - inputs: - source_branch: - description: 'Modify' - required: true - default: 'Original' - type: string - target_branch: - description: 'main' - required: true - default: 'Modify' - type: string - -jobs: - sync-branches: - runs-on: ubuntu-latest - - steps: - - name: 检出代码 - uses: actions/checkout@v4 - with: - fetch-depth: 0 # 获取完整历史记录 - - - name: 配置 Git - run: | - git config user.name "GitHub Actions Bot" - git config user.email "actions@github.com" - - - name: 同步分支 - run: | - echo "从 ${{ inputs.source_branch }} 同步到 ${{ inputs.target_branch }}" - git fetch origin ${{ inputs.source_branch }} - git checkout ${{ inputs.target_branch }} - git merge origin/${{ inputs.source_branch }} --no-ff -m "Merge ${{ inputs.source_branch }} into ${{ inputs.target_branch }}" - git push origin ${{ inputs.target_branch }} - - - name: 完成提示 - run: | - echo "✅ 成功将 ${{ inputs.source_branch }} 同步到 ${{ inputs.target_branch }}" diff --git a/.github/workflows/sync-original-to-main.yml b/.github/workflows/sync-original-to-main.yml new file mode 100644 index 0000000..165911c --- /dev/null +++ b/.github/workflows/sync-original-to-main.yml @@ -0,0 +1,36 @@ +name: Sync Original to Main + +on: + workflow_dispatch: + +permissions: + contents: write + +jobs: + sync-original-to-main: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Configure Git + run: | + git config user.name "GitHub Actions Bot" + git config user.email "actions@github.com" + + - name: Sync Original to Main + run: | + echo "📦 正在从 Original 同步到 main" + git fetch origin Original + git fetch origin main + git checkout main + git merge origin/Original --no-ff -m "🔄 Sync: Merge Original into main" + git push origin main + + - name: Success message + run: | + echo "✅ 成功将 Original 同步到 main" From 123a0a3c8843199d459d31e0d1c87bd68b5f7ed4 Mon Sep 17 00:00:00 2001 From: boy86001 <103086198+boy86001@users.noreply.github.com> Date: Sun, 30 Nov 2025 12:16:04 +0800 Subject: [PATCH 14/19] Add workflow to sync Modify branch to main This workflow automates the synchronization of changes from the 'Modify' branch to the 'main' branch, including checkout, merge, and push steps. --- .github/workflows/sync-modify-to-main.yml | 48 +++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/workflows/sync-modify-to-main.yml diff --git a/.github/workflows/sync-modify-to-main.yml b/.github/workflows/sync-modify-to-main.yml new file mode 100644 index 0000000..4421f21 --- /dev/null +++ b/.github/workflows/sync-modify-to-main.yml @@ -0,0 +1,48 @@ +name: Sync Modify to Main + +on: + workflow_dispatch: + +permissions: + contents: write + +jobs: + sync-modify-to-main: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Configure Git + run: | + git config user.name "GitHub Actions Bot" + git config user.email "actions@github.com" + + - name: Sync Modify to Main + run: | + echo "📦 正在从 Modify 同步到 main" + git fetch origin Modify + git fetch origin main + git checkout main + git merge origin/Modify --no-ff -m "🔄 Sync: Merge Modify into main" + git push origin main + + - name: Success message + run: | + echo "✅ 成功将 Modify 同步到 main" +``` + +--- + +## 📂 文件结构: + +在你的仓库中创建这两个文件: +``` +.github/ + └── workflows/ + ├── sync-original-to-main.yml + └── sync-modify-to-main.yml From 4dfe3f00235f2dbfa726b8f45512dd7979b496af Mon Sep 17 00:00:00 2001 From: boy86001 <103086198+boy86001@users.noreply.github.com> Date: Sun, 30 Nov 2025 12:18:49 +0800 Subject: [PATCH 15/19] Delete .github/workflows/sync-modify-to-main.yml --- .github/workflows/sync-modify-to-main.yml | 48 ----------------------- 1 file changed, 48 deletions(-) delete mode 100644 .github/workflows/sync-modify-to-main.yml diff --git a/.github/workflows/sync-modify-to-main.yml b/.github/workflows/sync-modify-to-main.yml deleted file mode 100644 index 4421f21..0000000 --- a/.github/workflows/sync-modify-to-main.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Sync Modify to Main - -on: - workflow_dispatch: - -permissions: - contents: write - -jobs: - sync-modify-to-main: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Configure Git - run: | - git config user.name "GitHub Actions Bot" - git config user.email "actions@github.com" - - - name: Sync Modify to Main - run: | - echo "📦 正在从 Modify 同步到 main" - git fetch origin Modify - git fetch origin main - git checkout main - git merge origin/Modify --no-ff -m "🔄 Sync: Merge Modify into main" - git push origin main - - - name: Success message - run: | - echo "✅ 成功将 Modify 同步到 main" -``` - ---- - -## 📂 文件结构: - -在你的仓库中创建这两个文件: -``` -.github/ - └── workflows/ - ├── sync-original-to-main.yml - └── sync-modify-to-main.yml From 894948f8391893ec7c27ace1456038195bdd1e7e Mon Sep 17 00:00:00 2001 From: boy86001 <103086198+boy86001@users.noreply.github.com> Date: Sun, 30 Nov 2025 12:19:43 +0800 Subject: [PATCH 16/19] Add workflow to sync Modify branch to main --- .github/workflows/sync-modify-to-main.yml | 36 +++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/sync-modify-to-main.yml diff --git a/.github/workflows/sync-modify-to-main.yml b/.github/workflows/sync-modify-to-main.yml new file mode 100644 index 0000000..bcfb4b0 --- /dev/null +++ b/.github/workflows/sync-modify-to-main.yml @@ -0,0 +1,36 @@ +name: Sync Modify to Main + +on: + workflow_dispatch: + +permissions: + contents: write + +jobs: + sync-modify-to-main: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Configure Git + run: | + git config user.name "GitHub Actions Bot" + git config user.email "actions@github.com" + + - name: Sync Modify to Main + run: | + echo "📦 正在从 Modify 同步到 main" + git fetch origin Modify + git fetch origin main + git checkout main + git merge origin/Modify --no-ff -m "🔄 Sync: Merge Modify into main" + git push origin main + + - name: Success message + run: | + echo "✅ 成功将 Modify 同步到 main" From 403187eb0aa26d45819d5147ec416f4458799e49 Mon Sep 17 00:00:00 2001 From: boy86001 <103086198+boy86001@users.noreply.github.com> Date: Sun, 30 Nov 2025 12:40:10 +0800 Subject: [PATCH 17/19] Create [[path]].ts --- functions/[[path]].ts | 107 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 functions/[[path]].ts diff --git a/functions/[[path]].ts b/functions/[[path]].ts new file mode 100644 index 0000000..b00251e --- /dev/null +++ b/functions/[[path]].ts @@ -0,0 +1,107 @@ +// functions/[[path]].ts +// 这个文件处理根目录的文件访问,同时保持 WebDAV 和管理界面正常工作 + +export const onRequest: PagesFunction<{ + BUCKET: R2Bucket; +}> = async function (context) { + const request = context.request; + const url = new URL(request.url); + const pathname = url.pathname; + + console.log(`[Root Handler] 请求路径: ${pathname}`); + + // ======================================== + // 跳过这些路径,让 TWO 系统处理 + // ======================================== + + const skipPaths = [ + '/', // 首页 - TWO 管理界面 + '/favicon.ico', // 网站图标 + '/robots.txt', // robots + ]; + + const skipPrefixes = [ + '/webdav/', // WebDAV 接口(重要!) + '/api/', // API + '/assets/', // 静态资源 + '/static/', // 静态文件 + '/_next/', // Next.js + '/build/', // Docusaurus 构建文件 + '/img/', // 图片资源 + '/css/', // CSS + '/js/', // JS + '/fonts/', // 字体 + ]; + + // 检查是否需要跳过 + if (skipPaths.includes(pathname)) { + console.log(`[Root Handler] 跳过: ${pathname}`); + return context.next(); + } + + for (const prefix of skipPrefixes) { + if (pathname.startsWith(prefix)) { + console.log(`[Root Handler] 跳过: ${pathname} (匹配 ${prefix})`); + return context.next(); + } + } + + // 如果路径没有文件扩展名且不以 / 结尾,可能是页面路由 + const hasExtension = pathname.includes('.') && !pathname.endsWith('/'); + if (!hasExtension) { + console.log(`[Root Handler] 跳过: ${pathname} (可能是页面路由)`); + return context.next(); + } + + // ======================================== + // 尝试从 R2 获取文件 + // ======================================== + + const bucket = context.env.BUCKET; + + if (!bucket) { + console.error('[Root Handler] R2 bucket 未绑定'); + return new Response('配置错误: R2 bucket 未绑定', { + status: 500, + headers: { 'Content-Type': 'text/plain; charset=utf-8' } + }); + } + + try { + // 移除开头的 / + const objectKey = pathname.substring(1); + + console.log(`[Root Handler] 尝试从 R2 获取: ${objectKey}`); + + // 从 R2 获取文件 + const object = await bucket.get(objectKey); + + if (!object) { + console.log(`[Root Handler] 文件不存在: ${objectKey}`); + + // 文件不存在,交给 TWO 的 404 处理 + return context.next(); + } + + console.log(`[Root Handler] 成功获取文件: ${objectKey}, 大小: ${object.size} 字节`); + + // 构建响应头 + const headers = new Headers(); + object.writeHttpMetadata(headers); + headers.set('ETag', object.httpEtag); + headers.set('Cache-Control', 'public, max-age=3600'); + headers.set('Access-Control-Allow-Origin', '*'); + + // 返回文件内容 + return new Response(object.body, { + status: 200, + headers: headers, + }); + + } catch (error: any) { + console.error(`[Root Handler] 错误: ${error.message}`); + + // 出错了,交给 TWO 处理 + return context.next(); + } +}; From d1400a12fd1262c6712ddae29b5a44897be5d398 Mon Sep 17 00:00:00 2001 From: boy86001 <103086198+boy86001@users.noreply.github.com> Date: Sun, 30 Nov 2025 15:02:12 +0800 Subject: [PATCH 18/19] Delete public/sitemap.xml --- public/sitemap.xml | 165 --------------------------------------------- 1 file changed, 165 deletions(-) delete mode 100644 public/sitemap.xml diff --git a/public/sitemap.xml b/public/sitemap.xml deleted file mode 100644 index b473888..0000000 --- a/public/sitemap.xml +++ /dev/null @@ -1,165 +0,0 @@ - - - - - https://zero001.icu/webdav/index.html - 2025-11-26 - weekly - 1.0 - - - - - https://zero001.icu/webdav/index.html?post=2024-06-25 - 2024-06-25 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2024-09-19 - 2024-09-19 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2024-09-25 - 2024-09-25 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2024-10-19 - 2024-10-19 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2024-10-21 - 2024-10-21 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2024-10-24 - 2024-10-24 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2024-10-31 - 2024-10-31 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2024-11-07 - 2024-11-07 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2024-11-19 - 2024-11-19 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2025-01-05 - 2025-01-05 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2025-01-22 - 2025-01-22 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2025-03-19 - 2025-03-19 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2025-04-10 - 2025-04-10 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2025-04-17 - 2025-04-17 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2025-05-30 - 2025-05-30 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2025-05-31 - 2025-05-31 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2025-07-14 - 2025-07-14 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2025-08-18 - 2025-08-18 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2025-08-23 - 2025-08-23 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2025-08-26 - 2025-08-26 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2025-11-26 - 2025-11-26 - monthly - 0.8 - - - - https://zero001.icu/webdav/index.html?post=2025-11-29 - 2025-11-29 - monthly - 0.8 - - \ No newline at end of file From 1ba6e7bfa1db5019c2c777959b493ac5783126d9 Mon Sep 17 00:00:00 2001 From: boy86001 <103086198+boy86001@users.noreply.github.com> Date: Sun, 30 Nov 2025 15:02:45 +0800 Subject: [PATCH 19/19] Delete functions/[[path]].ts --- functions/[[path]].ts | 107 ------------------------------------------ 1 file changed, 107 deletions(-) delete mode 100644 functions/[[path]].ts diff --git a/functions/[[path]].ts b/functions/[[path]].ts deleted file mode 100644 index b00251e..0000000 --- a/functions/[[path]].ts +++ /dev/null @@ -1,107 +0,0 @@ -// functions/[[path]].ts -// 这个文件处理根目录的文件访问,同时保持 WebDAV 和管理界面正常工作 - -export const onRequest: PagesFunction<{ - BUCKET: R2Bucket; -}> = async function (context) { - const request = context.request; - const url = new URL(request.url); - const pathname = url.pathname; - - console.log(`[Root Handler] 请求路径: ${pathname}`); - - // ======================================== - // 跳过这些路径,让 TWO 系统处理 - // ======================================== - - const skipPaths = [ - '/', // 首页 - TWO 管理界面 - '/favicon.ico', // 网站图标 - '/robots.txt', // robots - ]; - - const skipPrefixes = [ - '/webdav/', // WebDAV 接口(重要!) - '/api/', // API - '/assets/', // 静态资源 - '/static/', // 静态文件 - '/_next/', // Next.js - '/build/', // Docusaurus 构建文件 - '/img/', // 图片资源 - '/css/', // CSS - '/js/', // JS - '/fonts/', // 字体 - ]; - - // 检查是否需要跳过 - if (skipPaths.includes(pathname)) { - console.log(`[Root Handler] 跳过: ${pathname}`); - return context.next(); - } - - for (const prefix of skipPrefixes) { - if (pathname.startsWith(prefix)) { - console.log(`[Root Handler] 跳过: ${pathname} (匹配 ${prefix})`); - return context.next(); - } - } - - // 如果路径没有文件扩展名且不以 / 结尾,可能是页面路由 - const hasExtension = pathname.includes('.') && !pathname.endsWith('/'); - if (!hasExtension) { - console.log(`[Root Handler] 跳过: ${pathname} (可能是页面路由)`); - return context.next(); - } - - // ======================================== - // 尝试从 R2 获取文件 - // ======================================== - - const bucket = context.env.BUCKET; - - if (!bucket) { - console.error('[Root Handler] R2 bucket 未绑定'); - return new Response('配置错误: R2 bucket 未绑定', { - status: 500, - headers: { 'Content-Type': 'text/plain; charset=utf-8' } - }); - } - - try { - // 移除开头的 / - const objectKey = pathname.substring(1); - - console.log(`[Root Handler] 尝试从 R2 获取: ${objectKey}`); - - // 从 R2 获取文件 - const object = await bucket.get(objectKey); - - if (!object) { - console.log(`[Root Handler] 文件不存在: ${objectKey}`); - - // 文件不存在,交给 TWO 的 404 处理 - return context.next(); - } - - console.log(`[Root Handler] 成功获取文件: ${objectKey}, 大小: ${object.size} 字节`); - - // 构建响应头 - const headers = new Headers(); - object.writeHttpMetadata(headers); - headers.set('ETag', object.httpEtag); - headers.set('Cache-Control', 'public, max-age=3600'); - headers.set('Access-Control-Allow-Origin', '*'); - - // 返回文件内容 - return new Response(object.body, { - status: 200, - headers: headers, - }); - - } catch (error: any) { - console.error(`[Root Handler] 错误: ${error.message}`); - - // 出错了,交给 TWO 处理 - return context.next(); - } -};