> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nonefivem.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Storage

> Upload and manage files with the NoCloud Storage API

The Storage API allows you to upload files directly to NoCloud's serverless storage and manage them programmatically.

## Upload a File

Upload files using various input types:

```typescript theme={null}
// From File or Blob
const file = new File(["content"], "file.txt", { type: "text/plain" });
const { id, url } = await cloud.storage.upload(file);

// From ArrayBuffer
const buffer = new TextEncoder().encode("Hello!").buffer;
const { id, url } = await cloud.storage.upload(buffer);

// From base64 string (auto-detects MIME type)
const base64 = "data:image/png;base64,iVBORw0KGgo...";
const { id, url } = await cloud.storage.upload(base64);

// With metadata
const { id, url } = await cloud.storage.upload(file, {
  userId: "123",
  category: "avatars",
  isPublic: true
});
```

### Response

```typescript theme={null}
interface UploadResponse {
  id: string; // Unique identifier for the uploaded file
  url: string; // Public CDN URL to access the file
}
```

## Upload a Stream

For large files, use streaming uploads:

```typescript theme={null}
const stream = getReadableStream(); // Your ReadableStream
const { id, url } = await cloud.storage.uploadStream(
  stream,
  "video/mp4", // Content type
  fileSize // Content length in bytes
);
```

### Parameters

| Parameter       | Type             | Description                  |
| --------------- | ---------------- | ---------------------------- |
| `stream`        | `ReadableStream` | The stream to upload         |
| `contentType`   | `string`         | MIME type of the content     |
| `contentLength` | `number`         | Size of the content in bytes |
| `metadata`      | `FileMetadata`   | Optional metadata object     |

## Generate Signed URL

Get a pre-signed URL for direct uploads (useful for client-side uploads):

```typescript theme={null}
const signedUrl = await cloud.storage.generateSignedUrl(
  "image/png", // Content type
  1024, // File size in bytes
  { userId: "123" } // Optional metadata
);
```

### Response

```typescript theme={null}
interface SignedUrlResponse {
  url: string; // The signed URL for uploading
  expiresAt: string; // Expiration time (ISO 8601)
  mediaId: string; // The ID the file will have after upload
  mediaUrl: string; // The public URL after upload
}
```

### Using a Signed URL

After getting a signed URL, you can upload directly:

```typescript theme={null}
const { url, mediaId, mediaUrl } = await cloud.storage.generateSignedUrl(
  "image/png",
  fileSize
);

// Upload directly to the signed URL
await fetch(url, {
  method: "PUT",
  headers: { "Content-Length": fileSize.toString() },
  body: fileData
});

// File is now available at mediaUrl
console.log(`Uploaded: ${mediaUrl}`);
```

## Delete Files

Delete a single file or multiple files:

```typescript theme={null}
// Delete a single file
await cloud.storage.delete(mediaId);

// Delete multiple files (batched automatically, max 100 per batch)
await cloud.storage.delete([mediaId1, mediaId2, mediaId3]);
```

<Note>
  When deleting multiple files, the SDK automatically batches requests in groups
  of 100 for optimal performance.
</Note>

## Supported Body Types

| Type          | Description          |
| ------------- | -------------------- |
| `File`        | Browser File object  |
| `Blob`        | Binary data          |
| `ArrayBuffer` | Raw binary buffer    |
| `string`      | Base64 or plain text |

<Note>
  Base64 strings with data URLs (`data:image/png;base64,...`) or raw base64 are
  automatically detected and the MIME type is inferred.
</Note>

## Metadata

You can attach custom metadata to your uploads:

```typescript theme={null}
type FileMetadata = Record<string, string | number | boolean>;

// Example
const { id, url } = await cloud.storage.upload(file, {
  userId: "user_123",
  uploadedAt: Date.now(),
  isAvatar: true
});
```

Metadata is stored with the file and can be used for organization and filtering.
