From b0105d7d807b660be7e29643304eccf00509f35d Mon Sep 17 00:00:00 2001 From: Rory& Date: Thu, 25 Dec 2025 03:57:01 +0100 Subject: [PATCH] No s3 support by default --- package-lock.json | Bin 404842 -> 388957 bytes package.json | 1 - src/cdn/util/S3Storage.ts | 17 ++++++++++++++--- src/cdn/util/Storage.ts | 15 ++++++++++----- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6c0a33cdee6184b22c01a5171375184fc124f576..e8efb1e466aa7169905917b9e664f6010592b824 100644 GIT binary patch delta 2096 zcmZuydr(wm6rTgTF0i}oiVu`{iI9LBEGD7`>|&XiqBv2EGd2SyL#YF1Mruy1qL3CW za=?R`vg-JjSD*Nij=&U}X^N3f=?HC_uS})U9@9+NckkVWW$M3s&-Xj${Lb(DoqK<| zI;N*LuxTDJ8!Xl1#c}@ZbZ`)$b;dh5FJl<9hJNNHUUI7PUcrasmr_R;L}TH(6taE= zK4^_^6^FTKHJ=lyG1PVwG-SI2L9{5sJDJSigC6^X_Q@FY%X-!x^@CJ;8O|}@#@R6= zXk#vfpx%%!UfPv5q38^ZW7}i>Bw!x)mFTh97>pfRqnX*XPYSxY%s_2I*#GlkR`cHy zG8aWtv`^}!utYBnGo@|OifBJNGqhN+-k+Vw_)g3qx;SbQm^S+_Z~3JoNrmA>CalbV z1D&O<*uHQiYgqKG!e{W%M7E!ykh(sAB+N;#roQ(fx+?Dg!yNNaXy1~Ncxp*8>waCQ z@@Q~MWKCxMg&JUSZ+TP~aCU0RLQkm7g*g`c08_s`Se3oq&fR(6A$Ap$eU*(npw?G@6BNo~i^KH73^eQMPowc{n&%6xycvu&#>JURY4=$DUx! z&~YmBWdzzkiNmJ(zG%sg!SD_DSTM;zPj$~|n08m1lHONhM$7g@G~1_3s3j7=+N;)Mn-5870kMVY%Hg_f^^32tOSWylZFpvP0M9RiQA&o@tZ`L}L}#j=3cA5SKfVVVEMF5SMYv%5r-IE%4#0|8 z6NTp4bn!0uQ{B5TUU_Ob4_dUPPC|zzk*u8%Db^-lr2F#BweW{$s}yovhRH(YNJ$Jc z*=hlK@y8&WD_88ZhMbL1Indx3@89AgOO@+jDz-%#>Hb|9D>|H@zD=OvJzHJb%7Bd~ z6E$6f7clIZ2->?1Y9wvRS_eCM&JLJ9NG5#44Y>f#KM2~Y1zLW$4nmY;m%X@c7d)11 zDiaez6;SAPNW(6BAl%3X!R}7@emHZ9uPPV^AzqK>0@}~3265? zT-gTlQs;_`dI~?Zjg!nE+hk1#tX7nAX-7gkp{junSk#h}e58O5oyoBSIl?GkNX2u= zc@wI6&uI_U`15DLPbnyUO539hLvJ0;V}_B-c7FJEaFBH8v#I{P=wVCMP{=pX>@Ho) zMOfY`xl=6{|B@(WMll9Y{}!$f(5S^Yi$6MNyJ{W=6}MahgBz_;ZbKM=3j>UDPn?3L z#VNucDO|Wa5^$MC$HfO=#6X&~WMth0T<}(t5X(TVdhp*$V5FUQV5St(k-7&C4U(?t zg$TI->>d{SzE;TY$`aVa7loT)WPf?!~HuDD?(B zk}<|ii=ZMIXp+2xL-u%zbdwU3ByxNTEfQ6}>Xt%6R&E=$--KaY{AYcY$vm#6o&p}L z$I;2L>gS~2uP?oN9~|;9V#Uk(*$1%T0vV5~qRIA~R|KDX(rfcsaXglm=YwCFv&@@2 V%T&w$83>UGbt>58Qgz(^e*vIjP;&qP delta 5888 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. */ -import { S3 } from "@aws-sdk/client-s3"; import { Readable } from "stream"; import { Storage } from "./Storage"; @@ -29,11 +28,15 @@ const readableToBuffer = (readable: Readable): Promise => }); export class S3Storage implements Storage { + private client: unknown; public constructor( - private client: S3, + private region: string, private bucket: string, private basePath?: string, - ) {} + ) { + const { S3 } = require("@aws-sdk/client-s3"); + this.client = new S3({ region }); + } /** * Always return a string, to ensure consistency. @@ -43,6 +46,8 @@ export class S3Storage implements Storage { } async set(path: string, data: Buffer): Promise { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error await this.client.putObject({ Bucket: this.bucket, Key: `${this.bucketBasePath}${path}`, @@ -52,6 +57,8 @@ export class S3Storage implements Storage { async clone(path: string, newPath: string): Promise { // TODO: does this even work? + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error await this.client.copyObject({ Bucket: this.bucket, CopySource: `/${this.bucket}/${this.bucketBasePath}${path}`, @@ -61,6 +68,8 @@ export class S3Storage implements Storage { async get(path: string): Promise { try { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error const s3Object = await this.client.getObject({ Bucket: this.bucket, Key: `${this.bucketBasePath ?? ""}${path}`, @@ -79,6 +88,8 @@ export class S3Storage implements Storage { } async delete(path: string): Promise { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error await this.client.deleteObject({ Bucket: this.bucket, Key: `${this.bucketBasePath}${path}`, diff --git a/src/cdn/util/Storage.ts b/src/cdn/util/Storage.ts index 6ec1b796a..1184bde8d 100644 --- a/src/cdn/util/Storage.ts +++ b/src/cdn/util/Storage.ts @@ -19,8 +19,7 @@ import { FileStorage } from "./FileStorage"; import path from "path"; import fs from "fs"; -import { S3 } from "@aws-sdk/client-s3"; -import { S3Storage } from "./S3Storage"; +import { red } from "picocolors"; process.cwd(); export interface Storage { @@ -46,6 +45,13 @@ if (process.env.STORAGE_PROVIDER === "file" || !process.env.STORAGE_PROVIDER) { storage = new FileStorage(); } else if (process.env.STORAGE_PROVIDER === "s3") { + try { + require("@aws-sdk/client-s3"); + } catch (e) { + console.error(red(`[CDN] AWS S3 SDK not installed. Please run 'npm install --no-save @aws-sdk/client-s3' to use the S3 storage provider.`)); + process.exit(1); + } + const region = process.env.STORAGE_REGION, bucket = process.env.STORAGE_BUCKET; @@ -67,9 +73,8 @@ if (process.env.STORAGE_PROVIDER === "file" || !process.env.STORAGE_PROVIDER) { location = undefined; } - const client = new S3({ region }); - - storage = new S3Storage(client, bucket, location); + const { S3Storage } = require("S3Storage"); + storage = new S3Storage(region, bucket, location); } export { storage };