```swift title="Swift"
import Kreuzberg
import os.lock

final class StatefulPlugin: PostProcessor {
    private var lock = NSLock()
    private var callCount: Int = 0
    private var cache: [String: String] = [:]

    func name() -> String {
        "stateful-plugin"
    }

    func version() -> String {
        "1.0.0"
    }

    func processingStage() -> String {
        "middle"
    }

    func priority() -> Int32 {
        50
    }

    func process(result: ExtractionResult, config: ExtractionConfig) -> String {
        lock.lock()
        defer { lock.unlock() }

        callCount += 1
        cache["last_mime"] = result.mimeType()
        cache["call_count"] = String(callCount)

        return "{\"ok\": null}"
    }

    func shouldProcess(result: ExtractionResult, config: ExtractionConfig) -> Bool {
        true
    }

    func estimatedDurationMs(result: ExtractionResult) -> UInt64 {
        1  // Minimal overhead
    }

    func initialize() -> String {
        lock.lock()
        defer { lock.unlock() }
        callCount = 0
        cache.removeAll()
        return "{\"ok\": null}"
    }

    func shutdown() -> String {
        lock.lock()
        defer { lock.unlock() }
        let finalCount = callCount
        cache.removeAll()
        let message = "Processed \(finalCount) extractions"
        print(message)
        return "{\"ok\": null}"
    }
}

let plugin = StatefulPlugin()
try Kreuzberg.registerPostProcessor(plugin)
```
