# S3 Client

Interact with Amazon S3 buckets with full type safety and runtime validation.

## Methods

| Method                                                  | Description              |
| ------------------------------------------------------- | ------------------------ |
| `listBuckets(schema, metadata?)`                        | List all buckets         |
| `listObjects(bucket, schema, options?, metadata?)`      | List objects in a bucket |
| `getObject(bucket, path, schema, options?, metadata?)`  | Get an object            |
| `deleteObject(bucket, path, metadata?)`                 | Delete an object         |
| `uploadObject(bucket, path, body, metadata?)`           | Upload a single object   |
| `uploadMultipleObjects(bucket, fileObjects, metadata?)` | Upload multiple objects  |
| `generatePresignedUrl(bucket, path, schema, metadata?)` | Generate a presigned URL |

## Usage

### List Objects in a Bucket

```typescript
import { api, z, s3 } from "@superblocksteam/sdk-api";

// Integration ID from the integrations panel
const PROD_S3 = "a1b2c3d4-5678-90ab-cdef-s300000001";

export default api({
  name: "ListBucketObjects",
  integrations: {
    storage: s3(PROD_S3),
  },
  input: z.object({
    bucket: z.string(),
    prefix: z.string().optional(),
  }),
  output: z.object({
    files: z.array(
      z.object({
        Key: z.string(),
        Size: z.number(),
      }),
    ),
  }),
  async run(ctx, { bucket, prefix }) {
    const files = await ctx.integrations.storage.listObjects(
      bucket,
      z.array(z.object({ Key: z.string(), Size: z.number() })),
      prefix ? { prefix } : undefined,
    );

    return { files };
  },
});
```

### Get Object Content

```typescript
// For text files
const content = await ctx.integrations.storage.getObject(
  "my-bucket",
  "data/file.txt",
  z.string(),
);

// For JSON files
const data = await ctx.integrations.storage.getObject(
  "my-bucket",
  "data/config.json",
  z.object({ name: z.string(), value: z.number() }),
);
```

### Upload Object

```typescript
await ctx.integrations.storage.uploadObject(
  "my-bucket",
  "uploads/file.txt",
  "File content here",
);
```

### Delete Object

```typescript
await ctx.integrations.storage.deleteObject("my-bucket", "uploads/file.txt");
```

### List Buckets

```typescript
const buckets = await ctx.integrations.storage.listBuckets(
  z.array(z.object({ Name: z.string(), CreationDate: z.string() })),
);
```

### Generate Presigned URL

```typescript
const url = await ctx.integrations.storage.generatePresignedUrl(
  "my-bucket",
  "private/document.pdf",
  z.string(),
);
```

## Trace Metadata

All methods accept an optional `metadata` parameter as the last argument for diagnostics labeling. See the [root SDK README](../../../README.md#trace-metadata) for details.

## Error Handling

```typescript
import {
  RestApiValidationError,
  IntegrationError,
} from "@superblocksteam/sdk-api";

try {
  const content = await ctx.integrations.storage.getObject(
    "my-bucket",
    "file.txt",
    z.string(),
  );
} catch (error) {
  if (error instanceof RestApiValidationError) {
    console.error("Validation failed:", error.details.zodError);
  } else if (error instanceof IntegrationError) {
    console.error("S3 error:", error.message);
  }
}
```

## API Reference

- [Amazon S3 Documentation](https://docs.aws.amazon.com/s3/)
