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.9")
]
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.

connect()

Establish a WebSocket connection to the realtime server.

Example

do {
    try await insforge.realtime.connect()
    print("Connected to realtime server")
} catch {
    print("Connection failed: \(error)")
}

subscribe()

Subscribe to a channel to receive messages.

Parameters

  • to (String) - Channel name (e.g., “orders:123”, “chat:room-1”)
  • onMessage (Closure) - Callback for receiving messages

Example

await insforge.realtime.subscribe(to: "chat:lobby") { message in
    print("Event: \(message.eventName ?? "")")
    print("Channel: \(message.channelName ?? "")")

    if let payload = message.payload {
        print("Data: \(payload)")
    }

    if let senderId = message.senderId {
        print("From: \(senderId)")
    }
}

unsubscribe()

Unsubscribe from a channel.

Example

await insforge.realtime.unsubscribe(from: "chat:lobby")

publish()

Publish a message to a channel.

Parameters

  • to (String) - Channel name
  • event (String) - Event name
  • payload ([String: Any]) - Message payload as dictionary

Example

try await insforge.realtime.publish(
    to: "chat:lobby",
    event: "message.new",
    payload: [
        "text": "Hello everyone!",
        "author": currentUser.name,
        "timestamp": Date().timeIntervalSince1970
    ]
)

disconnect()

Disconnect from the realtime server.

Example

await insforge.realtime.disconnect()

Channel API

The high-level Channel API provides a more structured way to work with realtime features including broadcast messages and Postgres changes.

channel()

Get or create a channel instance.
let channel = await insforge.realtime.channel("chat:lobby")

removeChannel()

Remove a channel.
await insforge.realtime.removeChannel("chat:lobby")

RealtimeChannel

subscribe()

Subscribe to the channel. Must be called before receiving messages.
let channel = await insforge.realtime.channel("chat:lobby")
try await channel.subscribe()

unsubscribe()

Unsubscribe from the channel.
await channel.unsubscribe()

Broadcast Messages

Listening for Broadcasts

Use broadcast(event:) to receive broadcast messages as an AsyncStream.
let channel = await insforge.realtime.channel("chat:lobby")
try await channel.subscribe()

// Listen for specific event
for await message in await channel.broadcast(event: "new_message") {
    print("Event: \(message.event)")
    print("Payload: \(message.payload)")

    // Decode to typed struct
    if let chatMessage = try? message.decode(ChatMessage.self) {
        print("Message: \(chatMessage.text)")
    }
}

// Listen for all events (wildcard)
for await message in await channel.broadcast(event: "*") {
    print("Received: \(message.event)")
}

Sending Broadcasts

Send broadcast messages with typed or dictionary payloads.
// With Encodable struct
struct ChatMessage: Codable {
    let text: String
    let author: String
}

try await channel.broadcast(
    event: "new_message",
    message: ChatMessage(text: "Hello!", author: "John")
)

// With dictionary
try await channel.broadcast(
    event: "typing",
    message: ["userId": userId, "isTyping": true]
)

Postgres Changes

Listen for real-time database changes using typed actions.

Action Types

  • InsertAction<T> - New record inserted
  • UpdateAction<T> - Record updated (includes record and oldRecord)
  • DeleteAction<T> - Record deleted (includes oldRecord)
  • SelectAction<T> - Record selected
  • AnyAction<T> - Any of the above

Listening for Changes

struct Todo: Codable, Sendable {
    let id: String
    let title: String
    let completed: Bool
}

let channel = await insforge.realtime.channel("db-changes")
try await channel.subscribe()

// Listen for inserts only
for await action in await channel.postgresChange(
    InsertAction<Todo>.self,
    schema: "public",
    table: "todos"
) {
    print("New todo: \(action.record.title)")
}

// Listen for any change
for await action in await channel.postgresChange(
    AnyAction<Todo>.self,
    schema: "public",
    table: "todos"
) {
    switch action {
    case .insert(let insert):
        print("Inserted: \(insert.record.title)")
    case .update(let update):
        print("Updated: \(update.record.title)")
    case .delete(let delete):
        print("Deleted: \(delete.oldRecord.title)")
    case .select(let select):
        print("Selected: \(select.record.title)")
    }
}