bde148f286
* wip * some extra fixes * stuff kinda works? * need to figure out mocks * need to figure out mocks * fix db listener * gqlgen fix * minor gqlgen watch adjustment * lint fixes * delete old codegen file * converting migrations to ESM * getModuleDIrectory * vitest sort of works * added back ts-vitest * resolve gql double load * fixing test timeout configs * TSC lint fix * fix automate tests * moar debugging * debugging * more debugging * codegen update * server works * yargs migrated * chore(server): getting rid of global mocks for Server ESM (#5046) * got rid of email mock * got rid of comment mocks * got rid of multi region mocks * got rid of stripe mock * admin override mock updated * removed final mock * fixing import.meta.resolve calls * another import.meta.resolve fix * added requested test * nyc ESM fix * removed unneeded deps + linting * yarn lock forgot to commit * tryna fix flakyness * email capture util fix * sendEmail fix * fix TSX check * sender transporter fix + CR comments * merge main fix * test fixx * circleci fix * gqlgen bigint fix * error formatter fix * more error formatting improvements * esmloader added to Dockerfile * more dockerfile fixes * bg jobs fix
149 lines
4.1 KiB
TypeScript
149 lines
4.1 KiB
TypeScript
import {
|
|
getS3AccessKey,
|
|
getS3BucketName,
|
|
getS3Endpoint,
|
|
getS3PublicEndpoint,
|
|
getS3Region,
|
|
getS3SecretKey
|
|
} from '@/modules/shared/helpers/envHelper'
|
|
import {
|
|
HeadObjectCommand,
|
|
PutObjectCommand,
|
|
S3Client,
|
|
S3ClientConfig
|
|
} from '@aws-sdk/client-s3'
|
|
import { getSignedUrl as s3GetSignedUrl } from '@aws-sdk/s3-request-presigner'
|
|
import type { Optional } from '@speckle/shared'
|
|
import {
|
|
GetBlobMetadataFromStorage,
|
|
GetSignedUrl
|
|
} from '@/modules/blobstorage/domain/operations'
|
|
|
|
export type GetProjectObjectStorage = (args: {
|
|
projectId: string
|
|
}) => Promise<ObjectStorage>
|
|
|
|
export type GetObjectStorageParams = {
|
|
credentials: {
|
|
accessKeyId: string
|
|
secretAccessKey: string
|
|
}
|
|
endpoint: string
|
|
region: string
|
|
bucket: string
|
|
}
|
|
|
|
export type ObjectStorage = {
|
|
client: S3Client
|
|
bucket: string
|
|
params: GetObjectStorageParams
|
|
}
|
|
|
|
/**
|
|
* Get object storage client
|
|
*/
|
|
export const getObjectStorage = (params: GetObjectStorageParams): ObjectStorage => {
|
|
const { bucket, credentials, endpoint, region } = params
|
|
|
|
const config: S3ClientConfig = {
|
|
credentials,
|
|
endpoint,
|
|
region,
|
|
forcePathStyle: true
|
|
}
|
|
const client = new S3Client(config)
|
|
return { client, bucket, params }
|
|
}
|
|
|
|
let mainObjectStorage: Optional<ObjectStorage> = undefined
|
|
let publicMainObjectStorage: Optional<ObjectStorage> = undefined
|
|
|
|
/**
|
|
* Get main object storage client
|
|
*
|
|
* This is used for connecting the server to the S3 host. Where the S3 host is
|
|
* on the same private network as the server (e.g. in a Docker network),
|
|
* the S3_ENDPOINT can use the private IP or DNS name of the S3 host.
|
|
*
|
|
* S3_PUBLIC_ENDPOINT can be used to connect to the S3 host via the
|
|
* public internet (or localhost network if running locally or testing).
|
|
*/
|
|
export const getMainObjectStorage = (): ObjectStorage => {
|
|
if (mainObjectStorage) return mainObjectStorage
|
|
|
|
const mainParams: GetObjectStorageParams = {
|
|
credentials: {
|
|
accessKeyId: getS3AccessKey(),
|
|
secretAccessKey: getS3SecretKey()
|
|
},
|
|
endpoint: getS3Endpoint(),
|
|
region: getS3Region(),
|
|
bucket: getS3BucketName()
|
|
}
|
|
|
|
mainObjectStorage = getObjectStorage(mainParams)
|
|
return mainObjectStorage
|
|
}
|
|
|
|
/**
|
|
* (Optional) Used to connect to the S3 host via the public endpoint.
|
|
* This is useful for clients that need to access the S3 bucket directly, e.g
|
|
* during testing or when the S3 host is not on the same private network as the server.
|
|
*
|
|
* If `S3_PUBLIC_ENDPOINT` is not set, it will return the same object storage
|
|
* as `getMainObjectStorage`.
|
|
*/
|
|
export const getPublicMainObjectStorage = (): ObjectStorage => {
|
|
if (publicMainObjectStorage) return publicMainObjectStorage
|
|
|
|
const endpoint = getS3PublicEndpoint()
|
|
if (!endpoint) {
|
|
// If no public endpoint is set, return the main object storage
|
|
return getMainObjectStorage()
|
|
}
|
|
|
|
const mainParams: GetObjectStorageParams = {
|
|
credentials: {
|
|
accessKeyId: getS3AccessKey(),
|
|
secretAccessKey: getS3SecretKey()
|
|
},
|
|
endpoint,
|
|
region: getS3Region(),
|
|
bucket: getS3BucketName()
|
|
}
|
|
|
|
publicMainObjectStorage = getObjectStorage(mainParams)
|
|
return publicMainObjectStorage
|
|
}
|
|
|
|
export const getSignedUrlFactory = (deps: {
|
|
objectStorage: ObjectStorage
|
|
}): GetSignedUrl => {
|
|
const { objectStorage } = deps
|
|
const { client, bucket } = objectStorage
|
|
return async (params) => {
|
|
const { objectKey, urlExpiryDurationSeconds } = params
|
|
const command = new PutObjectCommand({ Bucket: bucket, Key: objectKey })
|
|
return s3GetSignedUrl(client, command, { expiresIn: urlExpiryDurationSeconds })
|
|
}
|
|
}
|
|
|
|
export const getBlobMetadataFromStorage = (deps: {
|
|
objectStorage: ObjectStorage
|
|
}): GetBlobMetadataFromStorage => {
|
|
const { objectStorage } = deps
|
|
const { client, bucket } = objectStorage
|
|
|
|
return async (params) => {
|
|
const { objectKey } = params
|
|
|
|
// https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/command/HeadObjectCommand/
|
|
const headObjectCommand = new HeadObjectCommand({ Bucket: bucket, Key: objectKey })
|
|
const metadata = await client.send(headObjectCommand)
|
|
return {
|
|
contentLength: metadata.ContentLength,
|
|
eTag: metadata.ETag
|
|
}
|
|
}
|
|
}
|