import io from botocore.exceptions import ClientError class GarageClient: def __init__(self, client, bucket: str): self._client = client self._bucket = bucket def list_objects(self, prefix: str) -> list[dict]: paginator = self._client.get_paginator("list_objects_v2") result = [] for page in paginator.paginate(Bucket=self._bucket, Prefix=prefix, Delimiter="/"): for common_prefix in page.get("CommonPrefixes", []): result.append({ "key": common_prefix["Prefix"], "size": None, "is_dir": True, "modifiedAt": None, }) for obj in page.get("Contents", []): result.append({ "key": obj["Key"], "size": obj["Size"], "is_dir": obj["Key"].endswith("/"), "modifiedAt": obj["LastModified"].isoformat() if obj.get("LastModified") else None, }) return result def get_object(self, key: str) -> bytes: try: response = self._client.get_object(Bucket=self._bucket, Key=key) except ClientError as exc: if exc.response.get("Error", {}).get("Code") in ("NoSuchKey", "404"): raise FileNotFoundError(key) from exc raise return response["Body"].read() def put_object(self, key: str, data: bytes, content_type: str) -> None: self._client.put_object( Bucket=self._bucket, Key=key, Body=io.BytesIO(data), ContentLength=len(data), ContentType=content_type, ) def delete_object(self, key: str) -> None: self._client.delete_object(Bucket=self._bucket, Key=key)