Files
luma/Sources/LumaCore/Services/CodeShareService.swift
Ole André Vadla Ravnås 3010f789db Extract TracerConfig, CodeShareConfig, services
Split UI-coupled types into portable data (LumaCore) and
platform-specific editor profiles (Luma):

- TracerConfig: data struct + template stubs to LumaCore,
  TracerEditorProfile stays with SwiftyMonaco in Luma
- CodeShareConfig + CodeShareProjectRef to LumaCore,
  CodeShareEditorProfile stays in Luma
- CodeShareService: drop ObservableObject, move as
  stateless enum with async methods to LumaCore
- HookPack: data struct to LumaCore, discovery stays

Add swift-crypto dependency for cross-platform SHA256.
Add FoundationNetworking import for Linux URLSession.
2026-04-06 19:26:53 +02:00

91 lines
3.0 KiB
Swift

import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
public enum CodeShareService {
private static let baseURL = URL(string: "https://codeshare.frida.re")!
public enum Mode: Sendable {
case popular
case search(query: String)
}
public struct ProjectSummary: Identifiable, Decodable, Hashable, Sendable {
public let id: String
public let owner: String
public let slug: String
public let name: String
public let description: String
public let fridaVersion: String
public let likes: Int
enum CodingKeys: String, CodingKey {
case id
case owner
case slug
case name = "project_name"
case description
case fridaVersion = "frida_version"
case likes
}
}
public struct ProjectDetails: Decodable, Sendable {
public let id: String
public let owner: String
public let slug: String
public let name: String
public let description: String
public let source: String
public let fridaVersion: String
public let likes: Int
enum CodingKeys: String, CodingKey {
case id
case owner
case slug
case name = "project_name"
case description
case source
case fridaVersion = "frida_version"
case likes
}
}
public static func fetchPopular() async throws -> [ProjectSummary] {
let url = baseURL.appendingPathComponent("api/projects/popular")
do {
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode([ProjectSummary].self, from: data)
} catch let error as URLError where error.code == .cancelled {
throw CancellationError()
}
}
public static func searchProjects(query: String) async throws -> [ProjectSummary] {
guard !query.isEmpty else { return [] }
var comps = URLComponents(
url: baseURL.appendingPathComponent("api/projects/search"),
resolvingAgainstBaseURL: false
)!
comps.queryItems = [URLQueryItem(name: "query", value: query)]
do {
let (data, _) = try await URLSession.shared.data(from: comps.url!)
return try JSONDecoder().decode([ProjectSummary].self, from: data)
} catch let error as URLError where error.code == .cancelled {
throw CancellationError()
}
}
public static func fetchProjectDetails(owner: String, slug: String) async throws -> ProjectDetails {
let url = baseURL.appendingPathComponent("api/project/\(owner)/\(slug)")
do {
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(ProjectDetails.self, from: data)
} catch let error as URLError where error.code == .cancelled {
throw CancellationError()
}
}
}