grammargem/Sources/GrammarGem/Licensing/LicenseModels.swift
BigMarc 3d749e8139 feat: Implement LiveMonitor for real-time grammar and spelling checks across applications
- Added LiveMonitor class to scan text areas in the frontmost window for grammar and spelling issues.
- Introduced DetectedField struct to represent text areas with issues, including suggestions for corrections.
- Implemented functionality to apply corrections and dismiss suggestions.
- Added Permissions class to manage Accessibility permissions required for monitoring.
- Created SnippetStore for managing text-expansion snippets, including persistence to UserDefaults.
- Developed TextCapture class to read and write text from the frontmost application using Accessibility API and clipboard fallback.
- Implemented TextFieldScanner to traverse the Accessibility tree and collect editable text elements.
- Added TextReplacementCoordinator to orchestrate the text correction process.
- Integrated UpdaterManager for handling application updates using Sparkle.
- Created comprehensive unit tests for various components, including grammar corrections and entitlement checks.
2026-06-18 16:49:55 +02:00

90 lines
2.4 KiB
Swift

import Foundation
/// The locally-stored license record (Keychain-persisted).
struct LicenseRecord: Codable, Equatable {
var key: String
var instanceID: String // Lemon Squeezy activation instance id
var tier: Tier
var lastValidated: Date
var activatedAt: Date // when this Mac was first activated
var deviceName: String // friendly name of this Mac
var activationUsage: Int // devices currently using the license
var activationLimit: Int // device cap for the tier
}
/// Result of an activate call.
struct ActivationResult {
let instanceID: String
let tier: Tier
let usage: Int
let limit: Int
}
/// Result of a validate call.
struct ValidationResult {
let valid: Bool
let tier: Tier
let usage: Int
let limit: Int
}
// MARK: - Lemon Squeezy API response shapes (subset we rely on)
struct LSActivateResponse: Codable {
let activated: Bool
let instance: LSInstance?
let license_key: LSLicenseKey?
let meta: LSMeta?
let error: String?
}
struct LSValidateResponse: Codable {
let valid: Bool
let license_key: LSLicenseKey?
let meta: LSMeta?
let error: String?
}
struct LSDeactivateResponse: Codable {
let deactivated: Bool
let error: String?
}
struct LSInstance: Codable {
let id: String
let name: String
}
struct LSLicenseKey: Codable {
let status: String // "active", "expired", "disabled", …
let activation_limit: Int?
let activation_usage: Int?
}
/// `meta` carries the store/product/variant identity we *hard-verify* against
/// AppConfig so a key from another Lemon Squeezy product can't unlock GrammaGem.
struct LSMeta: Codable {
let store_id: Int?
let product_id: Int?
let variant_id: Int?
let variant_name: String?
}
enum LicenseError: LocalizedError, Equatable {
case network(String)
case invalidKey
case wrongProduct
case activationLimitReached(Int)
case serverMessage(String)
var errorDescription: String? {
switch self {
case .network(let m): return "Couldn't reach the license server: \(m)"
case .invalidKey: return "That license key isn't valid."
case .wrongProduct: return "That key belongs to a different product."
case .activationLimitReached(let n): return "This plan is active on \(n) Macs — deactivate one or upgrade."
case .serverMessage(let m): return m
}
}
}