Skip to content

Commit 5f89d54

Browse files
Release 0.0.1
1 parent edefa50 commit 5f89d54

1,446 files changed

Lines changed: 316764 additions & 1 deletion

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.fernignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Specify files that shouldn't be modified by Fern

Package.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// swift-tools-version: 5.7
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "Vapi",
7+
platforms: [
8+
.iOS(.v15),
9+
.macOS(.v12),
10+
.tvOS(.v15),
11+
.watchOS(.v8)
12+
],
13+
products: [
14+
.library(
15+
name: "Vapi",
16+
targets: ["Vapi"]
17+
)
18+
],
19+
dependencies: [],
20+
targets: [
21+
.target(
22+
name: "Vapi",
23+
path: "Sources"
24+
),
25+
.testTarget(
26+
name: "VapiTests",
27+
dependencies: ["Vapi"],
28+
path: "Tests"
29+
)
30+
]
31+
)

README.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

Sources/Core/CalendarDate.swift

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import Foundation
2+
3+
/// Represents a calendar date without time information, following RFC 3339 section 5.6 (`YYYY-MM-DD` format)
4+
public struct CalendarDate: Codable, Hashable, Sendable, CustomStringConvertible, Comparable {
5+
/// The year component (expected range: 1-9999)
6+
public let year: Int
7+
8+
/// The month component (valid range: 1-12)
9+
public let month: Int
10+
11+
/// The day component (valid range: 1-31, depending on month)
12+
public let day: Int
13+
14+
/// Failable initializer for creating a CalendarDate with validation
15+
public init?(year: Int, month: Int, day: Int) {
16+
guard Self.isValidDate(year: year, month: month, day: day) else {
17+
return nil
18+
}
19+
self.year = year
20+
self.month = month
21+
self.day = day
22+
}
23+
24+
/// Failable initializer for creating a CalendarDate from a `YYYY-MM-DD` string
25+
public init?(_ dateString: String) {
26+
let components = dateString.split(separator: "-")
27+
guard components.count == 3,
28+
let year = Int(components[0]),
29+
let month = Int(components[1]),
30+
let day = Int(components[2])
31+
else {
32+
return nil
33+
}
34+
self.init(year: year, month: month, day: day)
35+
}
36+
37+
// MARK: - Codable
38+
39+
public init(from decoder: Decoder) throws {
40+
let container = try decoder.singleValueContainer()
41+
let dateString = try container.decode(String.self)
42+
guard let calendarDate = CalendarDate(dateString) else {
43+
throw Error.invalidFormat(dateString)
44+
}
45+
self = calendarDate
46+
}
47+
48+
public func encode(to encoder: Encoder) throws {
49+
var container = encoder.singleValueContainer()
50+
try container.encode(description)
51+
}
52+
53+
// MARK: - CustomStringConvertible
54+
55+
public var description: String {
56+
// Format as YYYY-MM-DD with zero-padding
57+
// %04d = 4-digit year with leading zeros (e.g., 2025)
58+
// %02d = 2-digit month/day with leading zeros (e.g., 01, 05)
59+
String(format: "%04d-%02d-%02d", year, month, day)
60+
}
61+
62+
// MARK: - Comparable
63+
64+
public static func < (lhs: CalendarDate, rhs: CalendarDate) -> Bool {
65+
if lhs.year != rhs.year { return lhs.year < rhs.year }
66+
if lhs.month != rhs.month { return lhs.month < rhs.month }
67+
return lhs.day < rhs.day
68+
}
69+
70+
// MARK: - Private Helpers
71+
72+
/// Validates that the given year, month, and day form a valid calendar date using Foundation's Calendar APIs.
73+
private static func isValidDate(year: Int, month: Int, day: Int) -> Bool {
74+
let calendar = Calendar(identifier: .gregorian)
75+
let components = DateComponents(year: year, month: month, day: day)
76+
77+
guard let date = calendar.date(from: components) else {
78+
return false
79+
}
80+
81+
// Ensure the date components match what we created (handles invalid dates like Feb 30)
82+
let reconstructedComponents = calendar.dateComponents([.year, .month, .day], from: date)
83+
return
84+
(reconstructedComponents.year == year
85+
&& reconstructedComponents.month == month
86+
&& reconstructedComponents.day == day)
87+
}
88+
89+
// MARK: - Error Types
90+
91+
/// Errors that can occur when working with CalendarDate
92+
public enum Error: Swift.Error, LocalizedError {
93+
case invalidFormat(String)
94+
95+
public var errorDescription: String? {
96+
switch self {
97+
case .invalidFormat(let string):
98+
return "Invalid date format: '\(string)'. Expected YYYY-MM-DD"
99+
}
100+
}
101+
}
102+
}

Sources/Core/Data+String.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import Foundation
2+
3+
// MARK: - Data + String Extensions
4+
extension Data {
5+
/// Safely appends a UTF-8 encoded string to the data
6+
///
7+
/// - Parameter string: The string to append
8+
mutating func appendUTF8String(_ string: String) {
9+
guard let data = string.data(using: .utf8) else {
10+
assertionFailure("Failed to encode string to UTF-8: \(string)")
11+
return
12+
}
13+
self.append(data)
14+
}
15+
}

Sources/Core/Networking/HTTP.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import Foundation
2+
3+
enum HTTP {
4+
enum Method: String, CaseIterable {
5+
case get = "GET"
6+
case post = "POST"
7+
case put = "PUT"
8+
case delete = "DELETE"
9+
case patch = "PATCH"
10+
case head = "HEAD"
11+
}
12+
13+
enum ContentType: String, CaseIterable {
14+
case applicationJson = "application/json"
15+
case applicationOctetStream = "application/octet-stream"
16+
case multipartFormData = "multipart/form-data"
17+
}
18+
19+
enum RequestBody {
20+
case jsonEncodable(any Encodable)
21+
case data(Data)
22+
case multipartFormData(MultipartFormData)
23+
}
24+
}

0 commit comments

Comments
 (0)