├── .github └── workflows │ └── deploy-to-cf.yaml ├── .gitignore ├── .prettierignore ├── LICENSE ├── README.md ├── package.json ├── pnpm-lock.yaml ├── prettier.config.js ├── renovate.json ├── src ├── index.ts └── util.ts ├── tsconfig.json └── wrangler.toml /.github/workflows/deploy-to-cf.yaml: -------------------------------------------------------------------------------- 1 | name: Deploy to Cloudflare Workers 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | deploy: 15 | runs-on: ubuntu-latest 16 | name: Deploy 17 | steps: 18 | - name: Checkout 🧳 19 | uses: actions/checkout@v4 20 | 21 | - name: Setup PNPM ⚙️ 22 | uses: AkashRajpurohit/.github/.github/actions/setup-pnpm@main 23 | with: 24 | node_version: 20 25 | pnpm_version: 9 26 | 27 | - name: Install dependencies ⏬ 28 | run: pnpm install --no-frozen-lockfile 29 | 30 | # Deploy 31 | - name: Deploy 🚀 32 | run: pnpm run deploy 33 | env: 34 | CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }} 35 | CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }} 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | 3 | logs 4 | _.log 5 | npm-debug.log_ 6 | yarn-debug.log* 7 | yarn-error.log* 8 | lerna-debug.log* 9 | .pnpm-debug.log* 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | 13 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 14 | 15 | # Runtime data 16 | 17 | pids 18 | _.pid 19 | _.seed 20 | \*.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | 28 | coverage 29 | \*.lcov 30 | 31 | # nyc test coverage 32 | 33 | .nyc_output 34 | 35 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 36 | 37 | .grunt 38 | 39 | # Bower dependency directory (https://bower.io/) 40 | 41 | bower_components 42 | 43 | # node-waf configuration 44 | 45 | .lock-wscript 46 | 47 | # Compiled binary addons (https://nodejs.org/api/addons.html) 48 | 49 | build/Release 50 | 51 | # Dependency directories 52 | 53 | node_modules/ 54 | jspm_packages/ 55 | 56 | # Snowpack dependency directory (https://snowpack.dev/) 57 | 58 | web_modules/ 59 | 60 | # TypeScript cache 61 | 62 | \*.tsbuildinfo 63 | 64 | # Optional npm cache directory 65 | 66 | .npm 67 | 68 | # Optional eslint cache 69 | 70 | .eslintcache 71 | 72 | # Optional stylelint cache 73 | 74 | .stylelintcache 75 | 76 | # Microbundle cache 77 | 78 | .rpt2_cache/ 79 | .rts2_cache_cjs/ 80 | .rts2_cache_es/ 81 | .rts2_cache_umd/ 82 | 83 | # Optional REPL history 84 | 85 | .node_repl_history 86 | 87 | # Output of 'npm pack' 88 | 89 | \*.tgz 90 | 91 | # Yarn Integrity file 92 | 93 | .yarn-integrity 94 | 95 | # dotenv environment variable files 96 | 97 | .env 98 | .env.development.local 99 | .env.test.local 100 | .env.production.local 101 | .env.local 102 | 103 | # parcel-bundler cache (https://parceljs.org/) 104 | 105 | .cache 106 | .parcel-cache 107 | 108 | # Next.js build output 109 | 110 | .next 111 | out 112 | 113 | # Nuxt.js build / generate output 114 | 115 | .nuxt 116 | dist 117 | 118 | # Gatsby files 119 | 120 | .cache/ 121 | 122 | # Comment in the public line in if your project uses Gatsby and not Next.js 123 | 124 | # https://nextjs.org/blog/next-9-1#public-directory-support 125 | 126 | # public 127 | 128 | # vuepress build output 129 | 130 | .vuepress/dist 131 | 132 | # vuepress v2.x temp and cache directory 133 | 134 | .temp 135 | .cache 136 | 137 | # Docusaurus cache and generated files 138 | 139 | .docusaurus 140 | 141 | # Serverless directories 142 | 143 | .serverless/ 144 | 145 | # FuseBox cache 146 | 147 | .fusebox/ 148 | 149 | # DynamoDB Local files 150 | 151 | .dynamodb/ 152 | 153 | # TernJS port file 154 | 155 | .tern-port 156 | 157 | # Stores VSCode versions used for testing VSCode extensions 158 | 159 | .vscode-test 160 | 161 | # yarn v2 162 | 163 | .yarn/cache 164 | .yarn/unplugged 165 | .yarn/build-state.yml 166 | .yarn/install-state.gz 167 | .pnp.\* 168 | 169 | # wrangler project 170 | 171 | .dev.vars 172 | .wrangler -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.json 3 | *.yml 4 | *.yaml -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Akash Rajpurohit 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

3 | 4 | Its go time 5 | 6 | 7 |

Time To Go!

8 | 9 |

10 | Simplify and Supercharge Your Links! 11 |
12 |
13 | Bug report 14 | · 15 | Feature request 16 |
17 |
18 | 19 | Deployed via Cloudflare Workers 20 | 21 | 22 | Data storage via Workers KV 23 | 24 | Visitors count 25 | 26 | follow on twitter 27 | 28 | 29 | GitHub 30 | 31 |

32 |

33 | 34 | Time to Go is a utility service built on top of Cloudflare Workers that allows you share Go URLs. 35 | 36 | > Read more about Go URLs by visiting this Go URL [https://go.akashrajpurohit.com/b/go-urls](https://go.akashrajpurohit.com/b/go-urls?via=github-desc) 37 | 38 | # Motivation 💪 39 | 40 | Have you ever wanted to share a long and complex URL with others, only to find it difficult to remember or share? Time to Go solves this problem by providing you with the ability to create short, personalized Go URLs that are easy to remember and share. 41 | 42 | Whether you're sharing a link on social media or including it in a presentation, Time to Go simplifies the process and makes it more convenient for you and your audience. 43 | 44 | # Self Hosting Guide 📖 45 | 46 | To self-host Time to Go, follow these steps: 47 | 48 | ## Prerequisites 🏃🏻 49 | 50 | - Account with [Cloudflare](https://dash.cloudflare.com/sign-up). Everything required for this is available on Free plan as well. 51 | - [Node.js](https://nodejs.org/) installed on your machine if you want to run it locally first. 52 | - [PNPM](https://pnpm.io/) - The package manager used. 53 | 54 | ## KV Setup 📦 55 | 56 | To store the URL data, Time to Go utilizes Cloudflare's Key-Value (KV) store. Follow these steps to set up KV: 57 | 58 | 1. Create a KV namespace in your Cloudflare account. 59 | 2. Note down the generated KV namespace ID. 60 | 61 | We will use the UI for KV to add/update go-urls. Simple add a key (the short code) and value as the actual URL and click on "Add Entry" 62 | 63 | Go ahead and take some time to add some GO URLs for yourself. 64 | 65 | ## Environment Variables 👀 66 | 67 | Before deploying Time to Go, make sure to set the following environment variables: 68 | 69 | ### For Github Actions ⛏ 70 | 71 | _All of the tokens mentioned in this section are required._ 72 | 73 | - `CF_API_TOKEN`: Your Cloudflare API token. Create the API tokens from [here](https://dash.cloudflare.com/profile/api-tokens) 74 | - `CF_ACCOUNT_ID`: The ID of the Cloudflare zone where you want to deploy Time to Go. 75 | 76 | ### For Cloudflare Worker 👷🏼‍♂️ 77 | 78 | - `NOT_FOUND_REDIRECT_URL` - This would be the URL where you want to re-direct a user when there is no go-url configured for incoming request. 79 | 80 | If this is not set then the service will just return a 404 response. 81 | - `REFERRER_TEXT` - If set, this will get attached to the go-url as a `ref` key in the url. 82 | 83 | For example if `REFERRER_TEXT=my-ref` and the URL is `https://example.com` it will be redirected to `https://example.com?ref=my-ref` 84 | 85 | ## Deployment 🚀 86 | 87 | To deploy Time to Go, follow these steps: 88 | 89 | 1. [Fork this repository](https://docs.github.com/en/get-started/quickstart/fork-a-repo) to your own GitHub account. 90 | 2. Add the environment variables for the forked repository from the [Github Actions](#for-github-actions-) section. 91 | 3. Clone the forked repository to your local machine. 92 | 4. Navigate to the repository directory. 93 | 5. Install the dependencies by running the command: `pnpm install`. 94 | 6. Edit the `wrangler.toml` file and update the values for `kv_namespaces` with the KV id we created earlier for both `id` and `preview_id`. 95 | 7. Update the `vars` section to add the environment variables from the [Cloudflare worker](#for-cloudflare-worker-%EF%B8%8F) section. 96 | 8. Commit your changes and push them to your forked repository. 97 | 9. GitHub Actions will automatically trigger the deployment process. Wait for the action to complete. 98 | 99 | Congratulations! Time to Go is now deployed and ready to use. 100 | 101 | # Technology Stack 💻 102 | 103 | - Framework - [Hono](https://honojs.dev/) 104 | - Deployment - [Cloudflare Workers](https://workers.cloudflare.com/) 105 | - Storage - [Workers KV](https://www.cloudflare.com/products/workers-kv/) 106 | 107 | # Bugs or Requests 🐛 108 | 109 | If you encounter any problems feel free to open an [issue](https://github.com/AkashRajpurohit/time-to-go/issues/new?template=bug_report.md). If you feel the project is missing a feature, please raise a [ticket](https://github.com/AkashRajpurohit/time-to-go/issues/new?template=feature_request.md) on GitHub and I'll look into it. Pull requests are also welcome. 110 | 111 | # Where to find me? 👀 112 | 113 | [![Website Badge](https://img.shields.io/badge/-akashrajpurohit.com-3b5998?logo=google-chrome&logoColor=white)](https://akashrajpurohit.com/) 114 | [![Twitter Badge](https://img.shields.io/badge/-@akashwhocodes-00acee?logo=Twitter&logoColor=white)](https://twitter.com/AkashWhoCodes) 115 | [![Linkedin Badge](https://img.shields.io/badge/-@AkashRajpurohit-0e76a8?logo=Linkedin&logoColor=white)](https://linkedin.com/in/AkashRajpurohit) 116 | [![Instagram Badge](https://img.shields.io/badge/-@akashwho.codes-e4405f?logo=Instagram&logoColor=white)](https://instagram.com/akashwho.codes/) 117 | [![Telegram Badge](https://img.shields.io/badge/-@AkashRajpurohit-0088cc?logo=Telegram&logoColor=white)](https://t.me/AkashRajpurohit) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "wrangler dev", 5 | "dev:remote": "wrangler dev --remote", 6 | "deploy": "wrangler deploy", 7 | "format": "prettier --write ." 8 | }, 9 | "dependencies": { 10 | "hono": "^4.6.8" 11 | }, 12 | "devDependencies": { 13 | "@cloudflare/workers-types": "^4.20241022.0", 14 | "prettier": "^3.3.3", 15 | "wrangler": "^3.84.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | hono: 12 | specifier: ^4.6.8 13 | version: 4.6.8 14 | devDependencies: 15 | '@cloudflare/workers-types': 16 | specifier: ^4.20241022.0 17 | version: 4.20241022.0 18 | prettier: 19 | specifier: ^3.3.3 20 | version: 3.3.3 21 | wrangler: 22 | specifier: ^3.84.1 23 | version: 3.84.1(@cloudflare/workers-types@4.20241022.0) 24 | 25 | packages: 26 | 27 | '@cloudflare/kv-asset-handler@0.3.4': 28 | resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} 29 | engines: {node: '>=16.13'} 30 | 31 | '@cloudflare/workerd-darwin-64@1.20241022.0': 32 | resolution: {integrity: sha512-1NNYun37myMTgCUiPQEJ0cMal4mKZVTpkD0b2tx9hV70xji+frVJcSK8YVLeUm1P+Rw1d/ct8DMgQuCpsz3Fsw==} 33 | engines: {node: '>=16'} 34 | cpu: [x64] 35 | os: [darwin] 36 | 37 | '@cloudflare/workerd-darwin-arm64@1.20241022.0': 38 | resolution: {integrity: sha512-FOO/0P0U82EsTLTdweNVgw+4VOk5nghExLPLSppdOziq6IR5HVgP44Kmq5LdsUeHUhwUmfOh9hzaTpkNzUqKvw==} 39 | engines: {node: '>=16'} 40 | cpu: [arm64] 41 | os: [darwin] 42 | 43 | '@cloudflare/workerd-linux-64@1.20241022.0': 44 | resolution: {integrity: sha512-RsNc19BQJG9yd+ngnjuDeG9ywZG+7t1L4JeglgceyY5ViMNMKVO7Zpbsu69kXslU9h6xyQG+lrmclg3cBpnhYA==} 45 | engines: {node: '>=16'} 46 | cpu: [x64] 47 | os: [linux] 48 | 49 | '@cloudflare/workerd-linux-arm64@1.20241022.0': 50 | resolution: {integrity: sha512-x5mUXpKxfsosxcFmcq5DaqLs37PejHYVRsNz1cWI59ma7aC4y4Qn6Tf3i0r9MwQTF/MccP4SjVslMU6m4W7IaA==} 51 | engines: {node: '>=16'} 52 | cpu: [arm64] 53 | os: [linux] 54 | 55 | '@cloudflare/workerd-windows-64@1.20241022.0': 56 | resolution: {integrity: sha512-eBCClx4szCOgKqOlxxbdNszMqQf3MRG1B9BRIqEM/diDfdR9IrZ8l3FaEm+l9gXgPmS6m1NBn40aWuGBl8UTSw==} 57 | engines: {node: '>=16'} 58 | cpu: [x64] 59 | os: [win32] 60 | 61 | '@cloudflare/workers-shared@0.7.0': 62 | resolution: {integrity: sha512-LLQRTqx7lKC7o2eCYMpyc5FXV8d0pUX6r3A+agzhqS9aoR5A6zCPefwQGcvbKx83ozX22ATZcemwxQXn12UofQ==} 63 | engines: {node: '>=16.7.0'} 64 | 65 | '@cloudflare/workers-types@4.20241022.0': 66 | resolution: {integrity: sha512-1zOAw5QIDKItzGatzCrEpfLOB1AuMTwVqKmbw9B9eBfCUGRFNfJYMrJxIwcse9EmKahsQt2GruqU00pY/GyXgg==} 67 | 68 | '@cspotcode/source-map-support@0.8.1': 69 | resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} 70 | engines: {node: '>=12'} 71 | 72 | '@esbuild-plugins/node-globals-polyfill@0.2.3': 73 | resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==} 74 | peerDependencies: 75 | esbuild: '*' 76 | 77 | '@esbuild-plugins/node-modules-polyfill@0.2.2': 78 | resolution: {integrity: sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==} 79 | peerDependencies: 80 | esbuild: '*' 81 | 82 | '@esbuild/android-arm64@0.17.19': 83 | resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} 84 | engines: {node: '>=12'} 85 | cpu: [arm64] 86 | os: [android] 87 | 88 | '@esbuild/android-arm@0.17.19': 89 | resolution: {integrity: sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==} 90 | engines: {node: '>=12'} 91 | cpu: [arm] 92 | os: [android] 93 | 94 | '@esbuild/android-x64@0.17.19': 95 | resolution: {integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==} 96 | engines: {node: '>=12'} 97 | cpu: [x64] 98 | os: [android] 99 | 100 | '@esbuild/darwin-arm64@0.17.19': 101 | resolution: {integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==} 102 | engines: {node: '>=12'} 103 | cpu: [arm64] 104 | os: [darwin] 105 | 106 | '@esbuild/darwin-x64@0.17.19': 107 | resolution: {integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==} 108 | engines: {node: '>=12'} 109 | cpu: [x64] 110 | os: [darwin] 111 | 112 | '@esbuild/freebsd-arm64@0.17.19': 113 | resolution: {integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==} 114 | engines: {node: '>=12'} 115 | cpu: [arm64] 116 | os: [freebsd] 117 | 118 | '@esbuild/freebsd-x64@0.17.19': 119 | resolution: {integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==} 120 | engines: {node: '>=12'} 121 | cpu: [x64] 122 | os: [freebsd] 123 | 124 | '@esbuild/linux-arm64@0.17.19': 125 | resolution: {integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==} 126 | engines: {node: '>=12'} 127 | cpu: [arm64] 128 | os: [linux] 129 | 130 | '@esbuild/linux-arm@0.17.19': 131 | resolution: {integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==} 132 | engines: {node: '>=12'} 133 | cpu: [arm] 134 | os: [linux] 135 | 136 | '@esbuild/linux-ia32@0.17.19': 137 | resolution: {integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==} 138 | engines: {node: '>=12'} 139 | cpu: [ia32] 140 | os: [linux] 141 | 142 | '@esbuild/linux-loong64@0.17.19': 143 | resolution: {integrity: sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==} 144 | engines: {node: '>=12'} 145 | cpu: [loong64] 146 | os: [linux] 147 | 148 | '@esbuild/linux-mips64el@0.17.19': 149 | resolution: {integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==} 150 | engines: {node: '>=12'} 151 | cpu: [mips64el] 152 | os: [linux] 153 | 154 | '@esbuild/linux-ppc64@0.17.19': 155 | resolution: {integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==} 156 | engines: {node: '>=12'} 157 | cpu: [ppc64] 158 | os: [linux] 159 | 160 | '@esbuild/linux-riscv64@0.17.19': 161 | resolution: {integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==} 162 | engines: {node: '>=12'} 163 | cpu: [riscv64] 164 | os: [linux] 165 | 166 | '@esbuild/linux-s390x@0.17.19': 167 | resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==} 168 | engines: {node: '>=12'} 169 | cpu: [s390x] 170 | os: [linux] 171 | 172 | '@esbuild/linux-x64@0.17.19': 173 | resolution: {integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==} 174 | engines: {node: '>=12'} 175 | cpu: [x64] 176 | os: [linux] 177 | 178 | '@esbuild/netbsd-x64@0.17.19': 179 | resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==} 180 | engines: {node: '>=12'} 181 | cpu: [x64] 182 | os: [netbsd] 183 | 184 | '@esbuild/openbsd-x64@0.17.19': 185 | resolution: {integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==} 186 | engines: {node: '>=12'} 187 | cpu: [x64] 188 | os: [openbsd] 189 | 190 | '@esbuild/sunos-x64@0.17.19': 191 | resolution: {integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==} 192 | engines: {node: '>=12'} 193 | cpu: [x64] 194 | os: [sunos] 195 | 196 | '@esbuild/win32-arm64@0.17.19': 197 | resolution: {integrity: sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==} 198 | engines: {node: '>=12'} 199 | cpu: [arm64] 200 | os: [win32] 201 | 202 | '@esbuild/win32-ia32@0.17.19': 203 | resolution: {integrity: sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==} 204 | engines: {node: '>=12'} 205 | cpu: [ia32] 206 | os: [win32] 207 | 208 | '@esbuild/win32-x64@0.17.19': 209 | resolution: {integrity: sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==} 210 | engines: {node: '>=12'} 211 | cpu: [x64] 212 | os: [win32] 213 | 214 | '@fastify/busboy@2.1.1': 215 | resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} 216 | engines: {node: '>=14'} 217 | 218 | '@jridgewell/resolve-uri@3.1.2': 219 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 220 | engines: {node: '>=6.0.0'} 221 | 222 | '@jridgewell/sourcemap-codec@1.5.0': 223 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 224 | 225 | '@jridgewell/trace-mapping@0.3.9': 226 | resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} 227 | 228 | '@types/node-forge@1.3.11': 229 | resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} 230 | 231 | '@types/node@22.8.6': 232 | resolution: {integrity: sha512-tosuJYKrIqjQIlVCM4PEGxOmyg3FCPa/fViuJChnGeEIhjA46oy8FMVoF9su1/v8PNs2a8Q0iFNyOx0uOF91nw==} 233 | 234 | acorn-walk@8.3.4: 235 | resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} 236 | engines: {node: '>=0.4.0'} 237 | 238 | acorn@8.14.0: 239 | resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} 240 | engines: {node: '>=0.4.0'} 241 | hasBin: true 242 | 243 | anymatch@3.1.3: 244 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 245 | engines: {node: '>= 8'} 246 | 247 | as-table@1.0.55: 248 | resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==} 249 | 250 | binary-extensions@2.3.0: 251 | resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} 252 | engines: {node: '>=8'} 253 | 254 | blake3-wasm@2.1.5: 255 | resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} 256 | 257 | braces@3.0.3: 258 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 259 | engines: {node: '>=8'} 260 | 261 | capnp-ts@0.7.0: 262 | resolution: {integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==} 263 | 264 | chokidar@3.6.0: 265 | resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} 266 | engines: {node: '>= 8.10.0'} 267 | 268 | cookie@0.7.2: 269 | resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} 270 | engines: {node: '>= 0.6'} 271 | 272 | data-uri-to-buffer@2.0.2: 273 | resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==} 274 | 275 | date-fns@4.1.0: 276 | resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} 277 | 278 | debug@4.3.7: 279 | resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} 280 | engines: {node: '>=6.0'} 281 | peerDependencies: 282 | supports-color: '*' 283 | peerDependenciesMeta: 284 | supports-color: 285 | optional: true 286 | 287 | defu@6.1.4: 288 | resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} 289 | 290 | esbuild@0.17.19: 291 | resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==} 292 | engines: {node: '>=12'} 293 | hasBin: true 294 | 295 | escape-string-regexp@4.0.0: 296 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 297 | engines: {node: '>=10'} 298 | 299 | estree-walker@0.6.1: 300 | resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} 301 | 302 | exit-hook@2.2.1: 303 | resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} 304 | engines: {node: '>=6'} 305 | 306 | fill-range@7.1.1: 307 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 308 | engines: {node: '>=8'} 309 | 310 | fsevents@2.3.3: 311 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 312 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 313 | os: [darwin] 314 | 315 | function-bind@1.1.2: 316 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 317 | 318 | get-source@2.0.12: 319 | resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==} 320 | 321 | glob-parent@5.1.2: 322 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 323 | engines: {node: '>= 6'} 324 | 325 | glob-to-regexp@0.4.1: 326 | resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} 327 | 328 | hasown@2.0.2: 329 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 330 | engines: {node: '>= 0.4'} 331 | 332 | hono@4.6.8: 333 | resolution: {integrity: sha512-f+2Ec9JAzabT61pglDiLJcF/DjiSefZkjCn9bzm1cYLGkD5ExJ3Jnv93ax9h0bn7UPLHF81KktoyjdQfWI2n1Q==} 334 | engines: {node: '>=16.9.0'} 335 | 336 | is-binary-path@2.1.0: 337 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 338 | engines: {node: '>=8'} 339 | 340 | is-core-module@2.15.1: 341 | resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} 342 | engines: {node: '>= 0.4'} 343 | 344 | is-extglob@2.1.1: 345 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 346 | engines: {node: '>=0.10.0'} 347 | 348 | is-glob@4.0.3: 349 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 350 | engines: {node: '>=0.10.0'} 351 | 352 | is-number@7.0.0: 353 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 354 | engines: {node: '>=0.12.0'} 355 | 356 | itty-time@1.0.6: 357 | resolution: {integrity: sha512-+P8IZaLLBtFv8hCkIjcymZOp4UJ+xW6bSlQsXGqrkmJh7vSiMFSlNne0mCYagEE0N7HDNR5jJBRxwN0oYv61Rw==} 358 | 359 | magic-string@0.25.9: 360 | resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} 361 | 362 | mime@3.0.0: 363 | resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} 364 | engines: {node: '>=10.0.0'} 365 | hasBin: true 366 | 367 | miniflare@3.20241022.0: 368 | resolution: {integrity: sha512-x9Fbq1Hmz1f0osIT9Qmj78iX4UpCP2EqlZnA/tzj/3+I49vc3Kq0fNqSSKplcdf6HlCHdL3fOBicmreQF4BUUQ==} 369 | engines: {node: '>=16.13'} 370 | hasBin: true 371 | 372 | ms@2.1.3: 373 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 374 | 375 | mustache@4.2.0: 376 | resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} 377 | hasBin: true 378 | 379 | nanoid@3.3.7: 380 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} 381 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 382 | hasBin: true 383 | 384 | node-forge@1.3.1: 385 | resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} 386 | engines: {node: '>= 6.13.0'} 387 | 388 | normalize-path@3.0.0: 389 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 390 | engines: {node: '>=0.10.0'} 391 | 392 | ohash@1.1.4: 393 | resolution: {integrity: sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==} 394 | 395 | path-parse@1.0.7: 396 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 397 | 398 | path-to-regexp@6.3.0: 399 | resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} 400 | 401 | pathe@1.1.2: 402 | resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} 403 | 404 | picomatch@2.3.1: 405 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 406 | engines: {node: '>=8.6'} 407 | 408 | prettier@3.3.3: 409 | resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} 410 | engines: {node: '>=14'} 411 | hasBin: true 412 | 413 | printable-characters@1.0.42: 414 | resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==} 415 | 416 | readdirp@3.6.0: 417 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 418 | engines: {node: '>=8.10.0'} 419 | 420 | resolve.exports@2.0.2: 421 | resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} 422 | engines: {node: '>=10'} 423 | 424 | resolve@1.22.8: 425 | resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} 426 | hasBin: true 427 | 428 | rollup-plugin-inject@3.0.2: 429 | resolution: {integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==} 430 | deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject. 431 | 432 | rollup-plugin-node-polyfills@0.2.1: 433 | resolution: {integrity: sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==} 434 | 435 | rollup-pluginutils@2.8.2: 436 | resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} 437 | 438 | selfsigned@2.4.1: 439 | resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==} 440 | engines: {node: '>=10'} 441 | 442 | source-map@0.6.1: 443 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 444 | engines: {node: '>=0.10.0'} 445 | 446 | sourcemap-codec@1.4.8: 447 | resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} 448 | deprecated: Please use @jridgewell/sourcemap-codec instead 449 | 450 | stacktracey@2.1.8: 451 | resolution: {integrity: sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==} 452 | 453 | stoppable@1.1.0: 454 | resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} 455 | engines: {node: '>=4', npm: '>=6'} 456 | 457 | supports-preserve-symlinks-flag@1.0.0: 458 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 459 | engines: {node: '>= 0.4'} 460 | 461 | to-regex-range@5.0.1: 462 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 463 | engines: {node: '>=8.0'} 464 | 465 | tslib@2.8.1: 466 | resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 467 | 468 | ufo@1.5.4: 469 | resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} 470 | 471 | undici-types@6.19.8: 472 | resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} 473 | 474 | undici@5.28.4: 475 | resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} 476 | engines: {node: '>=14.0'} 477 | 478 | unenv-nightly@2.0.0-20241024-111401-d4156ac: 479 | resolution: {integrity: sha512-xJO1hfY+Te+/XnfCYrCbFbRcgu6XEODND1s5wnVbaBCkuQX7JXF7fHEXPrukFE2j8EOH848P8QN19VO47XN8hw==} 480 | 481 | workerd@1.20241022.0: 482 | resolution: {integrity: sha512-jyGXsgO9DRcJyx6Ovv7gUyDPc3UYC2i/E0p9GFUg6GUzpldw4Y93y9kOmdfsOnKZ3+lY53veSiUniiBPE6Q2NQ==} 483 | engines: {node: '>=16'} 484 | hasBin: true 485 | 486 | wrangler@3.84.1: 487 | resolution: {integrity: sha512-w27/QpIk2qz6aMIVi9T8cDcXMvh/RXjcL+vf4o5J2GpQAE4U7wTCNHyaY9H3oTJWRN97KqCAEbiHBNtTKoUJEw==} 488 | engines: {node: '>=16.17.0'} 489 | hasBin: true 490 | peerDependencies: 491 | '@cloudflare/workers-types': ^4.20241022.0 492 | peerDependenciesMeta: 493 | '@cloudflare/workers-types': 494 | optional: true 495 | 496 | ws@8.18.0: 497 | resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} 498 | engines: {node: '>=10.0.0'} 499 | peerDependencies: 500 | bufferutil: ^4.0.1 501 | utf-8-validate: '>=5.0.2' 502 | peerDependenciesMeta: 503 | bufferutil: 504 | optional: true 505 | utf-8-validate: 506 | optional: true 507 | 508 | xxhash-wasm@1.0.2: 509 | resolution: {integrity: sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==} 510 | 511 | youch@3.3.4: 512 | resolution: {integrity: sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==} 513 | 514 | zod@3.23.8: 515 | resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} 516 | 517 | snapshots: 518 | 519 | '@cloudflare/kv-asset-handler@0.3.4': 520 | dependencies: 521 | mime: 3.0.0 522 | 523 | '@cloudflare/workerd-darwin-64@1.20241022.0': 524 | optional: true 525 | 526 | '@cloudflare/workerd-darwin-arm64@1.20241022.0': 527 | optional: true 528 | 529 | '@cloudflare/workerd-linux-64@1.20241022.0': 530 | optional: true 531 | 532 | '@cloudflare/workerd-linux-arm64@1.20241022.0': 533 | optional: true 534 | 535 | '@cloudflare/workerd-windows-64@1.20241022.0': 536 | optional: true 537 | 538 | '@cloudflare/workers-shared@0.7.0': 539 | dependencies: 540 | mime: 3.0.0 541 | zod: 3.23.8 542 | 543 | '@cloudflare/workers-types@4.20241022.0': {} 544 | 545 | '@cspotcode/source-map-support@0.8.1': 546 | dependencies: 547 | '@jridgewell/trace-mapping': 0.3.9 548 | 549 | '@esbuild-plugins/node-globals-polyfill@0.2.3(esbuild@0.17.19)': 550 | dependencies: 551 | esbuild: 0.17.19 552 | 553 | '@esbuild-plugins/node-modules-polyfill@0.2.2(esbuild@0.17.19)': 554 | dependencies: 555 | esbuild: 0.17.19 556 | escape-string-regexp: 4.0.0 557 | rollup-plugin-node-polyfills: 0.2.1 558 | 559 | '@esbuild/android-arm64@0.17.19': 560 | optional: true 561 | 562 | '@esbuild/android-arm@0.17.19': 563 | optional: true 564 | 565 | '@esbuild/android-x64@0.17.19': 566 | optional: true 567 | 568 | '@esbuild/darwin-arm64@0.17.19': 569 | optional: true 570 | 571 | '@esbuild/darwin-x64@0.17.19': 572 | optional: true 573 | 574 | '@esbuild/freebsd-arm64@0.17.19': 575 | optional: true 576 | 577 | '@esbuild/freebsd-x64@0.17.19': 578 | optional: true 579 | 580 | '@esbuild/linux-arm64@0.17.19': 581 | optional: true 582 | 583 | '@esbuild/linux-arm@0.17.19': 584 | optional: true 585 | 586 | '@esbuild/linux-ia32@0.17.19': 587 | optional: true 588 | 589 | '@esbuild/linux-loong64@0.17.19': 590 | optional: true 591 | 592 | '@esbuild/linux-mips64el@0.17.19': 593 | optional: true 594 | 595 | '@esbuild/linux-ppc64@0.17.19': 596 | optional: true 597 | 598 | '@esbuild/linux-riscv64@0.17.19': 599 | optional: true 600 | 601 | '@esbuild/linux-s390x@0.17.19': 602 | optional: true 603 | 604 | '@esbuild/linux-x64@0.17.19': 605 | optional: true 606 | 607 | '@esbuild/netbsd-x64@0.17.19': 608 | optional: true 609 | 610 | '@esbuild/openbsd-x64@0.17.19': 611 | optional: true 612 | 613 | '@esbuild/sunos-x64@0.17.19': 614 | optional: true 615 | 616 | '@esbuild/win32-arm64@0.17.19': 617 | optional: true 618 | 619 | '@esbuild/win32-ia32@0.17.19': 620 | optional: true 621 | 622 | '@esbuild/win32-x64@0.17.19': 623 | optional: true 624 | 625 | '@fastify/busboy@2.1.1': {} 626 | 627 | '@jridgewell/resolve-uri@3.1.2': {} 628 | 629 | '@jridgewell/sourcemap-codec@1.5.0': {} 630 | 631 | '@jridgewell/trace-mapping@0.3.9': 632 | dependencies: 633 | '@jridgewell/resolve-uri': 3.1.2 634 | '@jridgewell/sourcemap-codec': 1.5.0 635 | 636 | '@types/node-forge@1.3.11': 637 | dependencies: 638 | '@types/node': 22.8.6 639 | 640 | '@types/node@22.8.6': 641 | dependencies: 642 | undici-types: 6.19.8 643 | 644 | acorn-walk@8.3.4: 645 | dependencies: 646 | acorn: 8.14.0 647 | 648 | acorn@8.14.0: {} 649 | 650 | anymatch@3.1.3: 651 | dependencies: 652 | normalize-path: 3.0.0 653 | picomatch: 2.3.1 654 | 655 | as-table@1.0.55: 656 | dependencies: 657 | printable-characters: 1.0.42 658 | 659 | binary-extensions@2.3.0: {} 660 | 661 | blake3-wasm@2.1.5: {} 662 | 663 | braces@3.0.3: 664 | dependencies: 665 | fill-range: 7.1.1 666 | 667 | capnp-ts@0.7.0: 668 | dependencies: 669 | debug: 4.3.7 670 | tslib: 2.8.1 671 | transitivePeerDependencies: 672 | - supports-color 673 | 674 | chokidar@3.6.0: 675 | dependencies: 676 | anymatch: 3.1.3 677 | braces: 3.0.3 678 | glob-parent: 5.1.2 679 | is-binary-path: 2.1.0 680 | is-glob: 4.0.3 681 | normalize-path: 3.0.0 682 | readdirp: 3.6.0 683 | optionalDependencies: 684 | fsevents: 2.3.3 685 | 686 | cookie@0.7.2: {} 687 | 688 | data-uri-to-buffer@2.0.2: {} 689 | 690 | date-fns@4.1.0: {} 691 | 692 | debug@4.3.7: 693 | dependencies: 694 | ms: 2.1.3 695 | 696 | defu@6.1.4: {} 697 | 698 | esbuild@0.17.19: 699 | optionalDependencies: 700 | '@esbuild/android-arm': 0.17.19 701 | '@esbuild/android-arm64': 0.17.19 702 | '@esbuild/android-x64': 0.17.19 703 | '@esbuild/darwin-arm64': 0.17.19 704 | '@esbuild/darwin-x64': 0.17.19 705 | '@esbuild/freebsd-arm64': 0.17.19 706 | '@esbuild/freebsd-x64': 0.17.19 707 | '@esbuild/linux-arm': 0.17.19 708 | '@esbuild/linux-arm64': 0.17.19 709 | '@esbuild/linux-ia32': 0.17.19 710 | '@esbuild/linux-loong64': 0.17.19 711 | '@esbuild/linux-mips64el': 0.17.19 712 | '@esbuild/linux-ppc64': 0.17.19 713 | '@esbuild/linux-riscv64': 0.17.19 714 | '@esbuild/linux-s390x': 0.17.19 715 | '@esbuild/linux-x64': 0.17.19 716 | '@esbuild/netbsd-x64': 0.17.19 717 | '@esbuild/openbsd-x64': 0.17.19 718 | '@esbuild/sunos-x64': 0.17.19 719 | '@esbuild/win32-arm64': 0.17.19 720 | '@esbuild/win32-ia32': 0.17.19 721 | '@esbuild/win32-x64': 0.17.19 722 | 723 | escape-string-regexp@4.0.0: {} 724 | 725 | estree-walker@0.6.1: {} 726 | 727 | exit-hook@2.2.1: {} 728 | 729 | fill-range@7.1.1: 730 | dependencies: 731 | to-regex-range: 5.0.1 732 | 733 | fsevents@2.3.3: 734 | optional: true 735 | 736 | function-bind@1.1.2: {} 737 | 738 | get-source@2.0.12: 739 | dependencies: 740 | data-uri-to-buffer: 2.0.2 741 | source-map: 0.6.1 742 | 743 | glob-parent@5.1.2: 744 | dependencies: 745 | is-glob: 4.0.3 746 | 747 | glob-to-regexp@0.4.1: {} 748 | 749 | hasown@2.0.2: 750 | dependencies: 751 | function-bind: 1.1.2 752 | 753 | hono@4.6.8: {} 754 | 755 | is-binary-path@2.1.0: 756 | dependencies: 757 | binary-extensions: 2.3.0 758 | 759 | is-core-module@2.15.1: 760 | dependencies: 761 | hasown: 2.0.2 762 | 763 | is-extglob@2.1.1: {} 764 | 765 | is-glob@4.0.3: 766 | dependencies: 767 | is-extglob: 2.1.1 768 | 769 | is-number@7.0.0: {} 770 | 771 | itty-time@1.0.6: {} 772 | 773 | magic-string@0.25.9: 774 | dependencies: 775 | sourcemap-codec: 1.4.8 776 | 777 | mime@3.0.0: {} 778 | 779 | miniflare@3.20241022.0: 780 | dependencies: 781 | '@cspotcode/source-map-support': 0.8.1 782 | acorn: 8.14.0 783 | acorn-walk: 8.3.4 784 | capnp-ts: 0.7.0 785 | exit-hook: 2.2.1 786 | glob-to-regexp: 0.4.1 787 | stoppable: 1.1.0 788 | undici: 5.28.4 789 | workerd: 1.20241022.0 790 | ws: 8.18.0 791 | youch: 3.3.4 792 | zod: 3.23.8 793 | transitivePeerDependencies: 794 | - bufferutil 795 | - supports-color 796 | - utf-8-validate 797 | 798 | ms@2.1.3: {} 799 | 800 | mustache@4.2.0: {} 801 | 802 | nanoid@3.3.7: {} 803 | 804 | node-forge@1.3.1: {} 805 | 806 | normalize-path@3.0.0: {} 807 | 808 | ohash@1.1.4: {} 809 | 810 | path-parse@1.0.7: {} 811 | 812 | path-to-regexp@6.3.0: {} 813 | 814 | pathe@1.1.2: {} 815 | 816 | picomatch@2.3.1: {} 817 | 818 | prettier@3.3.3: {} 819 | 820 | printable-characters@1.0.42: {} 821 | 822 | readdirp@3.6.0: 823 | dependencies: 824 | picomatch: 2.3.1 825 | 826 | resolve.exports@2.0.2: {} 827 | 828 | resolve@1.22.8: 829 | dependencies: 830 | is-core-module: 2.15.1 831 | path-parse: 1.0.7 832 | supports-preserve-symlinks-flag: 1.0.0 833 | 834 | rollup-plugin-inject@3.0.2: 835 | dependencies: 836 | estree-walker: 0.6.1 837 | magic-string: 0.25.9 838 | rollup-pluginutils: 2.8.2 839 | 840 | rollup-plugin-node-polyfills@0.2.1: 841 | dependencies: 842 | rollup-plugin-inject: 3.0.2 843 | 844 | rollup-pluginutils@2.8.2: 845 | dependencies: 846 | estree-walker: 0.6.1 847 | 848 | selfsigned@2.4.1: 849 | dependencies: 850 | '@types/node-forge': 1.3.11 851 | node-forge: 1.3.1 852 | 853 | source-map@0.6.1: {} 854 | 855 | sourcemap-codec@1.4.8: {} 856 | 857 | stacktracey@2.1.8: 858 | dependencies: 859 | as-table: 1.0.55 860 | get-source: 2.0.12 861 | 862 | stoppable@1.1.0: {} 863 | 864 | supports-preserve-symlinks-flag@1.0.0: {} 865 | 866 | to-regex-range@5.0.1: 867 | dependencies: 868 | is-number: 7.0.0 869 | 870 | tslib@2.8.1: {} 871 | 872 | ufo@1.5.4: {} 873 | 874 | undici-types@6.19.8: {} 875 | 876 | undici@5.28.4: 877 | dependencies: 878 | '@fastify/busboy': 2.1.1 879 | 880 | unenv-nightly@2.0.0-20241024-111401-d4156ac: 881 | dependencies: 882 | defu: 6.1.4 883 | ohash: 1.1.4 884 | pathe: 1.1.2 885 | ufo: 1.5.4 886 | 887 | workerd@1.20241022.0: 888 | optionalDependencies: 889 | '@cloudflare/workerd-darwin-64': 1.20241022.0 890 | '@cloudflare/workerd-darwin-arm64': 1.20241022.0 891 | '@cloudflare/workerd-linux-64': 1.20241022.0 892 | '@cloudflare/workerd-linux-arm64': 1.20241022.0 893 | '@cloudflare/workerd-windows-64': 1.20241022.0 894 | 895 | wrangler@3.84.1(@cloudflare/workers-types@4.20241022.0): 896 | dependencies: 897 | '@cloudflare/kv-asset-handler': 0.3.4 898 | '@cloudflare/workers-shared': 0.7.0 899 | '@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19) 900 | '@esbuild-plugins/node-modules-polyfill': 0.2.2(esbuild@0.17.19) 901 | blake3-wasm: 2.1.5 902 | chokidar: 3.6.0 903 | date-fns: 4.1.0 904 | esbuild: 0.17.19 905 | itty-time: 1.0.6 906 | miniflare: 3.20241022.0 907 | nanoid: 3.3.7 908 | path-to-regexp: 6.3.0 909 | resolve: 1.22.8 910 | resolve.exports: 2.0.2 911 | selfsigned: 2.4.1 912 | source-map: 0.6.1 913 | unenv: unenv-nightly@2.0.0-20241024-111401-d4156ac 914 | workerd: 1.20241022.0 915 | xxhash-wasm: 1.0.2 916 | optionalDependencies: 917 | '@cloudflare/workers-types': 4.20241022.0 918 | fsevents: 2.3.3 919 | transitivePeerDependencies: 920 | - bufferutil 921 | - supports-color 922 | - utf-8-validate 923 | 924 | ws@8.18.0: {} 925 | 926 | xxhash-wasm@1.0.2: {} 927 | 928 | youch@3.3.4: 929 | dependencies: 930 | cookie: 0.7.2 931 | mustache: 4.2.0 932 | stacktracey: 2.1.8 933 | 934 | zod@3.23.8: {} 935 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | singleQuote: true, 3 | semi: true, 4 | trailingComma: 'es5', 5 | }; -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { Hono } from 'hono'; 2 | import { appendReferrerTextToUrl } from './util'; 3 | 4 | type Bindings = { 5 | GO_URLS: KVNamespace; 6 | NOT_FOUND_REDIRECT_URL: string; 7 | REFERRER_TEXT: string; 8 | }; 9 | 10 | const app = new Hono<{ Bindings: Bindings }>(); 11 | 12 | app.get('/', (c) => 13 | c.redirect('https://github.com/AkashRajpurohit/time-to-go', 307) 14 | ); 15 | 16 | app.get('*', async (c) => { 17 | const incomingUrl = new URL(c.req.url); 18 | const existingSearchParams = incomingUrl.searchParams; 19 | 20 | // Get the URL pathname as input text minus the leading "/" 21 | const text = incomingUrl.pathname.slice(1); 22 | const { NOT_FOUND_REDIRECT_URL, REFERRER_TEXT } = c.env; 23 | const url = await c.env.GO_URLS.get(text); 24 | 25 | if (!url) { 26 | if (NOT_FOUND_REDIRECT_URL) { 27 | const redirectUrl = appendReferrerTextToUrl( 28 | NOT_FOUND_REDIRECT_URL, 29 | REFERRER_TEXT, 30 | existingSearchParams 31 | ); 32 | return c.redirect(redirectUrl); 33 | } 34 | 35 | // NOT_FOUND_REDIRECT_URL is not configured so just return 404 response 36 | return c.text('Not found', 404); 37 | } 38 | 39 | const urlWithRef = appendReferrerTextToUrl(url, REFERRER_TEXT, existingSearchParams); 40 | 41 | return c.redirect(urlWithRef, 307); 42 | }) 43 | 44 | export default app; 45 | -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | export const appendReferrerTextToUrl = ( 2 | url = '/', 3 | referrerText: string, 4 | existingSearchParams: URLSearchParams 5 | ) => { 6 | if (!referrerText) return url; 7 | 8 | const uri = new URL(url); 9 | uri.searchParams.append('ref', referrerText); 10 | 11 | // Append all existing search params to the redirected URL as well 12 | // Note: if existing URL had a ref property then that will override 13 | // the referrerText we set above 14 | for (const [key, value] of existingSearchParams.entries()) { 15 | if (key === 'ref') { 16 | uri.searchParams.delete('ref'); 17 | } 18 | 19 | uri.searchParams.append(key, value); 20 | } 21 | 22 | return uri.toString(); 23 | }; 24 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "node", 6 | "esModuleInterop": true, 7 | "strict": true, 8 | "lib": [ 9 | "esnext" 10 | ], 11 | "types": [ 12 | "@cloudflare/workers-types" 13 | ], 14 | "jsx": "react-jsx", 15 | "jsxFragmentFactory": "Fragment", 16 | "jsxImportSource": "hono/jsx" 17 | } 18 | } -------------------------------------------------------------------------------- /wrangler.toml: -------------------------------------------------------------------------------- 1 | name = "go-urls" 2 | main = "src/index.ts" 3 | compatibility_date = "2023-01-01" 4 | 5 | [[kv_namespaces]] 6 | binding = "GO_URLS" 7 | preview_id = "6ec3404005ee4537bcb35a7660c4f93c" 8 | id = "6ec3404005ee4537bcb35a7660c4f93c" 9 | 10 | [vars] 11 | NOT_FOUND_REDIRECT_URL = "https://akashrajpurohit.com/404/" 12 | REFERRER_TEXT = "go.akashrajpurohit.com" 13 | 14 | [observability] 15 | enabled = true 16 | head_sampling_rate = 1 17 | --------------------------------------------------------------------------------