spb/zyquo-router Public MIT
One local endpoint, every AI provider — a private OpenAI-compatible LLM gateway for your Mac (170 models, 12 providers).
Swift 95.7%
Python 2.3%
Shell 1.2%
Makefile 0.9%
1//2// APIKeyRecord.swift3// Zyquo Router4//5// Author: Simon-Pierre Boucher6// Mail: contact@spboucher.ai7//8// A local router API key (`zyquo-sk-…`). The plaintext token is shown once at9// creation and never stored — only its SHA-256 hash persists.10//1112import CryptoKit13import Foundation1415struct APIKeyRecord: Codable, Identifiable, Hashable, Sendable {16 let id: UUID17 var name: String18 /// Hex SHA-256 of the full token.19 var tokenHash: String20 /// First 12 characters of the token, for display ("zyquo-sk-a1b…").21 var tokenPrefix: String22 var enabled: Bool23 var createdAt: Date24 /// Requests per minute; nil = unlimited.25 var rateLimitPerMinute: Int?26 /// Namespaced model IDs this key may use; nil = all models.27 var allowedModels: Set<String>?2829 init(30 id: UUID = UUID(),31 name: String,32 tokenHash: String,33 tokenPrefix: String,34 enabled: Bool = true,35 createdAt: Date = Date(),36 rateLimitPerMinute: Int? = nil,37 allowedModels: Set<String>? = nil38 ) {39 self.id = id40 self.name = name41 self.tokenHash = tokenHash42 self.tokenPrefix = tokenPrefix43 self.enabled = enabled44 self.createdAt = createdAt45 self.rateLimitPerMinute = rateLimitPerMinute46 self.allowedModels = allowedModels47 }4849 /// Generates a fresh token and its record. The token is returned exactly once.50 static func generate(name: String) -> (record: APIKeyRecord, token: String) {51 let random = Data((0..<24).map { _ in UInt8.random(in: 0...255) })52 let token = "zyquo-sk-" + random.base64EncodedString()53 .replacingOccurrences(of: "+", with: "a")54 .replacingOccurrences(of: "/", with: "b")55 .replacingOccurrences(of: "=", with: "")56 let record = APIKeyRecord(57 name: name,58 tokenHash: Self.hash(token),59 tokenPrefix: String(token.prefix(12))60 )61 return (record, token)62 }6364 static func hash(_ token: String) -> String {65 SHA256.hash(data: Data(token.utf8)).map { String(format: "%02x", $0) }.joined()66 }67}68