diff --git a/packages/core/package.json b/packages/core/package.json index ee88ec57..8eda5e55 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,7 @@ { "name": "@verkfi/core", "version": "1.7.2", - "devVersion": "935", + "devVersion": "938", "dev": true, "description": "Platform for Neila's something useless tools.", "private": true, diff --git a/packages/core/src/app/atoms/index.ts b/packages/core/src/app/atoms/index.ts index 533ff820..d3123cac 100644 --- a/packages/core/src/app/atoms/index.ts +++ b/packages/core/src/app/atoms/index.ts @@ -20,7 +20,8 @@ import isBrowser from "layout/isBrowser"; interface mostUsedMarks { [key: string]: number; } -export const sidebarMode = atomWithStorage<"menu" | "sidebar">("sidebarmode", "边栏模式", "menu"), +export type sidebarMode = "menu" | "sidebar"; +export const sidebarMode = atomWithStorage("sidebarmode", "边栏模式", "menu"), showSidebar = atomWithStorage("sidebar", "边栏", false), forkMeOnGitHub = atomWithStorage("fork-me-on-github", "Fork me on GitHub", false), share = atomWithStorage("share", "分享", isBrowser() ? "share" in navigator : false), diff --git a/packages/core/src/app/service-worker.ts b/packages/core/src/app/service-worker.ts index 9603f9c4..5385f321 100644 --- a/packages/core/src/app/service-worker.ts +++ b/packages/core/src/app/service-worker.ts @@ -5,19 +5,8 @@ import { version } from "../../package.json"; import pages from "./pages.json"; -/* const toolsTo = [ - "audiotools", - "countletter", - "clock", - "pi", - "reversal", - "shaizi", - "filter", - "keycode", - "readnumber", -]; */ declare const self: ServiceWorkerGlobalScope; -export const Cache = `Verkfi-${version}-${dev === true ? `dev${devVersion}` : "prod"}`, // C +export const Cache = `Verkfi-${version}-${dev === true ? `dev${devVersion}` : "prod"}`, log = (text: string) => console.log(`%cServiceWorker`, `background: #52c41a;border-radius: 0.5em;color: white;font-weight: bold;padding: 2px 0.5em`, text), clearOldCaches = async () => { const keylist = await caches.keys(); @@ -31,10 +20,8 @@ export const Cache = `Verkfi-${version}-${dev === true ? `dev${devVersion}` : "p installFilesEssential: string[] = [ "/index.webmanifest", "/image/favicon.png" - ].concat(pages); -log(`版本为${Cache}`); -self.addEventListener("install", async event => { - const installStaticFiles = async () => { + ].concat(pages), + installStaticFiles = async () => { const openedCache = await caches.open(Cache); try { await openedCache.addAll(installFilesEssential); @@ -42,11 +29,11 @@ self.addEventListener("install", async event => { console.error(error); } }; - return event.waitUntil((async () => { - await installStaticFiles(); - self.skipWaiting(); - })()); -}); +log(`版本为${Cache}`); +self.addEventListener("install", async event => event.waitUntil((async () => { + await installStaticFiles(); + self.skipWaiting(); +})())); self.addEventListener("activate", event => event.waitUntil((async () => { await clearOldCaches(); return self.clients.claim(); @@ -60,51 +47,52 @@ self.addEventListener("activate", event => event.waitUntil((async () => { * cache:缓存模式 * fetch:网络模式 */ -self.addEventListener("fetch", event => { - if (event.request.method !== "GET") return; - const requrl = event.request.url, - url = String(requrl), - urled = new URL(url), - path = urled.pathname.split("/"); - if (url.startsWith("chrome-extension://")) return; +self.addEventListener("fetch", event => event.respondWith((async () => { let response: Response; // 可能为空的响应 + if (event.request.method !== "GET") return; + const url = String(event.request.url), + urlObject = new URL(url), + cache = await caches.open(Cache), + realReq = event.request.clone(), + path = urlObject.pathname.split("/"); path.shift(); - event.respondWith((async () => { - const cache = await caches.open(Cache), - realReq = event.request.clone(); - log(`抓取: ${url}`); - if (path[0] === "handle") { - const toPath = `/tools/${urled.searchParams.get("handle").replace(/web\+verkfi:\/\//g, "")}`; - log(`检测到URL:${url}中含有"handle",重定向至${toPath}`); - const headers = new Headers(); - headers.append("Location", toPath); - return new Response("", { - status: 301, - statusText: "Redirected by ServiceWorker because this is a handler page", - headers: headers - }); - } else if (path[0] === "extensionfiles") { - return new Response(new Blob([(await db.extensionTools.get({ + if (urlObject.protocol === "chrome-extension:") return; + log(`抓取: ${url}`); + if (path[0] === "handle") { + const toPath = `/tools/${urlObject.searchParams.get("handle").replace(/web\+verkfi:\/\//g, "")}`; + log(`检测到URL:${url}中含有"handle",重定向至${toPath}`); + const headers = new Headers(); + headers.append("Location", toPath); + response = new Response("", { + status: 301, + statusText: "Redirected by ServiceWorker because this is a handler page", + headers: headers + }); + } else if (path[0] === "extensionfiles") { + const filePath = path.slice(2).join("/"), + tool = await db.extensionTools.get({ to: path[1] - })).files.filter(item => item[0] === path[2])[0][1]])); - } else if (path[0] === "tools" && path[1] === "extension") { - response = await cache.match(realReq, { - ignoreSearch: true - }); - } else if (url.includes("_rsc=")) { - log(`检测到URL:${url} 中含有searchParam“rsc”,已返回无rsc版本`); - response = await cache.match(realReq, { - ignoreSearch: true - }); - } else { - response = await cache.match(realReq); - } - if (!response) { - const newreq = await fetch(realReq); - cache.put(realReq, newreq.clone()); - return newreq; - } - return response; - })()); -}); + }), + file = tool.files.find(file => file.path === filePath).file; + log(`检测到扩展路径为${filePath}`); + response = new Response(new Blob([file])); + } else if (path[0] === "tools" && path[1] === "extension") { + response = await cache.match(realReq, { + ignoreSearch: true + }); + } else if (url.includes("_rsc=")) { + log(`检测到URL:${url} 中含有searchParam“rsc”,已返回无rsc版本`); + response = await cache.match(realReq, { + ignoreSearch: true + }); + } else { + response = await cache.match(realReq); + } + if (!response) { + const newreq = await fetch(realReq); + cache.put(realReq, newreq.clone()); + response = newreq; + } + return response; +})())); export default Cache; diff --git a/packages/core/src/app/setting/extensions/DialogButtons.tsx b/packages/core/src/app/setting/extensions/DialogButtons.tsx index d68462eb..b0d08746 100644 --- a/packages/core/src/app/setting/extensions/DialogButtons.tsx +++ b/packages/core/src/app/setting/extensions/DialogButtons.tsx @@ -19,12 +19,15 @@ import { import { NXTMetadata } from "./page"; +import { + single +} from "db"; export default function DialogButtons(props: { type: "modify" | "add"; fileInfo: NXTMetadata; setModifyDialogOpen: setState; setRemoveDialogOpen: setState; - files: [string, Uint8Array][]; + files: single["files"]; reset(): void; }) { const [lists, setLists] = useAtom(listsAtom), diff --git a/packages/core/src/app/setting/extensions/DialogInputs.tsx b/packages/core/src/app/setting/extensions/DialogInputs.tsx index 27aba97b..427e991a 100644 --- a/packages/core/src/app/setting/extensions/DialogInputs.tsx +++ b/packages/core/src/app/setting/extensions/DialogInputs.tsx @@ -17,11 +17,14 @@ import { NXTMetadata, inputTypes } from "./page"; +import { + single +} from "db"; export default function DialogInputs(props: { type: inputTypes; fileInfo: NXTMetadata; setFileInfo: setState; - files: [string, Uint8Array][]; + files: single["files"]; reset(): void; setModifyDialogOpen: setState; setRemoveDialogOpen: setState; @@ -70,8 +73,8 @@ export default function DialogInputs(props: { }); }}> {props.files.map(file => ( - - {file[0]} + + {file.path} ))} diff --git a/packages/core/src/app/setting/extensions/RemoveExtensionDialog.tsx b/packages/core/src/app/setting/extensions/RemoveExtensionDialog.tsx index 76e35f49..c13f5da5 100644 --- a/packages/core/src/app/setting/extensions/RemoveExtensionDialog.tsx +++ b/packages/core/src/app/setting/extensions/RemoveExtensionDialog.tsx @@ -21,12 +21,15 @@ import useClearExtensionData from "./clearExtensionData"; import { NXTMetadata } from "./page"; +import { + single +} from "db"; export default function RemoveExtensionDialog(props: { open: boolean; reset: () => any; fileInfo: NXTMetadata; onTrue?: () => any; - files: [string, Uint8Array][]; + files: single["files"]; }) { const [clearData, setClearData] = useState(false), clearExtensionData = useClearExtensionData(), diff --git a/packages/core/src/app/setting/extensions/ToolViewer.tsx b/packages/core/src/app/setting/extensions/ToolViewer.tsx index b52c619d..31bfd121 100644 --- a/packages/core/src/app/setting/extensions/ToolViewer.tsx +++ b/packages/core/src/app/setting/extensions/ToolViewer.tsx @@ -39,8 +39,8 @@ export default function ToolViewer(props: { modifyDialogOpen: boolean; setModifyDialogOpen: setState; setRemoveDialogOpen: setState; - files: [string, Uint8Array][]; - setFiles: setState<[string, Uint8Array][]>; + files: single["files"]; + setFiles: setState; reset(): void; }) { const { @@ -99,7 +99,8 @@ export default function ToolViewer(props: { { const { - files: thisFiles, ...metadata + files: thisFiles, + ...metadata } = single; clearExtensionData(metadata, thisFiles); }} aria-label={get("extensions.clear")}> diff --git a/packages/core/src/app/setting/extensions/clearExtensionData.ts b/packages/core/src/app/setting/extensions/clearExtensionData.ts index ce9a44b0..7cf2a98c 100644 --- a/packages/core/src/app/setting/extensions/clearExtensionData.ts +++ b/packages/core/src/app/setting/extensions/clearExtensionData.ts @@ -11,6 +11,9 @@ import { NXTMetadata, setting } from "./page"; +import { + single +} from "db"; export default function useClearExtensionData() { const [extensionsTools, setExtensions] = useAtom(extensionsAtom), [oldRecently, setRecently] = useAtom(recentlyUsedAtom), @@ -18,7 +21,7 @@ export default function useClearExtensionData() { oldMost = { ...mostUsed }; - return (clearingExtension: NXTMetadata, clearingFiles: [string, Uint8Array][]) => { + return (clearingExtension: NXTMetadata, clearingFiles: single["files"]) => { setExtensions({ ...clearingExtension, files: clearingFiles, diff --git a/packages/core/src/app/setting/extensions/page.tsx b/packages/core/src/app/setting/extensions/page.tsx index 9c011f0e..9e22250e 100644 --- a/packages/core/src/app/setting/extensions/page.tsx +++ b/packages/core/src/app/setting/extensions/page.tsx @@ -40,13 +40,17 @@ import DialogButtons from "./DialogButtons"; import DialogInputs from "./DialogInputs"; import RemoveExtensionDialog from "./RemoveExtensionDialog"; import ToolViewer from "./ToolViewer"; +import { + file, + single +} from "db"; const PureDialog = dynamic(() => import("dialog/Pure")); export type inputTypes = "modify" | "add"; export default function ExtensionManager() { const [addDialogOpen, setAddDialogOpen] = useState(false), [fileArray, setFileArray] = useState([]), [fileInfo, setFileInfo] = useState(emptyNXTMetadata), - [files, setFiles] = useState<[string, Uint8Array][]>([]), + [files, setFiles] = useState([]), [removeDialogOpen, setRemoveDialogOpen] = useState(false), [modifyDialogOpen, setModifyDialogOpen] = useState(false), theme = useTheme(), @@ -115,7 +119,17 @@ export default function ExtensionManager() { value: settingItem.defaultValue })) : [] }); - setFiles(dir.map(item => [item, fs.readFileSync(item)])); + function readInternal(path: string): file | file[] { + const stat = fs.statSync(path); + if (stat.isDirectory()) { + return fs.readdirSync(path).map(pathchild => readInternal(`${path}/${pathchild}`)).flat(20); // TS最大支持20 + } + return { + path, + file: fs.readFileSync(path) + }; + } + setFiles(dir.map(readInternal).flat(1)); if (extensionTools.some(item => item.to === main.to)) { setModifyDialogOpen(true); return setAddDialogOpen(false); diff --git a/packages/core/src/app/setting/reader/db.ts b/packages/core/src/app/setting/reader/db.ts index c883f699..7057c3ba 100644 --- a/packages/core/src/app/setting/reader/db.ts +++ b/packages/core/src/app/setting/reader/db.ts @@ -4,8 +4,12 @@ import Dexie, { import { NXTMetadata } from "setting/extensions/page"; +export interface file { + path: string; + file: Uint8Array; +} export interface single extends NXTMetadata { - files: [string, Uint8Array][]; + files: file[]; } export interface option { key: string; @@ -18,7 +22,7 @@ class ClassedDexie extends Dexie { options!: Table