From 984ed3a248bd4aed0a7ffb4a9260cca4ff898c19 Mon Sep 17 00:00:00 2001 From: Qin Guan Date: Tue, 26 Sep 2023 00:10:13 +0800 Subject: [PATCH] feat(server): r2 cdn endpoints (#2) --- package.json | 1 + pnpm-lock.yaml | 122 +++++++++----------- server/{api => routes}/cdn/[...path].get.ts | 14 ++- 3 files changed, 66 insertions(+), 71 deletions(-) rename server/{api => routes}/cdn/[...path].get.ts (50%) diff --git a/package.json b/package.json index b3ba376..89ea073 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ }, "devDependencies": { "@antfu/eslint-config": "latest", + "@cloudflare/workers-types": "^4.20230914.0", "@libsql/client": "^0.3.4", "@nuxt/devtools": "latest", "@paralleldrive/cuid2": "^2.2.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b8f8171..0c763d6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,13 +7,16 @@ settings: devDependencies: '@antfu/eslint-config': specifier: latest - version: 1.0.0-beta.7(eslint@8.49.0)(typescript@5.2.2) + version: 1.0.0-beta.10(eslint@8.49.0)(typescript@5.2.2) + '@cloudflare/workers-types': + specifier: ^4.20230914.0 + version: 4.20230914.0 '@libsql/client': specifier: ^0.3.4 version: 0.3.4 '@nuxt/devtools': specifier: latest - version: 0.8.4(nuxt@3.7.3)(rollup@2.79.1)(vite@4.4.9) + version: 0.8.5(nuxt@3.7.3)(rollup@2.79.1)(vite@4.4.9) '@paralleldrive/cuid2': specifier: ^2.2.2 version: 2.2.2 @@ -52,7 +55,7 @@ devDependencies: version: 0.19.13 drizzle-orm: specifier: ^0.28.6 - version: 0.28.6(@libsql/client@0.3.4) + version: 0.28.6(@cloudflare/workers-types@4.20230914.0)(@libsql/client@0.3.4) eslint: specifier: ^8.49.0 version: 8.49.0 @@ -105,17 +108,16 @@ packages: '@jridgewell/trace-mapping': 0.3.19 dev: true - /@antfu/eslint-config@1.0.0-beta.7(eslint@8.49.0)(typescript@5.2.2): - resolution: {integrity: sha512-6NGzVXzNikd7dTdkwjLPXMklDZp9csU6JwPsypJDCIbAA5F2OHhugo+pSgYaMsHa7fdC6QMDLL4u5G2Q9Okqtg==} + /@antfu/eslint-config@1.0.0-beta.10(eslint@8.49.0)(typescript@5.2.2): + resolution: {integrity: sha512-HemQkcPpb2trszxlFjBZqj1SJJWY3WBHurpQX4VKa3dtGCUjCgVwqc3BepE2TwVY2Oqz+AmIKOyvYeHSRXYS5w==} peerDependencies: eslint: '>=8.0.0' dependencies: - '@eslint-stylistic/metadata': 0.0.4 - '@stylistic/eslint-plugin-js': 0.0.4 - '@stylistic/eslint-plugin-ts': 0.0.4(eslint@8.49.0)(typescript@5.2.2) + '@stylistic/eslint-plugin': 0.0.5(eslint@8.49.0)(typescript@5.2.2) '@typescript-eslint/eslint-plugin': 6.7.2(@typescript-eslint/parser@6.7.2)(eslint@8.49.0)(typescript@5.2.2) '@typescript-eslint/parser': 6.7.2(eslint@8.49.0)(typescript@5.2.2) eslint: 8.49.0 + eslint-config-flat-gitignore: 0.1.0 eslint-define-config: 1.23.0 eslint-plugin-antfu: 1.0.0-beta.6(eslint@8.49.0)(typescript@5.2.2) eslint-plugin-eslint-comments: 3.2.0(eslint@8.49.0) @@ -1390,6 +1392,10 @@ packages: mime: 3.0.0 dev: true + /@cloudflare/workers-types@4.20230914.0: + resolution: {integrity: sha512-OVeN4lFVu1O0PJGZ2d0FwpK8lelFcr33qYOgCh77ErEYmEBO4adwnIxcIsdQbFbhF0ffN6joiVcljD4zakdaeQ==} + dev: true + /@drizzle-team/studio@0.0.5: resolution: {integrity: sha512-ps5qF0tMxWRVu+V5gvCRrQNqlY92aTnIKdq27gm9LZMSdaKYZt6AVvSK1dlUMzs6Rt0Jm80b+eWct6xShBKhIw==} dev: true @@ -1835,10 +1841,6 @@ packages: engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true - /@eslint-stylistic/metadata@0.0.4: - resolution: {integrity: sha512-PlM+6bksCXBSS31s8NNHV2NuUy05N70tLwlQJ9pQ7FQqXwkefULcdAEWUeX8CAk3FK29Jw0l+J8U/nOYJdPrOg==} - dev: true - /@eslint/eslintrc@2.1.2: resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2628,8 +2630,8 @@ packages: resolution: {integrity: sha512-GBzP8zOc7CGWyFQS6dv1lQz8VVpz5C2yRszbXufwG/9zhStTIH50EtD87NmWbTMwXDvZLNg8GIpb1UFdH93JCA==} dev: true - /@nuxt/devtools-kit@0.8.4(nuxt@3.7.3)(rollup@2.79.1)(vite@4.4.9): - resolution: {integrity: sha512-kBgXJ1NUcE37ea08hlLkA5ZYvEy8sY08Z/lfzpvEwra4aQ22hm/c9FlqIGLfTfDJ4vfvSBlPF6oRyC3zE28VWg==} + /@nuxt/devtools-kit@0.8.5(nuxt@3.7.3)(rollup@2.79.1)(vite@4.4.9): + resolution: {integrity: sha512-gkZuythYbx6ybwQc2zE1DC40B3cj3rrSxHG6GIihWseilTea7G4QMkDliEbGnqyM4cLQmMBD+SU4DxiDVSNlQQ==} peerDependencies: nuxt: ^3.7.3 vite: '*' @@ -2644,8 +2646,8 @@ packages: - supports-color dev: true - /@nuxt/devtools-wizard@0.8.4: - resolution: {integrity: sha512-oEIHqyDqxKGgcIhD+B1QMaFz/hAF68zUR4BTN3KU7UkAu6AFEfIYMwXc4E5NT5nnI+z4Qbkr+8VV67eteCMZ5w==} + /@nuxt/devtools-wizard@0.8.5: + resolution: {integrity: sha512-4QbI4SgzKJrJTWmObsgUAM5wZ0vlYAy0eNTpXsc2aMQZkpmb74ebY9yvgyz9e5tLOvPOjZNUkFYNmun5uy3QRA==} hasBin: true dependencies: consola: 3.2.3 @@ -2654,26 +2656,24 @@ packages: global-dirs: 3.0.1 magicast: 0.3.0 pathe: 1.1.1 - picocolors: 1.0.0 pkg-types: 1.0.3 prompts: 2.4.2 rc9: 2.1.1 semver: 7.5.4 dev: true - /@nuxt/devtools@0.8.4(nuxt@3.7.3)(rollup@2.79.1)(vite@4.4.9): - resolution: {integrity: sha512-Ti3j+w06IFVnJJAAWh8KhE3Dzzp+g5W+1CEus7obIUQC8amByd96wFV00CfnNNvaXLVmi4+1mo4mYUvQN+Pv4A==} + /@nuxt/devtools@0.8.5(nuxt@3.7.3)(rollup@2.79.1)(vite@4.4.9): + resolution: {integrity: sha512-xNogUcv257gj/1NreQ0TiS7SqalHRoDYkPM5zaBbimBtUa7tlmtpbI/VpFrkpVbHOvBpPWk8JMMFkIDScYyMyw==} hasBin: true peerDependencies: nuxt: ^3.7.3 vite: '*' dependencies: '@antfu/utils': 0.7.6 - '@nuxt/devtools-kit': 0.8.4(nuxt@3.7.3)(rollup@2.79.1)(vite@4.4.9) - '@nuxt/devtools-wizard': 0.8.4 + '@nuxt/devtools-kit': 0.8.5(nuxt@3.7.3)(rollup@2.79.1)(vite@4.4.9) + '@nuxt/devtools-wizard': 0.8.5 '@nuxt/kit': 3.7.3(rollup@2.79.1) birpc: 0.2.14 - boxen: 7.1.1 consola: 3.2.3 error-stack-parser-es: 0.1.1 execa: 7.2.0 @@ -2695,7 +2695,6 @@ packages: pacote: 17.0.4 pathe: 1.1.1 perfect-debounce: 1.0.0 - picocolors: 1.0.0 pkg-types: 1.0.3 rc9: 2.1.1 semver: 7.5.4 @@ -3336,8 +3335,8 @@ packages: - supports-color dev: true - /@stylistic/eslint-plugin-js@0.0.4: - resolution: {integrity: sha512-W1rq2xxlFNhgZZJO+L59wtvlDI0xARYxx0WD8EeWNBO7NDybUSYSozCIcY9XvxQbTAsEXBjwqokeYm0crt7RxQ==} + /@stylistic/eslint-plugin-js@0.0.5: + resolution: {integrity: sha512-Ca3DAk4lHGELPHnHIOUc/SF3Pg58xd/AATqNMSTSoxjoadRk6MGDblriURXjEg7gif4ygiB3+EcIuphAceFYvQ==} dependencies: acorn: 8.10.0 escape-string-regexp: 4.0.0 @@ -3347,21 +3346,33 @@ packages: graphemer: 1.4.0 dev: true - /@stylistic/eslint-plugin-ts@0.0.4(eslint@8.49.0)(typescript@5.2.2): - resolution: {integrity: sha512-sWL4Km5j8S+TLyzya/3adxMWGkCm3lVasJIVQqhxVfwnlGkpMI0GgYVIu/ubdKPS+dSvqjUHpsXgqWfMRF2+cQ==} + /@stylistic/eslint-plugin-ts@0.0.5(eslint@8.49.0)(typescript@5.2.2): + resolution: {integrity: sha512-Ei/arToTJEF2nxxJLsXqK9qMxPgZi8IyM2X+1q8HRA11Q3zRMut8u1B1zwE8q9EhorBwZsgnmphgzmDG0Mot+w==} peerDependencies: eslint: '*' - typescript: '*' dependencies: - '@stylistic/eslint-plugin-js': 0.0.4 + '@stylistic/eslint-plugin-js': 0.0.5 '@typescript-eslint/scope-manager': 6.7.2 '@typescript-eslint/type-utils': 6.7.2(eslint@8.49.0)(typescript@5.2.2) '@typescript-eslint/utils': 6.7.2(eslint@8.49.0)(typescript@5.2.2) eslint: 8.49.0 graphemer: 1.4.0 - typescript: 5.2.2 transitivePeerDependencies: - supports-color + - typescript + dev: true + + /@stylistic/eslint-plugin@0.0.5(eslint@8.49.0)(typescript@5.2.2): + resolution: {integrity: sha512-8InMNsdJrQqdKxCxd7Zc8HCYg2p5a4XXkqxRzjG7Soy+RWQdj7bAGfTmaDWB0i28CffYabOfOsAgRlfG9oe3Wg==} + peerDependencies: + eslint: '*' + dependencies: + '@stylistic/eslint-plugin-js': 0.0.5 + '@stylistic/eslint-plugin-ts': 0.0.5(eslint@8.49.0)(typescript@5.2.2) + eslint: 8.49.0 + transitivePeerDependencies: + - supports-color + - typescript dev: true /@surma/rollup-plugin-off-main-thread@2.2.3: @@ -4384,12 +4395,6 @@ packages: uri-js: 4.4.1 dev: true - /ansi-align@3.0.1: - resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} - dependencies: - string-width: 4.2.3 - dev: true - /ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -4676,20 +4681,6 @@ packages: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} dev: true - /boxen@7.1.1: - resolution: {integrity: sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==} - engines: {node: '>=14.16'} - dependencies: - ansi-align: 3.0.1 - camelcase: 7.0.1 - chalk: 5.3.0 - cli-boxes: 3.0.0 - string-width: 5.1.2 - type-fest: 2.19.0 - widest-line: 4.0.1 - wrap-ansi: 8.1.0 - dev: true - /bplist-parser@0.2.0: resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==} engines: {node: '>= 5.10.0'} @@ -4952,11 +4943,6 @@ packages: resolution: {integrity: sha512-qMjRnoL+JDPJHeLePZJuao6+8orzHMGP04A8CdwCNsKhRbOnKRjefxONR7bwILT3MHecxKBjHkKL/tkZ8r4Uzw==} dev: true - /cli-boxes@3.0.0: - resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} - engines: {node: '>=10'} - dev: true - /cli-color@2.0.3: resolution: {integrity: sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==} engines: {node: '>=0.10'} @@ -5557,7 +5543,7 @@ packages: - supports-color dev: true - /drizzle-orm@0.28.6(@libsql/client@0.3.4): + /drizzle-orm@0.28.6(@cloudflare/workers-types@4.20230914.0)(@libsql/client@0.3.4): resolution: {integrity: sha512-yBe+F9htrlYER7uXgDJUQsTHFoIrI5yMm5A0bg0GiZ/kY5jNXTWoEy4KQtg35cE27sw1VbgzoMWHAgCckUUUww==} peerDependencies: '@aws-sdk/client-rds-data': '>=3' @@ -5619,6 +5605,7 @@ packages: sqlite3: optional: true dependencies: + '@cloudflare/workers-types': 4.20230914.0 '@libsql/client': 0.3.4 dev: true @@ -5917,6 +5904,12 @@ packages: engines: {node: '>=12'} dev: true + /eslint-config-flat-gitignore@0.1.0: + resolution: {integrity: sha512-5nQMQFRkkhCb+ejFhKSATn/41I7ot9oRcnEDzfqwMlBE9036qM9ioYBDtKLpwmlICXr/J7naMFfb39pa4v4sGA==} + dependencies: + parse-gitignore: 2.0.0 + dev: true + /eslint-define-config@1.23.0: resolution: {integrity: sha512-4mMyu0JuBkQHsCtR+42irIQdFLmLIW+pMAVcyOV/gZRL4O1R8iuH0eMG3oL3Cbi1eo9fDAfT5CIHVHgdyxcf6w==} engines: {node: ^16.13.0 || >=18.0.0, npm: '>=7.0.0', pnpm: '>= 8.6.0'} @@ -8883,6 +8876,11 @@ packages: ini: 1.3.8 dev: true + /parse-gitignore@2.0.0: + resolution: {integrity: sha512-RmVuCHWsfu0QPNW+mraxh/xjQVw/lhUCUru8Zni3Ctq3AoMhpDTq0OVdKS6iesd6Kqb7viCV3isAL43dciOSog==} + engines: {node: '>=14'} + dev: true + /parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -10580,11 +10578,6 @@ packages: engines: {node: '>=8'} dev: true - /type-fest@2.19.0: - resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} - engines: {node: '>=12.20'} - dev: true - /type-fest@3.13.1: resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} engines: {node: '>=14.16'} @@ -11487,13 +11480,6 @@ packages: string-width: 4.2.3 dev: true - /widest-line@4.0.1: - resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} - engines: {node: '>=12'} - dependencies: - string-width: 5.1.2 - dev: true - /wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} dev: true diff --git a/server/api/cdn/[...path].get.ts b/server/routes/cdn/[...path].get.ts similarity index 50% rename from server/api/cdn/[...path].get.ts rename to server/routes/cdn/[...path].get.ts index 2f8b5e6..d22a34e 100644 --- a/server/api/cdn/[...path].get.ts +++ b/server/routes/cdn/[...path].get.ts @@ -1,8 +1,9 @@ import type { R2Bucket } from '@cloudflare/workers-types' -export default defineCachedEventHandler(async (event) => { +export default defineProtectedEventHandler(async (event) => { const bucket: R2Bucket = event.context.cloudflare.env.R2_SSTAA const file = await bucket.get(event.context.params!.path) + if (!file) { throw createError({ statusCode: 404, @@ -10,7 +11,14 @@ export default defineCachedEventHandler(async (event) => { }) } - return sendStream(event, file.body as any) + const headers = new Headers() + file.writeHttpMetadata(headers as any) + headers.set('etag', file.httpEtag) + setResponseHeaders(event, Object.fromEntries(headers.entries())) + + return file.body }, { - maxAge: 60, + cache: { + maxAge: 60 * 60, + }, })