use cloudflare r2

This commit is contained in:
EGOIST 2022-05-15 00:43:49 +08:00
parent 7c47af4a32
commit fd0c9f92ef
27 changed files with 1654 additions and 213 deletions

View File

@ -2,7 +2,7 @@
Follow the steps to run it locally.
1. Copy `.env.example` to `.env`
1. Copy `web/.env.example` to `web/.env`
2. Run `postgres` locally, the easiest way on mac is `brew install postgresql`, you can also use docker
3. Install dependencies: `pnpm i`
4. Initialize the database by running `pnpm prisma db push`

View File

@ -2,7 +2,7 @@
"private": true,
"name": "proselog-workspace",
"scripts": {
"dev": "pnpm --filter web dev",
"dev": "pnpm -r dev",
"db-generate": "pnpm --filter web db-generate"
}
}

View File

@ -5,6 +5,18 @@ importers:
.:
specifiers: {}
r2:
specifiers:
'@cloudflare/workers-types': ^3.10.0
'@proselog/jwt': ^0.1.1
typescript: ^4.6.4
wrangler: 2.0.5
devDependencies:
'@cloudflare/workers-types': 3.10.0
'@proselog/jwt': 0.1.1
typescript: 4.6.4
wrangler: 2.0.5
web:
specifiers:
'@aws-sdk/client-s3': ^3.81.0
@ -16,6 +28,7 @@ importers:
'@hapi/iron': ^6.0.0
'@headlessui/react': ^1.6.0
'@prisma/client': ^3.14.0
'@proselog/jwt': ^0.1.1
'@trpc/client': ^9.23.2
'@trpc/next': ^9.23.2
'@trpc/react': ^9.23.2
@ -76,6 +89,7 @@ importers:
'@hapi/iron': 6.0.0
'@headlessui/react': 1.6.1_ef5jwxihqo6n7gxfmzogljlgcm
'@prisma/client': 3.14.0_prisma@3.14.0
'@proselog/jwt': 0.1.1
'@trpc/client': 9.23.2_@trpc+server@9.23.2
'@trpc/next': 9.23.2_ekhln2aut74ytaacni4ejzffly
'@trpc/react': 9.23.2_ztktndqynogm35aelp247cafku
@ -1166,6 +1180,10 @@ packages:
to-fast-properties: 2.0.0
dev: false
/@cloudflare/workers-types/3.10.0:
resolution: {integrity: sha512-gn+H5Ps9yV1VYz8FJ08bMfXLW8ubNblRF9Z+m+0ctNMyl3CdoZmUfH1pMTxYE8SMUJbLxuNvpdlZhwLDoGFXaw==}
dev: true
/@codemirror/autocomplete/0.20.0:
resolution: {integrity: sha512-F6VOM8lImn5ApqxJcaWgdl7hhlw8B5yAfZJGlsQifcpNotkZOMND61mBFZ84OmSLWxtT8/smkSeLvJupKbjP9w==}
dependencies:
@ -1257,6 +1275,24 @@ packages:
w3c-keyname: 2.2.4
dev: false
/@esbuild-plugins/node-globals-polyfill/0.1.1_esbuild@0.14.34:
resolution: {integrity: sha512-MR0oAA+mlnJWrt1RQVQ+4VYuRJW/P2YmRTv1AsplObyvuBMnPHiizUF95HHYiSsMGLhyGtWufaq2XQg6+iurBg==}
peerDependencies:
esbuild: '*'
dependencies:
esbuild: 0.14.34
dev: true
/@esbuild-plugins/node-modules-polyfill/0.1.4_esbuild@0.14.34:
resolution: {integrity: sha512-uZbcXi0zbmKC/050p3gJnne5Qdzw8vkXIv+c2BW0Lsc1ji1SkrxbKPUy5Efr0blbTu1SL8w4eyfpnSdPg3G0Qg==}
peerDependencies:
esbuild: '*'
dependencies:
esbuild: 0.14.34
escape-string-regexp: 4.0.0
rollup-plugin-node-polyfills: 0.2.1
dev: true
/@eslint/eslintrc/1.2.3:
resolution: {integrity: sha512-uGo44hIwoLGNyduRpjdEpovcbMdd+Nv7amtmJxnKmI8xj6yd5LncmSwDa5NgX/41lIFJtkjD6YdVfgEzPfJ5UA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -1337,6 +1373,10 @@ packages:
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
dev: true
/@iarna/toml/2.2.5:
resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
dev: true
/@jridgewell/gen-mapping/0.1.1:
resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==}
engines: {node: '>=6.0.0'}
@ -1398,6 +1438,150 @@ packages:
'@lezer/highlight': 0.16.0
dev: false
/@miniflare/cache/2.4.0:
resolution: {integrity: sha512-tMDXlUVlThgFubJmlxZoKmLK8kBxDmuMbVMt7csHpXegzkuo2TmIsDqBE/C3CRiJ5xeCQgpD6iZtKBu5Zn5fRA==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/core': 2.4.0
'@miniflare/shared': 2.4.0
http-cache-semantics: 4.1.0
undici: 4.13.0
dev: true
/@miniflare/cli-parser/2.4.0:
resolution: {integrity: sha512-Xr5lO8f+oIr9r/b2dfo0on1p0MNN+pkwRHWoY5ACSnp9FaGnwm/g71DM7AajIQPIk0TpRsSVNDx8Ygj1LPT+sQ==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/shared': 2.4.0
kleur: 4.1.4
dev: true
/@miniflare/core/2.4.0:
resolution: {integrity: sha512-vYl8xaWTFzxtkbzx3IkT4Py0OAFdfmFnVo627O1HKHWVGlkjVr8UKtxBpIR+f5pq/HCMzzqA1HM9FXO0dQfy3A==}
engines: {node: '>=16.7'}
dependencies:
'@iarna/toml': 2.2.5
'@miniflare/shared': 2.4.0
'@miniflare/watcher': 2.4.0
busboy: 0.3.1
dotenv: 10.0.0
kleur: 4.1.4
set-cookie-parser: 2.4.8
undici: 4.13.0
dev: true
/@miniflare/durable-objects/2.4.0:
resolution: {integrity: sha512-VVLaUXXcAQcYE/3YmDLTacZf5OzR8bib6q1T9NqVb0uK5sLMQqyHvQdsG5rMqs7iyxfJxyZ0bL2OW9XGALOkoQ==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/core': 2.4.0
'@miniflare/shared': 2.4.0
'@miniflare/storage-memory': 2.4.0
undici: 4.13.0
dev: true
/@miniflare/html-rewriter/2.4.0:
resolution: {integrity: sha512-ZG8819N7LelDD+8+Ss5FZpVyQQq/V2igod0qE68JK4he/w4/yn57Rk6Efb49y15HoHAXl2RpCCsnCyIow/Xjug==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/core': 2.4.0
'@miniflare/shared': 2.4.0
html-rewriter-wasm: 0.4.1
undici: 4.13.0
dev: true
/@miniflare/http-server/2.4.0:
resolution: {integrity: sha512-r6Z/nqxE0oa1z63L95yvnG0PUeLRxZOeGS7ADxZMFKan4WD5lvYtSKDuDEm0lkbQshCOHQ3uXFr0cotOm8JoMQ==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/core': 2.4.0
'@miniflare/shared': 2.4.0
'@miniflare/web-sockets': 2.4.0
kleur: 4.1.4
selfsigned: 2.0.1
undici: 4.13.0
ws: 8.6.0
youch: 2.2.2
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: true
/@miniflare/kv/2.4.0:
resolution: {integrity: sha512-1UW7f1386xR6EDEXNZOR1TpFwQfRRSxUPqD6m/U0WprlsbM0cIYGz+AUeaVbkFf8lfE2MeXCUrjbWsLOvsnw3g==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/shared': 2.4.0
dev: true
/@miniflare/runner-vm/2.4.0:
resolution: {integrity: sha512-7sdwBYzXQTwYeR3tTvQ+vJfzc7BXwqR8AUPK9l5gvCtg+Geq9sMslr5SikIJpgcvbYqKDjvC9DQEPJ3sqr9cSQ==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/shared': 2.4.0
dev: true
/@miniflare/scheduler/2.4.0:
resolution: {integrity: sha512-dfMCXoAS8Y+3xABNxYju62I2xIBS54Op7ohCHoatvAM5RvualJUPICEMPZzX6/z29q5xPIeSLhLDhl/asAQ19w==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/core': 2.4.0
'@miniflare/shared': 2.4.0
cron-schedule: 3.0.6
dev: true
/@miniflare/shared/2.4.0:
resolution: {integrity: sha512-lPQFzBUVGNQ93gQ/dliToWnO0OqAgsD3/902Pd/IixVSRwRj3BTnYv2dHMUKZcODBPrhnbqZeqcPWdBLzEx8uw==}
engines: {node: '>=16.7'}
dependencies:
ignore: 5.2.0
kleur: 4.1.4
dev: true
/@miniflare/sites/2.4.0:
resolution: {integrity: sha512-YZy/TujnR1lkBvCncDDQ8tsWsXRE4JJ4x9a0bKN/XnZh7r6OhDM0sw4BFcBQhT6Ukdtttam1O3FlJxnMitrDGg==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/kv': 2.4.0
'@miniflare/shared': 2.4.0
'@miniflare/storage-file': 2.4.0
dev: true
/@miniflare/storage-file/2.4.0:
resolution: {integrity: sha512-f1AUMz8xps/4VhNJMb8JeCevZFeU4pg2lIWmC11gG4xeq2nibTPBi6Qtx594Le7ZKij/tF6rRsoNfGau2Q5gdw==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/shared': 2.4.0
'@miniflare/storage-memory': 2.4.0
dev: true
/@miniflare/storage-memory/2.4.0:
resolution: {integrity: sha512-mhWwgHhDNtEa7y1bYbdVucV0lqUmzagYXUSppAdSGS5JPyJMyw3HseqRNTk6gC/vKlvEYlFf3ugWcREGCedr9A==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/shared': 2.4.0
dev: true
/@miniflare/watcher/2.4.0:
resolution: {integrity: sha512-gDQRUxwOjmctvowyd4Hcdy3fjxz3ERKzirp6TvA3AWUohKZk3IhwGlaA8aCwbdP+ELYQlG5wK44AfLSGi956fg==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/shared': 2.4.0
dev: true
/@miniflare/web-sockets/2.4.0:
resolution: {integrity: sha512-cz/cN0GoQOXRLh80UmlcEJODPIw2ijKBK3PLRzvfTzqQ5avK6wp2M8Fj8C/5JIT6g7siwvBANyKXD3U3RpKGHQ==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/core': 2.4.0
'@miniflare/shared': 2.4.0
undici: 4.13.0
ws: 8.6.0
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: true
/@next/env/12.1.6:
resolution: {integrity: sha512-Te/OBDXFSodPU6jlXYPAXpmZr/AkG6DCATAxttQxqOWaq6eDFX25Db3dK0120GZrSZmv4QCe9KsZmJKDbWs4OA==}
dev: false
@ -1537,6 +1721,9 @@ packages:
fastq: 1.13.0
dev: true
/@panva/hkdf/1.0.2:
resolution: {integrity: sha512-MSAs9t3Go7GUkMhpKC44T58DJ5KGk2vBo+h1cqQeqlMfdGkxaVB78ZWpv9gYi/g2fa4sopag9gJsNvS8XGgWJA==}
/@prisma/client/3.14.0_prisma@3.14.0:
resolution: {integrity: sha512-atb41UpgTR1MCst0VIbiHTMw8lmXnwUvE1KyUCAkq08+wJyjRE78Due+nSf+7uwqQn+fBFYVmoojtinhlLOSaA==}
engines: {node: '>=12.6'}
@ -1560,6 +1747,13 @@ packages:
requiresBuild: true
dev: true
/@proselog/jwt/0.1.1:
resolution: {integrity: sha512-bmAHf70G5b29FDF8G14twg109DgN3Eu3jbd5+6FSdFEeWK8afs+X3zCNiePeNolPUfJuMiepxfTgWaFlBs1L1Q==}
dependencies:
'@panva/hkdf': 1.0.2
jose: 4.8.1
nanoid: 3.3.4
/@rushstack/eslint-patch/1.1.3:
resolution: {integrity: sha512-WiBSI6JBIhC6LRIsB2Kwh8DsGTlbBU+mLRxJmAe3LjHTdkDpwIbEOZgoXBbZilk/vlfjK8i6nKRAvIRn1XaIMw==}
dev: true
@ -1701,6 +1895,10 @@ packages:
resolution: {integrity: sha512-C3064MH72iEfeGCYEGCt7FCxXoAXaMPG0QPnstcxvPmbl54erpISu06d++FY37Smja64iWy5L8wOyHHBghWbJQ==}
dev: true
/@types/stack-trace/0.0.29:
resolution: {integrity: sha512-TgfOX+mGY/NyNxJLIbDWrO9DjGoVSW9+aB8H2yy1fy32jsvxijhmyJI9fDFgvz3YP4lvJaq9DzdR/M1bOgVc9g==}
dev: true
/@types/ua-parser-js/0.7.36:
resolution: {integrity: sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ==}
dev: true
@ -1988,6 +2186,10 @@ packages:
engines: {node: '>=8'}
dev: true
/blake3-wasm/2.1.5:
resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==}
dev: true
/bluebird/3.7.2:
resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
dev: false
@ -2034,12 +2236,15 @@ packages:
picocolors: 1.0.0
dev: false
/buffer-from/1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
dev: true
/busboy/0.3.1:
resolution: {integrity: sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==}
engines: {node: '>=4.5.0'}
dependencies:
dicer: 0.3.0
dev: false
/busboy/1.6.0:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
@ -2149,6 +2354,11 @@ packages:
/concat-map/0.0.1:
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
/cookie/0.4.2:
resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==}
engines: {node: '>= 0.6'}
dev: true
/cookie/0.5.0:
resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
engines: {node: '>= 0.6'}
@ -2170,6 +2380,10 @@ packages:
resolution: {integrity: sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==}
dev: false
/cron-schedule/3.0.6:
resolution: {integrity: sha512-izfGgKyzzIyLaeb1EtZ3KbglkS6AKp9cv7LxmiyoOu+fXfol1tQDC0Cof0enVZGNtudTHW+3lfuW9ZkLQss4Wg==}
dev: true
/cross-spawn/7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
@ -2274,7 +2488,6 @@ packages:
engines: {node: '>=4.5.0'}
dependencies:
streamsearch: 0.1.2
dev: false
/didyoumean/1.2.2:
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
@ -2305,6 +2518,11 @@ packages:
esutils: 2.0.3
dev: true
/dotenv/10.0.0:
resolution: {integrity: sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==}
engines: {node: '>=10'}
dev: true
/dotenv/16.0.0:
resolution: {integrity: sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==}
engines: {node: '>=12'}
@ -2369,6 +2587,214 @@ packages:
is-date-object: 1.0.5
is-symbol: 1.0.4
/esbuild-android-64/0.14.34:
resolution: {integrity: sha512-XfxcfJqmMYsT/LXqrptzFxmaR3GWzXHDLdFNIhm6S00zPaQF1TBBWm+9t0RZ6LRR7iwH57DPjaOeW20vMqI4Yw==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
requiresBuild: true
dev: true
optional: true
/esbuild-android-arm64/0.14.34:
resolution: {integrity: sha512-T02+NXTmSRL1Mc6puz+R9CB54rSPICkXKq6+tw8B6vxZFnCPzbJxgwIX4kcluz9p8nYBjF3+lSilTGWb7+Xgew==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: true
optional: true
/esbuild-darwin-64/0.14.34:
resolution: {integrity: sha512-pLRip2Bh4Ng7Bf6AMgCrSp3pPe/qZyf11h5Qo2mOfJqLWzSVjxrXW+CFRJfrOVP7TCnh/gmZSM2AFdCPB72vtw==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/esbuild-darwin-arm64/0.14.34:
resolution: {integrity: sha512-vpidSJEBxx6lf1NWgXC+DCmGqesJuZ5Y8aQVVsaoO4i8tRXbXb0whChRvop/zd3nfNM4dIl5EXAky0knRX5I6w==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/esbuild-freebsd-64/0.14.34:
resolution: {integrity: sha512-m0HBjePhe0hAQJgtMRMNV9kMgIyV4/qSnzPx42kRMQBcPhgjAq1JRu4Il26czC+9FgpMbFkUktb07f/Lwnc6CA==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/esbuild-freebsd-arm64/0.14.34:
resolution: {integrity: sha512-cpRc2B94L1KvMPPYB4D6G39jLqpKlD3noAMY4/e86iXXXkhUYJJEtTuyNFTa9JRpWM0xCAp4mxjHjoIiLuoCLA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-32/0.14.34:
resolution: {integrity: sha512-8nQaEaoW7MH/K/RlozJa+lE1ejHIr8fuPIHhc513UebRav7HtXgQvxHQ6VZRUkWtep23M6dd7UqhwO1tMOfzQQ==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-64/0.14.34:
resolution: {integrity: sha512-Y3of4qQoLLlAgf042MlrY1P+7PnN9zWj8nVtw9XQG5hcLOZLz7IKpU35oeu7n4wvyaZHwvQqDJ93gRLqdJekcQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-arm/0.14.34:
resolution: {integrity: sha512-9lpq1NcJqssAF7alCO6zL3gvBVVt/lKw4oetUM7OgNnRX0OWpB+ZIO9FwCrSj/dMdmgDhPLf+119zB8QxSMmAg==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-arm64/0.14.34:
resolution: {integrity: sha512-IlWaGtj9ir7+Nrume1DGcyzBDlK8GcnJq0ANKwcI9pVw8tqr+6GD0eqyF9SF1mR8UmAp+odrx1H5NdR2cHdFHA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-mips64le/0.14.34:
resolution: {integrity: sha512-k3or+01Rska1AjUyNjA4buEwB51eyN/xPQAoOx1CjzAQC3l8rpjUDw55kXyL63O/1MUi4ISvtNtl8gLwdyEcxw==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-ppc64le/0.14.34:
resolution: {integrity: sha512-+qxb8M9FfM2CJaVU7GgYpJOHM1ngQOx+/VrtBjb4C8oVqaPcESCeg2anjl+HRZy8VpYc71q/iBYausPPbJ+Keg==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-riscv64/0.14.34:
resolution: {integrity: sha512-Y717ltBdQ5j5sZIHdy1DV9kieo0wMip0dCmVSTceowCPYSn1Cg33Kd6981+F/3b9FDMzNWldZFOBRILViENZSA==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-s390x/0.14.34:
resolution: {integrity: sha512-bDDgYO4LhL4+zPs+WcBkXph+AQoPcQRTv18FzZS0WhjfH8TZx2QqlVPGhmhZ6WidrY+jKthUqO6UhGyIb4MpmA==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-netbsd-64/0.14.34:
resolution: {integrity: sha512-cfaFGXdRt0+vHsjNPyF0POM4BVSHPSbhLPe8mppDc7GDDxjIl08mV1Zou14oDWMp/XZMjYN1kWYRSfftiD0vvQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
requiresBuild: true
dev: true
optional: true
/esbuild-openbsd-64/0.14.34:
resolution: {integrity: sha512-vmy9DxXVnRiI14s8GKuYBtess+EVcDALkbpTqd5jw4XITutIzyB7n4x0Tj5utAkKsgZJB22lLWGekr0ABnSLow==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
requiresBuild: true
dev: true
optional: true
/esbuild-sunos-64/0.14.34:
resolution: {integrity: sha512-eNPVatNET1F7tRMhii7goL/eptfxc0ALRjrj9SPFNqp0zmxrehBFD6BaP3R4LjMn6DbMO0jOAnTLFKr8NqcJAA==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
requiresBuild: true
dev: true
optional: true
/esbuild-windows-32/0.14.34:
resolution: {integrity: sha512-EFhpXyHEcnqWYe2rAHFd8dRw8wkrd9U+9oqcyoEL84GbanAYjiiIjBZsnR8kl0sCQ5w6bLpk7vCEIA2VS32Vcg==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
/esbuild-windows-64/0.14.34:
resolution: {integrity: sha512-a8fbl8Ky7PxNEjf1aJmtxdDZj32/hC7S1OcA2ckEpCJRTjiKslI9vAdPpSjrKIWhws4Galpaawy0nB7fjHYf5Q==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/esbuild-windows-arm64/0.14.34:
resolution: {integrity: sha512-EYvmKbSa2B3sPnpC28UEu9jBK5atGV4BaVRE7CYGUci2Hlz4AvtV/LML+TcDMT6gBgibnN2gcltWclab3UutMg==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/esbuild/0.14.34:
resolution: {integrity: sha512-QIWdPT/gFF6hCaf4m7kP0cJ+JIuFkdHibI7vVFvu3eJS1HpVmYHWDulyN5WXwbRA0SX/7ZDaJ/1DH8SdY9xOJg==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
esbuild-android-64: 0.14.34
esbuild-android-arm64: 0.14.34
esbuild-darwin-64: 0.14.34
esbuild-darwin-arm64: 0.14.34
esbuild-freebsd-64: 0.14.34
esbuild-freebsd-arm64: 0.14.34
esbuild-linux-32: 0.14.34
esbuild-linux-64: 0.14.34
esbuild-linux-arm: 0.14.34
esbuild-linux-arm64: 0.14.34
esbuild-linux-mips64le: 0.14.34
esbuild-linux-ppc64le: 0.14.34
esbuild-linux-riscv64: 0.14.34
esbuild-linux-s390x: 0.14.34
esbuild-netbsd-64: 0.14.34
esbuild-openbsd-64: 0.14.34
esbuild-sunos-64: 0.14.34
esbuild-windows-32: 0.14.34
esbuild-windows-64: 0.14.34
esbuild-windows-arm64: 0.14.34
dev: true
/escalade/3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
engines: {node: '>=6'}
@ -2649,6 +3075,10 @@ packages:
engines: {node: '>=4.0'}
dev: true
/estree-walker/0.6.1:
resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==}
dev: true
/esutils/2.0.3:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
@ -2895,6 +3325,14 @@ packages:
dependencies:
function-bind: 1.1.1
/html-rewriter-wasm/0.4.1:
resolution: {integrity: sha512-lNovG8CMCCmcVB1Q7xggMSf7tqPCijZXaH4gL6iE8BFghdQCbaY5Met9i1x2Ex8m/cZHDUtXK9H6/znKamRP8Q==}
dev: true
/http-cache-semantics/4.1.0:
resolution: {integrity: sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==}
dev: true
/ignore/5.2.0:
resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==}
engines: {node: '>= 4'}
@ -3062,6 +3500,9 @@ packages:
engines: {node: '>=0.10.0'}
dev: false
/jose/4.8.1:
resolution: {integrity: sha512-+/hpTbRcCw9YC0TOfN1W47pej4a9lRmltdOVdRLz5FP5UvUq3CenhXjQK7u/8NdMIIShMXYAh9VLPhc7TjhvFw==}
/js-sha3/0.8.0:
resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==}
dev: false
@ -3110,6 +3551,11 @@ packages:
engines: {node: '>=0.10.0'}
dev: false
/kleur/4.1.4:
resolution: {integrity: sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==}
engines: {node: '>=6'}
dev: true
/ky-universal/0.8.2_pkdcfzdjosae4cy3uef4ugd56u:
resolution: {integrity: sha512-xe0JaOH9QeYxdyGLnzUOVGK4Z6FGvDVzcXFTdrYA1f33MZdEa45sUDaMBy98xQMcsd2XIBrTXRrRYnegcSdgVQ==}
engines: {node: '>=10.17'}
@ -3191,6 +3637,12 @@ packages:
yallist: 4.0.0
dev: true
/magic-string/0.25.9:
resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
dependencies:
sourcemap-codec: 1.4.8
dev: true
/mailgun.js/5.2.2:
resolution: {integrity: sha512-stnq7qJSwxpbHZFHoxw+IBRMm1A+pEwxCGdRZlyujdjIy7wENX+6XHbA8syfuSaWg/gklSGUBa3IMtfzxQ8ZwQ==}
dependencies:
@ -3256,6 +3708,45 @@ packages:
mime-db: 1.52.0
dev: false
/miniflare/2.4.0:
resolution: {integrity: sha512-xOBL/dQsUL95rxIYO+KrrVPPpm2TAf6TKl4AvhcjSfUeVkzDWd/y9f7hXCt8x6srDoK0Z2LpYouatvSfSUzGOw==}
engines: {node: '>=16.7'}
hasBin: true
peerDependencies:
'@miniflare/storage-redis': 2.4.0
cron-schedule: ^3.0.4
ioredis: ^4.27.9
peerDependenciesMeta:
'@miniflare/storage-redis':
optional: true
cron-schedule:
optional: true
ioredis:
optional: true
dependencies:
'@miniflare/cache': 2.4.0
'@miniflare/cli-parser': 2.4.0
'@miniflare/core': 2.4.0
'@miniflare/durable-objects': 2.4.0
'@miniflare/html-rewriter': 2.4.0
'@miniflare/http-server': 2.4.0
'@miniflare/kv': 2.4.0
'@miniflare/runner-vm': 2.4.0
'@miniflare/scheduler': 2.4.0
'@miniflare/shared': 2.4.0
'@miniflare/sites': 2.4.0
'@miniflare/storage-file': 2.4.0
'@miniflare/storage-memory': 2.4.0
'@miniflare/web-sockets': 2.4.0
kleur: 4.1.4
semiver: 1.1.0
source-map-support: 0.5.21
undici: 4.13.0
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: true
/minimatch/3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies:
@ -3279,6 +3770,11 @@ packages:
object-assign: 4.1.1
dev: false
/mustache/4.2.0:
resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
hasBin: true
dev: true
/nano-time/1.0.0:
resolution: {integrity: sha1-sFVPaa2J4i0JB/ehKwmTpdlhN+8=}
dependencies:
@ -3346,6 +3842,11 @@ packages:
- domexception
dev: false
/node-forge/1.3.1:
resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==}
engines: {node: '>= 6.13.0'}
dev: true
/node-releases/2.0.4:
resolution: {integrity: sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==}
dev: false
@ -3478,6 +3979,10 @@ packages:
/path-parse/1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
/path-to-regexp/6.2.1:
resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==}
dev: true
/path-type/4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
@ -3789,6 +4294,27 @@ packages:
dependencies:
glob: 7.2.0
/rollup-plugin-inject/3.0.2:
resolution: {integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==}
deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.
dependencies:
estree-walker: 0.6.1
magic-string: 0.25.9
rollup-pluginutils: 2.8.2
dev: true
/rollup-plugin-node-polyfills/0.2.1:
resolution: {integrity: sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==}
dependencies:
rollup-plugin-inject: 3.0.2
dev: true
/rollup-pluginutils/2.8.2:
resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==}
dependencies:
estree-walker: 0.6.1
dev: true
/run-parallel/1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
@ -3805,6 +4331,18 @@ packages:
loose-envify: 1.4.0
dev: false
/selfsigned/2.0.1:
resolution: {integrity: sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ==}
engines: {node: '>=10'}
dependencies:
node-forge: 1.3.1
dev: true
/semiver/1.1.0:
resolution: {integrity: sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==}
engines: {node: '>=6'}
dev: true
/semver/6.3.0:
resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
hasBin: true
@ -3822,6 +4360,10 @@ packages:
lru-cache: 6.0.0
dev: true
/set-cookie-parser/2.4.8:
resolution: {integrity: sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg==}
dev: true
/shallow-clone/3.0.1:
resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==}
engines: {node: '>=8'}
@ -3861,10 +4403,29 @@ packages:
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
engines: {node: '>=0.10.0'}
/source-map-support/0.5.21:
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
dependencies:
buffer-from: 1.1.2
source-map: 0.6.1
dev: true
/source-map/0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
dev: true
/sourcemap-codec/1.4.8:
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
dev: true
/stack-trace/0.0.10:
resolution: {integrity: sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=}
dev: true
/streamsearch/0.1.2:
resolution: {integrity: sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=}
engines: {node: '>=0.8.0'}
dev: false
/streamsearch/1.1.0:
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
@ -4063,6 +4624,11 @@ packages:
has-symbols: 1.0.3
which-boxed-primitive: 1.0.2
/undici/4.13.0:
resolution: {integrity: sha512-8lk8S/f2V0VUNGf2scU2b+KI2JSzEQLdCyRNRF3XmHu+5jectlSDaPSBCXAHFaUlt1rzngzOBVDgJS9/Gue/KA==}
engines: {node: '>=12.18'}
dev: true
/unload/2.2.0:
resolution: {integrity: sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==}
dependencies:
@ -4179,14 +4745,56 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/wrangler/2.0.5:
resolution: {integrity: sha512-0BVKQDGm9whPrzLPACGJ9CGdk/taKYYIEvnjLSVOBOxa8her6R9VcmGP6U0wXQnvMasQqlmj+NnjNWgfRw8nIQ==}
engines: {node: '>=16.7.0'}
hasBin: true
dependencies:
'@esbuild-plugins/node-globals-polyfill': 0.1.1_esbuild@0.14.34
'@esbuild-plugins/node-modules-polyfill': 0.1.4_esbuild@0.14.34
blake3-wasm: 2.1.5
esbuild: 0.14.34
miniflare: 2.4.0
nanoid: 3.3.4
path-to-regexp: 6.2.1
selfsigned: 2.0.1
semiver: 1.1.0
xxhash-wasm: 1.0.1
optionalDependencies:
fsevents: 2.3.2
transitivePeerDependencies:
- '@miniflare/storage-redis'
- bufferutil
- cron-schedule
- ioredis
- utf-8-validate
dev: true
/wrappy/1.0.2:
resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=}
/ws/8.6.0:
resolution: {integrity: sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: ^5.0.2
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
dev: true
/xtend/4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
dev: true
/xxhash-wasm/1.0.1:
resolution: {integrity: sha512-Lc9CTvDrH2vRoiaUzz25q7lRaviMhz90pkx6YxR9EPYtF99yOJnv2cB+CQ0hp/TLoqrUsk8z/W2EN31T568Azw==}
dev: true
/yallist/4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
dev: true
@ -4196,6 +4804,15 @@ packages:
engines: {node: '>= 6'}
dev: true
/youch/2.2.2:
resolution: {integrity: sha512-/FaCeG3GkuJwaMR34GHVg0l8jCbafZLHiFowSjqLlqhC6OMyf2tPJBu8UirF7/NI9X/R5ai4QfEKUCOxMAGxZQ==}
dependencies:
'@types/stack-trace': 0.0.29
cookie: 0.4.2
mustache: 4.2.0
stack-trace: 0.0.10
dev: true
/zod/3.15.1:
resolution: {integrity: sha512-WAdjcoOxa4S9oc/u7fTbC3CC7uVqptLLU0LKqS8RDBOrCXp2t5avM8BUfgNVZJymGWAx6SEUYxWPPoYuQ5rgwQ==}
dev: false

View File

@ -1,2 +1,3 @@
packages:
- web
- web
- r2

15
r2/README.md Normal file
View File

@ -0,0 +1,15 @@
A cloudflare worker based REST API for your R2 bucket.
Usage:
- Change the `bucket_name` and `preview_bucket_name` in `wrangler.toml` if you want.
- Set `API_TOKEN` in the worker secrets using Wrangler CLI.
Endpoints:
- GET `/:key`: Public access
- POST `/`: Require `authorization: Bearer TOKEN` header, where `TOKEN` should match `API_TOKEN` from your worker secrets. The request content type should be `multipart/form-data` with following fields:
- `prefix`: optional prefix for the key, see blow
- `file`: `File` file to upload
The object key is generated from `prefix` + `uuid()` + `file.extension`

16
r2/package.json Normal file
View File

@ -0,0 +1,16 @@
{
"name": "r2",
"version": "0.0.0",
"devDependencies": {
"@cloudflare/workers-types": "^3.10.0",
"typescript": "^4.6.4",
"wrangler": "2.0.5",
"@proselog/jwt": "^0.1.1"
},
"private": true,
"scripts": {
"dev": "wrangler dev --env development",
"deploy": "wrangler publish"
},
"license": "MIT"
}

655
r2/pnpm-lock.yaml Normal file
View File

@ -0,0 +1,655 @@
lockfileVersion: 5.4
specifiers:
'@cloudflare/workers-types': ^3.10.0
typescript: ^4.6.4
wrangler: 2.0.5
devDependencies:
'@cloudflare/workers-types': 3.10.0
typescript: 4.6.4
wrangler: 2.0.5
packages:
/@cloudflare/workers-types/3.10.0:
resolution: {integrity: sha512-gn+H5Ps9yV1VYz8FJ08bMfXLW8ubNblRF9Z+m+0ctNMyl3CdoZmUfH1pMTxYE8SMUJbLxuNvpdlZhwLDoGFXaw==}
dev: true
/@esbuild-plugins/node-globals-polyfill/0.1.1_esbuild@0.14.34:
resolution: {integrity: sha512-MR0oAA+mlnJWrt1RQVQ+4VYuRJW/P2YmRTv1AsplObyvuBMnPHiizUF95HHYiSsMGLhyGtWufaq2XQg6+iurBg==}
peerDependencies:
esbuild: '*'
dependencies:
esbuild: 0.14.34
dev: true
/@esbuild-plugins/node-modules-polyfill/0.1.4_esbuild@0.14.34:
resolution: {integrity: sha512-uZbcXi0zbmKC/050p3gJnne5Qdzw8vkXIv+c2BW0Lsc1ji1SkrxbKPUy5Efr0blbTu1SL8w4eyfpnSdPg3G0Qg==}
peerDependencies:
esbuild: '*'
dependencies:
esbuild: 0.14.34
escape-string-regexp: 4.0.0
rollup-plugin-node-polyfills: 0.2.1
dev: true
/@iarna/toml/2.2.5:
resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
dev: true
/@miniflare/cache/2.4.0:
resolution: {integrity: sha512-tMDXlUVlThgFubJmlxZoKmLK8kBxDmuMbVMt7csHpXegzkuo2TmIsDqBE/C3CRiJ5xeCQgpD6iZtKBu5Zn5fRA==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/core': 2.4.0
'@miniflare/shared': 2.4.0
http-cache-semantics: 4.1.0
undici: 4.13.0
dev: true
/@miniflare/cli-parser/2.4.0:
resolution: {integrity: sha512-Xr5lO8f+oIr9r/b2dfo0on1p0MNN+pkwRHWoY5ACSnp9FaGnwm/g71DM7AajIQPIk0TpRsSVNDx8Ygj1LPT+sQ==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/shared': 2.4.0
kleur: 4.1.4
dev: true
/@miniflare/core/2.4.0:
resolution: {integrity: sha512-vYl8xaWTFzxtkbzx3IkT4Py0OAFdfmFnVo627O1HKHWVGlkjVr8UKtxBpIR+f5pq/HCMzzqA1HM9FXO0dQfy3A==}
engines: {node: '>=16.7'}
dependencies:
'@iarna/toml': 2.2.5
'@miniflare/shared': 2.4.0
'@miniflare/watcher': 2.4.0
busboy: 0.3.1
dotenv: 10.0.0
kleur: 4.1.4
set-cookie-parser: 2.4.8
undici: 4.13.0
dev: true
/@miniflare/durable-objects/2.4.0:
resolution: {integrity: sha512-VVLaUXXcAQcYE/3YmDLTacZf5OzR8bib6q1T9NqVb0uK5sLMQqyHvQdsG5rMqs7iyxfJxyZ0bL2OW9XGALOkoQ==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/core': 2.4.0
'@miniflare/shared': 2.4.0
'@miniflare/storage-memory': 2.4.0
undici: 4.13.0
dev: true
/@miniflare/html-rewriter/2.4.0:
resolution: {integrity: sha512-ZG8819N7LelDD+8+Ss5FZpVyQQq/V2igod0qE68JK4he/w4/yn57Rk6Efb49y15HoHAXl2RpCCsnCyIow/Xjug==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/core': 2.4.0
'@miniflare/shared': 2.4.0
html-rewriter-wasm: 0.4.1
undici: 4.13.0
dev: true
/@miniflare/http-server/2.4.0:
resolution: {integrity: sha512-r6Z/nqxE0oa1z63L95yvnG0PUeLRxZOeGS7ADxZMFKan4WD5lvYtSKDuDEm0lkbQshCOHQ3uXFr0cotOm8JoMQ==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/core': 2.4.0
'@miniflare/shared': 2.4.0
'@miniflare/web-sockets': 2.4.0
kleur: 4.1.4
selfsigned: 2.0.1
undici: 4.13.0
ws: 8.6.0
youch: 2.2.2
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: true
/@miniflare/kv/2.4.0:
resolution: {integrity: sha512-1UW7f1386xR6EDEXNZOR1TpFwQfRRSxUPqD6m/U0WprlsbM0cIYGz+AUeaVbkFf8lfE2MeXCUrjbWsLOvsnw3g==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/shared': 2.4.0
dev: true
/@miniflare/runner-vm/2.4.0:
resolution: {integrity: sha512-7sdwBYzXQTwYeR3tTvQ+vJfzc7BXwqR8AUPK9l5gvCtg+Geq9sMslr5SikIJpgcvbYqKDjvC9DQEPJ3sqr9cSQ==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/shared': 2.4.0
dev: true
/@miniflare/scheduler/2.4.0:
resolution: {integrity: sha512-dfMCXoAS8Y+3xABNxYju62I2xIBS54Op7ohCHoatvAM5RvualJUPICEMPZzX6/z29q5xPIeSLhLDhl/asAQ19w==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/core': 2.4.0
'@miniflare/shared': 2.4.0
cron-schedule: 3.0.6
dev: true
/@miniflare/shared/2.4.0:
resolution: {integrity: sha512-lPQFzBUVGNQ93gQ/dliToWnO0OqAgsD3/902Pd/IixVSRwRj3BTnYv2dHMUKZcODBPrhnbqZeqcPWdBLzEx8uw==}
engines: {node: '>=16.7'}
dependencies:
ignore: 5.2.0
kleur: 4.1.4
dev: true
/@miniflare/sites/2.4.0:
resolution: {integrity: sha512-YZy/TujnR1lkBvCncDDQ8tsWsXRE4JJ4x9a0bKN/XnZh7r6OhDM0sw4BFcBQhT6Ukdtttam1O3FlJxnMitrDGg==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/kv': 2.4.0
'@miniflare/shared': 2.4.0
'@miniflare/storage-file': 2.4.0
dev: true
/@miniflare/storage-file/2.4.0:
resolution: {integrity: sha512-f1AUMz8xps/4VhNJMb8JeCevZFeU4pg2lIWmC11gG4xeq2nibTPBi6Qtx594Le7ZKij/tF6rRsoNfGau2Q5gdw==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/shared': 2.4.0
'@miniflare/storage-memory': 2.4.0
dev: true
/@miniflare/storage-memory/2.4.0:
resolution: {integrity: sha512-mhWwgHhDNtEa7y1bYbdVucV0lqUmzagYXUSppAdSGS5JPyJMyw3HseqRNTk6gC/vKlvEYlFf3ugWcREGCedr9A==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/shared': 2.4.0
dev: true
/@miniflare/watcher/2.4.0:
resolution: {integrity: sha512-gDQRUxwOjmctvowyd4Hcdy3fjxz3ERKzirp6TvA3AWUohKZk3IhwGlaA8aCwbdP+ELYQlG5wK44AfLSGi956fg==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/shared': 2.4.0
dev: true
/@miniflare/web-sockets/2.4.0:
resolution: {integrity: sha512-cz/cN0GoQOXRLh80UmlcEJODPIw2ijKBK3PLRzvfTzqQ5avK6wp2M8Fj8C/5JIT6g7siwvBANyKXD3U3RpKGHQ==}
engines: {node: '>=16.7'}
dependencies:
'@miniflare/core': 2.4.0
'@miniflare/shared': 2.4.0
undici: 4.13.0
ws: 8.6.0
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: true
/@types/stack-trace/0.0.29:
resolution: {integrity: sha512-TgfOX+mGY/NyNxJLIbDWrO9DjGoVSW9+aB8H2yy1fy32jsvxijhmyJI9fDFgvz3YP4lvJaq9DzdR/M1bOgVc9g==}
dev: true
/blake3-wasm/2.1.5:
resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==}
dev: true
/buffer-from/1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
dev: true
/busboy/0.3.1:
resolution: {integrity: sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==}
engines: {node: '>=4.5.0'}
dependencies:
dicer: 0.3.0
dev: true
/cookie/0.4.2:
resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==}
engines: {node: '>= 0.6'}
dev: true
/cron-schedule/3.0.6:
resolution: {integrity: sha512-izfGgKyzzIyLaeb1EtZ3KbglkS6AKp9cv7LxmiyoOu+fXfol1tQDC0Cof0enVZGNtudTHW+3lfuW9ZkLQss4Wg==}
dev: true
/dicer/0.3.0:
resolution: {integrity: sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==}
engines: {node: '>=4.5.0'}
dependencies:
streamsearch: 0.1.2
dev: true
/dotenv/10.0.0:
resolution: {integrity: sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==}
engines: {node: '>=10'}
dev: true
/esbuild-android-64/0.14.34:
resolution: {integrity: sha512-XfxcfJqmMYsT/LXqrptzFxmaR3GWzXHDLdFNIhm6S00zPaQF1TBBWm+9t0RZ6LRR7iwH57DPjaOeW20vMqI4Yw==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
requiresBuild: true
dev: true
optional: true
/esbuild-android-arm64/0.14.34:
resolution: {integrity: sha512-T02+NXTmSRL1Mc6puz+R9CB54rSPICkXKq6+tw8B6vxZFnCPzbJxgwIX4kcluz9p8nYBjF3+lSilTGWb7+Xgew==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: true
optional: true
/esbuild-darwin-64/0.14.34:
resolution: {integrity: sha512-pLRip2Bh4Ng7Bf6AMgCrSp3pPe/qZyf11h5Qo2mOfJqLWzSVjxrXW+CFRJfrOVP7TCnh/gmZSM2AFdCPB72vtw==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/esbuild-darwin-arm64/0.14.34:
resolution: {integrity: sha512-vpidSJEBxx6lf1NWgXC+DCmGqesJuZ5Y8aQVVsaoO4i8tRXbXb0whChRvop/zd3nfNM4dIl5EXAky0knRX5I6w==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/esbuild-freebsd-64/0.14.34:
resolution: {integrity: sha512-m0HBjePhe0hAQJgtMRMNV9kMgIyV4/qSnzPx42kRMQBcPhgjAq1JRu4Il26czC+9FgpMbFkUktb07f/Lwnc6CA==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/esbuild-freebsd-arm64/0.14.34:
resolution: {integrity: sha512-cpRc2B94L1KvMPPYB4D6G39jLqpKlD3noAMY4/e86iXXXkhUYJJEtTuyNFTa9JRpWM0xCAp4mxjHjoIiLuoCLA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-32/0.14.34:
resolution: {integrity: sha512-8nQaEaoW7MH/K/RlozJa+lE1ejHIr8fuPIHhc513UebRav7HtXgQvxHQ6VZRUkWtep23M6dd7UqhwO1tMOfzQQ==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-64/0.14.34:
resolution: {integrity: sha512-Y3of4qQoLLlAgf042MlrY1P+7PnN9zWj8nVtw9XQG5hcLOZLz7IKpU35oeu7n4wvyaZHwvQqDJ93gRLqdJekcQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-arm/0.14.34:
resolution: {integrity: sha512-9lpq1NcJqssAF7alCO6zL3gvBVVt/lKw4oetUM7OgNnRX0OWpB+ZIO9FwCrSj/dMdmgDhPLf+119zB8QxSMmAg==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-arm64/0.14.34:
resolution: {integrity: sha512-IlWaGtj9ir7+Nrume1DGcyzBDlK8GcnJq0ANKwcI9pVw8tqr+6GD0eqyF9SF1mR8UmAp+odrx1H5NdR2cHdFHA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-mips64le/0.14.34:
resolution: {integrity: sha512-k3or+01Rska1AjUyNjA4buEwB51eyN/xPQAoOx1CjzAQC3l8rpjUDw55kXyL63O/1MUi4ISvtNtl8gLwdyEcxw==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-ppc64le/0.14.34:
resolution: {integrity: sha512-+qxb8M9FfM2CJaVU7GgYpJOHM1ngQOx+/VrtBjb4C8oVqaPcESCeg2anjl+HRZy8VpYc71q/iBYausPPbJ+Keg==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-riscv64/0.14.34:
resolution: {integrity: sha512-Y717ltBdQ5j5sZIHdy1DV9kieo0wMip0dCmVSTceowCPYSn1Cg33Kd6981+F/3b9FDMzNWldZFOBRILViENZSA==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-s390x/0.14.34:
resolution: {integrity: sha512-bDDgYO4LhL4+zPs+WcBkXph+AQoPcQRTv18FzZS0WhjfH8TZx2QqlVPGhmhZ6WidrY+jKthUqO6UhGyIb4MpmA==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-netbsd-64/0.14.34:
resolution: {integrity: sha512-cfaFGXdRt0+vHsjNPyF0POM4BVSHPSbhLPe8mppDc7GDDxjIl08mV1Zou14oDWMp/XZMjYN1kWYRSfftiD0vvQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
requiresBuild: true
dev: true
optional: true
/esbuild-openbsd-64/0.14.34:
resolution: {integrity: sha512-vmy9DxXVnRiI14s8GKuYBtess+EVcDALkbpTqd5jw4XITutIzyB7n4x0Tj5utAkKsgZJB22lLWGekr0ABnSLow==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
requiresBuild: true
dev: true
optional: true
/esbuild-sunos-64/0.14.34:
resolution: {integrity: sha512-eNPVatNET1F7tRMhii7goL/eptfxc0ALRjrj9SPFNqp0zmxrehBFD6BaP3R4LjMn6DbMO0jOAnTLFKr8NqcJAA==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
requiresBuild: true
dev: true
optional: true
/esbuild-windows-32/0.14.34:
resolution: {integrity: sha512-EFhpXyHEcnqWYe2rAHFd8dRw8wkrd9U+9oqcyoEL84GbanAYjiiIjBZsnR8kl0sCQ5w6bLpk7vCEIA2VS32Vcg==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
/esbuild-windows-64/0.14.34:
resolution: {integrity: sha512-a8fbl8Ky7PxNEjf1aJmtxdDZj32/hC7S1OcA2ckEpCJRTjiKslI9vAdPpSjrKIWhws4Galpaawy0nB7fjHYf5Q==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/esbuild-windows-arm64/0.14.34:
resolution: {integrity: sha512-EYvmKbSa2B3sPnpC28UEu9jBK5atGV4BaVRE7CYGUci2Hlz4AvtV/LML+TcDMT6gBgibnN2gcltWclab3UutMg==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/esbuild/0.14.34:
resolution: {integrity: sha512-QIWdPT/gFF6hCaf4m7kP0cJ+JIuFkdHibI7vVFvu3eJS1HpVmYHWDulyN5WXwbRA0SX/7ZDaJ/1DH8SdY9xOJg==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
esbuild-android-64: 0.14.34
esbuild-android-arm64: 0.14.34
esbuild-darwin-64: 0.14.34
esbuild-darwin-arm64: 0.14.34
esbuild-freebsd-64: 0.14.34
esbuild-freebsd-arm64: 0.14.34
esbuild-linux-32: 0.14.34
esbuild-linux-64: 0.14.34
esbuild-linux-arm: 0.14.34
esbuild-linux-arm64: 0.14.34
esbuild-linux-mips64le: 0.14.34
esbuild-linux-ppc64le: 0.14.34
esbuild-linux-riscv64: 0.14.34
esbuild-linux-s390x: 0.14.34
esbuild-netbsd-64: 0.14.34
esbuild-openbsd-64: 0.14.34
esbuild-sunos-64: 0.14.34
esbuild-windows-32: 0.14.34
esbuild-windows-64: 0.14.34
esbuild-windows-arm64: 0.14.34
dev: true
/escape-string-regexp/4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
dev: true
/estree-walker/0.6.1:
resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==}
dev: true
/fsevents/2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
dev: true
optional: true
/html-rewriter-wasm/0.4.1:
resolution: {integrity: sha512-lNovG8CMCCmcVB1Q7xggMSf7tqPCijZXaH4gL6iE8BFghdQCbaY5Met9i1x2Ex8m/cZHDUtXK9H6/znKamRP8Q==}
dev: true
/http-cache-semantics/4.1.0:
resolution: {integrity: sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==}
dev: true
/ignore/5.2.0:
resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==}
engines: {node: '>= 4'}
dev: true
/kleur/4.1.4:
resolution: {integrity: sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==}
engines: {node: '>=6'}
dev: true
/magic-string/0.25.9:
resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
dependencies:
sourcemap-codec: 1.4.8
dev: true
/miniflare/2.4.0:
resolution: {integrity: sha512-xOBL/dQsUL95rxIYO+KrrVPPpm2TAf6TKl4AvhcjSfUeVkzDWd/y9f7hXCt8x6srDoK0Z2LpYouatvSfSUzGOw==}
engines: {node: '>=16.7'}
hasBin: true
peerDependencies:
'@miniflare/storage-redis': 2.4.0
cron-schedule: ^3.0.4
ioredis: ^4.27.9
peerDependenciesMeta:
'@miniflare/storage-redis':
optional: true
cron-schedule:
optional: true
ioredis:
optional: true
dependencies:
'@miniflare/cache': 2.4.0
'@miniflare/cli-parser': 2.4.0
'@miniflare/core': 2.4.0
'@miniflare/durable-objects': 2.4.0
'@miniflare/html-rewriter': 2.4.0
'@miniflare/http-server': 2.4.0
'@miniflare/kv': 2.4.0
'@miniflare/runner-vm': 2.4.0
'@miniflare/scheduler': 2.4.0
'@miniflare/shared': 2.4.0
'@miniflare/sites': 2.4.0
'@miniflare/storage-file': 2.4.0
'@miniflare/storage-memory': 2.4.0
'@miniflare/web-sockets': 2.4.0
kleur: 4.1.4
semiver: 1.1.0
source-map-support: 0.5.21
undici: 4.13.0
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: true
/mustache/4.2.0:
resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
hasBin: true
dev: true
/nanoid/3.3.4:
resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
dev: true
/node-forge/1.3.1:
resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==}
engines: {node: '>= 6.13.0'}
dev: true
/path-to-regexp/6.2.1:
resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==}
dev: true
/rollup-plugin-inject/3.0.2:
resolution: {integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==}
deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.
dependencies:
estree-walker: 0.6.1
magic-string: 0.25.9
rollup-pluginutils: 2.8.2
dev: true
/rollup-plugin-node-polyfills/0.2.1:
resolution: {integrity: sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==}
dependencies:
rollup-plugin-inject: 3.0.2
dev: true
/rollup-pluginutils/2.8.2:
resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==}
dependencies:
estree-walker: 0.6.1
dev: true
/selfsigned/2.0.1:
resolution: {integrity: sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ==}
engines: {node: '>=10'}
dependencies:
node-forge: 1.3.1
dev: true
/semiver/1.1.0:
resolution: {integrity: sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==}
engines: {node: '>=6'}
dev: true
/set-cookie-parser/2.4.8:
resolution: {integrity: sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg==}
dev: true
/source-map-support/0.5.21:
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
dependencies:
buffer-from: 1.1.2
source-map: 0.6.1
dev: true
/source-map/0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
dev: true
/sourcemap-codec/1.4.8:
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
dev: true
/stack-trace/0.0.10:
resolution: {integrity: sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=}
dev: true
/streamsearch/0.1.2:
resolution: {integrity: sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=}
engines: {node: '>=0.8.0'}
dev: true
/typescript/4.6.4:
resolution: {integrity: sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==}
engines: {node: '>=4.2.0'}
hasBin: true
dev: true
/undici/4.13.0:
resolution: {integrity: sha512-8lk8S/f2V0VUNGf2scU2b+KI2JSzEQLdCyRNRF3XmHu+5jectlSDaPSBCXAHFaUlt1rzngzOBVDgJS9/Gue/KA==}
engines: {node: '>=12.18'}
dev: true
/wrangler/2.0.5:
resolution: {integrity: sha512-0BVKQDGm9whPrzLPACGJ9CGdk/taKYYIEvnjLSVOBOxa8her6R9VcmGP6U0wXQnvMasQqlmj+NnjNWgfRw8nIQ==}
engines: {node: '>=16.7.0'}
hasBin: true
dependencies:
'@esbuild-plugins/node-globals-polyfill': 0.1.1_esbuild@0.14.34
'@esbuild-plugins/node-modules-polyfill': 0.1.4_esbuild@0.14.34
blake3-wasm: 2.1.5
esbuild: 0.14.34
miniflare: 2.4.0
nanoid: 3.3.4
path-to-regexp: 6.2.1
selfsigned: 2.0.1
semiver: 1.1.0
xxhash-wasm: 1.0.1
optionalDependencies:
fsevents: 2.3.2
transitivePeerDependencies:
- '@miniflare/storage-redis'
- bufferutil
- cron-schedule
- ioredis
- utf-8-validate
dev: true
/ws/8.6.0:
resolution: {integrity: sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: ^5.0.2
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
dev: true
/xxhash-wasm/1.0.1:
resolution: {integrity: sha512-Lc9CTvDrH2vRoiaUzz25q7lRaviMhz90pkx6YxR9EPYtF99yOJnv2cB+CQ0hp/TLoqrUsk8z/W2EN31T568Azw==}
dev: true
/youch/2.2.2:
resolution: {integrity: sha512-/FaCeG3GkuJwaMR34GHVg0l8jCbafZLHiFowSjqLlqhC6OMyf2tPJBu8UirF7/NI9X/R5ai4QfEKUCOxMAGxZQ==}
dependencies:
'@types/stack-trace': 0.0.29
cookie: 0.4.2
mustache: 4.2.0
stack-trace: 0.0.10
dev: true

104
r2/src/index.ts Normal file
View File

@ -0,0 +1,104 @@
import { decrypt, getDerivedKey } from "@proselog/jwt"
const randomId = () => crypto.randomUUID()
const getExtension = (path: string) => {
const lastPart = path.split(".").pop()
return lastPart ? `.${lastPart}` : ""
}
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "*",
"Access-Control-Allow-Methods": "*",
}
const send = (data: string | Record<string, string>, init?: ResponseInit) => {
const isJSON = data && typeof data === "object"
return new Response(isJSON ? JSON.stringify(data) : data, {
...init,
headers: {
...init?.headers,
...corsHeaders,
"content-type": isJSON ? "application/json" : "text/plain",
},
})
}
const handler: ExportedHandler<{ BUCKET: R2Bucket; ENCRYPT_SECRET: string }> = {
async fetch(request, env): Promise<Response> {
try {
// Files are publicly accessible
if (request.method === "GET") {
const url = new URL(request.url)
if (url.pathname === "/") {
return send("hello world")
}
const key = url.pathname.substring(1)
const object = await env.BUCKET.get(key)
if (!object) {
return send("object not found", { status: 404 })
}
return new Response(object.body)
}
if (request.method === "OPTIONS") {
return send("")
}
if (request.method === "POST") {
const token = request.headers
.get("authorization")
?.replace("Bearer ", "")
if (!token) {
throw new Error("missing auth token")
}
let uid: string | undefined
if (env.ENCRYPT_SECRET && token) {
const key = await getDerivedKey(env.ENCRYPT_SECRET)
try {
const payload = await decrypt(token, key)
uid = payload.uid as string
} catch (error) {
console.error({ error })
return send("invalid token", {
status: 401,
})
}
}
if (!uid) {
throw new Error("failed to extract uid")
}
const data = await request.formData()
const id = randomId()
const file = data.get("file") as File
if (!file || !(file instanceof File)) {
throw new Error("missing file or invalid file")
}
const key = `${uid}/${id}${getExtension(file.name)}`
await env.BUCKET.put(key, await file.arrayBuffer(), {
httpMetadata: {
contentType: file.type,
},
})
return send({ key })
}
} catch (error: any) {
console.error({ error })
return send(error.message, { status: 500 })
}
return send("Hello World!")
},
}
export default handler

105
r2/tsconfig.json Normal file
View File

@ -0,0 +1,105 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Projects */
// "incremental": true, /* Enable incremental compilation */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
"lib": [
"es2021"
] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
// "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
/* Modules */
"module": "es2022" /* Specify what module code is generated. */,
// "rootDir": "./", /* Specify the root folder within your source files. */
"moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
"types": [
"@cloudflare/workers-types"
] /* Specify type package names to be included without being referenced in a source file. */,
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
"resolveJsonModule": true /* Enable importing .json files */,
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
"allowJs": true /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */,
"checkJs": true /* Enable error reporting in type-checked JavaScript files. */,
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
"noEmit": true /* Disable emitting files from a compilation. */,
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
"isolatedModules": true /* Ensure that each file can be safely transpiled without relying on other imports. */,
"allowSyntheticDefaultImports": true /* Allow 'import x from y' when a module doesn't have a default export. */,
// "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
/* Type Checking */
"strict": true /* Enable all strict type-checking options. */,
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
// "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
// "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}

19
r2/wrangler.toml Normal file
View File

@ -0,0 +1,19 @@
name = "r2"
main = "src/index.ts"
compatibility_date = "2022-05-14"
[[r2_buckets]]
binding = 'BUCKET'
bucket_name = 'proselog'
preview_bucket_name ='proselog-dev'
# secrets
# API_TOKEN
[env.development.vars]
ENCRYPT_SECRET="uIeqyCW1E5PbK2ztsc+UXcPwsZ0L/Z4k08ArOSaKpHHFViRbdnFJcQ=="
# Why do I need to set it again? Cloudflare?
[[env.development.r2_buckets]]
binding = 'BUCKET'
bucket_name = 'proselog'
preview_bucket_name ='proselog-dev'

View File

@ -16,13 +16,8 @@ ENCRYPT_SECRET=uIeqyCW1E5PbK2ztsc+UXcPwsZ0L/Z4k08ArOSaKpHHFViRbdnFJcQ==
OUR_DOMAIN=localhost:3000
NEXT_PUBLIC_OUR_DOMAIN=$OUR_DOMAIN
S3_BUCKET_NAME=xxx
S3_REGION=us-west-004
S3_ACCESS_KEY_ID=xxx
S3_SECRET_ACCESS_KEY=xxx
S3_ENDPOINT=xxx
S3_CDN_PREFIX=https://user-contents.proselog.com/
NEXT_PUBLIC_S3_CDN_PREFIX=$S3_CDN_PREFIX
NEXT_PUBLIC_R2_URL=http://localhost:8787
R2_API_TOKEN=xxx
MAILGUN_APIKEY=
MAILGUN_DOMAIN=

View File

@ -1,5 +1,5 @@
{
"name": "web",
"name": "proselog",
"private": true,
"description": "A publishing platform",
"license": "unlicensed",
@ -19,6 +19,7 @@
"@hapi/iron": "^6.0.0",
"@headlessui/react": "^1.6.0",
"@prisma/client": "^3.14.0",
"@proselog/jwt": "^0.1.1",
"@trpc/client": "^9.23.2",
"@trpc/next": "^9.23.2",
"@trpc/react": "^9.23.2",

View File

@ -7,22 +7,28 @@ import { Button } from "~/components/ui/Button"
import toast from "react-hot-toast"
import createPica from "pica"
import { trpc } from "~/lib/trpc"
import { UploadFile, useUploadFile } from "~/hooks/useUploadFile"
const AvatarEditorModal: React.FC<{
isOpen: boolean
image?: File | null
setIsOpen: (open: boolean) => void
site?: string
}> = ({ isOpen, setIsOpen, image, site }) => {
uploadFile: UploadFile
}> = ({ isOpen, setIsOpen, image, site, uploadFile }) => {
const editorRef = useRef<ReactAvatarEditor | null>(null)
const [isSaving, setIsSaving] = useState(false)
const ctx = trpc.useContext()
const updateProfile = trpc.useMutation("user.updateProfile")
const updateSite = trpc.useMutation("site.updateSite")
const cropAndSave = async () => {
if (!editorRef.current) return
try {
setIsSaving(true)
// Get cropped image
const fromCanvas = editorRef.current.getImage()
const toCanvas = document.createElement("canvas")
toCanvas.width = 460
@ -30,23 +36,17 @@ const AvatarEditorModal: React.FC<{
const pica = createPica()
const result = await pica.resize(fromCanvas, toCanvas)
const blob = await pica.toBlob(result, "image/jpeg", 0.9)
const form = new FormData()
// Upload image to R2
const { key } = await uploadFile(blob, image!.name)
// Save the image to profile / site
if (site) {
form.append("site", site)
}
form.append("file", blob)
const res = await fetch("/api/save-avatar", {
body: form,
method: "post",
credentials: "same-origin",
})
if (!res.ok) {
throw new Error(res.statusText)
}
const data = await res.json()
if (data.error) {
throw new Error(data.error)
await updateSite.mutateAsync({ site, icon: key })
} else {
await updateProfile.mutateAsync({ avatar: key })
}
setIsOpen(false)
toast.success("Updated!")
ctx.invalidateQueries()
@ -102,6 +102,7 @@ export const AvatarForm: React.FC<{
const [isOpen, setIsOpen] = useState(false)
const inputEl = useRef<HTMLInputElement>(null)
const [image, setImage] = useState<File | null>(null)
const uploadFile = useUploadFile()
const onClick = () => {
inputEl.current?.click()
@ -122,6 +123,7 @@ export const AvatarForm: React.FC<{
setIsOpen={setIsOpen}
image={image}
site={site}
uploadFile={uploadFile}
/>
<input
aria-hidden

View File

@ -1,6 +1,5 @@
import clsx from "clsx"
import React, { useMemo } from "react"
import Image from "next/image"
export const Avatar: React.FC<
{
@ -61,7 +60,7 @@ export const Avatar: React.FC<
height: `${size}px`,
}}
>
<Image
<img
className={borderRadius}
src={image}
width={size}

View File

@ -0,0 +1,8 @@
import { trpc } from "~/lib/trpc"
export const useSignedJwt = () => {
const jwt = trpc.useQuery(["user.getSignedJwt"], {
refetchInterval: 60_000,
})
return jwt.data
}

View File

@ -0,0 +1,38 @@
import { useCallback } from "react"
import { R2_URL } from "~/lib/env"
import { useSignedJwt } from "./useSignedJwt"
export const useUploadFile = () => {
const signedJwt = useSignedJwt()
const uploadFile = useCallback<UploadFile>(
async (blob, filename) => {
if (!signedJwt) {
throw new Error("failed to retrieve signed jwt, please try again")
}
const form = new FormData()
form.append("file", blob, filename)
const res = await fetch(R2_URL, {
body: form,
method: "post",
headers: {
authorization: `Bearer ${signedJwt}`,
},
})
if (!res.ok) {
throw new Error(await res.text())
}
const data = await res.json()
return data
},
[signedJwt]
)
return uploadFile
}
export type UploadFile = (
blob: Blob,
filename: string
) => Promise<{ key: string }>

View File

@ -1,8 +1,4 @@
export const S3_REGION = process.env.S3_REGION
export const S3_ACCESS_KEY_ID = process.env.S3_ACCESS_KEY_ID
export const S3_SECRET_ACCESS_KEY = process.env.S3_SECRET_ACCESS_KEY
export const S3_BUCKET_NAME = process.env.S3_BUCKET_NAME
export const S3_ENDPOINT = process.env.S3_ENDPOINT
export const R2_API_TOKEN = process.env.R2_API_TOKEN
export const MAILGUN_APIKEY = process.env.MAILGUN_APIKEY
export const MAILGUN_DOMAIN = process.env.MAILGUN_DOMAIN
export const ENCRYPT_SECRET = process.env.ENCRYPT_SECRET

View File

@ -2,5 +2,5 @@ import { IS_PROD } from "./constants"
export const APP_NAME = process.env.NEXT_PUBLIC_APP_NAME
export const OUR_DOMAIN = process.env.NEXT_PUBLIC_OUR_DOMAIN
export const S3_CDN_PREFIX = process.env.NEXT_PUBLIC_S3_CDN_PREFIX
export const SITE_URL = `${IS_PROD ? "https" : "http"}://${OUR_DOMAIN}`
export const R2_URL = process.env.NEXT_PUBLIC_R2_URL

View File

@ -1,15 +0,0 @@
export const uploadFileInBrowser = async (blob: Blob) => {
const form = new FormData()
form.append("file", blob)
form.append("type", "image")
const res = await fetch(`/api/upload`, {
credentials: "same-origin",
body: form,
method: "POST",
})
if (!res.ok) {
throw new Error(`Upload failed: ${res.statusText}`)
}
const json = await res.json()
return json as { file: string }
}

View File

@ -1,64 +0,0 @@
import { nanoid } from "nanoid"
import path from "path"
import busboy, { FileInfo } from "busboy"
import { s3uploadFile } from "./s3.server"
import { IncomingMessage } from "http"
type File = { name: string; buffer: Buffer; info: FileInfo }
export const uploadImage = async (
req: IncomingMessage,
{ userId }: { userId: string }
) => {
const filePromises: Promise<void>[] = []
const { files, fields } = await new Promise<{
files: File[]
fields: Record<string, any>
}>((resolve, reject) => {
const bb = busboy({ headers: req.headers, highWaterMark: 2 * 1024 * 1024 })
const fields: Record<string, any> = {}
const files: File[] = []
bb.on("file", async (name, file, info) => {
const fn = async () => {
const chunks = []
for await (let chunk of file) {
chunks.push(chunk)
}
const buffer = Buffer.concat(chunks)
files.push({ name, buffer, info })
}
filePromises.push(fn())
})
bb.on("field", (name, val) => {
fields[name] = val
})
const onEnd = (err?: Error) => {
if (err) return reject(err)
resolve({ files, fields })
}
bb.on("close", onEnd)
bb.on("error", (error) => reject(error))
req.pipe(bb)
})
await Promise.all(filePromises)
await Promise.all(
files.map(async (file) => {
const saveAs = `${userId}/${nanoid()}${
path.extname(file.info.filename) || ".jpg"
}`
await s3uploadFile(saveAs, file.buffer, file.info.mimeType)
fields[file.name] = saveAs
})
)
return fields
}

View File

@ -1,5 +1,4 @@
import { IS_PROD } from "./constants"
import { S3_CDN_PREFIX } from "./env"
import { R2_URL } from "./env"
export function getUserContentsUrl(filename: string): string
export function getUserContentsUrl(filename: undefined | null): undefined
@ -8,10 +7,5 @@ export function getUserContentsUrl<T extends string | undefined | null>(
): T
export function getUserContentsUrl(filename: string | undefined | null) {
if (!filename) return undefined
if (IS_PROD) {
return `${S3_CDN_PREFIX}/${filename}`
}
return `/dev-s3-proxy?${new URLSearchParams({
filename: filename,
}).toString()}`
return `${R2_URL}/${filename}`
}

View File

@ -1,19 +1,9 @@
import { NextRequest, NextResponse } from "next/server"
import { IS_PROD } from "~/lib/constants"
import { S3_BUCKET_NAME, S3_ENDPOINT } from "~/lib/env.server"
import { getTenant } from "~/lib/tenant.server"
export default function middleware(req: NextRequest) {
const { pathname } = req.nextUrl
if (!IS_PROD && pathname.startsWith("/dev-s3-proxy")) {
const filename = req.nextUrl.searchParams.get("filename")
console.log(`https://${S3_BUCKET_NAME}.${S3_ENDPOINT}/${filename}`)
return NextResponse.rewrite(
`https://${S3_BUCKET_NAME}.${S3_ENDPOINT}/${filename}`
)
}
if (pathname.startsWith("/api/") || pathname.startsWith("/dashboard")) {
return NextResponse.next()
}

View File

@ -1,33 +0,0 @@
import { NextApiHandler } from "next"
import { z } from "zod"
import { getAuthUser } from "~/lib/auth.server"
import { uploadImage } from "~/lib/upload.server"
export const config = {
api: {
bodyParser: false,
},
}
const handler: NextApiHandler = async (req, res) => {
if (req.method !== "POST") return res.end("only POST")
try {
const user = await getAuthUser(req, true)
const data = await uploadImage(req, { userId: user.id })
const values = z
.object({
file: z.string(),
})
.parse(data)
res.send({ file: values.file })
} catch (error: any) {
console.error(error)
res.send({
error: error.message,
})
}
}
export default handler

View File

@ -15,6 +15,7 @@ import { trpc } from "~/lib/trpc"
import { useRouter } from "next/router"
import { DashboardLayout } from "~/components/dashboard/DashboardLayout"
import { UniLink } from "~/components/ui/UniLink"
import { useUploadFile } from "~/hooks/useUploadFile"
const getInputDatetimeValue = (date: Date | string) => {
const str = dayjs(date).format()
@ -44,6 +45,7 @@ export default function SubdomainEditor() {
publishedAt: page?.publishedAt || null,
})
const createOrUpdatePage = trpc.useMutation("site.createOrUpdatePage")
const uploadFile = useUploadFile()
const [values, setValues] = useState({
title: "",
@ -101,42 +103,29 @@ export default function SubdomainEditor() {
[]
)
const handleDropFile = useCallback(async (file: File, view: EditorView) => {
if (!file.type.startsWith("image/")) {
toast.error("You can only upload images")
return
}
const handleDropFile = useCallback(
async (file: File, view: EditorView) => {
const toastId = toast.loading("Uploading...")
try {
if (!file.type.startsWith("image/")) {
throw new Error("You can only upload images")
}
const toastId = toast.loading("Uploading...")
const form = new FormData()
form.append("file", file)
const res = await fetch("/api/upload-image", {
body: form,
headers: {},
credentials: "same-origin",
method: "POST",
})
if (!res.ok) {
toast.error("Upload failed", {
id: toastId,
})
} else {
const data = await res.json()
if (data.error) {
toast.error(data.error, { id: toastId })
} else {
const { key } = await uploadFile(file, file.name)
toast.success("Uploaded!", {
id: toastId,
})
view.dispatch(
view.state.replaceSelection(
`\n\n![${file.name.replace(/\.\w+$/, "")}](${data.file})\n\n`
`\n\n![${file.name.replace(/\.\w+$/, "")}](${key})\n\n`
)
)
} catch (error: any) {
toast.error(error.mesage, { id: toastId })
}
}
}, [])
},
[uploadFile]
)
const { editorRef } = useEditor({
value: values.content,

View File

@ -118,7 +118,7 @@ export const siteRouter = createRouter()
site: z.string(),
name: z.string().optional(),
description: z.string().optional(),
icon: z.string().nullish().optional(),
icon: z.string().nullish(),
subdomain: z.string().optional(),
navigation: z
.array(

View File

@ -1,15 +1,28 @@
import { encrypt, getDerivedKey } from "@proselog/jwt"
import { z } from "zod"
import { ENCRYPT_SECRET } from "~/lib/env.server"
import { createRouter } from "~/lib/trpc.server"
import { userModel } from "~/models/user.model"
export const userRouter = createRouter().mutation("updateProfile", {
input: z.object({
username: z.string().optional(),
name: z.string().optional(),
email: z.string().optional(),
bio: z.string().optional(),
}),
async resolve({ ctx, input }) {
await userModel.updateProfile(ctx.gate, input)
},
})
export const userRouter = createRouter()
.query("getSignedJwt", {
output: z.string(),
async resolve({ ctx }) {
const user = ctx.gate.getUser(true)
const key = await getDerivedKey(ENCRYPT_SECRET)
const token = await encrypt({ uid: user.id }, key, { expiresIn: "1h" })
return token
},
})
.mutation("updateProfile", {
input: z.object({
username: z.string().optional(),
name: z.string().optional(),
email: z.string().optional(),
bio: z.string().optional(),
avatar: z.string().optional(),
}),
async resolve({ ctx, input }) {
await userModel.updateProfile(ctx.gate, input)
},
})

8
web/types.d.ts vendored
View File

@ -4,17 +4,13 @@ declare interface ServerEnv {
DATABASE_URL: string
AUTH_COOKIE_NAME: string
OUR_DOMAIN: string
S3_REGION: string
S3_ACCESS_KEY_ID: string
S3_SECRET_ACCESS_KEY: string
S3_BUCKET_NAME: string
S3_ENDPOINT?: string
MAILGUN_APIKEY: string
MAILGUN_DOMAIN: string
S3_CDN_PREFIX: string
FLY_REGION?: string
PRIMARY_REGION?: string
ENCRYPT_SECRET: string
NEXT_PUBLIC_R2_URL: string
R2_API_TOKEN: string
}
declare interface BrowserEnv {