diff --git a/.vscode/settings.json b/.vscode/settings.json index 87589341d80..a6b1d9843e3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,6 +10,12 @@ "mode": "auto" } ], + "json.schemas": [ + { + "fileMatch": ["manifest.json"], + "url": "https://json.schemastore.org/chrome-manifest.json" + } + ], "cSpell.words": [ "accountsstage", "adduser", diff --git a/package-lock.json b/package-lock.json index b95d0b128f6..68ba7bff125 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33280,16 +33280,16 @@ }, "packages/backend": { "name": "@clerk/backend", - "version": "1.0.0-alpha-v5.4", + "version": "1.0.0-alpha-v5.6", "license": "MIT", "dependencies": { - "@clerk/shared": "2.0.0-alpha-v5.3", + "@clerk/shared": "2.0.0-alpha-v5.5", "cookie": "0.5.0", "snakecase-keys": "5.4.4", "tslib": "2.4.1" }, "devDependencies": { - "@clerk/types": "4.0.0-alpha-v5.6", + "@clerk/types": "4.0.0-alpha-v5.8", "@cloudflare/workers-types": "^3.18.0", "@types/chai": "^4.3.3", "@types/cookie": "^0.5.1", @@ -33319,11 +33319,11 @@ }, "packages/chrome-extension": { "name": "@clerk/chrome-extension", - "version": "1.0.0-alpha-v5.6", + "version": "1.0.0-alpha-v5.8", "license": "MIT", "dependencies": { - "@clerk/clerk-js": "5.0.0-alpha-v5.6", - "@clerk/clerk-react": "5.0.0-alpha-v5.6" + "@clerk/clerk-js": "5.0.0-alpha-v5.8", + "@clerk/clerk-react": "5.0.0-alpha-v5.8" }, "devDependencies": { "@types/chrome": "*", @@ -33344,12 +33344,12 @@ }, "packages/clerk-js": { "name": "@clerk/clerk-js", - "version": "5.0.0-alpha-v5.6", + "version": "5.0.0-alpha-v5.8", "license": "MIT", "dependencies": { - "@clerk/localizations": "2.0.0-alpha-v5.5", - "@clerk/shared": "2.0.0-alpha-v5.3", - "@clerk/types": "4.0.0-alpha-v5.6", + "@clerk/localizations": "2.0.0-alpha-v5.6", + "@clerk/shared": "2.0.0-alpha-v5.5", + "@clerk/types": "4.0.0-alpha-v5.8", "@emotion/cache": "11.11.0", "@emotion/react": "11.11.1", "@floating-ui/react": "0.25.4", @@ -33684,17 +33684,17 @@ }, "packages/expo": { "name": "@clerk/clerk-expo", - "version": "1.0.0-alpha-v5.6", + "version": "1.0.0-alpha-v5.8", "license": "MIT", "dependencies": { - "@clerk/clerk-js": "5.0.0-alpha-v5.6", - "@clerk/clerk-react": "5.0.0-alpha-v5.6", - "@clerk/shared": "2.0.0-alpha-v5.3", + "@clerk/clerk-js": "5.0.0-alpha-v5.8", + "@clerk/clerk-react": "5.0.0-alpha-v5.8", + "@clerk/shared": "2.0.0-alpha-v5.5", "base-64": "^1.0.0", "react-native-url-polyfill": "2.0.0" }, "devDependencies": { - "@clerk/types": "^4.0.0-alpha-v5.6", + "@clerk/types": "^4.0.0-alpha-v5.8", "@types/base-64": "^1.0.2", "@types/node": "^18.17.0", "@types/react": "*", @@ -33717,12 +33717,12 @@ }, "packages/fastify": { "name": "@clerk/fastify", - "version": "1.0.0-alpha-v5.6", + "version": "1.0.0-alpha-v5.8", "license": "MIT", "dependencies": { - "@clerk/backend": "1.0.0-alpha-v5.4", - "@clerk/shared": "2.0.0-alpha-v5.3", - "@clerk/types": "4.0.0-alpha-v5.6", + "@clerk/backend": "1.0.0-alpha-v5.6", + "@clerk/shared": "2.0.0-alpha-v5.5", + "@clerk/types": "4.0.0-alpha-v5.8", "cookies": "0.8.0" }, "devDependencies": { @@ -33740,17 +33740,17 @@ } }, "packages/gatsby-plugin-clerk": { - "version": "5.0.0-alpha-v5.6", + "version": "5.0.0-alpha-v5.8", "license": "MIT", "dependencies": { - "@clerk/backend": "1.0.0-alpha-v5.4", - "@clerk/clerk-react": "5.0.0-alpha-v5.6", - "@clerk/clerk-sdk-node": "5.0.0-alpha-v5.4", + "@clerk/backend": "1.0.0-alpha-v5.6", + "@clerk/clerk-react": "5.0.0-alpha-v5.8", + "@clerk/clerk-sdk-node": "5.0.0-alpha-v5.6", "cookie": "0.5.0", "tslib": "2.4.1" }, "devDependencies": { - "@clerk/types": "4.0.0-alpha-v5.6", + "@clerk/types": "4.0.0-alpha-v5.8", "@types/cookie": "^0.5.0", "@types/node": "^18.17.0", "eslint-config-custom": "*", @@ -33770,10 +33770,10 @@ }, "packages/localizations": { "name": "@clerk/localizations", - "version": "2.0.0-alpha-v5.5", + "version": "2.0.0-alpha-v5.6", "license": "MIT", "devDependencies": { - "@clerk/types": "4.0.0-alpha-v5.6", + "@clerk/types": "4.0.0-alpha-v5.8", "@types/node": "^18.17.0", "eslint-config-custom": "*", "tsup": "*", @@ -33789,16 +33789,16 @@ }, "packages/nextjs": { "name": "@clerk/nextjs", - "version": "5.0.0-alpha-v5.6", + "version": "5.0.0-alpha-v5.8", "license": "MIT", "dependencies": { - "@clerk/backend": "1.0.0-alpha-v5.4", - "@clerk/clerk-react": "5.0.0-alpha-v5.6", - "@clerk/shared": "2.0.0-alpha-v5.3", + "@clerk/backend": "1.0.0-alpha-v5.6", + "@clerk/clerk-react": "5.0.0-alpha-v5.8", + "@clerk/shared": "2.0.0-alpha-v5.5", "path-to-regexp": "6.2.1" }, "devDependencies": { - "@clerk/types": "4.0.0-alpha-v5.6", + "@clerk/types": "4.0.0-alpha-v5.8", "@types/node": "^18.17.0", "@types/react": "*", "@types/react-dom": "*", @@ -33823,11 +33823,11 @@ }, "packages/react": { "name": "@clerk/clerk-react", - "version": "5.0.0-alpha-v5.6", + "version": "5.0.0-alpha-v5.8", "license": "MIT", "dependencies": { - "@clerk/shared": "2.0.0-alpha-v5.3", - "@clerk/types": "4.0.0-alpha-v5.6", + "@clerk/shared": "2.0.0-alpha-v5.5", + "@clerk/types": "4.0.0-alpha-v5.8", "eslint-config-custom": "*", "semver": "^7.5.4", "tslib": "2.4.1" @@ -33855,17 +33855,17 @@ }, "packages/remix": { "name": "@clerk/remix", - "version": "4.0.0-alpha-v5.6", + "version": "4.0.0-alpha-v5.8", "license": "MIT", "dependencies": { - "@clerk/backend": "1.0.0-alpha-v5.4", - "@clerk/clerk-react": "5.0.0-alpha-v5.6", - "@clerk/shared": "2.0.0-alpha-v5.3", + "@clerk/backend": "1.0.0-alpha-v5.6", + "@clerk/clerk-react": "5.0.0-alpha-v5.8", + "@clerk/shared": "2.0.0-alpha-v5.5", "cookie": "0.5.0", "tslib": "2.4.1" }, "devDependencies": { - "@clerk/types": "4.0.0-alpha-v5.6", + "@clerk/types": "4.0.0-alpha-v5.8", "@remix-run/react": "^2.0.0", "@remix-run/server-runtime": "^2.0.0", "@types/cookie": "^0.5.0", @@ -33891,16 +33891,16 @@ }, "packages/sdk-node": { "name": "@clerk/clerk-sdk-node", - "version": "5.0.0-alpha-v5.4", + "version": "5.0.0-alpha-v5.6", "license": "MIT", "dependencies": { - "@clerk/backend": "1.0.0-alpha-v5.4", - "@clerk/shared": "2.0.0-alpha-v5.3", + "@clerk/backend": "1.0.0-alpha-v5.6", + "@clerk/shared": "2.0.0-alpha-v5.5", "camelcase-keys": "6.2.2", "snakecase-keys": "3.2.1" }, "devDependencies": { - "@clerk/types": "4.0.0-alpha-v5.6", + "@clerk/types": "4.0.0-alpha-v5.8", "@types/express": "4.17.14", "@types/node": "^18.17.0", "eslint-config-custom": "*", @@ -33933,7 +33933,7 @@ }, "packages/shared": { "name": "@clerk/shared", - "version": "2.0.0-alpha-v5.3", + "version": "2.0.0-alpha-v5.5", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -33942,7 +33942,7 @@ "swr": "2.2.0" }, "devDependencies": { - "@clerk/types": "4.0.0-alpha-v5.6", + "@clerk/types": "4.0.0-alpha-v5.8", "@types/glob-to-regexp": "0.4.1", "@types/js-cookie": "3.0.2", "@types/node": "^18.17.0", @@ -33978,7 +33978,7 @@ "version": "2.0.0-alpha-v5.2", "license": "MIT", "devDependencies": { - "@clerk/types": "4.0.0-alpha-v5.6", + "@clerk/types": "4.0.0-alpha-v5.8", "@types/node": "^18.17.0", "eslint-config-custom": "*", "typescript": "*" @@ -33993,7 +33993,7 @@ }, "packages/types": { "name": "@clerk/types", - "version": "4.0.0-alpha-v5.6", + "version": "4.0.0-alpha-v5.8", "license": "MIT", "dependencies": { "csstype": "3.1.1" diff --git a/playground/chrome-extension/.env.example b/playground/chrome-extension/.env.example new file mode 100644 index 00000000000..4f4796f3fc9 --- /dev/null +++ b/playground/chrome-extension/.env.example @@ -0,0 +1 @@ +VITE_CLERK_PUBLISHABLE_KEY=YOUR_CLERK_PUBLISHABLE_KEY_GOES_HERE diff --git a/playground/chrome-extension/.gitignore b/playground/chrome-extension/.gitignore new file mode 100644 index 00000000000..b780dd861d3 --- /dev/null +++ b/playground/chrome-extension/.gitignore @@ -0,0 +1,14 @@ +# dependencies +/node_modules + +# manifests +manifest.* +!manifest.*.example + +# production +/build +/dist + +# misc +.DS_Store +.env diff --git a/playground/chrome-extension/README.md b/playground/chrome-extension/README.md new file mode 100644 index 00000000000..ec04cbcaf49 --- /dev/null +++ b/playground/chrome-extension/README.md @@ -0,0 +1,66 @@ +

+ + + + + + +
+

+ +# Clerk Chrome Extension Starter + +This starter project shows how to use [Clerk](https://www.clerk.dev/?utm_source=github&utm_medium=starter_repos&utm_campaign=chrome_extension_start) authentication in a React based [Chrome Extension](https://developer.chrome.com/docs/extensions/). + +[![chat on Discord](https://img.shields.io/discord/856971667393609759.svg?logo=discord)](https://discord.com/invite/b5rXHjAg7A) +[![documentation](https://img.shields.io/badge/documentation-clerk-green.svg)](https://docs.clerk.dev) +[![twitter](https://img.shields.io/twitter/follow/ClerkDev?style=social)](https://twitter.com/intent/follow?screen_name=ClerkDev) + +If you run into issues, be sure to check our [main npm page](https://www.npmjs.com/package/@clerk/chrome-extension) for any updated settings/steps you may need to be aware of. + +--- + +**Clerk is Hiring!** + +Would you like to work on Open Source software and help maintain this repository? [Apply today!](https://apply.workable.com/clerk-dev/) + +--- + +## Introduction + +This project was bootstrapped with [Vite](https://vitejs.dev/) with [CRXJ](https://crxjs.dev/vite-plugin/). + +It's a kitchen-sink starter of how to use ClerkJS in a Chrome Extension either as a Standalone App or alongside a Web Application via WebSSO. + + + +It demonstrates a basic password or OTP flow using ClerkJS Components in the following extension contexts: + +- [x] Popup `action.*` +- [x] Chrome Pages + - [x] New Tab `chrome_url_overrides.newtab` + - [x] History `chrome_url_overrides.history` + - [x] Bookmark Manager `chrome_url_overrides.bookmarks` +- [x] Dev Tools `devtools_page` +- [x] Extension Options `options_ui` + +You may safely remove any of the above contexts from the `manifest.json` if you do not need them. + +This repo will be enhanced with examples of authentication redirection flows such as OAuth or Magic Links and advanced extension patterns. + +## Getting Started + +1. Sign up for a Clerk account at [https://clerk.com](https://dashboard.clerk.com/sign-up?utm_source=github&utm_medium=template_repos&utm_campaign=chrome_extension_template). +2. Go to the [Clerk dashboard](https://dashboard.clerk.com?utm_source=github&utm_medium=template_repos&utm_campaign=chrome_extension_template) and create an application. +3. Clone the repository `git clone https://github.com/clerkinc/clerk-chrome-extension-starter.git clerk-chrome-extension-starter` +4. Go to the project directory: cd clerk-chrome-extension-starter +5. Install dependencies: `npm install` +6. Copy example files and sent the required variables in each file: + - `cp .env.example .env` + - `cp manifest.json.example manifest.json` + - `cp manifest.dev.json.example manifest.dev.json` (The attributes in this file overwrite the attributes in `manifest.json` when running in development mode.) +7. Launch the development server: `npm run dev` + +The files generated in the `dist` directory can be loaded as an unpacked extension in Chrome. + +PLEASE NOTE: Any changes to the manifest require a reload of the extension in [chrome://extensions/](chrome://extensions/). diff --git a/playground/chrome-extension/demo.png b/playground/chrome-extension/demo.png new file mode 100644 index 00000000000..4f7f1975a5e Binary files /dev/null and b/playground/chrome-extension/demo.png differ diff --git a/playground/chrome-extension/manifest.dev.json.example b/playground/chrome-extension/manifest.dev.json.example new file mode 100644 index 00000000000..4e80c18a706 --- /dev/null +++ b/playground/chrome-extension/manifest.dev.json.example @@ -0,0 +1,10 @@ +{ + "host_permissions": [ + "*://localhost/*", + "https:///*" + ], + "icons": { + "32": "dev-icon-32.png", + "128": "dev-icon-128.png" + } +} diff --git a/playground/chrome-extension/manifest.json.example b/playground/chrome-extension/manifest.json.example new file mode 100644 index 00000000000..adf133812bc --- /dev/null +++ b/playground/chrome-extension/manifest.json.example @@ -0,0 +1,26 @@ +{ + "manifest_version": 3, + "name": "Clerk Chrome Extension Playground", + "description": "Playground App for the Clerk Chrome Extension", + "action": { + "default_popup": "src/pages/popup/index.html" + }, + "chrome_url_overrides": { + "newtab": "src/pages/new-tab/index.html" + }, + "devtools_page": "src/pages/devtools/index.html", + "host_permissions": [ + "https:///*" + ], + "icons": { + "32": "icon-32.png", + "128": "icon-128.png" + }, + "options_ui": { + "page": "src/pages/options/index.html" + }, + "permissions": [ + "cookies", + "storage" + ] +} diff --git a/playground/chrome-extension/nodemon.json b/playground/chrome-extension/nodemon.json new file mode 100644 index 00000000000..72faa888928 --- /dev/null +++ b/playground/chrome-extension/nodemon.json @@ -0,0 +1,14 @@ +{ + "env": { + "__DEV__": "true" + }, + "watch": [ + ".yalc/**/*", "src", "utils", "vite.config.ts", "manifest.json", "manifest.dev.json", "node_modules/@clerk/**/*" + ], + "ext": "tsx,css,html,ts,json", + "ignore": [ + "src/**/*.spec.ts" + ], + "exec": "vite build", + "delay": "1000" +} diff --git a/playground/chrome-extension/package.json b/playground/chrome-extension/package.json new file mode 100644 index 00000000000..fe85b6c9017 --- /dev/null +++ b/playground/chrome-extension/package.json @@ -0,0 +1,39 @@ +{ + "name": "clerk-chrome-extension-starter", + "version": "0.1.0", + "private": true, + "type": "module", + "dependencies": { + "@clerk/chrome-extension": "file:.yalc/@clerk/chrome-extension", + "@clerk/clerk-js": "file:.yalc/@clerk/clerk-js", + "@clerk/clerk-react": "file:.yalc/@clerk/clerk-react", + "@clerk/localizations": "file:.yalc/@clerk/localizations", + "@clerk/shared": "file:.yalc/@clerk/shared", + "@clerk/themes": "file:.yalc/@clerk/themes", + "@clerk/types": "file:.yalc/@clerk/types", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.9.0", + "webextension-polyfill": "^0.10.0" + }, + "devDependencies": { + "@crxjs/vite-plugin": "^1.0.14", + "@types/chrome": "^0.0.253", + "@types/node": "^18.17.1", + "@types/react": "^18.2.39", + "@types/react-dom": "^18.2.17", + "@types/webextension-polyfill": "^0.10.0", + "@vitejs/plugin-react-swc": "^3.0.1", + "autoprefixer": "^10.4.16", + "nodemon": "^2.0.20", + "postcss": "^8.4.31", + "ts-node": "^10.9.1", + "typescript": "^4.9.4", + "vite": "^4.5.0" + }, + "scripts": { + "build": "vite build", + "dev": "npm run yalc:add && nodemon", + "yalc:add": "yalc add -- @clerk/chrome-extension @clerk/clerk-react @clerk/clerk-js @clerk/localizations @clerk/themes @clerk/types @clerk/shared" + } +} diff --git a/playground/chrome-extension/public/dev-icon-128.png b/playground/chrome-extension/public/dev-icon-128.png new file mode 100644 index 00000000000..2272f3c2883 Binary files /dev/null and b/playground/chrome-extension/public/dev-icon-128.png differ diff --git a/playground/chrome-extension/public/dev-icon-32.png b/playground/chrome-extension/public/dev-icon-32.png new file mode 100644 index 00000000000..2b72ebdb2ce Binary files /dev/null and b/playground/chrome-extension/public/dev-icon-32.png differ diff --git a/playground/chrome-extension/public/icon-128.png b/playground/chrome-extension/public/icon-128.png new file mode 100644 index 00000000000..15bd934a116 Binary files /dev/null and b/playground/chrome-extension/public/icon-128.png differ diff --git a/playground/chrome-extension/public/icon-32.png b/playground/chrome-extension/public/icon-32.png new file mode 100644 index 00000000000..d93c9d3a09f Binary files /dev/null and b/playground/chrome-extension/public/icon-32.png differ diff --git a/playground/chrome-extension/src/assets/styles/index.css b/playground/chrome-extension/src/assets/styles/index.css new file mode 100644 index 00000000000..629dadba4fa --- /dev/null +++ b/playground/chrome-extension/src/assets/styles/index.css @@ -0,0 +1,134 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&family=Source+Code+Pro&display=swap'); + +body { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + background-color: #0c042a; + font-family: 'Inter', sans-serif; + font-weight: 400; + margin: 0; + padding: 24px; +} + +pre { + background-image: radial-gradient(at 50% 100%, rgba(91, 197, 239, 0.1) 0%, rgba(255, 255, 255, 0) 80%, rgba(91, 197, 239, 0) 80%); + background: linear-gradient(0deg, rgba(28, 15, 77, 0.12) -52.71%, rgba(28, 15, 77, 0) 85%),rgba(10, 12, 61, 1); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + box-shadow: 0px 42px 56px rgba(5, 1, 54, 0.42),0px 17.5466px 23.3955px rgba(5, 1, 54, 0.301919),0px 9.38125px 12.5083px rgba(5, 1, 54, 0.250365),0px 5.25905px 7.01207px rgba(5, 1, 54, 0.21),0px 2.79304px 3.72406px rgba(5, 1, 54, 0.169635),0px 1.16225px 1.54966px rgba(5, 1, 54, 0.118081); + font-family: 'Source Code Pro', monospace; + font-weight: 400; + letter-spacing: 1px; + line-height: 1.5; + margin: auto; + max-width: 100%; + min-height: 100px; + padding: 1.5rem; + text-align: left; + white-space: pre-wrap; + word-wrap: break-word; + user-select: all; +} + +a { + color: #61dafb; +} + +h1 { + font-size: 56px; + font-weight: 700; + letter-spacing: -1.12px; + margin: 2vh 0 0; + margin-bottom: 5vh; +} + +h2 { + font-size: 32px; + font-weight: 700; + letter-spacing: -1.12px; + margin: 0; +} + +header { + align-items: center; + border-bottom: 1px solid #3d3b3b; + color: white; + display: flex; + flex-direction: column; + justify-content: center; + min-height: 40vh; + padding-bottom: 5vh; +} + +main { + margin-left: 2vw; + margin-right: 2vw; + text-align: left; +} + +.cl-rootBox { + margin: auto; +} + +.container { + color: white; + display: flex; + flex-direction: column; + gap: 10vh; + margin-inline: auto; + min-height: 100vh; + text-align: center; + width: 600px; +} + +.content { + display: flex; + flex-direction: column; + gap: 18px; +} + +button, a.button { + align-items: center; + appearance: none; + background: #FFFFFF; + border: 0 solid #d8dde8; + border-width: 0; + border-style: solid; + border-radius: 0.5rem; + border-color: #D8DDE8; + box-sizing: border-box; + box-shadow: 0px 1px 2px rgba(57, 67, 86, 0.08); + color: #6C47FF; + cursor: pointer; + display: inline-flex; + font-size: 14px; + font-weight: 700; + height: 3rem; + justify-content: center; + line-height: 1.2; + margin: 0; + min-width: 2.5rem; + min-height: 48px; + outline: 2px solid transparent; + outline-offset: 2px; + overflow: visible; + text-decoration: none; + text-transform: uppercase; + padding: 0; + padding-top: 0.5rem; + padding-bottom: 0.5rem; + padding-inline-start: 1rem; + padding-inline-end: 1rem; + position: relative; + user-select: none; + vertical-align: middle; + white-space: nowrap; + width: 225px; + word-wrap: break-word; + z-index: 100; +} + +a.invert { + background: #6C47FF; + color: #FFFFFF; +} diff --git a/playground/chrome-extension/src/components/CurrentUser.tsx b/playground/chrome-extension/src/components/CurrentUser.tsx new file mode 100644 index 00000000000..5b8d5ddb796 --- /dev/null +++ b/playground/chrome-extension/src/components/CurrentUser.tsx @@ -0,0 +1,36 @@ +import { useEffect, useState } from 'react'; +import { useAuth, useUser } from "@clerk/chrome-extension"; + +export function CurrentUser() { + const [sessionToken, setSessionToken] = useState(""); + const { isSignedIn, user } = useUser(); + const { getToken, signOut } = useAuth(); + + useEffect(() => { + const scheduler = setInterval(async () => { + const token = await getToken(); + setSessionToken(token as string); + }, 1000); + + return () => clearInterval(scheduler); + }, []); + + if (!isSignedIn) { + return null; + } + + const email = user.primaryEmailAddress?.emailAddress; + + return ( +
+

Hi, {email ? `${email}!` : ''}

+ +
+

Clerk Session Token:

+
{sessionToken}
+
+ + +
+ ); +} diff --git a/playground/chrome-extension/src/components/SharedApp.tsx b/playground/chrome-extension/src/components/SharedApp.tsx new file mode 100644 index 00000000000..7b49b579938 --- /dev/null +++ b/playground/chrome-extension/src/components/SharedApp.tsx @@ -0,0 +1,78 @@ +import { ClerkProvider, type ChromeExtensionClerkProviderProps } from "@clerk/chrome-extension"; +import { Routes, Route, useNavigate } from "react-router-dom"; +import { + SignedIn, + SignedOut, + SignIn, + SignUp, +} from "@clerk/chrome-extension"; + +import "@/assets/styles/index.css" + +import { CurrentUser } from '@/components/CurrentUser'; + +const publishableKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY || ""; + +export type SharedAppProps = Pick & { + className?: string; +} + +export function SharedApp({ className, ...rest }: SharedAppProps) { + const navigate = useNavigate(); + + return ( + navigate(to)} + routerReplace={to => navigate(to, { replace: true })} + syncSessionWithTab + {...rest} + > +
+
+ + + + + + + + + + + + + + + + + +

Clerk Chrome Extension Starter!

+ + + Learn more about Clerk + +
+ +
+ + } /> + + + + + + + + + } + /> + +
+
+
+ ); +} diff --git a/playground/chrome-extension/src/global.d.ts b/playground/chrome-extension/src/global.d.ts new file mode 100644 index 00000000000..7ad3edd14db --- /dev/null +++ b/playground/chrome-extension/src/global.d.ts @@ -0,0 +1,11 @@ +declare module '*.svg' { + import React = require('react'); + export const ReactComponent: React.SFC>; + const src: string; + export default src; +} + +declare module '*.json' { + const content: string; + export default content; +} diff --git a/playground/chrome-extension/src/pages/background/index.ts b/playground/chrome-extension/src/pages/background/index.ts new file mode 100644 index 00000000000..def0db5c2cf --- /dev/null +++ b/playground/chrome-extension/src/pages/background/index.ts @@ -0,0 +1 @@ +console.log('background script loaded'); diff --git a/playground/chrome-extension/src/pages/content/index.tsx b/playground/chrome-extension/src/pages/content/index.tsx new file mode 100644 index 00000000000..de0869e4012 --- /dev/null +++ b/playground/chrome-extension/src/pages/content/index.tsx @@ -0,0 +1 @@ +console.log('content script loaded') diff --git a/playground/chrome-extension/src/pages/devtools/index.html b/playground/chrome-extension/src/pages/devtools/index.html new file mode 100644 index 00000000000..666bb682e32 --- /dev/null +++ b/playground/chrome-extension/src/pages/devtools/index.html @@ -0,0 +1,10 @@ + + + + + Devtools + + + + + diff --git a/playground/chrome-extension/src/pages/devtools/index.ts b/playground/chrome-extension/src/pages/devtools/index.ts new file mode 100644 index 00000000000..cf2258c594f --- /dev/null +++ b/playground/chrome-extension/src/pages/devtools/index.ts @@ -0,0 +1,6 @@ +import browser from 'webextension-polyfill'; + +browser + .devtools + .panels + .create('Clerk Starter', 'icon-32.png', 'src/pages/panel/index.html'); diff --git a/playground/chrome-extension/src/pages/new-tab/index.html b/playground/chrome-extension/src/pages/new-tab/index.html new file mode 100644 index 00000000000..e794ed94acd --- /dev/null +++ b/playground/chrome-extension/src/pages/new-tab/index.html @@ -0,0 +1,12 @@ + + + + + New tab + + + +
+ + + diff --git a/playground/chrome-extension/src/pages/new-tab/index.tsx b/playground/chrome-extension/src/pages/new-tab/index.tsx new file mode 100644 index 00000000000..48b5565878b --- /dev/null +++ b/playground/chrome-extension/src/pages/new-tab/index.tsx @@ -0,0 +1,11 @@ +import { createRoot } from 'react-dom/client'; +import NewTab from './new-tab'; + +function init() { + const rootContainer = document.querySelector("#__root"); + if (!rootContainer) throw new Error("Can't find NewTab root element"); + const root = createRoot(rootContainer); + root.render(); +} + +init(); diff --git a/playground/chrome-extension/src/pages/new-tab/new-tab.tsx b/playground/chrome-extension/src/pages/new-tab/new-tab.tsx new file mode 100644 index 00000000000..aeb1cd4b2dc --- /dev/null +++ b/playground/chrome-extension/src/pages/new-tab/new-tab.tsx @@ -0,0 +1,12 @@ +import { MemoryRouter } from "react-router-dom"; +import { SharedApp } from '@/components/SharedApp'; + +function NewTab() { + return ( + + + + ) +} + +export default NewTab; diff --git a/playground/chrome-extension/src/pages/options/Options.tsx b/playground/chrome-extension/src/pages/options/Options.tsx new file mode 100644 index 00000000000..f2b20d9fed4 --- /dev/null +++ b/playground/chrome-extension/src/pages/options/Options.tsx @@ -0,0 +1,12 @@ +import { MemoryRouter } from "react-router-dom"; +import { SharedApp } from '@/components/SharedApp'; + +function Options() { + return ( + + + + ) +} + +export default Options; diff --git a/playground/chrome-extension/src/pages/options/index.html b/playground/chrome-extension/src/pages/options/index.html new file mode 100644 index 00000000000..db5fa745afe --- /dev/null +++ b/playground/chrome-extension/src/pages/options/index.html @@ -0,0 +1,12 @@ + + + + + Options + + + +
+ + + diff --git a/playground/chrome-extension/src/pages/options/index.tsx b/playground/chrome-extension/src/pages/options/index.tsx new file mode 100644 index 00000000000..48630999fb9 --- /dev/null +++ b/playground/chrome-extension/src/pages/options/index.tsx @@ -0,0 +1,11 @@ +import { createRoot } from 'react-dom/client'; +import Options from './options'; + +function init() { + const rootContainer = document.querySelector("#__root"); + if (!rootContainer) throw new Error("Can't find Options root element"); + const root = createRoot(rootContainer); + root.render(); +} + +init(); diff --git a/playground/chrome-extension/src/pages/panel/Panel.tsx b/playground/chrome-extension/src/pages/panel/Panel.tsx new file mode 100644 index 00000000000..a2ae4f3cb00 --- /dev/null +++ b/playground/chrome-extension/src/pages/panel/Panel.tsx @@ -0,0 +1,12 @@ +import { MemoryRouter } from "react-router-dom"; +import { SharedApp } from '@/components/SharedApp'; + +function Panel() { + return ( + + + + ) +} + +export default Panel; diff --git a/playground/chrome-extension/src/pages/panel/index.html b/playground/chrome-extension/src/pages/panel/index.html new file mode 100644 index 00000000000..7aa306d0ca7 --- /dev/null +++ b/playground/chrome-extension/src/pages/panel/index.html @@ -0,0 +1,12 @@ + + + + + Devtools Panel + + + +
+ + + diff --git a/playground/chrome-extension/src/pages/panel/index.tsx b/playground/chrome-extension/src/pages/panel/index.tsx new file mode 100644 index 00000000000..88ce49ce797 --- /dev/null +++ b/playground/chrome-extension/src/pages/panel/index.tsx @@ -0,0 +1,11 @@ +import { createRoot } from 'react-dom/client'; +import Panel from './panel'; + +function init() { + const rootContainer = document.querySelector("#__root"); + if (!rootContainer) throw new Error("Can't find Panel root element"); + const root = createRoot(rootContainer); + root.render(); +} + +init(); diff --git a/playground/chrome-extension/src/pages/popup/Popup.tsx b/playground/chrome-extension/src/pages/popup/Popup.tsx new file mode 100644 index 00000000000..f3fa7470612 --- /dev/null +++ b/playground/chrome-extension/src/pages/popup/Popup.tsx @@ -0,0 +1,12 @@ +import { MemoryRouter } from "react-router-dom"; +import { SharedApp } from '@/components/SharedApp'; + +function Popup() { + return ( + + + + ) +} + +export default Popup; diff --git a/playground/chrome-extension/src/pages/popup/index.html b/playground/chrome-extension/src/pages/popup/index.html new file mode 100644 index 00000000000..b60f054fcee --- /dev/null +++ b/playground/chrome-extension/src/pages/popup/index.html @@ -0,0 +1,12 @@ + + + + + Popup + + + +
+ + + diff --git a/playground/chrome-extension/src/pages/popup/index.tsx b/playground/chrome-extension/src/pages/popup/index.tsx new file mode 100644 index 00000000000..695a35a37d8 --- /dev/null +++ b/playground/chrome-extension/src/pages/popup/index.tsx @@ -0,0 +1,11 @@ +import { createRoot } from 'react-dom/client'; +import Popup from './popup'; + +function init() { + const rootContainer = document.querySelector("#__root"); + if (!rootContainer) throw new Error("Can't find Popup root element"); + const root = createRoot(rootContainer); + root.render(); +} + +init(); diff --git a/playground/chrome-extension/src/vite-env.d.ts b/playground/chrome-extension/src/vite-env.d.ts new file mode 100644 index 00000000000..11f02fe2a00 --- /dev/null +++ b/playground/chrome-extension/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/playground/chrome-extension/tsconfig.json b/playground/chrome-extension/tsconfig.json new file mode 100644 index 00000000000..5dd31527680 --- /dev/null +++ b/playground/chrome-extension/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "esnext", + "types": ["vite/client", "node", "chrome"], + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "noEmit": true, + "jsx": "react-jsx", + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } + }, + "include": ["src", "vite.config.ts"], +} diff --git a/playground/chrome-extension/vite.config.ts b/playground/chrome-extension/vite.config.ts new file mode 100644 index 00000000000..0e40558bb78 --- /dev/null +++ b/playground/chrome-extension/vite.config.ts @@ -0,0 +1,50 @@ +import { fileURLToPath, URL } from 'url'; +import { resolve } from 'path'; + +import react from '@vitejs/plugin-react-swc'; +import { crx, ManifestV3Export } from '@crxjs/vite-plugin'; +import { defineConfig } from 'vite'; + +import manifest from './manifest.json'; +import devManifest from './manifest.dev.json'; +import pkg from './package.json'; + +const isDev = process.env.__DEV__ === 'true'; + +const extensionManifest = { + ...manifest, + ...(isDev ? devManifest : {} as ManifestV3Export), + name: isDev ? `[DEV] ${manifest.name}` : manifest.name, + version: pkg.version, +}; + +const crxPlugin = crx({ + manifest: extensionManifest as ManifestV3Export, + contentScripts: { + injectCss: true, + } +}) + +export default defineConfig({ + resolve: { + alias: [ + { find: '@/', replacement: fileURLToPath(new URL('./src/', import.meta.url)) }, + ], + }, + plugins: [ + react(), + crxPlugin, + ], + publicDir: resolve(__dirname, 'public'), + build: { + emptyOutDir: !isDev, + outDir: resolve(__dirname, 'dist'), + minify: !isDev, + sourcemap: isDev, + rollupOptions: { + input: { + panel: 'src/pages/panel/index.html', + }, + }, + }, +}); diff --git a/playground/vite-react-ts/.gitignore b/playground/vite-react-ts/.gitignore index a547bf36d8d..d7de12f3812 100644 --- a/playground/vite-react-ts/.gitignore +++ b/playground/vite-react-ts/.gitignore @@ -12,6 +12,8 @@ dist dist-ssr *.local +.env + # Editor directories and files .vscode/* !.vscode/extensions.json