diff --git a/.env.example b/.env.example index cd9775f..a1230c2 100644 --- a/.env.example +++ b/.env.example @@ -10,14 +10,18 @@ AUTH_SECRET= GOOGLE_CLIENT_ID= GOOGLE_CLIENT_SECRET= +GITHUB_ID= +GITHUB_SECRET= +LinuxDo_CLIENT_ID= +LinuxDo_CLIENT_SECRET= # ----------------------------------------------------------------------------- -# Database (MySQL - Neon DB) +# Database, example: DATABASE_URL='postgres://[user]:[password]@[hostname]:5432/[dbname]' # ----------------------------------------------------------------------------- DATABASE_URL='postgres://[user]:[password]@[neon_hostname]/[dbname]?sslmode=require' # ----------------------------------------------------------------------------- -# Email (Resend) +# Email api (https://resend.com) for login and send email # ----------------------------------------------------------------------------- RESEND_API_KEY= @@ -27,9 +31,11 @@ RESEND_API_KEY= CLOUDFLARE_ZONE_ID= CLOUDFLARE_API_KEY= CLOUDFLARE_EMAIL= +# Cloudflare zone name, example: wr.do +CLOUDFLARE_ZONE_NAME= # ----------------------------------------------------------------------------- -# Free Quota +# About to be deprecated # ----------------------------------------------------------------------------- NEXT_PUBLIC_FREE_RECORD_QUOTA=3 NEXT_PUBLIC_FREE_URL_QUOTA=100 @@ -37,11 +43,16 @@ NEXT_PUBLIC_FREE_URL_QUOTA=100 # Open Signup NEXT_PUBLIC_OPEN_SIGNUP=1 +# Google Analytics NEXT_PUBLIC_GOOGLE_ID= -SCREENSHOTONE_BASE_URL= +# ScreenShot API +SCREENSHOTONE_BASE_URL=https://shot.wr.do +# GitHub api token for getting gitHub stars count GITHUB_TOKEN= -OPENAI_API_KEY= -OPENAI_API_BASE= \ No newline at end of file +# Short domains, split by "," +NEXT_PUBLIC_SHORT_DOMAINS=wr.do,uv.do + + diff --git a/README-zh.md b/README-zh.md index 10e5ea2..760a4e3 100644 --- a/README-zh.md +++ b/README-zh.md @@ -1,7 +1,7 @@

WR.DO

Discord · English | 简体中文

-

创建 DNS 记录,生成短链接

+

创建 DNS 记录,生成短链接,临时邮箱

@@ -35,10 +35,13 @@ ### 要求 - [Vercel](https://vercel.com) 账户用于部署应用 -- [Cloudflare](https://dash.cloudflare.com/) 账户 -- 在 Cloudflare 托管的 **域名** +- 至少一个在 [Cloudflare](https://dash.cloudflare.com/) 托管的 **域名** -查看有关[开发者](https://wr.do/docs/developer/installation)的文档。 +查看[开发文档](https://wr.do/docs/developer/installation)。 + +### Email worker + +查看 [email worker](https://wr.do/docs/developer/cloudflare-email-worker) 文档用于邮件接收。 ## 本地开发 diff --git a/README.md b/README.md index 924e6c5..cdffb0f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

WR.DO

Discord · English | 简体中文

-

Craft DNS Records, Make Short Links

+

Craft DNS Records, Make Short Links, Email Support.

@@ -29,18 +29,21 @@ ## Quick Start -See docs about [guide](https://wr.do/docs/quick-start) for quick start. +See usage docs about [guide](https://wr.do/docs/quick-start) for quick start. ## Self-hosted Tutorial ### Requirements - [Vercel](https://vercel.com) to deploy app -- [Cloudflare](https://dash.cloudflare.com/) account -- A **domain** name hosted on Cloudflare +- A **domain** name hosted on [Cloudflare](https://dash.cloudflare.com/) See more docs about [developer](https://wr.do/docs/developer/installation). +### Email worker + +See more docs about [email worker](https://wr.do/docs/developer/cloudflare-email-worker). + ## Local development copy `.env.example` to `.env` and fill in the necessary environment variables. diff --git a/components/ui/scroll-area.tsx b/components/ui/scroll-area.tsx index 277caac..6be6bb6 100644 --- a/components/ui/scroll-area.tsx +++ b/components/ui/scroll-area.tsx @@ -14,7 +14,7 @@ const ScrollArea = React.forwardRef< className={cn("relative overflow-hidden", className)} {...props} > - + {children} diff --git a/config/docs.ts b/config/docs.ts index 5a1de01..d642eec 100644 --- a/config/docs.ts +++ b/config/docs.ts @@ -121,6 +121,11 @@ export const docsConfig: DocsConfig = { href: "/docs/developer/email", icon: "page", }, + { + title: "Email Worker", + href: "/docs/developer/cloudflare-email-worker", + icon: "page", + }, { title: "Database", href: "/docs/developer/database", diff --git a/content/docs/developer/cloudflare-email-worker.mdx b/content/docs/developer/cloudflare-email-worker.mdx new file mode 100644 index 0000000..421de34 --- /dev/null +++ b/content/docs/developer/cloudflare-email-worker.mdx @@ -0,0 +1,102 @@ +--- +title: Cloudflare Email Worker Configs +description: How to config the cloudflare api. +--- + +Before you start, you must have a Cloudflare account and a domain be hosted on Cloudflare. + +### Introduction to Cloudflare Email Worker and R2 + +#### Cloudflare Email Worker + +Cloudflare Email Worker is a feature of Cloudflare's Email Routing service combined with the Workers platform. +It allows users to process incoming emails programmatically at Cloudflare's edge network. +When an email is sent to a custom address configured in Email Routing, +the associated Worker is triggered, receiving the email data (e.g., sender, recipient, headers, and body). +Developers can write JavaScript code to define custom logic, +such as forwarding emails to specific addresses, filtering spam, +or integrating with external APIs. + +#### Cloudflare R2 + +Cloudflare R2 (Object Storage) is a scalable, S3-compatible storage solution provided by Cloudflare. +It allows users to store and retrieve files (e.g., email attachments) at the edge with zero egress fees. +In the context of an Email Worker, R2 can be used to store email attachments or other data, accessible via environment bindings in the Worker script. + +### Overview of cf-email-forwarding-worker + +[oiov/cf-email-forwarding-worker](https://github.com/oiov/cf-email-forwarding-worker), +implements an advanced email forwarding solution using Cloudflare Email Worker and R2. +Instead of directly forwarding emails to another email address, +it sends the email data to a third-party API endpoint for custom processing. +Additionally, it leverages Cloudflare R2 to store email attachments, making them accessible to the third-party application. + +#### Key Features + +- **API-based Forwarding**: Emails are sent as structured data to a configurable third-party API (APP_API_URL) via HTTP POST requests. +- **Attachment Storage**: Email attachments are uploaded to an R2 bucket and their URLs are included in the API payload. +- **Customizable**: The third-party app can process the email data (e.g., sender, subject, body, attachments) as needed. +#### Configuration + +The Worker relies on two environment variables defined in the wrangler.jsonc file: + +```json +"vars": { + "APP_API_URL": "https://wr.do/api/v1/email-catcher" +}, +"r2_buckets": [ + { + "binding": "R2_BUCKET", + "bucket_name": "wremail" + } +] +``` + +`APP_API_URL`: The URL of the third-party API endpoint that receives the email data. This allows the third-party app to handle emails in a custom way (e.g., logging, processing, or forwarding). + +`R2_BUCKET`: The binding name for the R2 storage bucket, accessible in the Worker code as env.R2_BUCKET. The bucket_name (`wremail`) specifies the R2 bucket where email attachments are stored. Note: R2 must be activated and configured in your Cloudflare account beforehand. + +#### How It Works + +- Email Reception: An email sent to the configured address triggers the Worker. +- Attachment Handling: If the email contains attachments, they are extracted and uploaded to the R2 bucket (wremail). The Worker generates accessible URLs for these attachments. +- API Forwarding: The email data (e.g., sender, recipient, subject, body, and attachment URLs) is packaged into a JSON payload and sent to the `APP_API_URL` via an HTTP POST request. +- Third-Party Processing: The third-party app receives the payload and processes it according to its own logic. + +#### Example Usage + +- A user sends an email to example@yourdomain.com. +- The Worker uploads any attachments to the wremail R2 bucket. +- The Worker sends a POST request to https://wr.do/api/v1/email-catcher with the email details and attachment URLs. +- The third-party app logs the email, stores it in a database, or forwards it elsewhere. +#### Prerequisites +- A Cloudflare account with Email Routing enabled. +- An R2 bucket created and bound to the Worker (e.g., wremail). +- A third-party API endpoint ready to receive POST requests with email data. + +### Deploy email worker to Cloudflare + +```bash +git clone https://github.com/oiov/cf-email-forwarding-worker.git +cd cf-email-forwarding-worker +pnpm install + +wranler login +wranler deploy +``` +Remember to add your environment variables in `wrangler.jsonc` before deploy. + +### Config your domain email rule + + +Via the [https://dash.cloudflare.com/account_id/zone_name/email/routing/routes](https://dash.cloudflare.com/[account_id]/[zone_name]/email/routing/routes]), +edit `Catch-all address`, select: +- `Action` -> `Send to a worker` +- `Destination` -> `wrdo-email-worker`(The worker name you deploy). + +Then save and active it. + +Once you add a new domain, you need to perform the same action, the email worker can be the same. + + + diff --git a/content/docs/developer/cloudflare.mdx b/content/docs/developer/cloudflare.mdx index 9af6573..80bceb6 100644 --- a/content/docs/developer/cloudflare.mdx +++ b/content/docs/developer/cloudflare.mdx @@ -11,6 +11,7 @@ In this section, you can update these variables: CLOUDFLARE_ZONE_ID=abcdef1234567890 CLOUDFLARE_API_KEY=1234567890abcdef1234567890abcdef CLOUDFLARE_EMAIL=user@example.com +CLOUDFLARE_ZONE_NAME=wr.do ``` ### Variable Descriptions @@ -25,5 +26,5 @@ CLOUDFLARE_EMAIL=user@example.com - **CLOUDFLARE_EMAIL**: This is the email address associated with your Cloudflare account. It is used for authentication alongside the API key. - +- **CLOUDFLARE_ZONE_NAME**: This is the name of your Cloudflare zone. It is used to specify the zone in the Cloudflare API requests. diff --git a/content/docs/developer/installation.mdx b/content/docs/developer/installation.mdx index bd90a88..a0993f1 100644 --- a/content/docs/developer/installation.mdx +++ b/content/docs/developer/installation.mdx @@ -56,11 +56,13 @@ Copy/paste the `.env.example` in the `.env` file: | NEXT_PUBLIC_OPEN_SIGNUP | `1` | Open signup. | | SCREENSHOTONE_BASE_URL | `https://api.example.com` | pending | | GITHUB_TOKEN | `ghp_sscsfarwetqet` | https://github.com/settings/tokens | +| NEXT_PUBLIC_SHORT_DOMAINS | `wr.do,uv.do` | The list of short domains. Separated by `,` | - How to get `GOOGLE_CLIENT_ID`、`GITHUB_ID`, see [Authentification](/docs/developer/authentification). - How to get `RESEND_API_KEY`, see [Email](/docs/developer/email). - How to get `CLOUDFLARE_ZONE_ID`、`CLOUDFLARE_API_KEY`、`CLOUDFLARE_EMAIL`, see [Cloudflare Configs](/docs/developer/cloudflare). - How to get `DATABASE_URL`, see [Database](/docs/developer/database). +- How to active email worker, see [Email Worker](/docs/developer/cloudflare-email-worker). ### Configuration part diff --git a/public/sw.js.map b/public/sw.js.map index 0602c5e..1d8df32 100644 --- a/public/sw.js.map +++ b/public/sw.js.map @@ -1 +1 @@ -{"version":3,"file":"sw.js","sources":["../../../../../../private/var/folders/9b/3qmyp8zd2xvdspdrp149fyg00000gn/T/ddd1b9320625d99d17d6e201ea930412/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-routing@6.6.0/node_modules/workbox-routing/registerRoute.mjs';\nimport {NetworkFirst as workbox_strategies_NetworkFirst} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-core@6.6.0/node_modules/workbox-core/clientsClaim.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\nimportScripts(\n \n);\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n\nworkbox_routing_registerRoute(\"/\", new workbox_strategies_NetworkFirst({ \"cacheName\":\"start-url\", plugins: [{ cacheWillUpdate: async ({ request, response, event, state }) => { if (response && response.type === 'opaqueredirect') { return new Response(response.body, { status: 200, statusText: 'OK', headers: response.headers }) } return response } }] }), 'GET');\nworkbox_routing_registerRoute(/.*/i, new workbox_strategies_NetworkOnly({ \"cacheName\":\"dev\", plugins: [] }), 'GET');\n\n\n\n\n"],"names":["importScripts","self","skipWaiting","workbox_core_clientsClaim","workbox_routing_registerRoute","workbox_strategies_NetworkFirst","plugins","cacheWillUpdate","request","response","event","state","type","Response","body","status","statusText","headers","workbox_strategies_NetworkOnly"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"sw.js","sources":["../../../../../../private/var/folders/9b/3qmyp8zd2xvdspdrp149fyg00000gn/T/7d0a89aab5e742e14a569aa244e668c1/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-routing@6.6.0/node_modules/workbox-routing/registerRoute.mjs';\nimport {NetworkFirst as workbox_strategies_NetworkFirst} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-core@6.6.0/node_modules/workbox-core/clientsClaim.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\nimportScripts(\n \n);\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n\nworkbox_routing_registerRoute(\"/\", new workbox_strategies_NetworkFirst({ \"cacheName\":\"start-url\", plugins: [{ cacheWillUpdate: async ({ request, response, event, state }) => { if (response && response.type === 'opaqueredirect') { return new Response(response.body, { status: 200, statusText: 'OK', headers: response.headers }) } return response } }] }), 'GET');\nworkbox_routing_registerRoute(/.*/i, new workbox_strategies_NetworkOnly({ \"cacheName\":\"dev\", plugins: [] }), 'GET');\n\n\n\n\n"],"names":["importScripts","self","skipWaiting","workbox_core_clientsClaim","workbox_routing_registerRoute","workbox_strategies_NetworkFirst","plugins","cacheWillUpdate","request","response","event","state","type","Response","body","status","statusText","headers","workbox_strategies_NetworkOnly"],"mappings":"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"} \ No newline at end of file