diff --git a/.env.example b/.env.example index 97b8431..87021be 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,6 @@ # Supabase -PLASMO_PUBLIC_SUPABASE_URL="" -PLASMO_PUBLIC_SUPABASE_ANON_KEY="" +VITE_SUPABASE_URL="" +VITE_SUPABASE_ANON_KEY="" # OpenPanel Analytics -PLASMO_PUBLIC_OPEN_PANEL_KEY="" \ No newline at end of file +VITE_OPEN_PANEL_KEY="" \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8a35351..c9617b4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -33,17 +33,24 @@ jobs: uses: actions/upload-artifact@v4 with: name: chrome-${{ github.sha }} - path: build/chrome-mv3-prod + path: build/*-chrome.zip - name: 🗃️ Archive Firefox artifact uses: actions/upload-artifact@v4 with: name: firefox-${{ github.sha }} - path: build/firefox-mv2-prod + path: build/*-firefox.zip - name: 💨 Publish! - uses: PlasmoHQ/bpp@v3 - with: - chrome-file: build/chrome-mv3-prod.zip - firefox-file: build/firefox-mv2-prod.zip - keys: ${{ secrets.SUBMIT_KEYS }} + run: | + bun wxt submit \ + --chrome-zip build/*-chrome.zip \ + --firefox-zip build/*-firefox.zip --firefox-sources-zip build/*-sources.zip + env: + CHROME_EXTENSION_ID: ${{ secrets.CHROME_EXTENSION_ID }} + CHROME_CLIENT_ID: ${{ secrets.CHROME_CLIENT_ID }} + CHROME_CLIENT_SECRET: ${{ secrets.CHROME_CLIENT_SECRET }} + CHROME_REFRESH_TOKEN: ${{ secrets.CHROME_REFRESH_TOKEN }} + FIREFOX_EXTENSION_ID: ${{ secrets.FIREFOX_EXTENSION_ID }} + FIREFOX_JWT_ISSUER: ${{ secrets.FIREFOX_JWT_ISSUER }} + FIREFOX_JWT_SECRET: ${{ secrets.FIREFOX_JWT_SECRET }} diff --git a/.gitignore b/.gitignore index cae41a3..c8ab41d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,10 +6,11 @@ node_modules .pnp.js # extension -.plasmo build/ -.cache -keys.json +stats.html +stats-*.json +.wxt +web-ext.config.ts # misc .DS_Store diff --git a/bun.lockb b/bun.lockb index 99ed6f5..d99e2ef 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/keys.template.json b/keys.template.json deleted file mode 100644 index 395fc75..0000000 --- a/keys.template.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "$schema": "https://github.com/PlasmoHQ/bpp/raw/main/keys.schema.json", - "chrome": { - "clientId": "123", - "clientSecret": "123", - "refreshToken": "789", - "extId": "abcd", - "uploadOnly": true - }, - "firefox": { - "extId": "aaaaaaa-aaaa-bbbb-cccc-dddddddddddd", - "apiKey": "abcd", - "apiSecret": "efgh" - }, - "edge": { - "clientId": "aaaaaaa-aaaa-bbbb-cccc-dddddddddddd", - "clientSecret": "abcdefg", - "productId": "aaaaaaa-aaaa-bbbb-cccc-dddddddddddd", - "accessTokenUrl": "https://login.microsoftonline.com/aaaaaaa-aaaa-bbbb-cccc-dddddddddddd/oauth2/v2.0/token" - } -} diff --git a/package.json b/package.json index 981af83..446f8b8 100644 --- a/package.json +++ b/package.json @@ -6,22 +6,21 @@ "author": "Bartosz Zagrodzki", "scripts": { "build": "run-p build:chrome build:firefox", - "build:chrome": "plasmo build --src-path=src/app --zip", - "build:firefox": "plasmo build --src-path=src/app --target=firefox-mv2 --zip", + "build:chrome": "wxt zip", + "build:firefox": "wxt -b firefox zip", "dev": "bun dev:chrome", - "dev:chrome": "plasmo dev --src-path=src/app", - "dev:firefox": "plasmo dev --src-path=src/app --target=firefox-mv2", + "dev:chrome": "wxt", + "dev:firefox": "wxt -b firefox", "lint": "biome check", "lint:fix": "biome check --write", "prepare": "husky", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "postinstall": "wxt prepare" }, "dependencies": { "@biomejs/biome": "^1.9.4", "@hookform/resolvers": "^3.9.1", "@openpanel/web": "^1.0.1", - "@plasmohq/messaging": "0.6.2", - "@plasmohq/storage": "1.12.0", "@radix-ui/react-avatar": "^1.1.1", "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-label": "^2.1.0", @@ -39,13 +38,13 @@ "marked": "^14.1.3", "next-themes": "^0.3.0", "npm-run-all": "^4.1.5", - "plasmo": "0.89.4", "react": "18.3.1", "react-dom": "18.3.1", "react-hook-form": "^7.53.1", "sonner": "^1.5.0", "tailwind-merge": "^2.5.4", "tailwindcss-animate": "^1.0.7", + "vite-plugin-svgr": "^4.3.0", "zod": "^3.23.8" }, "devDependencies": { @@ -54,23 +53,16 @@ "@commitlint/types": "19.0.3", "@tailwindcss/typography": "^0.5.15", "@total-typescript/ts-reset": "^0.6.1", - "@types/bun": "latest", + "@types/bun": "^1.1.13", "@types/chrome": "0.0.270", "@types/node": "20.16.10", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", + "@wxt-dev/auto-icons": "^1.0.2", + "@wxt-dev/module-react": "^1.1.2", "husky": "^9.1.6", - "typescript": "^5.6.3" - }, - "manifest": { - "name": "__MSG_extensionName__", - "default_locale": "en", - "host_permissions": [""], - "permissions": ["storage", "sidePanel", "scripting", "cookies"], - "browser_specific_settings": { - "gecko": { - "id": "extension@extro.dev" - } - } + "typescript": "^5.6.3", + "vitest": "^2.1.5", + "wxt": "^0.19.16" } } diff --git a/src/app/background/index.ts b/src/app/background/index.ts index 47f130b..2ea2774 100644 --- a/src/app/background/index.ts +++ b/src/app/background/index.ts @@ -1,11 +1,9 @@ -import { setupStorage } from "~/lib/storage"; - -const main = async () => { - await setupStorage(); +import { defineBackground } from "wxt/sandbox"; +const main = () => { console.log( "Background service worker is running! Edit `src/app/background` and save to reload.", ); }; -void main(); +export default defineBackground(main); diff --git a/src/app/background/messages/user.ts b/src/app/background/messages/user.ts deleted file mode 100644 index 5569f83..0000000 --- a/src/app/background/messages/user.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { PlasmoMessaging } from "@plasmohq/messaging"; -import { STORAGE_KEY, storage } from "~/lib/storage"; -import type { User } from "~/types"; - -const handler: PlasmoMessaging.MessageHandler< - undefined, - { - user: User | null; - } -> = async (_, res) => { - const user = await storage.get(STORAGE_KEY.USER); - - return res.send({ - user: user ?? null, - }); -}; - -export default handler; diff --git a/src/app/contents/index.ts b/src/app/contents/index.ts deleted file mode 100644 index 070d327..0000000 --- a/src/app/contents/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export {}; - -console.log( - "Content script is running! Edit `src/app/contents` and save to reload.", -); diff --git a/src/app/contents/ui.tsx b/src/app/contents/ui.tsx deleted file mode 100644 index 6d2a6e3..0000000 --- a/src/app/contents/ui.tsx +++ /dev/null @@ -1,9 +0,0 @@ -const ContentScriptUI = () => { - return ( - - ); -}; - -export default ContentScriptUI; diff --git a/src/app/devtools/index.html b/src/app/devtools/index.html new file mode 100644 index 0000000..2f6c255 --- /dev/null +++ b/src/app/devtools/index.html @@ -0,0 +1,13 @@ + + + + + + DevTools + + + +
+ + + diff --git a/src/app/devtools/index.tsx b/src/app/devtools/index.tsx deleted file mode 100644 index e85bd93..0000000 --- a/src/app/devtools/index.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import sidebarHTML from "url:./panels/sidebar/index.html"; - -import { Main } from "~/components/common/main"; -import { Layout } from "~/components/layout/layout"; - -import panelIcon from "url:../../../assets/icon.png"; - -import panelHTML from "./panels/panel/index.html"; - -chrome.devtools.panels.create( - chrome.i18n.getMessage("extensionName"), - panelIcon, - // See: https://github.com/PlasmoHQ/plasmo/issues/106#issuecomment-1188539625 - panelHTML.substring(panelHTML.lastIndexOf("/") + 1), -); - -chrome.devtools.panels.elements.createSidebarPane( - chrome.i18n.getMessage("extensionName"), - (sidebar) => { - sidebar.setPage(sidebarHTML.substring(sidebarHTML.lastIndexOf("/") + 1)); - }, -); - -const Devtools = () => { - return ( - -
- - ); -}; - -export default Devtools; diff --git a/src/app/devtools/main.tsx b/src/app/devtools/main.tsx new file mode 100644 index 0000000..3d7cf5f --- /dev/null +++ b/src/app/devtools/main.tsx @@ -0,0 +1,34 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import { browser } from "wxt/browser"; + +import { Main } from "~/components/common/main"; +import { Layout } from "~/components/layout/layout"; + +browser.devtools.panels.create( + browser.i18n.getMessage("extensionName"), + "icons/128.png", + "popup.html", +); + +browser.devtools.panels.elements + .createSidebarPane(browser.i18n.getMessage("extensionName")) + .then((sidebar) => { + sidebar.setPage("

siema

"); + }); + +console.log("siema"); + +const DevTools = () => { + return ( + +
+ + ); +}; + +ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( + + + , +); diff --git a/src/app/devtools/panels/panel/index.html b/src/app/devtools/panels/panel/index.html index 4d6594c..1b921d6 100644 --- a/src/app/devtools/panels/panel/index.html +++ b/src/app/devtools/panels/panel/index.html @@ -1,13 +1,13 @@ - + - TurboStarter Panel - - + + + DevTools Panel + -
- + diff --git a/src/app/devtools/panels/panel/index.tsx b/src/app/devtools/panels/panel/main.tsx similarity index 54% rename from src/app/devtools/panels/panel/index.tsx rename to src/app/devtools/panels/panel/main.tsx index dc10a3f..b806912 100644 --- a/src/app/devtools/panels/panel/index.tsx +++ b/src/app/devtools/panels/panel/main.tsx @@ -1,4 +1,5 @@ -import { createRoot } from "react-dom/client"; +import React from "react"; +import ReactDOM from "react-dom/client"; import { Main } from "~/components/common/main"; import { Layout } from "~/components/layout/layout"; @@ -11,7 +12,8 @@ const Panel = () => { ); }; -const element = document.getElementById("root"); - -const root = element ? createRoot(element) : null; -root?.render(); +ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( + + + , +); diff --git a/src/app/devtools/panels/sidebar/index.html b/src/app/devtools/panels/sidebar/index.html deleted file mode 100644 index 0aebdcd..0000000 --- a/src/app/devtools/panels/sidebar/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - TurboStarter Sidebar - - - - - -
- - - diff --git a/src/app/devtools/panels/sidebar/index.tsx b/src/app/devtools/panels/sidebar/index.tsx deleted file mode 100644 index a703345..0000000 --- a/src/app/devtools/panels/sidebar/index.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { createRoot } from "react-dom/client"; - -import { Main } from "~/components/common/main"; -import { Layout } from "~/components/layout/layout"; - -const Sidebar = () => { - return ( - -
- - ); -}; - -const element = document.getElementById("root"); - -const root = element ? createRoot(element) : null; -root?.render(); diff --git a/src/app/newtab/index.html b/src/app/newtab/index.html new file mode 100644 index 0000000..d03c45b --- /dev/null +++ b/src/app/newtab/index.html @@ -0,0 +1,13 @@ + + + + + + New Tab + + + +
+ + + diff --git a/src/app/newtab/index.tsx b/src/app/newtab/main.tsx similarity index 52% rename from src/app/newtab/index.tsx rename to src/app/newtab/main.tsx index 9908dd2..ba0ee15 100644 --- a/src/app/newtab/index.tsx +++ b/src/app/newtab/main.tsx @@ -1,6 +1,8 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; + import { Main } from "~/components/common/main"; import { Layout } from "~/components/layout/layout"; -import "~/styles/globals.css"; const NewTab = () => { return ( @@ -10,4 +12,8 @@ const NewTab = () => { ); }; -export default NewTab; +ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( + + + , +); diff --git a/src/app/options/index.html b/src/app/options/index.html new file mode 100644 index 0000000..534afca --- /dev/null +++ b/src/app/options/index.html @@ -0,0 +1,13 @@ + + + + + + Options + + + +
+ + + diff --git a/src/app/options/index.tsx b/src/app/options/main.tsx similarity index 52% rename from src/app/options/index.tsx rename to src/app/options/main.tsx index 01f281f..53d0a40 100644 --- a/src/app/options/index.tsx +++ b/src/app/options/main.tsx @@ -1,3 +1,6 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; + import { Main } from "~/components/common/main"; import { Layout } from "~/components/layout/layout"; @@ -9,4 +12,8 @@ const Options = () => { ); }; -export default Options; +ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( + + + , +); diff --git a/src/app/popup/index.html b/src/app/popup/index.html new file mode 100644 index 0000000..a20490e --- /dev/null +++ b/src/app/popup/index.html @@ -0,0 +1,13 @@ + + + + + + Popup + + + +
+ + + diff --git a/src/app/popup/index.tsx b/src/app/popup/main.tsx similarity index 53% rename from src/app/popup/index.tsx rename to src/app/popup/main.tsx index 8184db9..e1f6b83 100644 --- a/src/app/popup/index.tsx +++ b/src/app/popup/main.tsx @@ -1,3 +1,6 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; + import { Main } from "~/components/common/main"; import { Layout } from "~/components/layout/layout"; @@ -9,4 +12,8 @@ const Popup = () => { ); }; -export default Popup; +ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( + + + , +); diff --git a/src/app/sidepanel/index.html b/src/app/sidepanel/index.html new file mode 100644 index 0000000..787f7d9 --- /dev/null +++ b/src/app/sidepanel/index.html @@ -0,0 +1,13 @@ + + + + + + Side Panel + + + +
+ + + diff --git a/src/app/sidepanel/index.tsx b/src/app/sidepanel/main.tsx similarity index 52% rename from src/app/sidepanel/index.tsx rename to src/app/sidepanel/main.tsx index 31f7c2d..2411bcf 100644 --- a/src/app/sidepanel/index.tsx +++ b/src/app/sidepanel/main.tsx @@ -1,3 +1,6 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; + import { Main } from "~/components/common/main"; import { Layout } from "~/components/layout/layout"; @@ -9,4 +12,8 @@ const SidePanel = () => { ); }; -export default SidePanel; +ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( + + + , +); diff --git a/src/app/tabs/ai.tsx b/src/app/tabs/ai.tsx deleted file mode 100644 index 1eb53e1..0000000 --- a/src/app/tabs/ai.tsx +++ /dev/null @@ -1,234 +0,0 @@ -import { useMutation } from "@tanstack/react-query"; -import { type CoreMessage, streamText } from "ai"; -import { chromeai } from "chrome-ai"; -import { type KeyboardEvent, useState } from "react"; -import { Layout } from "~/components/layout/layout"; - -import { zodResolver } from "@hookform/resolvers/zod"; -import { ArrowUp, X } from "lucide-react"; -import { marked } from "marked"; -import { useForm } from "react-hook-form"; -import { z } from "zod"; -import { Button } from "~/components/ui/button"; -import { - Form, - FormControl, - FormField, - FormItem, - FormMessage, -} from "~/components/ui/form"; -import { ScrollArea } from "~/components/ui/scroll-area"; -import { Textarea } from "~/components/ui/textarea"; -import { cn } from "~/lib/utils"; - -const promptSchema = z.object({ - prompt: z.string(), -}); - -type Message = { - role: CoreMessage["role"]; - content: string; -}; - -const Chat = () => { - const [isThinking, setIsThinking] = useState(false); - const [error, setError] = useState(null); - const [messages, setMessages] = useState([]); - const { mutate, isPending } = useMutation({ - mutationFn: async (messages: Message[]) => { - const { textStream } = await streamText({ - model: chromeai(), - messages, - }); - return textStream; - }, - onMutate: () => { - setIsThinking(true); - }, - onSuccess: async (data) => { - for await (const chunk of data) { - setMessages((prev) => { - if (prev.at(-1)?.role === "user") { - return [...prev, { role: "assistant", content: chunk }]; - } - - return [ - ...prev.slice(0, -1), - { - role: "assistant", - content: (prev.at(-1)?.content ?? "") + chunk, - }, - ]; - }); - - setIsThinking(false); - } - }, - onError: (e) => { - setError(e.message); - setIsThinking(false); - }, - }); - - const form = useForm>({ - resolver: zodResolver(promptSchema), - }); - - const messagesToDisplay = messages.filter((message) => - ["assistant", "user"].includes(message.role), - ); - - const onSubmit = (values: z.infer) => { - const message = { role: "user", content: values.prompt } as const; - form.reset({ - prompt: "", - }); - mutate([...messages, message]); - setMessages((prev) => [...prev, message]); - }; - - const handleKeyDown = async (event: KeyboardEvent) => { - if (event.key === "Enter" && !event.shiftKey) { - event.preventDefault(); - await form.handleSubmit(onSubmit)(); - } - }; - - return ( -
- -
- {messagesToDisplay.map((message) => ( -
- {message.role === "assistant" ? ( -
- ) : ( - message.content - )} -
- ))} - {isThinking && Thinking...} - {error && ( - - {error} - - )} -
-
- -
- - ( - - -