{"version":3,"file":"metadataManager.mjs","names":["client: S3","bucket: string","shouldUseExpirationTags: () => boolean","generateCompleteTag: (value: 'false' | 'true') => string | undefined"],"sources":["../../../../src/tus/stores/s3/metadataManager.ts"],"sourcesContent":["import { TUS_RESUMABLE, Upload } from '@tus/utils'\n\nimport { useErrorHandler } from '../../../hooks/useErrorHandler'\nimport { MediaCloudLogs } from '../../../types/errors'\n\nimport type { S3 } from '@aws-sdk/client-s3'\nimport type { TusUploadMetadata } from '../../../types'\n\ntype GenerateInfoKeyArgs = {\n  id: string\n}\n\ntype GeneratePartKeyArgs = {\n  id: string\n  prefix?: string\n  isIncomplete?: boolean\n}\n\ntype GetMetadataArgs = {\n  id: string\n}\n\ntype SaveMetadataArgs = {\n  upload: Upload\n  uploadId: string\n}\n\ntype CompleteMetadataArgs = {\n  upload: Upload\n}\n\nconst { log } = useErrorHandler()\n\nexport class S3MetadataManager {\n  constructor(\n    private client: S3,\n    private bucket: string,\n    private shouldUseExpirationTags: () => boolean,\n    private generateCompleteTag: (value: 'false' | 'true') => string | undefined\n  ) {}\n  /**\n   * Generates the S3 key for metadata info files\n   * @param args - The function arguments\n   * @param args.id - The file ID\n   * @returns The S3 key for the metadata file\n   */\n  generateInfoKey(args: GenerateInfoKeyArgs): string {\n    return `${args.id}.info`\n  }\n\n  /**\n   * Generates the S3 key for part files\n   * @param args - The function arguments\n   * @param args.id - The file ID\n   * @param args.prefix - Path prefix for nested media items\n   * @param args.isIncomplete - Whether this is an incomplete part\n   * @returns The S3 key for the part file\n   */\n  generatePartKey(args: GeneratePartKeyArgs): string {\n    const { id, prefix, isIncomplete = false } = args\n    let key = id\n\n    if (prefix) {\n      key = `${prefix}/${key}`\n    }\n\n    if (isIncomplete) {\n      key += '.part'\n    }\n\n    // TODO: introduce ObjectPrefixing for parts and incomplete parts\n    // ObjectPrefix is prepended to the name of each S3 object that is created\n    // to store uploaded files. It can be used to create a pseudo-directory\n    // structure in the bucket, e.g. \"path/to/my/uploads\".\n    return key\n  }\n\n  /**\n   * Retrieves upload metadata previously saved in `${file_id}.info`.\n   * Always fetches fresh data from S3 to ensure correctness.\n   * @param args - The function arguments\n   * @param args.id - The file ID to retrieve metadata for\n   * @returns Promise that resolves to the upload metadata\n   */\n  async getMetadata(args: GetMetadataArgs): Promise<TusUploadMetadata> {\n    const { id } = args\n\n    const { Body, Metadata } = await this.client.getObject({\n      Bucket: this.bucket,\n      Key: this.generateInfoKey({ id }),\n    })\n\n    const file = JSON.parse((await Body?.transformToString()) as string)\n\n    const parsedSize =\n      file.size === undefined || file.size === null\n        ? undefined\n        : Number(file.size)\n\n    const metadata: TusUploadMetadata = {\n      file: new Upload({\n        id,\n        creation_date: file.creation_date,\n        metadata: file.metadata,\n        offset: Number.parseInt(file.offset, 10),\n        size: Number.isFinite(parsedSize) ? parsedSize : undefined,\n        storage: file.storage,\n      }),\n      'tus-version': Metadata?.['tus-version'] as string,\n      'upload-id': (Metadata?.['upload-id'] || file['upload-id']) as string,\n    }\n\n    return metadata\n  }\n\n  /**\n   * Saves upload metadata to a `${file_id}.info` file on S3.\n   * The upload-id is stored in the S3 object metadata.\n   * @param args - The function arguments\n   * @param args.upload - The upload object containing metadata\n   * @param args.uploadId - The upload ID for the multipart upload\n   * @returns Promise that resolves when metadata is saved\n   */\n  async saveMetadata(args: SaveMetadataArgs): Promise<void> {\n    const { upload, uploadId } = args\n    log(MediaCloudLogs.S3_STORE_METADATA_SAVING)\n\n    await this.client.putObject({\n      Body: JSON.stringify(upload),\n      Bucket: this.bucket,\n      Key: this.generateInfoKey({ id: upload.id }),\n      Metadata: {\n        'tus-version': TUS_RESUMABLE,\n        'upload-id': uploadId,\n      },\n      Tagging: this.generateCompleteTag('false'),\n    })\n    log(MediaCloudLogs.S3_STORE_METADATA_SAVED)\n  }\n\n  /**\n   * Completes metadata by updating it with completion tags\n   * @param args - The function arguments\n   * @param args.upload - The completed upload object\n   * @returns Promise that resolves when metadata is updated\n   */\n  async completeMetadata(args: CompleteMetadataArgs): Promise<void> {\n    const { upload } = args\n\n    if (!this.shouldUseExpirationTags()) {\n      return\n    }\n\n    const metadata = await this.getMetadata({ id: upload.id })\n    const { 'upload-id': uploadId } = metadata\n\n    await this.client.putObject({\n      Body: JSON.stringify(upload),\n      Bucket: this.bucket,\n      Key: this.generateInfoKey({ id: upload.id }),\n      Metadata: {\n        'tus-version': TUS_RESUMABLE,\n        'upload-id': uploadId,\n      },\n      Tagging: this.generateCompleteTag('true'),\n    })\n  }\n}\n"],"mappings":";;;;;AA+BA,MAAM,EAAE,QAAQ,iBAAiB;AAEjC,IAAa,oBAAb,MAA+B;CAC7B,YACE,AAAQA,QACR,AAAQC,QACR,AAAQC,yBACR,AAAQC,qBACR;EAJQ;EACA;EACA;EACA;;;;;;;;CAQV,gBAAgB,MAAmC;AACjD,SAAO,GAAG,KAAK,GAAG;;;;;;;;;;CAWpB,gBAAgB,MAAmC;EACjD,MAAM,EAAE,IAAI,QAAQ,eAAe,UAAU;EAC7C,IAAI,MAAM;AAEV,MAAI,OACF,OAAM,GAAG,OAAO,GAAG;AAGrB,MAAI,aACF,QAAO;AAOT,SAAO;;;;;;;;;CAUT,MAAM,YAAY,MAAmD;EACnE,MAAM,EAAE,OAAO;EAEf,MAAM,EAAE,MAAM,aAAa,MAAM,KAAK,OAAO,UAAU;GACrD,QAAQ,KAAK;GACb,KAAK,KAAK,gBAAgB,EAAE,IAAI,CAAC;GAClC,CAAC;EAEF,MAAM,OAAO,KAAK,MAAO,MAAM,MAAM,mBAAmB,CAAY;EAEpE,MAAM,aACJ,KAAK,SAAS,UAAa,KAAK,SAAS,OACrC,SACA,OAAO,KAAK,KAAK;AAevB,SAboC;GAClC,MAAM,IAAI,OAAO;IACf;IACA,eAAe,KAAK;IACpB,UAAU,KAAK;IACf,QAAQ,OAAO,SAAS,KAAK,QAAQ,GAAG;IACxC,MAAM,OAAO,SAAS,WAAW,GAAG,aAAa;IACjD,SAAS,KAAK;IACf,CAAC;GACF,eAAe,WAAW;GAC1B,aAAc,WAAW,gBAAgB,KAAK;GAC/C;;;;;;;;;;CAaH,MAAM,aAAa,MAAuC;EACxD,MAAM,EAAE,QAAQ,aAAa;AAC7B,MAAI,eAAe,yBAAyB;AAE5C,QAAM,KAAK,OAAO,UAAU;GAC1B,MAAM,KAAK,UAAU,OAAO;GAC5B,QAAQ,KAAK;GACb,KAAK,KAAK,gBAAgB,EAAE,IAAI,OAAO,IAAI,CAAC;GAC5C,UAAU;IACR,eAAe;IACf,aAAa;IACd;GACD,SAAS,KAAK,oBAAoB,QAAQ;GAC3C,CAAC;AACF,MAAI,eAAe,wBAAwB;;;;;;;;CAS7C,MAAM,iBAAiB,MAA2C;EAChE,MAAM,EAAE,WAAW;AAEnB,MAAI,CAAC,KAAK,yBAAyB,CACjC;EAIF,MAAM,EAAE,aAAa,aADJ,MAAM,KAAK,YAAY,EAAE,IAAI,OAAO,IAAI,CAAC;AAG1D,QAAM,KAAK,OAAO,UAAU;GAC1B,MAAM,KAAK,UAAU,OAAO;GAC5B,QAAQ,KAAK;GACb,KAAK,KAAK,gBAAgB,EAAE,IAAI,OAAO,IAAI,CAAC;GAC5C,UAAU;IACR,eAAe;IACf,aAAa;IACd;GACD,SAAS,KAAK,oBAAoB,OAAO;GAC1C,CAAC"}