Skip to main content

Installation

Add InsForge to your Swift Package Manager dependencies:
dependencies: [
    .package(url: "https://github.com/insforge/insforge-swift.git", from: "0.0.7")
]
import InsForge

let insforge = InsForgeClient(
    baseURL: URL(string: "https://your-app.insforge.app")!,
    anonKey: "your-anon-key"
)

Enable Logging (Optional)

For debugging, you can configure the SDK log level and destination:
let options = InsForgeClientOptions(
    global: .init(
        logLevel: .debug,
        logDestination: .osLog,
        logSubsystem: "com.example.MyApp"
    )
)

let insforge = InsForgeClient(
    baseURL: URL(string: "https://your-app.insforge.app")!,
    anonKey: "your-anon-key",
    options: options
)
Log Levels:
LevelDescription
.traceMost verbose, includes all internal details
.debugDetailed information for debugging
.infoGeneral operational information (default)
.warningWarnings that don’t prevent operation
.errorErrors that affect functionality
.criticalCritical failures
Log Destinations:
DestinationDescription
.consoleStandard output (print)
.osLogApple’s unified logging system (recommended for iOS/macOS)
.noneDisable logging
.customProvide your own LogHandler factory
Use .info or .error in production to avoid exposing sensitive data in logs.

from()

Get a file API reference for a bucket.

Example

let bucket = insforge.storage.from("images")

Bucket Operations

createBucket()

Creates a new storage bucket.
// Create a public bucket
try await insforge.storage.createBucket("avatars")

// Create a private bucket
try await insforge.storage.createBucket(
    "documents",
    options: BucketOptions(isPublic: false)
)

listBuckets()

List all bucket names.
let buckets = try await insforge.storage.listBuckets()
// ["avatars", "documents", "uploads"]

updateBucket()

Update a bucket’s visibility.
try await insforge.storage.updateBucket(
    "documents",
    options: BucketOptions(isPublic: true)
)

deleteBucket()

Delete a bucket.
try await insforge.storage.deleteBucket("old-bucket")

upload()

Upload a file to the bucket.

Parameters

  • path (String) - The object key/path for the file
  • data (Data) - File data to upload
  • options (FileOptions, optional) - Upload options including contentType

Examples

// Upload with specific path
let imageData = UIImage(named: "photo")?.jpegData(compressionQuality: 0.8)
let file = try await insforge.storage
    .from("images")
    .upload(
        path: "posts/post-123/cover.jpg",
        data: imageData!,
        options: FileOptions(contentType: "image/jpeg")
    )

print("Uploaded: \(file.url)")
print("Key: \(file.key)")

// Upload from file URL
let fileURL = URL(fileURLWithPath: "/path/to/document.pdf")
let file = try await insforge.storage
    .from("documents")
    .upload(
        path: "reports/annual-2024.pdf",
        fileURL: fileURL
    )

// Upload with auto-generated key
let file = try await insforge.storage
    .from("uploads")
    .upload(
        data: imageData!,
        fileName: "profile.jpg",
        options: FileOptions(contentType: "image/jpeg")
    )

download()

Download a file as Data.

Example

// Download file
let data = try await insforge.storage
    .from("images")
    .download(path: "posts/post-123/cover.jpg")

// Convert to UIImage
if let image = UIImage(data: data) {
    imageView.image = image
}

list()

List files in a bucket.

Parameters

  • options (ListOptions, optional) - Options including prefix, limit, offset

Examples

// List all files
let files = try await insforge.storage
    .from("images")
    .list()

// List with prefix filter
let userFiles = try await insforge.storage
    .from("images")
    .list(options: ListOptions(prefix: "users/", limit: 50))

// Shorthand with prefix
let files = try await insforge.storage
    .from("images")
    .list(prefix: "posts/", limit: 20, offset: 0)

// Iterate results
for file in files {
    print("Key: \(file.key), Size: \(file.size)")
}

delete()

Delete a file from storage.

Example

// Delete a file
try await insforge.storage
    .from("images")
    .delete(path: "posts/post-123/cover.jpg")

// Delete with database cleanup
let posts: [Post] = try await insforge.database
    .from("posts")
    .select("id, image_key")
    .eq("id", value: "post-123")
    .execute()

if let post = posts.first, let imageKey = post.imageKey {
    // Delete from storage
    try await insforge.storage
        .from("images")
        .delete(path: imageKey)

    // Clear database reference
    struct PostUpdate: Codable {
        let imageUrl: String?
        let imageKey: String?
    }

    let _: [Post] = try await insforge.database
        .from("posts")
        .eq("id", value: "post-123")
        .update(PostUpdate(imageUrl: nil, imageKey: nil))
}

getPublicURL()

Get a public URL for a file in a public bucket.

Example

let url = insforge.storage
    .from("images")
    .getPublicURL(path: "posts/post-123/cover.jpg")

print("Public URL: \(url)")

Upload Strategy

Get upload strategy for large files (direct or presigned URL).

getUploadStrategy()

let strategy = try await insforge.storage
    .from("videos")
    .getUploadStrategy(
        filename: "large-video.mp4",
        contentType: "video/mp4",
        size: 104857600  // 100MB
    )

if strategy.method == "presigned" {
    // Upload directly to S3 using presigned URL
    print("Upload URL: \(strategy.uploadUrl)")
    print("Key: \(strategy.key)")

    // After uploading to presigned URL, confirm the upload
    if strategy.confirmRequired {
        let file = try await insforge.storage
            .from("videos")
            .confirmUpload(
                path: strategy.key,
                size: 104857600,
                contentType: "video/mp4"
            )
    }
}

confirmUpload()

Confirm a presigned upload after uploading directly to S3.
let file = try await insforge.storage
    .from("videos")
    .confirmUpload(
        path: "videos/large-video.mp4",
        size: 104857600,
        contentType: "video/mp4",
        etag: "\"abc123\""  // Optional S3 ETag
    )

Download Strategy

Get download strategy for private files (direct or presigned URL).

getDownloadStrategy()

let strategy = try await insforge.storage
    .from("documents")
    .getDownloadStrategy(
        path: "private/confidential.pdf",
        expiresIn: 3600  // URL expires in 1 hour
    )

if strategy.method == "presigned" {
    // Use presigned URL to download
    print("Download URL: \(strategy.url)")
    print("Expires: \(strategy.expiresAt ?? "N/A")")
}

SwiftUI Integration

Image Picker with Upload

import SwiftUI
import PhotosUI

struct ImageUploadView: View {
    @State private var selectedItem: PhotosPickerItem?
    @State private var uploadedUrl: String?
    @State private var isUploading = false

    var body: some View {
        VStack {
            PhotosPicker(selection: $selectedItem, matching: .images) {
                Label("Select Photo", systemImage: "photo")
            }

            if isUploading {
                ProgressView("Uploading...")
            }

            if let url = uploadedUrl {
                AsyncImage(url: URL(string: url)) { image in
                    image.resizable().scaledToFit()
                } placeholder: {
                    ProgressView()
                }
                .frame(height: 200)
            }
        }
        .onChange(of: selectedItem) { newItem in
            Task {
                await uploadPhoto(item: newItem)
            }
        }
    }

    func uploadPhoto(item: PhotosPickerItem?) async {
        guard let item = item,
              let data = try? await item.loadTransferable(type: Data.self) else {
            return
        }

        isUploading = true

        do {
            let file = try await insforge.storage
                .from("photos")
                .upload(
                    data: data,
                    fileName: "photo.jpg",
                    options: FileOptions(contentType: "image/jpeg")
                )

            uploadedUrl = file.url
        } catch {
            print("Upload failed: \(error)")
        }

        isUploading = false
    }
}

Async Image with InsForge

struct InsForgeImage: View {
    let bucket: String
    let path: String

    @State private var imageData: Data?

    var body: some View {
        Group {
            if let data = imageData, let uiImage = UIImage(data: data) {
                Image(uiImage: uiImage)
                    .resizable()
                    .scaledToFit()
            } else {
                ProgressView()
            }
        }
        .task {
            await loadImage()
        }
    }

    func loadImage() async {
        do {
            imageData = try await insforge.storage
                .from(bucket)
                .download(path: path)
        } catch {
            print("Failed to load image: \(error)")
        }
    }
}

Options Reference

FileOptions

Options for file upload operations.
public struct FileOptions {
    /// The Content-Type header value (auto-inferred if not specified)
    var contentType: String?

    /// Optional extra headers for the request
    var headers: [String: String]?
}

BucketOptions

Options for bucket creation/update.
public struct BucketOptions {
    /// Whether the bucket is publicly accessible (default: true)
    var isPublic: Bool
}

ListOptions

Options for listing files.
public struct ListOptions {
    /// Filter objects by key prefix
    var prefix: String?

    /// Maximum number of results (1-1000, default: 100)
    var limit: Int

    /// Offset for pagination (default: 0)
    var offset: Int
}

StoredFile Model

The response model for storage operations.
public struct StoredFile {
    let bucket: String      // Bucket name
    let key: String         // Object key/path
    let size: Int           // File size in bytes
    let mimeType: String?   // MIME type
    let uploadedAt: Date    // Upload timestamp
    let url: String         // Public or signed URL
}