feat(bridge): add Bonjour node bridge
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
public enum ClawdisBonjour {
|
||||
// v0: internal-only, subject to rename.
|
||||
public static let bridgeServiceType = "_clawdis-bridge._tcp"
|
||||
public static let bridgeServiceDomain = "local."
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
import Foundation
|
||||
|
||||
public struct BridgeBaseFrame: Codable, Sendable {
|
||||
public let type: String
|
||||
|
||||
public init(type: String) {
|
||||
self.type = type
|
||||
}
|
||||
}
|
||||
|
||||
public struct BridgeInvokeRequest: Codable, Sendable {
|
||||
public let type: String
|
||||
public let id: String
|
||||
public let command: String
|
||||
public let paramsJSON: String?
|
||||
|
||||
public init(type: String = "invoke", id: String, command: String, paramsJSON: String? = nil) {
|
||||
self.type = type
|
||||
self.id = id
|
||||
self.command = command
|
||||
self.paramsJSON = paramsJSON
|
||||
}
|
||||
}
|
||||
|
||||
public struct BridgeInvokeResponse: Codable, Sendable {
|
||||
public let type: String
|
||||
public let id: String
|
||||
public let ok: Bool
|
||||
public let payloadJSON: String?
|
||||
public let error: ClawdisNodeError?
|
||||
|
||||
public init(
|
||||
type: String = "invoke-res",
|
||||
id: String,
|
||||
ok: Bool,
|
||||
payloadJSON: String? = nil,
|
||||
error: ClawdisNodeError? = nil)
|
||||
{
|
||||
self.type = type
|
||||
self.id = id
|
||||
self.ok = ok
|
||||
self.payloadJSON = payloadJSON
|
||||
self.error = error
|
||||
}
|
||||
}
|
||||
|
||||
public struct BridgeEventFrame: Codable, Sendable {
|
||||
public let type: String
|
||||
public let event: String
|
||||
public let payloadJSON: String?
|
||||
|
||||
public init(type: String = "event", event: String, payloadJSON: String? = nil) {
|
||||
self.type = type
|
||||
self.event = event
|
||||
self.payloadJSON = payloadJSON
|
||||
}
|
||||
}
|
||||
|
||||
public struct BridgeHello: Codable, Sendable {
|
||||
public let type: String
|
||||
public let nodeId: String
|
||||
public let displayName: String?
|
||||
public let token: String?
|
||||
public let platform: String?
|
||||
public let version: String?
|
||||
|
||||
public init(
|
||||
type: String = "hello",
|
||||
nodeId: String,
|
||||
displayName: String?,
|
||||
token: String?,
|
||||
platform: String?,
|
||||
version: String?)
|
||||
{
|
||||
self.type = type
|
||||
self.nodeId = nodeId
|
||||
self.displayName = displayName
|
||||
self.token = token
|
||||
self.platform = platform
|
||||
self.version = version
|
||||
}
|
||||
}
|
||||
|
||||
public struct BridgeHelloOk: Codable, Sendable {
|
||||
public let type: String
|
||||
public let serverName: String
|
||||
|
||||
public init(type: String = "hello-ok", serverName: String) {
|
||||
self.type = type
|
||||
self.serverName = serverName
|
||||
}
|
||||
}
|
||||
|
||||
public struct BridgePairRequest: Codable, Sendable {
|
||||
public let type: String
|
||||
public let nodeId: String
|
||||
public let displayName: String?
|
||||
public let platform: String?
|
||||
public let version: String?
|
||||
|
||||
public init(
|
||||
type: String = "pair-request",
|
||||
nodeId: String,
|
||||
displayName: String?,
|
||||
platform: String?,
|
||||
version: String?)
|
||||
{
|
||||
self.type = type
|
||||
self.nodeId = nodeId
|
||||
self.displayName = displayName
|
||||
self.platform = platform
|
||||
self.version = version
|
||||
}
|
||||
}
|
||||
|
||||
public struct BridgePairOk: Codable, Sendable {
|
||||
public let type: String
|
||||
public let token: String
|
||||
|
||||
public init(type: String = "pair-ok", token: String) {
|
||||
self.type = type
|
||||
self.token = token
|
||||
}
|
||||
}
|
||||
|
||||
public struct BridgePing: Codable, Sendable {
|
||||
public let type: String
|
||||
public let id: String
|
||||
|
||||
public init(type: String = "ping", id: String) {
|
||||
self.type = type
|
||||
self.id = id
|
||||
}
|
||||
}
|
||||
|
||||
public struct BridgePong: Codable, Sendable {
|
||||
public let type: String
|
||||
public let id: String
|
||||
|
||||
public init(type: String = "pong", id: String) {
|
||||
self.type = type
|
||||
self.id = id
|
||||
}
|
||||
}
|
||||
|
||||
public struct BridgeErrorFrame: Codable, Sendable {
|
||||
public let type: String
|
||||
public let code: String
|
||||
public let message: String
|
||||
|
||||
public init(type: String = "error", code: String, message: String) {
|
||||
self.type = type
|
||||
self.code = code
|
||||
self.message = message
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import Foundation
|
||||
|
||||
public enum ClawdisNodeErrorCode: String, Codable, Sendable {
|
||||
case notPaired = "NOT_PAIRED"
|
||||
case unauthorized = "UNAUTHORIZED"
|
||||
case backgroundUnavailable = "NODE_BACKGROUND_UNAVAILABLE"
|
||||
case invalidRequest = "INVALID_REQUEST"
|
||||
case unavailable = "UNAVAILABLE"
|
||||
}
|
||||
|
||||
public struct ClawdisNodeError: Error, Codable, Sendable, Equatable {
|
||||
public var code: ClawdisNodeErrorCode
|
||||
public var message: String
|
||||
public var retryable: Bool?
|
||||
public var retryAfterMs: Int?
|
||||
|
||||
public init(
|
||||
code: ClawdisNodeErrorCode,
|
||||
message: String,
|
||||
retryable: Bool? = nil,
|
||||
retryAfterMs: Int? = nil)
|
||||
{
|
||||
self.code = code
|
||||
self.message = message
|
||||
self.retryable = retryable
|
||||
self.retryAfterMs = retryAfterMs
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import Foundation
|
||||
|
||||
public enum ClawdisScreenMode: String, Codable, Sendable {
|
||||
case canvas
|
||||
case web
|
||||
}
|
||||
|
||||
public enum ClawdisScreenCommand: String, Codable, Sendable {
|
||||
case show = "screen.show"
|
||||
case hide = "screen.hide"
|
||||
case setMode = "screen.setMode"
|
||||
case navigate = "screen.navigate"
|
||||
case evalJS = "screen.eval"
|
||||
case snapshot = "screen.snapshot"
|
||||
}
|
||||
|
||||
public struct ClawdisScreenNavigateParams: Codable, Sendable, Equatable {
|
||||
public var url: String
|
||||
|
||||
public init(url: String) {
|
||||
self.url = url
|
||||
}
|
||||
}
|
||||
|
||||
public struct ClawdisScreenSetModeParams: Codable, Sendable, Equatable {
|
||||
public var mode: ClawdisScreenMode
|
||||
|
||||
public init(mode: ClawdisScreenMode) {
|
||||
self.mode = mode
|
||||
}
|
||||
}
|
||||
|
||||
public struct ClawdisScreenEvalParams: Codable, Sendable, Equatable {
|
||||
public var javaScript: String
|
||||
|
||||
public init(javaScript: String) {
|
||||
self.javaScript = javaScript
|
||||
}
|
||||
}
|
||||
|
||||
public enum ClawdisSnapshotFormat: String, Codable, Sendable {
|
||||
case png
|
||||
case jpeg
|
||||
}
|
||||
|
||||
public struct ClawdisScreenSnapshotParams: Codable, Sendable, Equatable {
|
||||
public var maxWidth: Int?
|
||||
public var quality: Double?
|
||||
public var format: ClawdisSnapshotFormat?
|
||||
|
||||
public init(maxWidth: Int? = nil, quality: Double? = nil, format: ClawdisSnapshotFormat? = nil) {
|
||||
self.maxWidth = maxWidth
|
||||
self.quality = quality
|
||||
self.format = format
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import Foundation
|
||||
|
||||
public enum ClawdisNodeStorage {
|
||||
public static func appSupportDir() throws -> URL {
|
||||
let base = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first
|
||||
guard let base else {
|
||||
throw NSError(domain: "ClawdisNodeStorage", code: 1, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Application Support directory unavailable",
|
||||
])
|
||||
}
|
||||
return base.appendingPathComponent("Clawdis", isDirectory: true)
|
||||
}
|
||||
|
||||
public static func canvasRoot(sessionKey: String) throws -> URL {
|
||||
let root = try appSupportDir().appendingPathComponent("canvas", isDirectory: true)
|
||||
let safe = sessionKey.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let session = safe.isEmpty ? "main" : safe
|
||||
return root.appendingPathComponent(session, isDirectory: true)
|
||||
}
|
||||
|
||||
public static func cachesDir() throws -> URL {
|
||||
let base = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first
|
||||
guard let base else {
|
||||
throw NSError(domain: "ClawdisNodeStorage", code: 2, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Caches directory unavailable",
|
||||
])
|
||||
}
|
||||
return base.appendingPathComponent("Clawdis", isDirectory: true)
|
||||
}
|
||||
|
||||
public static func canvasSnapshotsRoot(sessionKey: String) throws -> URL {
|
||||
let root = try cachesDir().appendingPathComponent("canvas-snapshots", isDirectory: true)
|
||||
let safe = sessionKey.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let session = safe.isEmpty ? "main" : safe
|
||||
return root.appendingPathComponent(session, isDirectory: true)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user