diff --git a/README.md b/README.md index 2e48b44..dfe2460 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,137 @@ for try await chunk in stream { } ``` +### [Message Batches (beta)](https://docs.anthropic.com/en/docs/build-with-claude/message-batches) + +The Message Batches API is a powerful, cost-effective way to asynchronously process large volumes of [Messages](https://docs.anthropic.com/en/api/messages) requests. This approach is well-suited to tasks that do not require immediate responses, reducing costs by 50% while increasing throughput. + +This is especially useful for bulk operations that don’t require immediate results. + +Here's an example of how to process many messages with the Message Batches API: + +```swift +let anthropic = Anthropic(apiKey: "YOUR_OWN_API_KEY") + +let messages = [ + Message(role: .user, content: [.text("Write a haiku about robots.")]), + Message(role: .user, content: [.text("Write a haiku about robots. Skip the preamble; go straight into the poem.")]), + Message(role: .user, content: [.text("Who is the best basketball player of all time?")]), + Message(role: .user, content: [.text("Who is the best basketball player of all time? Yes, there are differing opinions, but if you absolutely had to pick one player, who would it be?")]) + // .... +] + +let batch = MessageBatch( + customId: "my-first-batch-request", + parameter: .init( + messages: messages, + maxTokens: 1024 + ) +) + +let response = try await anthropic.messageBatches.createBatches(batches: [batch]) +``` + +### [Admin API](https://docs.anthropic.com/en/docs/administration/administration-api) + +This library also supports an Admin API for managing workspaces and organization members. + +#### [Organization Members API](https://docs.anthropic.com/en/docs/administration/administration-api#organization-members) + +- **Get Organization Member**: Retrieve details about a specific organization member. +- **List Organization Members**: List organization members. +- **Remove Organization Member**: Remove a member from the organization. +- **Update Organization Member**: Update the role or details of an existing organization member. + +Example of updating an organization member: + +```swift +let admin = AnthropicAdmin(adminAPIKey: "YOUR_OWN_ADMIN_API_KEY") +try await admin.organizationMembers.get(userId: "user_01WCz1FkmYMm4gnmykNKUu3Q") +``` + +#### [Organization Invites API](https://docs.anthropic.com/en/docs/administration/administration-api#organization-invites) + +- **Get Organization Invites**: Retrieve details about a specific organization invitation. +- **List Organization Invites**: List organization invitations. +- **Remove Organization Invites**: Remove a invitation from the organization. +- **Create Organization Invites**: Create a new organization invitation. + +Example of updating an organization invitation: + +```swift +let admin = AnthropicAdmin(adminAPIKey: "YOUR_OWN_ADMIN_API_KEY") +try await admin.organizationInvites.list() +``` + +#### [Workspaces API](https://docs.anthropic.com/en/docs/administration/administration-api#workspaces) + +- **Get Workspace**: Retrieve details about a specific workspace. +- **List Workspaces**: List workspaces. +- **Create Workspace**: Create a new workspace. +- **Archive Workspace**: Archive an existing workspace. +- **Update Workspace**: Update the details of an existing workspace. + +Example of creating a workspace: + +```swift +let admin = AnthropicAdmin(adminAPIKey: "YOUR_OWN_ADMIN_API_KEY") +try await admin.workspaces.get(workspaceId: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") +``` + +#### [Workspace Members API](https://docs.anthropic.com/en/docs/administration/administration-api#workspace-members) + +- **Get Workspace Member**: Retrieve details about a specific workspace member. +- **List Workspace Members**: List workspace members. +- **Create Workspace Member**: Add a new member for the workspace. +- **Remove Workspace Member**: Remove a member from the workspace. +- **Update Workspace Member**: Update the role or details of an existing workspace member. + +Example of updating an workspace member: + +```swift +let admin = AnthropicAdmin(adminAPIKey: "YOUR_OWN_ADMIN_API_KEY") +try await admin.workspaceMembers.get(userId: "user_01WCz1FkmYMm4gnmykNKUu3Q") +``` + +#### [API Keys API](https://docs.anthropic.com/en/docs/administration/administration-api#api-keys) + +- **Get Organization Member**: Retrieve details about a specific API key. +- **List Organization Members**: List API keys. +- **Update Organization Member**: Update the status or name of an existing API key. + +Example of updating an organization member: + +```swift +let admin = AnthropicAdmin(adminAPIKey: "YOUR_OWN_ADMIN_API_KEY") +try await admin.apiKeys.get(apiKeyId: "apikey_01Rj2N8SVvo6BePZj99NhmiT") +``` + +### [Token Counting](https://docs.anthropic.com/en/docs/build-with-claude/token-counting) + +Token counting enables you to determine the number of tokens in a message before sending it to Claude, helping you make informed decisions about your prompts and usage. With token counting, you can + +- Proactively manage rate limits and costs +- Make smart model routing decisions +- Optimize prompts to be a specific length + +```swift +let anthropic = Anthropic(apiKey: "YOUR_OWN_API_KEY") + +let message = Message(role: .user, content: [.text("Find flights from San Francisco to a place with warmer weather.")]) +let response = try await anthropic.countTokens.countTokens( + [message], + maxTokens: 1024, + tools: [ + .computer(.init(name: "my_computer", displayWidthPx: 1024, displayHeightPx: 768, displayNumber: 1), + .bash(.init(name: "bash")) + ] +) +``` + +The token counting endpoint accepts the same structured list of inputs for creating a message, including support for system prompts, tools, images, and PDFs. The response contains the total number of input tokens. + +## Supporting Features + ### [Tool Use](https://docs.anthropic.com/en/docs/build-with-claude/tool-use) Claude is capable of interacting with external client-side tools and functions, allowing you to equip Claude with your own custom tools to perform a wider variety of tasks. @@ -134,36 +265,6 @@ let response = try await anthropic.messages.createMessage( ) ``` -### [Message Batches (beta)](https://docs.anthropic.com/en/docs/build-with-claude/message-batches) - -The Message Batches API is a powerful, cost-effective way to asynchronously process large volumes of [Messages](https://docs.anthropic.com/en/api/messages) requests. This approach is well-suited to tasks that do not require immediate responses, reducing costs by 50% while increasing throughput. - -This is especially useful for bulk operations that don’t require immediate results. - -Here's an example of how to process many messages with the Message Bathches API: - -```swift -let anthropic = Anthropic(apiKey: "YOUR_OWN_API_KEY") - -let messages = [ - Message(role: .user, content: [.text("Write a haiku about robots.")]), - Message(role: .user, content: [.text("Write a haiku about robots. Skip the preamble; go straight into the poem.")]), - Message(role: .user, content: [.text("Who is the best basketball player of all time?")]), - Message(role: .user, content: [.text("Who is the best basketball player of all time? Yes, there are differing opinions, but if you absolutely had to pick one player, who would it be?")]) - // .... -] - -let batch = MessageBatch( - customId: "my-first-batch-request", - parameter: .init( - messages: messages, - maxTokens: 1024 - ) -) - -let response = try await anthropic.messageBatches.createBatches(batches: [batch]) -``` - ### [Computer Use (beta)](https://docs.anthropic.com/en/docs/build-with-claude/computer-use#computer-tool) The upgraded Claude 3.5 Sonnet model is capable of interacting with tools that can manipulate a computer desktop environment. @@ -184,30 +285,6 @@ let response = try await anthropic.messages.createMessage( ) ``` -### [Token Counting](https://docs.anthropic.com/en/docs/build-with-claude/token-counting) - -Token counting enables you to determine the number of tokens in a message before sending it to Claude, helping you make informed decisions about your prompts and usage. With token counting, you can - -- Proactively manage rate limits and costs -- Make smart model routing decisions -- Optimize prompts to be a specific length - -```swift -let anthropic = Anthropic(apiKey: "YOUR_OWN_API_KEY") - -let message = Message(role: .user, content: [.text("Find flights from San Francisco to a place with warmer weather.")]) -let response = try await anthropic.countTokens.countTokens( - [message], - maxTokens: 1024, - tools: [ - .computer(.init(name: "my_computer", displayWidthPx: 1024, displayHeightPx: 768, displayNumber: 1), - .bash(.init(name: "bash")) - ] -) -``` - -The token counting endpoint accepts the same structured list of inputs for creating a message, including support for system prompts, tools, images, and PDFs. The response contains the total number of input tokens. - ## Extensions By introducing an extension Swift package, it is possible to access the Anthropic Claude API through AWS Bedrock and Vertex AI. The supported services are as follows: diff --git a/Sources/AnthropicSwiftSDK-TestUtils/HTTPMock.swift b/Sources/AnthropicSwiftSDK-TestUtils/HTTPMock.swift index 6044bfa..225a885 100644 --- a/Sources/AnthropicSwiftSDK-TestUtils/HTTPMock.swift +++ b/Sources/AnthropicSwiftSDK-TestUtils/HTTPMock.swift @@ -45,6 +45,7 @@ public class HTTPMock: URLProtocol { client?.urlProtocol(self, didLoad: getBasicJSONStringData()) case .request(_, nil), .requestHeader(_, nil): client?.urlProtocol(self, didReceive: succeedResponse, cacheStoragePolicy: .notAllowed) + client?.urlProtocol(self, didLoad: getBasicJSONStringData()) case .request(_, let jsonString), .requestHeader(_, let jsonString): client?.urlProtocol(self, didReceive: succeedResponse, cacheStoragePolicy: .notAllowed) guard let jsonString, let data = jsonString.data(using: .utf8) else { diff --git a/Sources/AnthropicSwiftSDK-TestUtils/MessagesRequest+Extensions.swift b/Sources/AnthropicSwiftSDK-TestUtils/MessagesRequest+Extensions.swift index 7744d4e..5db67cd 100644 --- a/Sources/AnthropicSwiftSDK-TestUtils/MessagesRequest+Extensions.swift +++ b/Sources/AnthropicSwiftSDK-TestUtils/MessagesRequest+Extensions.swift @@ -11,7 +11,7 @@ import AnthropicSwiftSDK public struct NopRequest: Request { public let method: HttpMethod public let path: String - public let queries: [String : any CustomStringConvertible]? = nil + public let queries: [String: any CustomStringConvertible]? = nil public let body: Never? = nil public init( diff --git a/Sources/AnthropicSwiftSDK/API/Admin/APIKeys.swift b/Sources/AnthropicSwiftSDK/API/Admin/APIKeys.swift new file mode 100644 index 0000000..aae31b7 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/API/Admin/APIKeys.swift @@ -0,0 +1,106 @@ +// +// APIKeys.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// +import Foundation + +public struct APIKeys { + private let apiKey: String + private let session: URLSession + + init(adminAPIKey: String, session: URLSession) { + self.apiKey = adminAPIKey + self.session = session + } + + public func get(apiKeyId: String) async throws -> APIKeyResponse { + try await get( + apiKeyId: apiKeyId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func get( + apiKeyId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> APIKeyResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: GetAPIKeyRequest(apiKeyId: apiKeyId)) + } + + public func list( + limit: Int = 20, + beforeId: String? = nil, + afterId: String? = nil, + status: APIKeyStatus? = nil, + workspaceId: String? = nil, + createdByUserId: String? = nil + ) async throws -> ObjectListResponse { + fatalError("not implemented") + } + + public func list( + limit: Int = 20, + beforeId: String? = nil, + afterId: String? = nil, + status: APIKeyStatus? = nil, + workspaceId: String? = nil, + createdByUserId: String? = nil, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> ObjectListResponse { + try await list( + session: session, + type: .apiKey, + limit: limit, + beforeId: beforeId, + afterId: afterId, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + } + + public func update(apiKeyId: String, name: String, status: APIKeyStatus? = nil) async throws -> APIKeyResponse { + try await update( + apiKeyId: apiKeyId, + name: name, + status: status, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func update( + apiKeyId: String, + name: String, + status: APIKeyStatus? = nil, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> APIKeyResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send( + request: UpdateAPIKeyRequest( + body: .init(name: name, status: status), + apiKeyId: apiKeyId + ) + ) + } +} + +extension APIKeys: ObjectListable { + typealias Object = APIKeyResponse +} diff --git a/Sources/AnthropicSwiftSDK/API/Admin/Admin.swift b/Sources/AnthropicSwiftSDK/API/Admin/Admin.swift new file mode 100644 index 0000000..024e539 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/API/Admin/Admin.swift @@ -0,0 +1,23 @@ +// +// Admin.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// +import Foundation + +public struct Admin { + public let organizationMembers: OrganizationMembers + public let organizationInvites: OrganizationInvites + public let workspaces: Workspaces + public let workspaceMembers: WorkspaceMembers + public let apiKeys: APIKeys + + public init(adminAPIKey apiKey: String, session: URLSession = .shared) { + self.organizationMembers = OrganizationMembers(adminAPIKey: apiKey, session: session) + self.organizationInvites = OrganizationInvites(adminAPIKey: apiKey, session: session) + self.workspaces = Workspaces(adminAPIKey: apiKey, session: session) + self.workspaceMembers = WorkspaceMembers(adminAPIKey: apiKey, session: session) + self.apiKeys = APIKeys(adminAPIKey: apiKey, session: session) + } +} diff --git a/Sources/AnthropicSwiftSDK/API/Admin/OrganizationInvites.swift b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationInvites.swift new file mode 100644 index 0000000..6f42a0e --- /dev/null +++ b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationInvites.swift @@ -0,0 +1,122 @@ +// +// OrganizationInvites.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// +import Foundation + +public struct OrganizationInvites { + private let apiKey: String + private let session: URLSession + + init(adminAPIKey: String, session: URLSession) { + self.apiKey = adminAPIKey + self.session = session + } + + public func get(invitationId: String) async throws -> InvitationResponse { + try await get( + invitationId: invitationId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func get( + invitationId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> InvitationResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: GetOrganizationInviteRequest(invitationId: invitationId)) + } + + public func list(limit: Int = 20, beforeId: String? = nil, afterId: String? = nil) async throws -> ObjectListResponse { + try await list( + limit: limit, + beforeId: beforeId, + afterId: afterId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func list( + limit: Int = 20, + beforeId: String? = nil, + afterId: String? = nil, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> ObjectListResponse { + try await list( + session: session, + type: .organizationInvite, + limit: limit, + beforeId: beforeId, + afterId: afterId, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + } + + public func send(invitation: Invitation) async throws -> InvitationResponse { + try await send( + invitation: invitation, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func send( + invitation: Invitation, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> InvitationResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send( + request: CreateOrganizationInviteRequest( + body: .init( + email: invitation.email, + role: invitation.role + ) + ) + ) + } + + public func remove(invitationId: String) async throws -> InvitationRemoveResponse { + try await remove( + invitationId: invitationId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func remove( + invitationId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> InvitationRemoveResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: DeleteOrganizationInviteRequest(invitationId: invitationId)) + } +} + +extension OrganizationInvites: ObjectListable { + typealias Object = InvitationResponse +} diff --git a/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift new file mode 100644 index 0000000..03be294 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift @@ -0,0 +1,117 @@ +// +// OrganizationMembers.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// +import Foundation + +public struct OrganizationMembers { + let apiKey: String + let session: URLSession + + init(adminAPIKey apiKey: String, session: URLSession) { + self.apiKey = apiKey + self.session = session + } + + public func get(userId: String) async throws -> OrganizationMemberResponse { + try await get( + userId: userId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func get( + userId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> OrganizationMemberResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: GetOrganizationMemberRequest(userId: userId)) + } + + public func list(limit: Int = 20, beforeId: String? = nil, afterId: String? = nil) async throws -> ObjectListResponse { + try await list( + limit: limit, + beforeId: beforeId, + afterId: afterId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func list( + limit: Int = 20, + beforeId: String? = nil, + afterId: String? = nil, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> ObjectListResponse { + try await list( + session: session, + type: .organizationMember, + limit: limit, + beforeId: beforeId, + afterId: afterId, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + } + + public func update(userId: String, role: OrganizationRole) async throws -> OrganizationMemberResponse { + try await update( + userId: userId, + role: role, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func update( + userId: String, + role: OrganizationRole, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> OrganizationMemberResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: UpdateOrganizationMemberRequest(body: .init(role: role), userId: userId)) + } + + public func remove(userId: String) async throws -> OrganizationMemberRemoveResponse { + try await remove( + userId: userId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func remove( + userId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> OrganizationMemberRemoveResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: RemoveOrganizationMemberRequest(userId: userId)) + } +} + +extension OrganizationMembers: ObjectListable { + typealias Object = OrganizationMemberResponse +} diff --git a/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift b/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift new file mode 100644 index 0000000..ef1ab46 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift @@ -0,0 +1,154 @@ +// +// WorkspaceMembers.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// +import Foundation + +public struct WorkspaceMembers { + private let apiKey: String + private let session: URLSession + + init(adminAPIKey: String, session: URLSession) { + self.apiKey = adminAPIKey + self.session = session + } + + public func get(userId: String, workspaceId: String) async throws -> WorkspaceMemberResponse { + try await get( + userId: userId, + workspaceId: workspaceId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func get( + userId: String, + workspaceId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> WorkspaceMemberResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: GetWorkspaceMemberRequest(workspaceId: workspaceId, userId: userId)) + } + + public func list(workspaceId: String, limit: Int = 20, beforeId: String? = nil, afterId: String? = nil) async throws -> ObjectListResponse { + try await list( + workspaceId: workspaceId, + limit: limit, + beforeId: beforeId, + afterId: afterId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func list( + workspaceId: String, + limit: Int = 20, + beforeId: String? = nil, + afterId: String? = nil, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> ObjectListResponse { + try await list( + session: session, + type: .workspaceMember(workspaceId: workspaceId), + limit: limit, + beforeId: beforeId, + afterId: afterId, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + } + + public func add(registration: Registration, workspaceId: String) async throws -> WorkspaceMemberResponse { + try await add( + registration: registration, + workspaceId: workspaceId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func add( + registration: Registration, + workspaceId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> WorkspaceMemberResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send( + request: CreateWorkspaceMemberRequest( + body: registration, + workspaceId: workspaceId + ) + ) + } + + public func update(userId: String, workspaceId: String, role: WorkspaceRole) async throws -> WorkspaceMemberResponse { + try await update( + userId: userId, + workspaceId: workspaceId, + role: role, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func update( + userId: String, + workspaceId: String, + role: WorkspaceRole, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> WorkspaceMemberResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: UpdateWorkspaceMemberRequest(body: .init(role: role), userId: userId, workspaceId: workspaceId)) + } + + public func remove(userId: String, workspaceId: String) async throws -> WorkspaceMemberRemoveResponse { + try await remove( + userId: userId, + workspaceId: workspaceId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func remove( + userId: String, + workspaceId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> WorkspaceMemberRemoveResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: DeleteWorkspaceMemberRequest(userId: userId, workspaceId: workspaceId)) + } +} + +extension WorkspaceMembers: ObjectListable { + typealias Object = WorkspaceMemberResponse +} diff --git a/Sources/AnthropicSwiftSDK/API/Admin/Workspaces.swift b/Sources/AnthropicSwiftSDK/API/Admin/Workspaces.swift new file mode 100644 index 0000000..0e20a21 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/API/Admin/Workspaces.swift @@ -0,0 +1,151 @@ +// +// Workspaces.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// +import Foundation + +public struct Workspaces { + private let apiKey: String + private let session: URLSession + + init(adminAPIKey: String, session: URLSession) { + self.apiKey = adminAPIKey + self.session = session + } + + public func get(workspaceId: String) async throws -> WorkspaceResponse { + try await get( + workspaceId: workspaceId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func get( + workspaceId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> WorkspaceResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: GetWorkspaceRequest(workspaceId: workspaceId)) + } + + public func list(limit: Int = 20, includeArchive: Bool = false, beforeId: String? = nil, afterId: String? = nil) async throws -> ObjectListResponse { + try await list( + limit: limit, + includeArchive: includeArchive, + beforeId: beforeId, + afterId: afterId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func list( + limit: Int = 20, + includeArchive: Bool = false, + beforeId: String? = nil, + afterId: String? = nil, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> ObjectListResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + let queries: [String: CustomStringConvertible] = { + var queries: [String: CustomStringConvertible] = [ListObjectRequest.Parameter.limit.rawValue: limit] + queries["include_archived"] = includeArchive + if let beforeId { + queries[ListObjectRequest.Parameter.beforeId.rawValue] = beforeId + } + if let afterId { + queries[ListObjectRequest.Parameter.afterId.rawValue] = afterId + } + return queries + }() + + return try await client.send(request: ListObjectRequest(queries: queries, type: .workspace)) + } + + public func update(name: String, workspaceId: String) async throws -> WorkspaceResponse { + try await update( + name: name, + workspaceId: workspaceId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func update( + name: String, + workspaceId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> WorkspaceResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: UpdateWorkspaceRequest(body: .init(name: name), workspaceId: workspaceId)) + } + + public func create(name: String) async throws -> WorkspaceResponse { + try await create( + name: name, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func create( + name: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> WorkspaceResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: CreateWorkspaceRequest(body: .init(name: name))) + } + + public func archive(_ workspaceId: String) async throws -> WorkspaceResponse { + try await archive( + workspaceId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func archive( + _ workspaceId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> WorkspaceResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: ArchiveWorkspaceRequest(workspaceId: workspaceId)) + } +} + +extension Workspaces: ObjectListable { + typealias Object = WorkspaceResponse +} diff --git a/Sources/AnthropicSwiftSDK/CountTokens.swift b/Sources/AnthropicSwiftSDK/API/CountTokens.swift similarity index 86% rename from Sources/AnthropicSwiftSDK/CountTokens.swift rename to Sources/AnthropicSwiftSDK/API/CountTokens.swift index c2eb5cc..ca6cd50 100644 --- a/Sources/AnthropicSwiftSDK/CountTokens.swift +++ b/Sources/AnthropicSwiftSDK/API/CountTokens.swift @@ -90,16 +90,6 @@ public struct CountTokens { ) ) - let (data, response) = try await client.send(request: request) - - guard let httpResponse = response as? HTTPURLResponse else { - throw ClientError.cannotHandleURLResponse(response) - } - - guard httpResponse.statusCode == 200 else { - throw AnthropicAPIError(fromHttpStatusCode: httpResponse.statusCode) - } - - return try anthropicJSONDecoder.decode(CountTokenResponse.self, from: data) + return try await client.send(request: request) } } diff --git a/Sources/AnthropicSwiftSDK/MessageBatches.swift b/Sources/AnthropicSwiftSDK/API/MessageBatches.swift similarity index 83% rename from Sources/AnthropicSwiftSDK/MessageBatches.swift rename to Sources/AnthropicSwiftSDK/API/MessageBatches.swift index 2f745f0..bcebfe3 100644 --- a/Sources/AnthropicSwiftSDK/MessageBatches.swift +++ b/Sources/AnthropicSwiftSDK/API/MessageBatches.swift @@ -59,18 +59,7 @@ public struct MessageBatches { authenticationHeaderProvider: authenticationHeaderProvider ) - let request = MessageBatchesRequest(body: .init(from: batches)) - let (data, response) = try await client.send(request: request) - - guard let httpResponse = response as? HTTPURLResponse else { - throw ClientError.cannotHandleURLResponse(response) - } - - guard httpResponse.statusCode == 200 else { - throw AnthropicAPIError(fromHttpStatusCode: httpResponse.statusCode) - } - - return try anthropicJSONDecoder.decode(BatchResponse.self, from: data) + return try await client.send(request: MessageBatchesRequest(body: .init(from: batches))) } /// Retrieves a specific message batch by its ID. @@ -105,18 +94,7 @@ public struct MessageBatches { authenticationHeaderProvider: authenticationHeaderProvider ) - let request = RetrieveMessageBatchesRequest(batchId: batchId) - let (data, response) = try await client.send(request: request) - - guard let httpResponse = response as? HTTPURLResponse else { - throw ClientError.cannotHandleURLResponse(response) - } - - guard httpResponse.statusCode == 200 else { - throw AnthropicAPIError(fromHttpStatusCode: httpResponse.statusCode) - } - - return try anthropicJSONDecoder.decode(BatchResponse.self, from: data) + return try await client.send(request: RetrieveMessageBatchesRequest(batchId: batchId)) } /// Retrieves the results of a specific message batch by its ID. @@ -231,9 +209,9 @@ public struct MessageBatches { /// - beforeId: The ID to list batches before. /// - afterId: The ID to list batches after. /// - limit: The maximum number of batches to list. - /// - Returns: A `BatchListResponse` containing the list of batches. + /// - Returns: A `ObjectListResponse` containing the list of batches. /// - Throws: An error if the request fails. - public func list(beforeId: String? = nil, afterId: String? = nil, limit: Int = 20) async throws -> BatchListResponse { + public func list(beforeId: String? = nil, afterId: String? = nil, limit: Int = 20) async throws -> ObjectListResponse { try await list( beforeId: beforeId, afterId: afterId, @@ -251,7 +229,7 @@ public struct MessageBatches { /// - limit: The maximum number of batches to list. /// - anthropicHeaderProvider: The provider for Anthropic-specific headers. /// - authenticationHeaderProvider: The provider for authentication headers. - /// - Returns: A `BatchListResponse` containing the list of batches. + /// - Returns: A `ObjectListResponse` containing the list of batches. /// - Throws: An error if the request fails. public func list( beforeId: String?, @@ -259,7 +237,7 @@ public struct MessageBatches { limit: Int, anthropicHeaderProvider: AnthropicHeaderProvider, authenticationHeaderProvider: AuthenticationHeaderProvider - ) async throws -> BatchListResponse { + ) async throws -> ObjectListResponse { let client = APIClient( session: session, anthropicHeaderProvider: anthropicHeaderProvider, @@ -267,29 +245,18 @@ public struct MessageBatches { ) let queries: [String: CustomStringConvertible] = { - var queries: [String: CustomStringConvertible] = [ListMessageBatchesRequest.Parameter.limit.rawValue: limit] + var queries: [String: CustomStringConvertible] = [ListObjectRequest.Parameter.limit.rawValue: limit] if let beforeId { - queries[ListMessageBatchesRequest.Parameter.beforeId.rawValue] = beforeId + queries[ListObjectRequest.Parameter.beforeId.rawValue] = beforeId } if let afterId { - queries[ListMessageBatchesRequest.Parameter.afterId.rawValue] = afterId + queries[ListObjectRequest.Parameter.afterId.rawValue] = afterId } return queries }() - let request = ListMessageBatchesRequest(queries: queries) - let (data, response) = try await client.send(request: request) - - guard let httpResponse = response as? HTTPURLResponse else { - throw ClientError.cannotHandleURLResponse(response) - } - - guard httpResponse.statusCode == 200 else { - throw AnthropicAPIError(fromHttpStatusCode: httpResponse.statusCode) - } - - return try anthropicJSONDecoder.decode(BatchListResponse.self, from: data) + return try await client.send(request: ListObjectRequest(queries: queries, type: .batches)) } /// Cancels a specific message batch by its ID. @@ -324,18 +291,7 @@ public struct MessageBatches { authenticationHeaderProvider: authenticationHeaderProvider ) - let request = CancelMessageBatchRequest(batchId: batchId) - let (data, response) = try await client.send(request: request) - - guard let httpResponse = response as? HTTPURLResponse else { - throw ClientError.cannotHandleURLResponse(response) - } - - guard httpResponse.statusCode == 200 else { - throw AnthropicAPIError(fromHttpStatusCode: httpResponse.statusCode) - } - - return try anthropicJSONDecoder.decode(BatchResponse.self, from: data) + return try await client.send(request: CancelMessageBatchRequest(batchId: batchId)) } } diff --git a/Sources/AnthropicSwiftSDK/Messages.swift b/Sources/AnthropicSwiftSDK/API/Messages.swift similarity index 96% rename from Sources/AnthropicSwiftSDK/Messages.swift rename to Sources/AnthropicSwiftSDK/API/Messages.swift index 536e941..0212f28 100644 --- a/Sources/AnthropicSwiftSDK/Messages.swift +++ b/Sources/AnthropicSwiftSDK/API/Messages.swift @@ -120,17 +120,7 @@ public struct Messages { ) ) - let (data, response) = try await client.send(request: request) - - guard let httpResponse = response as? HTTPURLResponse else { - throw ClientError.cannotHandleURLResponse(response) - } - - guard httpResponse.statusCode == 200 else { - throw AnthropicAPIError(fromHttpStatusCode: httpResponse.statusCode) - } - - return try anthropicJSONDecoder.decode(MessagesResponse.self, from: data) + return try await client.send(request: request) } /// Streams messages using the specified parameters and sends a request to the Anthropic API asynchronously. diff --git a/Sources/AnthropicSwiftSDK/Anthropic.swift b/Sources/AnthropicSwiftSDK/Anthropic.swift index 24ab227..a6d200d 100644 --- a/Sources/AnthropicSwiftSDK/Anthropic.swift +++ b/Sources/AnthropicSwiftSDK/Anthropic.swift @@ -26,3 +26,15 @@ public final class Anthropic { self.countTokens = CountTokens(apiKey: apiKey, session: .shared) } } + +public final class AnthropicAdmin { + /// Admin API interface + public let admin: Admin + + /// Construction of Admin SDK + /// + /// - Parameter adminAPIKey: API key to access Anthropic Admin API + public init(adminAPIKey: String, session: URLSession = .shared) { + self.admin = Admin(adminAPIKey: adminAPIKey, session: session) + } +} diff --git a/Sources/AnthropicSwiftSDK/Entity/Admin/Invitation.swift b/Sources/AnthropicSwiftSDK/Entity/Admin/Invitation.swift new file mode 100644 index 0000000..eb960f7 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Entity/Admin/Invitation.swift @@ -0,0 +1,13 @@ +// +// Invitation.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +public struct Invitation: Encodable { + /// Email of the User. + public let email: String + /// Role for the invited User. Cannot be "admin". + public let role: OrganizationRole +} diff --git a/Sources/AnthropicSwiftSDK/Entity/Admin/OrganizationRole.swift b/Sources/AnthropicSwiftSDK/Entity/Admin/OrganizationRole.swift new file mode 100644 index 0000000..67977a3 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Entity/Admin/OrganizationRole.swift @@ -0,0 +1,17 @@ +// +// OrganizationRole.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/27. +// + +public enum OrganizationRole: String, Codable { + /// Can use Workbench + case user + /// Can use Workbench and manage API keys + case developer + /// Can use Workbench and manage billing details + case billing + /// Can do all of the above, plus manage users + case admin +} diff --git a/Sources/AnthropicSwiftSDK/Entity/Admin/Registration.swift b/Sources/AnthropicSwiftSDK/Entity/Admin/Registration.swift new file mode 100644 index 0000000..bead933 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Entity/Admin/Registration.swift @@ -0,0 +1,13 @@ +// +// Registration.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +public struct Registration: Encodable { + /// ID of the User. + public let userId: String + /// Role of the new Workspace Member. Cannot be "workspace_billing". + public let workspaceRole: WorkspaceRole +} diff --git a/Sources/AnthropicSwiftSDK/Entity/Admin/WorkspaceRole.swift b/Sources/AnthropicSwiftSDK/Entity/Admin/WorkspaceRole.swift new file mode 100644 index 0000000..0505076 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Entity/Admin/WorkspaceRole.swift @@ -0,0 +1,14 @@ +// +// WorkspaceRole.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +/// workspace role for the user. +public enum WorkspaceRole: String, Codable { + case user = "workspace_user" + case developer = "workspace_developer" + case admin = "workspace_admin" + case billing = "workspace_billing" +} diff --git a/Sources/AnthropicSwiftSDK/Network/AnthropicAPIClient.swift b/Sources/AnthropicSwiftSDK/Network/AnthropicAPIClient.swift index 5cfcbcb..f4ff1db 100644 --- a/Sources/AnthropicSwiftSDK/Network/AnthropicAPIClient.swift +++ b/Sources/AnthropicSwiftSDK/Network/AnthropicAPIClient.swift @@ -52,6 +52,21 @@ struct APIClient { return try await session.data(for: urlRequest) } + func send(request: any Request) async throws -> Object { + let (data, response) = try await self.send(request: request) + + guard let httpResponse = response as? HTTPURLResponse else { + throw ClientError.cannotHandleURLResponse(response) + } + + guard httpResponse.statusCode == 200 else { + throw AnthropicAPIError(fromHttpStatusCode: httpResponse.statusCode) + } + + return try anthropicJSONDecoder.decode(Object.self, from: data) + } + + /// Send messages API request. This method read the API response sequentially. /// /// - Parameter request: request body for api request diff --git a/Sources/AnthropicSwiftSDK/Network/ObjectListable.swift b/Sources/AnthropicSwiftSDK/Network/ObjectListable.swift new file mode 100644 index 0000000..ceed9d7 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/ObjectListable.swift @@ -0,0 +1,44 @@ +// +// ObjectListable.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/03. +// +import Foundation + +protocol ObjectListable { + associatedtype Object: Decodable +} + +extension ObjectListable { + // swiftlint:disable:next function_parameter_count + func list( + session: URLSession, + type: RequestType, + limit: Int, + beforeId: String?, + afterId: String?, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> ObjectListResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + let queries: [String: CustomStringConvertible] = { + var queries: [String: CustomStringConvertible] = [ListObjectRequest.Parameter.limit.rawValue: limit] + if let beforeId { + queries[ListObjectRequest.Parameter.beforeId.rawValue] = beforeId + } + if let afterId { + queries[ListObjectRequest.Parameter.afterId.rawValue] = afterId + } + + return queries + }() + + return try await client.send(request: ListObjectRequest(queries: queries, type: type)) + } +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/GetAPIKeyRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/GetAPIKeyRequest.swift new file mode 100644 index 0000000..a8d216e --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/GetAPIKeyRequest.swift @@ -0,0 +1,17 @@ +// +// GetAPIKeyRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct GetAPIKeyRequest: Request { + let method: HttpMethod = .get + var path: String { + "\(RequestType.apiKey.basePath)/\(apiKeyId)" + } + let queries: [String: any CustomStringConvertible]? = nil + let body: Never? = nil + + let apiKeyId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/UpdateAPIKeyRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/UpdateAPIKeyRequest.swift new file mode 100644 index 0000000..b286d56 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/UpdateAPIKeyRequest.swift @@ -0,0 +1,23 @@ +// +// UpdateAPIKeyRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct UpdateAPIKeyRequest: Request { + typealias Body = APIKeyRequestBody + let method: HttpMethod = .post + var path: String { + "\(RequestType.apiKey.basePath)/\(apiKeyId)" + } + let queries: [String: any CustomStringConvertible]? = nil + + let body: APIKeyRequestBody? + let apiKeyId: String +} + +struct APIKeyRequestBody: Encodable { + let name: String + let status: APIKeyStatus? +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/ListMessageBatchesRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/ListObjectRequest.swift similarity index 68% rename from Sources/AnthropicSwiftSDK/Network/Request/ListMessageBatchesRequest.swift rename to Sources/AnthropicSwiftSDK/Network/Request/ListObjectRequest.swift index 59fdcc5..2e0498d 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/ListMessageBatchesRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/ListObjectRequest.swift @@ -1,17 +1,11 @@ // -// ListMessageBatchesRequest.swift +// ListObjectRequest.swift // AnthropicSwiftSDK // // Created by 伊藤史 on 2024/10/16. // -/// List all Message Batches within a Workspace. Most recently created batches are returned first. -struct ListMessageBatchesRequest: Request { - let method: HttpMethod = .get - let path: String = RequestType.batches.basePath - let queries: [String: CustomStringConvertible]? - let body: Never? = nil - +struct ListObjectRequest: Request { enum Parameter: String { /// ID of the object to use as a cursor for pagination. When provided, returns the page of results immediately before this object. case beforeId = "before_id" @@ -22,4 +16,17 @@ struct ListMessageBatchesRequest: Request { /// Defaults to 20. Ranges from 1 to 100. case limit } + + /// HTTP method of request. It's always `GET` + let method: HttpMethod = .get + /// HTTP request path. It's always base path of `type`. + var path: String { + type.basePath + } + /// HTTP request body. It's always empty + let body: Never? = nil + + let queries: [String: CustomStringConvertible]? + /// type of objects + let type: RequestType } diff --git a/Sources/AnthropicSwiftSDK/Network/Request/CancelMessageBatchRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/MessageBatches/CancelMessageBatchRequest.swift similarity index 100% rename from Sources/AnthropicSwiftSDK/Network/Request/CancelMessageBatchRequest.swift rename to Sources/AnthropicSwiftSDK/Network/Request/MessageBatches/CancelMessageBatchRequest.swift diff --git a/Sources/AnthropicSwiftSDK/Network/Request/MessageBatchesRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/MessageBatches/MessageBatchesRequest.swift similarity index 100% rename from Sources/AnthropicSwiftSDK/Network/Request/MessageBatchesRequest.swift rename to Sources/AnthropicSwiftSDK/Network/Request/MessageBatches/MessageBatchesRequest.swift diff --git a/Sources/AnthropicSwiftSDK/Network/Request/RetrieveMessageBatchResultsRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/MessageBatches/RetrieveMessageBatchResultsRequest.swift similarity index 100% rename from Sources/AnthropicSwiftSDK/Network/Request/RetrieveMessageBatchResultsRequest.swift rename to Sources/AnthropicSwiftSDK/Network/Request/MessageBatches/RetrieveMessageBatchResultsRequest.swift diff --git a/Sources/AnthropicSwiftSDK/Network/Request/RetrieveMessageBatchesRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/MessageBatches/RetrieveMessageBatchesRequest.swift similarity index 100% rename from Sources/AnthropicSwiftSDK/Network/Request/RetrieveMessageBatchesRequest.swift rename to Sources/AnthropicSwiftSDK/Network/Request/MessageBatches/RetrieveMessageBatchesRequest.swift diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/CreateOrganizationInviteRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/CreateOrganizationInviteRequest.swift new file mode 100644 index 0000000..5a925ff --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/CreateOrganizationInviteRequest.swift @@ -0,0 +1,16 @@ +// +// CreateOrganizationInviteRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct CreateOrganizationInviteRequest: Request { + typealias Body = Invitation + + let method: HttpMethod = .post + let path: String = RequestType.organizationInvite.basePath + let queries: [String: any CustomStringConvertible]? = nil + + let body: Invitation? +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/DeleteOrganizationInviteRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/DeleteOrganizationInviteRequest.swift new file mode 100644 index 0000000..b7fbb1d --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/DeleteOrganizationInviteRequest.swift @@ -0,0 +1,17 @@ +// +// DeleteOrganizationInviteRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct DeleteOrganizationInviteRequest: Request { + let method: HttpMethod = .delete + var path: String { + "\(RequestType.organizationInvite.basePath)/\(invitationId)" + } + let queries: [String: any CustomStringConvertible]? = nil + let body: Never? = nil + + let invitationId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/GetOrganizationInviteRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/GetOrganizationInviteRequest.swift new file mode 100644 index 0000000..8fd4eee --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/GetOrganizationInviteRequest.swift @@ -0,0 +1,17 @@ +// +// GetOrganizationInviteRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct GetOrganizationInviteRequest: Request { + let method: HttpMethod = .get + var path: String { + "\(RequestType.organizationInvite.basePath)/\(invitationId)" + } + let queries: [String: any CustomStringConvertible]? = nil + let body: Never? = nil + + let invitationId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/GetOrganizationMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/GetOrganizationMemberRequest.swift new file mode 100644 index 0000000..77fa477 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/GetOrganizationMemberRequest.swift @@ -0,0 +1,19 @@ +// +// GetOrganizationMemberRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +/// https://docs.anthropic.com/en/api/admin-api/users/get-user +struct GetOrganizationMemberRequest: Request { + let method: HttpMethod = .get + var path: String { + "\(RequestType.organizationMember.basePath)/\(userId)" + } + let queries: [String: CustomStringConvertible]? = nil + let body: Never? = nil + + /// ID of the User. + let userId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/RemoveOrganizationMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/RemoveOrganizationMemberRequest.swift new file mode 100644 index 0000000..8333340 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/RemoveOrganizationMemberRequest.swift @@ -0,0 +1,17 @@ +// +// RemoveOrganizationMemberRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct RemoveOrganizationMemberRequest: Request { + let method: HttpMethod = .delete + var path: String { + "\(RequestType.organizationMember.basePath)/\(userId)" + } + let queries: [String: any CustomStringConvertible]? = nil + let body: Never? = nil + + let userId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/UpdateOrganizationMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/UpdateOrganizationMemberRequest.swift new file mode 100644 index 0000000..9289213 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/UpdateOrganizationMemberRequest.swift @@ -0,0 +1,23 @@ +// +// UpdateOrganizationMemberRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct UpdateOrganizationMemberRequest: Request { + typealias Body = OrganizationMememberRequestBody + + let method: HttpMethod = .post + var path: String { + "\(RequestType.organizationMember.basePath)/\(userId)" + } + let queries: [String: any CustomStringConvertible]? = nil + + let body: OrganizationMememberRequestBody? + let userId: String +} + +struct OrganizationMememberRequestBody: Encodable { + let role: OrganizationRole +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/Request.swift b/Sources/AnthropicSwiftSDK/Network/Request/Request.swift index 80e7b8d..117c700 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/Request.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/Request.swift @@ -10,12 +10,18 @@ import Foundation public enum HttpMethod: String { case post = "POST" case get = "GET" + case delete = "DELETE" } enum RequestType { case messages case batches case countTokens + case organizationMember + case organizationInvite + case workspace + case workspaceMember(workspaceId: String) + case apiKey var basePath: String { switch self { @@ -24,7 +30,17 @@ enum RequestType { case .batches: return "/v1/messages/batches" case .countTokens: - return "v1/messages/count_tokens" + return "/v1/messages/count_tokens" + case .organizationMember: + return "/v1/organizations/users" + case .organizationInvite: + return "/v1/organizations/invites" + case .workspace: + return "/v1/organizations/workspaces" + case .workspaceMember(let workspaceId): + return "/v1/organizations/workspaces/\(workspaceId)/members" + case .apiKey: + return "/v1/organizations/api_keys" } } } diff --git a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/CreateWorkspaceMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/CreateWorkspaceMemberRequest.swift new file mode 100644 index 0000000..4ec0e65 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/CreateWorkspaceMemberRequest.swift @@ -0,0 +1,19 @@ +// +// CreateWorkspaceMemberRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct CreateWorkspaceMemberRequest: Request { + typealias Body = Registration + + let method: HttpMethod = .post + var path: String { + RequestType.workspaceMember(workspaceId: workspaceId).basePath + } + let queries: [String: any CustomStringConvertible]? = nil + + let body: Registration? + let workspaceId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/DeleteWorkspaceMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/DeleteWorkspaceMemberRequest.swift new file mode 100644 index 0000000..7430460 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/DeleteWorkspaceMemberRequest.swift @@ -0,0 +1,18 @@ +// +// DeleteWorkspaceMemberRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct DeleteWorkspaceMemberRequest: Request { + let method: HttpMethod = .delete + var path: String { + "\(RequestType.workspaceMember(workspaceId: workspaceId).basePath)/\(userId)" + } + let queries: [String: any CustomStringConvertible]? = nil + let body: Never? = nil + + let userId: String + let workspaceId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/GetWorkspaceMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/GetWorkspaceMemberRequest.swift new file mode 100644 index 0000000..7350a35 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/GetWorkspaceMemberRequest.swift @@ -0,0 +1,18 @@ +// +// GetWorkspaceMemberRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct GetWorkspaceMemberRequest: Request { + let method: HttpMethod = .get + var path: String { + "\(RequestType.workspaceMember(workspaceId: workspaceId).basePath)/\(userId)" + } + let queries: [String: any CustomStringConvertible]? = nil + let body: Never? = nil + + let workspaceId: String + let userId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/UpdateWorkspaceMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/UpdateWorkspaceMemberRequest.swift new file mode 100644 index 0000000..b7a3d44 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/UpdateWorkspaceMemberRequest.swift @@ -0,0 +1,24 @@ +// +// UpdateWorkspaceMemberRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct UpdateWorkspaceMemberRequest: Request { + typealias Body = WorkspaceMemberRequestBody + + let method: HttpMethod = .post + var path: String { + "\(RequestType.workspaceMember(workspaceId: workspaceId).basePath)/\(userId)" + } + let queries: [String: any CustomStringConvertible]? = nil + + let body: WorkspaceMemberRequestBody? + let userId: String + let workspaceId: String +} + +struct WorkspaceMemberRequestBody: Encodable { + let role: WorkspaceRole +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/ArchiveWorkspaceRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/ArchiveWorkspaceRequest.swift new file mode 100644 index 0000000..206a2c2 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/ArchiveWorkspaceRequest.swift @@ -0,0 +1,17 @@ +// +// ArchiveWorkspaceRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct ArchiveWorkspaceRequest: Request { + let method: HttpMethod = .post + var path: String { + "\(RequestType.workspace.basePath)/\(workspaceId)/archive" + } + var queries: [String: any CustomStringConvertible]? + let body: Never? = nil + + let workspaceId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/CreateWorkspaceRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/CreateWorkspaceRequest.swift new file mode 100644 index 0000000..bb8e728 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/CreateWorkspaceRequest.swift @@ -0,0 +1,16 @@ +// +// CreateWorkspaceRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct CreateWorkspaceRequest: Request { + typealias Body = WorkspaceRequestBody + + let method: HttpMethod = .post + let path: String = RequestType.workspace.basePath + let queries: [String: any CustomStringConvertible]? = nil + + let body: WorkspaceRequestBody? +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/GetWorkspaceRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/GetWorkspaceRequest.swift new file mode 100644 index 0000000..47444aa --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/GetWorkspaceRequest.swift @@ -0,0 +1,17 @@ +// +// GetWorkspaceRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct GetWorkspaceRequest: Request { + let method: HttpMethod = .get + var path: String { + "\(RequestType.workspace.basePath)/\(workspaceId)" + } + let queries: [String: any CustomStringConvertible]? = nil + let body: Never? = nil + + let workspaceId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/UpdateWorkspaceRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/UpdateWorkspaceRequest.swift new file mode 100644 index 0000000..e6ab5ed --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/UpdateWorkspaceRequest.swift @@ -0,0 +1,23 @@ +// +// UpdateWorkspaceRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct UpdateWorkspaceRequest: Request { + typealias Body = WorkspaceRequestBody + + let method: HttpMethod = .post + var path: String { + "\(RequestType.workspace.basePath)/\(workspaceId)" + } + let queries: [String: any CustomStringConvertible]? = nil + + let body: WorkspaceRequestBody? + let workspaceId: String +} + +struct WorkspaceRequestBody: Encodable { + let name: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/APIKeyResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/APIKeyResponse.swift new file mode 100644 index 0000000..2695127 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/APIKeyResponse.swift @@ -0,0 +1,45 @@ +// +// APIKeyResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +/// Object type for API Keys, this is always "api_key". +public enum APIKeyType: String, Decodable { + case apiKey = "api_key" +} + +/// The ID and type of the actor that created the API key. +public struct APIKeyActor: Decodable { + /// ID of the actor that created the object. + public let id: String + /// Type of the actor that created the object. + public let type: String +} + +/// Status of the API key. +public enum APIKeyStatus: String, Codable { + case active + case inactive + case archived +} + +public struct APIKeyResponse: Decodable { + /// ID of the API key. + public let id: String + /// Object type for API Keys, this is always "api_key". + public let type: APIKeyType + /// Name of the API key. + public let name: String + /// ID of the Workspace associated with the API key, or null if the API key belongs to the default Workspace. + public let workspaceId: String? + /// RFC 3339 datetime string indicating when the API Key was created. + public let createdAt: String + /// The ID and type of the actor that created the API key. + public let createdBy: APIKeyActor + /// Partially redacted hint for the API key. + public let partialKeyHint: String? + /// Status of the API key. + public let status: APIKeyStatus +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/BatchListResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/BatchListResponse.swift deleted file mode 100644 index a73ca81..0000000 --- a/Sources/AnthropicSwiftSDK/Network/Response/BatchListResponse.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// BatchListResponse.swift -// AnthropicSwiftSDK -// -// Created by 伊藤史 on 2024/10/09. -// - -/// https://docs.anthropic.com/en/api/listing-message-batches -public struct BatchListResponse: Decodable { - /// List of `BatchResponse` object. - public let data: [BatchResponse] - /// Indicates if there are more results in the requested page direction. - public let hasMore: Bool - /// First ID in the `data` list. Can be used as the `before_id` for the previous page. - public let firstId: String? - /// Last ID in the `data` list. Can be used as the `after_id` for the next page. - public let lastId: String? -} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/InvitationRemoveResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/InvitationRemoveResponse.swift new file mode 100644 index 0000000..68121ea --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/InvitationRemoveResponse.swift @@ -0,0 +1,18 @@ +// +// InvitationRemoveResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +/// Deleted object type for Invites, this is always "invite_deleted". +public enum InvitationDeletedType: String, Decodable { + case deleted = "invite_deleted" +} + +public struct InvitationRemoveResponse: Decodable { + /// ID of the Invite. + public let id: String + /// Deleted object type for Invites, this is always "invite_deleted". + public let type: InvitationDeletedType +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/InvitationResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/InvitationResponse.swift new file mode 100644 index 0000000..1e4b8d5 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/InvitationResponse.swift @@ -0,0 +1,36 @@ +// +// InvitationResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +/// Object type for Invites, this is always "invite". +public enum InvitationType: String, Decodable { + case invite +} + +/// Status of the Invite. +public enum InvitationStatus: String, Decodable { + case accepted + case expired + case deleted + case pending +} + +public struct InvitationResponse: Decodable { + /// ID of the Invite. + public let id: String + /// Object type for Invites, this is always "invite". + public let type: InvitationType + /// Email of the User being invited. + public let email: String + /// Organization role of the User. + public let role: OrganizationRole + /// RFC 3339 datetime string indicating when the Invite was created. + public let invitedAt: String + /// RFC 3339 datetime string indicating when the Invite expires. + public let expiresAt: String + /// Status of the Invite. + public let status: InvitationStatus +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/ObjectListResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/ObjectListResponse.swift new file mode 100644 index 0000000..38cfe06 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/ObjectListResponse.swift @@ -0,0 +1,13 @@ +// +// ObjectListResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +public struct ObjectListResponse: Decodable { + public let data: [Object] + public let hasMore: Bool + public let firstId: String? + public let lastId: String? +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberRemoveResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberRemoveResponse.swift new file mode 100644 index 0000000..2032256 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberRemoveResponse.swift @@ -0,0 +1,18 @@ +// +// OrganizationMemberRemoveResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +/// Deleted object type for Users, this is always "user_deleted". +public enum OrganizationMemberDeletedType: String, Decodable { + case deleted = "user_deleted" +} + +public struct OrganizationMemberRemoveResponse: Decodable { + /// ID of the User. + public let id: String + /// Deleted object type for Users, this is always "user_deleted". + public let type: OrganizationMemberDeletedType +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberResponse.swift new file mode 100644 index 0000000..3ace29a --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberResponse.swift @@ -0,0 +1,26 @@ +// +// OrganizationMemberResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +/// Object type for Users, this is always "user". +public enum OrganizationMemberType: String, Decodable { + case user +} + +public struct OrganizationMemberResponse: Decodable { + /// ID of the User. + public let id: String + /// Object type for Users, this is always "user". + public let type: OrganizationMemberType + /// Email of the User. + public let email: String + /// Name of the User. + public let name: String + /// Organization role of the User. + public let role: OrganizationRole + /// RFC 3339 datetime string indicating when the User joined the Organization. + public let addedAt: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberRemoveResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberRemoveResponse.swift new file mode 100644 index 0000000..61be82a --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberRemoveResponse.swift @@ -0,0 +1,20 @@ +// +// WorkspaceMemberRemoveResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +public struct WorkspaceMemberRemoveResponse: Decodable { + /// ID of the User. + public let userId: String + /// ID of the Workspace. + public let workspaceId: String + /// Deleted object type for Workspace Members, this is always + public let type: WorkspaceMemberDeletedType +} + +/// Deleted object type for Invites, this is always "invite_deleted". +public enum WorkspaceMemberDeletedType: String, Decodable { + case deleted = "workspace_member_deleted" +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberResponse.swift new file mode 100644 index 0000000..204ba90 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberResponse.swift @@ -0,0 +1,21 @@ +// +// WorkspaceMemberResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +public enum WorkspaceMemberType: String, Decodable { + case workspaceMember = "workspace_member" +} + +public struct WorkspaceMemberResponse: Decodable { + /// Object type for Workspace Members, this is always + public let type: WorkspaceMemberType + /// ID of the User. + public let userId: String + /// ID of the Workspace. + public let workspaceId: String + /// Role of the Workspace Member. + public let workspaceRole: WorkspaceRole +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceResponse.swift new file mode 100644 index 0000000..857e6dc --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceResponse.swift @@ -0,0 +1,26 @@ +// +// WorkspaceResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +/// Object type for Workspaces, this is always "workspace". +public enum WorkspaceType: String, Decodable { + case workspace +} + +public struct WorkspaceResponse: Decodable { + /// ID of the Workspace. + public let id: String + /// Object type for Workspaces, this is always "workspace". + public let type: WorkspaceType + /// Name of the Workspace. + public let name: String + /// RFC 3339 datetime string indicating when the Workspace was created. + public let createdAt: String + /// RFC 3339 datetime string indicating when the Workspace was archived, or null if the Workspace is not archived. + public let archivedAt: String? + /// Hex color code representing the Workspace in the Anthropic Console. + public let displayColor: String +} diff --git a/Tests/AnthropicSwiftSDKTests/API/APIKeysTests.swift b/Tests/AnthropicSwiftSDKTests/API/APIKeysTests.swift new file mode 100644 index 0000000..22c239e --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/API/APIKeysTests.swift @@ -0,0 +1,94 @@ +// +// APIKeysTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +import AnthropicSwiftSDK_TestUtils +@testable import AnthropicSwiftSDK + +final class APIKeysTests: XCTestCase { + var session: URLSession! + var apiKeys: APIKeys! + + override func setUp() { + super.setUp() + let configuration = URLSessionConfiguration.default + configuration.protocolClasses = [HTTPMock.self] + session = URLSession(configuration: configuration) + + let apiKey = "test-api-key" + apiKeys = APIKeys(adminAPIKey: apiKey, session: session) + } + + func testGetAPIKey() async throws { + let expectation = XCTestExpectation(description: "Get API Key response") + + HTTPMock.inspectType = .response(""" + { + "id": "apikey_01Rj2N8SVvo6BePZj99NhmiT", + "type": "api_key", + "name": "Developer Key", + "workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "created_at": "2024-10-30T23:58:27.427722Z", + "created_by": { + "id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "type": "user" + }, + "partial_key_hint": "sk-ant-api03-R2D...igAA", + "status": "active" + } + """) + + let response = try await apiKeys.get(apiKeyId: "test-key-id") + XCTAssertEqual(response.id, "apikey_01Rj2N8SVvo6BePZj99NhmiT") + XCTAssertEqual(response.type, .apiKey) + XCTAssertEqual(response.name, "Developer Key") + XCTAssertEqual(response.workspaceId, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.createdAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.createdBy.id, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.createdBy.type, "user") + XCTAssertEqual(response.partialKeyHint, "sk-ant-api03-R2D...igAA") + XCTAssertEqual(response.status, .active) + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testUpdateAPIKey() async throws { + let expectation = XCTestExpectation(description: "Update API Key response") + + HTTPMock.inspectType = .response(""" + { + "id": "apikey_01Rj2N8SVvo6BePZj99NhmiT", + "type": "api_key", + "name": "Updated API Key", + "workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "created_at": "2024-10-30T23:58:27.427722Z", + "created_by": { + "id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "type": "user" + }, + "partial_key_hint": "sk-ant-api03-R2D...igAA", + "status": "inactive" + } + """) + + let updatedResponse = try await apiKeys.update(apiKeyId: "test-key-id", name: "Updated API Key", status: .inactive) + XCTAssertEqual(updatedResponse.id, "apikey_01Rj2N8SVvo6BePZj99NhmiT") + XCTAssertEqual(updatedResponse.type, .apiKey) + XCTAssertEqual(updatedResponse.name, "Updated API Key") + XCTAssertEqual(updatedResponse.workspaceId, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(updatedResponse.createdAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(updatedResponse.createdBy.id, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(updatedResponse.createdBy.type, "user") + XCTAssertEqual(updatedResponse.partialKeyHint, "sk-ant-api03-R2D...igAA") + XCTAssertEqual(updatedResponse.status, .inactive) + + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/MessageBatchesTests.swift b/Tests/AnthropicSwiftSDKTests/API/MessageBatchesTests.swift similarity index 100% rename from Tests/AnthropicSwiftSDKTests/MessageBatchesTests.swift rename to Tests/AnthropicSwiftSDKTests/API/MessageBatchesTests.swift diff --git a/Tests/AnthropicSwiftSDKTests/MessagesTests.swift b/Tests/AnthropicSwiftSDKTests/API/MessagesTests.swift similarity index 100% rename from Tests/AnthropicSwiftSDKTests/MessagesTests.swift rename to Tests/AnthropicSwiftSDKTests/API/MessagesTests.swift diff --git a/Tests/AnthropicSwiftSDKTests/API/OrganizationInvitesTests.swift b/Tests/AnthropicSwiftSDKTests/API/OrganizationInvitesTests.swift new file mode 100644 index 0000000..977e8a4 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/API/OrganizationInvitesTests.swift @@ -0,0 +1,100 @@ +// +// OrganizationInvitesTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +import AnthropicSwiftSDK_TestUtils +@testable import AnthropicSwiftSDK + +final class OrganizationInvitesTests: XCTestCase { + var session: URLSession! + var organizationInvites: OrganizationInvites! + + override func setUp() { + super.setUp() + let configuration = URLSessionConfiguration.default + configuration.protocolClasses = [HTTPMock.self] + session = URLSession(configuration: configuration) + + let apiKey = "test-api-key" + organizationInvites = OrganizationInvites(adminAPIKey: apiKey, session: session) + } + + func testGetOrganizationInvite() async throws { + let expectation = XCTestExpectation(description: "Get Organization Invite response") + + HTTPMock.inspectType = .response(""" + { + "id": "invite_015gWxCN9Hfg2QhZwTK7Mdeu", + "type": "invite", + "email": "user@emaildomain.com", + "role": "user", + "invited_at": "2024-10-30T23:58:27.427722Z", + "expires_at": "2024-11-20T23:58:27.427722Z", + "status": "pending" + } + """) + + let response = try await organizationInvites.get(invitationId: "invite_015gWxCN9Hfg2QhZwTK7Mdeu") + XCTAssertEqual(response.id, "invite_015gWxCN9Hfg2QhZwTK7Mdeu") + XCTAssertEqual(response.type, .invite) + XCTAssertEqual(response.email, "user@emaildomain.com") + XCTAssertEqual(response.role, .user) + XCTAssertEqual(response.invitedAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.expiresAt, "2024-11-20T23:58:27.427722Z") + XCTAssertEqual(response.status, .pending) + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testRemoveOrganizationInvite() async throws { + let expectation = XCTestExpectation(description: "Remove Organization Invite response") + + HTTPMock.inspectType = .response(""" + { + "id": "invite_015gWxCN9Hfg2QhZwTK7Mdeu", + "type": "invite_deleted" + } + """) + + let response = try await organizationInvites.remove(invitationId: "invite_015gWxCN9Hfg2QhZwTK7Mdeu") + XCTAssertEqual(response.id, "invite_015gWxCN9Hfg2QhZwTK7Mdeu") + XCTAssertEqual(response.type, .deleted) + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testSendOrganizationInvite() async throws { + let expectation = XCTestExpectation(description: "Send Organization Invite response") + + HTTPMock.inspectType = .response(""" + { + "id": "invite_015gWxCN9Hfg2QhZwTK7Mdeu", + "type": "invite", + "email": "user@emaildomain.com", + "role": "user", + "invited_at": "2024-10-30T23:58:27.427722Z", + "expires_at": "2024-11-20T23:58:27.427722Z", + "status": "pending" + } + """) + + let invite = Invitation(email: "user@emaildomain.com", role: .user) + let response = try await organizationInvites.send(invitation: invite) + XCTAssertEqual(response.id, "invite_015gWxCN9Hfg2QhZwTK7Mdeu") + XCTAssertEqual(response.type, .invite) + XCTAssertEqual(response.email, "user@emaildomain.com") + XCTAssertEqual(response.role, .user) + XCTAssertEqual(response.invitedAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.expiresAt, "2024-11-20T23:58:27.427722Z") + XCTAssertEqual(response.status, .pending) + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/API/OrganizationMembersTests.swift b/Tests/AnthropicSwiftSDKTests/API/OrganizationMembersTests.swift new file mode 100644 index 0000000..c9563b1 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/API/OrganizationMembersTests.swift @@ -0,0 +1,95 @@ +// +// OrganizationMembersTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +import AnthropicSwiftSDK_TestUtils +@testable import AnthropicSwiftSDK + +final class OrganizationMembersTests: XCTestCase { + var session: URLSession! + var organizationMembers: OrganizationMembers! + + override func setUp() { + super.setUp() + let configuration = URLSessionConfiguration.default + configuration.protocolClasses = [HTTPMock.self] + session = URLSession(configuration: configuration) + + let apiKey = "test-api-key" + organizationMembers = OrganizationMembers(adminAPIKey: apiKey, session: session) + } + + func testGetOrganizationMember() async throws { + let expectation = XCTestExpectation(description: "Get Organization Member response") + + HTTPMock.inspectType = .response(""" + { + "id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "type": "user", + "email": "user@emaildomain.com", + "name": "Jane Doe", + "role": "user", + "added_at": "2024-10-30T23:58:27.427722Z" + } + """) + + let response = try await organizationMembers.get(userId: "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.id, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.type, .user) + XCTAssertEqual(response.email, "user@emaildomain.com") + XCTAssertEqual(response.name, "Jane Doe") + XCTAssertEqual(response.role, .user) + XCTAssertEqual(response.addedAt, "2024-10-30T23:58:27.427722Z") + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testRemoveOrganizationMember() async throws { + let expectation = XCTestExpectation(description: "Remove Organization Member response") + + HTTPMock.inspectType = .response(""" + { + "id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "type": "user_deleted" + } + """) + + let response = try await organizationMembers.remove(userId: "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.id, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.type, .deleted) + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testUpdateOrganizationMember() async throws { + let expectation = XCTestExpectation(description: "Update Organization Member response") + + HTTPMock.inspectType = .response(""" + { + "id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "type": "user", + "email": "updated_user@emaildomain.com", + "name": "Updated Jane Doe", + "role": "admin", + "added_at": "2024-10-30T23:58:27.427722Z" + } + """) + + let response = try await organizationMembers.update(userId: "user_01WCz1FkmYMm4gnmykNKUu3Q", role: .admin) + XCTAssertEqual(response.id, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.type, .user) + XCTAssertEqual(response.email, "updated_user@emaildomain.com") + XCTAssertEqual(response.name, "Updated Jane Doe") + XCTAssertEqual(response.role, .admin) + XCTAssertEqual(response.addedAt, "2024-10-30T23:58:27.427722Z") + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/API/WorkspaceMembersTests.swift b/Tests/AnthropicSwiftSDKTests/API/WorkspaceMembersTests.swift new file mode 100644 index 0000000..3b87da4 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/API/WorkspaceMembersTests.swift @@ -0,0 +1,89 @@ +// +// WorkspaceMembersTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +import AnthropicSwiftSDK_TestUtils +@testable import AnthropicSwiftSDK + +final class WorkspaceMembersTests: XCTestCase { + var session: URLSession! + var workspaceMembers: WorkspaceMembers! + + override func setUp() { + super.setUp() + let configuration = URLSessionConfiguration.default + configuration.protocolClasses = [HTTPMock.self] + session = URLSession(configuration: configuration) + + let apiKey = "test-api-key" + workspaceMembers = WorkspaceMembers(adminAPIKey: apiKey, session: session) + } + + func testGetWorkspaceMember() async throws { + let expectation = XCTestExpectation(description: "Get Workspace Member response") + + HTTPMock.inspectType = .response(""" + { + "type": "workspace_member", + "user_id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "workspace_role": "workspace_user" + } + """) + + let response = try await workspaceMembers.get(userId: "user_01WCz1FkmYMm4gnmykNKUu3Q", workspaceId: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.userId, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.workspaceId, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.workspaceRole, .user) + XCTAssertEqual(response.type, .workspaceMember) + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testRemoveWorkspaceMember() async throws { + let expectation = XCTestExpectation(description: "Remove Workspace Member response") + + HTTPMock.inspectType = .response(""" + { + "user_id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "type": "workspace_member_deleted" + } + """) + + let response = try await workspaceMembers.remove(userId: "user_01WCz1FkmYMm4gnmykNKUu3Q", workspaceId: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.userId, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.workspaceId, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.type, .deleted) + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testUpdateWorkspaceMember() async throws { + let expectation = XCTestExpectation(description: "Update Workspace Member response") + + HTTPMock.inspectType = .response(""" + { + "type": "workspace_member", + "user_id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "workspace_role": "workspace_admin" + } + """) + + let response = try await workspaceMembers.update(userId: "user_01WCz1FkmYMm4gnmykNKUu3Q", workspaceId: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", role: .admin) + XCTAssertEqual(response.userId, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.workspaceId, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.workspaceRole, .admin) + XCTAssertEqual(response.type, .workspaceMember) + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/API/WorkspacesTests.swift b/Tests/AnthropicSwiftSDKTests/API/WorkspacesTests.swift new file mode 100644 index 0000000..52a7313 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/API/WorkspacesTests.swift @@ -0,0 +1,129 @@ +// +// WorkspacesTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +import AnthropicSwiftSDK_TestUtils +@testable import AnthropicSwiftSDK + +final class WorkspacesTests: XCTestCase { + var session: URLSession! + var workspaces: Workspaces! + + override func setUp() { + super.setUp() + let configuration = URLSessionConfiguration.default + configuration.protocolClasses = [HTTPMock.self] + session = URLSession(configuration: configuration) + + let apiKey = "test-api-key" + workspaces = Workspaces(adminAPIKey: apiKey, session: session) + } + + func testGetWorkspace() async throws { + let expectation = XCTestExpectation(description: "Get Workspace response") + + HTTPMock.inspectType = .response(""" + { + "id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "type": "workspace", + "name": "Workspace Name", + "created_at": "2024-10-30T23:58:27.427722Z", + "archived_at": "2024-11-01T23:59:27.427722Z", + "display_color": "#6C5BB9" + } + """) + + let response = try await workspaces.get(workspaceId: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.id, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.type, .workspace) + XCTAssertEqual(response.name, "Workspace Name") + XCTAssertEqual(response.createdAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.archivedAt, "2024-11-01T23:59:27.427722Z") + XCTAssertEqual(response.displayColor, "#6C5BB9") + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testCreateWorkspace() async throws { + let expectation = XCTestExpectation(description: "Create Workspace response") + + HTTPMock.inspectType = .response(""" + { + "id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "type": "workspace", + "name": "New Workspace", + "created_at": "2024-10-30T23:58:27.427722Z", + "archived_at": null, + "display_color": "#6C5BB9" + } + """) + + let response = try await workspaces.create(name: "New Workspace") + XCTAssertEqual(response.id, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.type, .workspace) + XCTAssertEqual(response.name, "New Workspace") + XCTAssertEqual(response.createdAt, "2024-10-30T23:58:27.427722Z") + XCTAssertNil(response.archivedAt) + XCTAssertEqual(response.displayColor, "#6C5BB9") + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testArchiveWorkspace() async throws { + let expectation = XCTestExpectation(description: "Archive Workspace response") + + HTTPMock.inspectType = .response(""" + { + "id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "type": "workspace", + "name": "Workspace Name", + "created_at": "2024-10-30T23:58:27.427722Z", + "archived_at": "2024-11-01T23:59:27.427722Z", + "display_color": "#6C5BB9" + } + """) + + let response = try await workspaces.archive("wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.id, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.type, .workspace) + XCTAssertEqual(response.name, "Workspace Name") + XCTAssertEqual(response.createdAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.archivedAt, "2024-11-01T23:59:27.427722Z") + XCTAssertEqual(response.displayColor, "#6C5BB9") + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testUpdateWorkspace() async throws { + let expectation = XCTestExpectation(description: "Update Workspace response") + + HTTPMock.inspectType = .response(""" + { + "id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "type": "workspace", + "name": "Updated Workspace Name", + "created_at": "2024-10-30T23:58:27.427722Z", + "archived_at": "2024-11-01T23:59:27.427722Z", + "display_color": "#6C5BB9" + } + """) + + let response = try await workspaces.update(name: "Updated Workspace Name", workspaceId: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.id, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.type, .workspace) + XCTAssertEqual(response.name, "Updated Workspace Name") + XCTAssertEqual(response.createdAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.archivedAt, "2024-11-01T23:59:27.427722Z") + XCTAssertEqual(response.displayColor, "#6C5BB9") + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } +} \ No newline at end of file diff --git a/Tests/AnthropicSwiftSDKTests/Network/AnthropicAPIClientTests.swift b/Tests/AnthropicSwiftSDKTests/Network/AnthropicAPIClientTests.swift index 3d73270..481d1d5 100644 --- a/Tests/AnthropicSwiftSDKTests/Network/AnthropicAPIClientTests.swift +++ b/Tests/AnthropicSwiftSDKTests/Network/AnthropicAPIClientTests.swift @@ -34,7 +34,7 @@ final class AnthropicAPIClientTests: XCTestCase { expectation.fulfill() }, nil) - let _ = try await client.send(request: NopRequest()) + let _: MessagesResponse = try await client.send(request: NopRequest()) await fulfillment(of: [expectation], timeout: 1.0) } @@ -74,7 +74,7 @@ final class AnthropicAPIClientTests: XCTestCase { expectation.fulfill() }, nil) - let _ = try await client.send(request: NopRequest()) + let _: MessagesResponse = try await client.send(request: NopRequest()) await fulfillment(of: [expectation], timeout: 1.0) } diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/ArchiveWorkspaceRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/ArchiveWorkspaceRequestTests.swift new file mode 100644 index 0000000..52b703a --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/ArchiveWorkspaceRequestTests.swift @@ -0,0 +1,20 @@ +// +// ArchiveWorkspaceRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class ArchiveWorkspaceRequestTests: XCTestCase { + func testArchiveWorkspaceRequest() throws { + let request = ArchiveWorkspaceRequest(workspaceId: "test-workspace-id") + + XCTAssertEqual(request.method, HttpMethod.post) + XCTAssertEqual(request.path, "\(RequestType.workspace.basePath)/test-workspace-id/archive") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateOrganizationInviteRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateOrganizationInviteRequestTests.swift new file mode 100644 index 0000000..fde6d41 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateOrganizationInviteRequestTests.swift @@ -0,0 +1,23 @@ +// +// CreateOrganizationInviteRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class CreateOrganizationInviteRequestTests: XCTestCase { + func testCreateOrganizationInviteRequest() throws { + let invite = Invitation(email: "test@example.com", role: .user) + let request = CreateOrganizationInviteRequest(body: invite) + + XCTAssertEqual(request.method, HttpMethod.post) + XCTAssertEqual(request.path, RequestType.organizationInvite.basePath) + XCTAssertNil(request.queries) + XCTAssertNotNil(request.body) + XCTAssertEqual(request.body?.email, invite.email) + XCTAssertEqual(request.body?.role, invite.role) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateWorkspaceMemberRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateWorkspaceMemberRequestTests.swift new file mode 100644 index 0000000..9b54fc9 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateWorkspaceMemberRequestTests.swift @@ -0,0 +1,23 @@ +// +// CreateWorkspaceMemberRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class CreateWorkspaceMemberRequestTests: XCTestCase { + func testCreateWorkspaceMemberRequest() throws { + let registration = Registration(userId: "1234wert", workspaceRole: .developer) + let request = CreateWorkspaceMemberRequest(body: registration, workspaceId: "test-workspace-id") + + XCTAssertEqual(request.method, HttpMethod.post) + XCTAssertEqual(request.path, RequestType.workspaceMember(workspaceId: "test-workspace-id").basePath) + XCTAssertNil(request.queries) + XCTAssertNotNil(request.body) + XCTAssertEqual(request.body?.userId, registration.userId) + XCTAssertEqual(request.body?.workspaceRole, registration.workspaceRole) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateWorkspaceRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateWorkspaceRequestTests.swift new file mode 100644 index 0000000..39c88df --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateWorkspaceRequestTests.swift @@ -0,0 +1,21 @@ +// +// CreateWorkspaceRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class CreateWorkspaceRequestTests: XCTestCase { + func testCreateWorkspaceRequest() throws { + let request = CreateWorkspaceRequest(body: .init(name: "Test Workspace")) + + XCTAssertEqual(request.method, HttpMethod.post) + XCTAssertEqual(request.path, RequestType.workspace.basePath) + XCTAssertNil(request.queries) + XCTAssertNotNil(request.body) + XCTAssertEqual(request.body?.name, "Test Workspace") + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/DeleteOrganizationInviteRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/DeleteOrganizationInviteRequestTests.swift new file mode 100644 index 0000000..033c512 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/DeleteOrganizationInviteRequestTests.swift @@ -0,0 +1,20 @@ +// +// DeleteOrganizationInviteRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class DeleteOrganizationInviteRequestTests: XCTestCase { + func testDeleteOrganizationInviteRequest() throws { + let request = DeleteOrganizationInviteRequest(invitationId: "foo-bar") + + XCTAssertEqual(request.method, HttpMethod.delete) + XCTAssertEqual(request.path, "\(RequestType.organizationInvite.basePath)/foo-bar") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/DeleteWorkspaceMemberRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/DeleteWorkspaceMemberRequestTests.swift new file mode 100644 index 0000000..56c9bfb --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/DeleteWorkspaceMemberRequestTests.swift @@ -0,0 +1,22 @@ +// +// DeleteWorkspaceMemberRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class DeleteWorkspaceMemberRequestTests: XCTestCase { + func testDeleteWorkspaceMemberRequest() throws { + let userId = "test-user-id" + let workspaceId = "test-workspace-id" + let request = DeleteWorkspaceMemberRequest(userId: userId, workspaceId: workspaceId) + + XCTAssertEqual(request.method, HttpMethod.delete) + XCTAssertEqual(request.path, "\(RequestType.workspaceMember(workspaceId: workspaceId).basePath)/\(userId)") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetAPIKeyRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetAPIKeyRequestTests.swift new file mode 100644 index 0000000..3f88108 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetAPIKeyRequestTests.swift @@ -0,0 +1,20 @@ +// +// GetAPIKeyRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class GetAPIKeyRequestTests: XCTestCase { + func testGetAPIKeyRequest() throws { + let request = GetAPIKeyRequest(apiKeyId: "apikeyid") + + XCTAssertEqual(request.method, HttpMethod.get) + XCTAssertEqual(request.path, "\(RequestType.apiKey.basePath)/apikeyid") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetOrganizationInviteRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetOrganizationInviteRequestTests.swift new file mode 100644 index 0000000..ccda114 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetOrganizationInviteRequestTests.swift @@ -0,0 +1,21 @@ +// +// GetOrganizationInviteRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class GetOrganizationInviteRequestTests: XCTestCase { + func testGetOrganizationInviteRequest() throws { + let invitationId = "invite-id" + let request = GetOrganizationInviteRequest(invitationId: invitationId) + + XCTAssertEqual(request.method, HttpMethod.get) + XCTAssertEqual(request.path, "\(RequestType.organizationInvite.basePath)/\(invitationId)") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetOrganizationMemberRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetOrganizationMemberRequestTests.swift new file mode 100644 index 0000000..2fbebac --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetOrganizationMemberRequestTests.swift @@ -0,0 +1,21 @@ +// +// GetOrganizationMemberRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class GetOrganizationMemberRequestTests: XCTestCase { + func testGetOrganizationMemberRequest() throws { + let userId = "test-user-id" + let request = GetOrganizationMemberRequest(userId: userId) + + XCTAssertEqual(request.method, HttpMethod.get) + XCTAssertEqual(request.path, "\(RequestType.organizationMember.basePath)/\(userId)") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetWorkspaceMemberRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetWorkspaceMemberRequestTests.swift new file mode 100644 index 0000000..24b8695 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetWorkspaceMemberRequestTests.swift @@ -0,0 +1,22 @@ +// +// GetWorkspaceMemberRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class GetWorkspaceMemberRequestTests: XCTestCase { + func testGetWorkspaceMemberRequest() throws { + let userId = "test-user-id" + let workspaceId = "test-workspace-id" + let request = GetWorkspaceMemberRequest(workspaceId: workspaceId, userId: userId) + + XCTAssertEqual(request.method, HttpMethod.get) + XCTAssertEqual(request.path, "\(RequestType.workspaceMember(workspaceId: workspaceId).basePath)/\(userId)") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetWorkspaceRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetWorkspaceRequestTests.swift new file mode 100644 index 0000000..4914813 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetWorkspaceRequestTests.swift @@ -0,0 +1,21 @@ +// +// GetWorkspaceRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class GetWorkspaceRequestTests: XCTestCase { + func testGetWorkspaceRequest() throws { + let workspaceId = "test-workspace-id" + let request = GetWorkspaceRequest(workspaceId: workspaceId) + + XCTAssertEqual(request.method, HttpMethod.get) + XCTAssertEqual(request.path, "\(RequestType.workspace.basePath)/\(workspaceId)") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/RemoveOrganizationMemberRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/RemoveOrganizationMemberRequestTests.swift new file mode 100644 index 0000000..570b704 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/RemoveOrganizationMemberRequestTests.swift @@ -0,0 +1,21 @@ +// +// RemoveOrganizationMemberRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class RemoveOrganizationMemberRequestTests: XCTestCase { + func testRemoveOrganizationMemberRequest() throws { + let userId = "test-user-id" + let request = RemoveOrganizationMemberRequest(userId: userId) + + XCTAssertEqual(request.method, HttpMethod.delete) + XCTAssertEqual(request.path, "\(RequestType.organizationMember.basePath)/\(userId)") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateAPIKeyRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateAPIKeyRequestTests.swift new file mode 100644 index 0000000..0b2a952 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateAPIKeyRequestTests.swift @@ -0,0 +1,24 @@ +// +// UpdateAPIKeyRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class UpdateAPIKeyRequestTests: XCTestCase { + func testUpdateAPIKeyRequest() throws { + let apiKeyId = "apikeyid" + let newKeyName = "newkeyname" + let request = UpdateAPIKeyRequest(body: .init(name: newKeyName, status: .inactive), apiKeyId: apiKeyId) + + XCTAssertEqual(request.method, .post) + XCTAssertEqual(request.path, "\(RequestType.apiKey.basePath)/\(apiKeyId)") + XCTAssertNil(request.queries) + XCTAssertNotNil(request.body) + XCTAssertEqual(request.body?.name, newKeyName) + XCTAssertEqual(request.body?.status, .inactive) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateOrganizationMemberRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateOrganizationMemberRequestTests.swift new file mode 100644 index 0000000..2fd75ae --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateOrganizationMemberRequestTests.swift @@ -0,0 +1,23 @@ +// +// UpdateOrganizationMemberRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class UpdateOrganizationMemberRequestTests: XCTestCase { + func testUpdateOrganizationMemberRequest() throws { + let userId = "test-user-id" + let role = OrganizationRole.admin + let request = UpdateOrganizationMemberRequest(body: .init(role: role), userId: userId) + + XCTAssertEqual(request.method, .post) + XCTAssertEqual(request.path, "\(RequestType.organizationMember.basePath)/\(userId)") + XCTAssertNil(request.queries) + XCTAssertNotNil(request.body) + XCTAssertEqual(request.body?.role, role) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateWorkspaceMemberRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateWorkspaceMemberRequestTests.swift new file mode 100644 index 0000000..129bffc --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateWorkspaceMemberRequestTests.swift @@ -0,0 +1,24 @@ +// +// UpdateWorkspaceMemberRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class UpdateWorkspaceMemberRequestTests: XCTestCase { + func testUpdateWorkspaceMemberRequest() throws { + let userId = "test-user-id" + let workspaceId = "test-workspace-id" + let role = WorkspaceRole.developer + let request = UpdateWorkspaceMemberRequest(body: .init(role: role), userId: userId, workspaceId: workspaceId) + + XCTAssertEqual(request.method, HttpMethod.post) + XCTAssertEqual(request.path, "\(RequestType.workspaceMember(workspaceId: workspaceId).basePath)/\(userId)") + XCTAssertNil(request.queries) + XCTAssertNotNil(request.body) + XCTAssertEqual(request.body?.role, role) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateWorkspaceRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateWorkspaceRequestTests.swift new file mode 100644 index 0000000..a47081e --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateWorkspaceRequestTests.swift @@ -0,0 +1,35 @@ +// +// UpdateWorkspaceRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest + +final class UpdateWorkspaceRequestTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/ListMessageBatchesRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/ListMessageBatchesRequestTests.swift index e0f8018..dfd63c7 100644 --- a/Tests/AnthropicSwiftSDKTests/Network/Request/ListMessageBatchesRequestTests.swift +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/ListMessageBatchesRequestTests.swift @@ -8,15 +8,15 @@ import XCTest @testable import AnthropicSwiftSDK -final class ListMessageBatchesRequestTests: XCTestCase { +final class ListObjectRequestTests: XCTestCase { - func testListMessageBatchesRequestProperties() { + func testListObjectRequestProperties() { let queries: [String: CustomStringConvertible] = [ "before_id": "batch123", "after_id": "batch456", "limit": 10 ] - let request = ListMessageBatchesRequest(queries: queries) + let request = ListObjectRequest(queries: queries, type: .batches) XCTAssertEqual(request.method, .get) XCTAssertEqual(request.path, RequestType.batches.basePath) @@ -27,8 +27,8 @@ final class ListMessageBatchesRequestTests: XCTestCase { } func testParameterRawValues() { - XCTAssertEqual(ListMessageBatchesRequest.Parameter.beforeId.rawValue, "before_id") - XCTAssertEqual(ListMessageBatchesRequest.Parameter.afterId.rawValue, "after_id") - XCTAssertEqual(ListMessageBatchesRequest.Parameter.limit.rawValue, "limit") + XCTAssertEqual(ListObjectRequest.Parameter.beforeId.rawValue, "before_id") + XCTAssertEqual(ListObjectRequest.Parameter.afterId.rawValue, "after_id") + XCTAssertEqual(ListObjectRequest.Parameter.limit.rawValue, "limit") } } diff --git a/Tests/AnthropicSwiftSDKTests/Network/Response/APIKeyResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/APIKeyResponseTests.swift new file mode 100644 index 0000000..ac9588c --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Response/APIKeyResponseTests.swift @@ -0,0 +1,42 @@ +// +// APIKeyResponseTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/06. +// + +import XCTest +import AnthropicSwiftSDK + +final class APIKeyResponseTests: XCTestCase { + func testDecodeAPIKeyResponse() throws { + let json = """ + { + "id": "apikey_01Rj2N8SVvo6BePZj99NhmiT", + "type": "api_key", + "name": "Developer Key", + "workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "created_at": "2024-10-30T23:58:27.427722Z", + "created_by": { + "id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "type": "user" + }, + "partial_key_hint": "sk-ant-api03-R2D...igAA", + "status": "active" + } + """ + + let jsonData = json.data(using: .utf8)! + let response = try anthropicJSONDecoder.decode(APIKeyResponse.self, from: jsonData) + + XCTAssertEqual(response.id, "apikey_01Rj2N8SVvo6BePZj99NhmiT") + XCTAssertEqual(response.type, .apiKey) + XCTAssertEqual(response.name, "Developer Key") + XCTAssertEqual(response.workspaceId, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.createdAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.createdBy.id, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.createdBy.type, "user") + XCTAssertEqual(response.partialKeyHint, "sk-ant-api03-R2D...igAA") + XCTAssertEqual(response.status, .active) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/BatchResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/BatchResponseTests.swift similarity index 100% rename from Tests/AnthropicSwiftSDKTests/Network/BatchResponseTests.swift rename to Tests/AnthropicSwiftSDKTests/Network/Response/BatchResponseTests.swift diff --git a/Tests/AnthropicSwiftSDKTests/Network/BatchResultResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/BatchResultResponseTests.swift similarity index 100% rename from Tests/AnthropicSwiftSDKTests/Network/BatchResultResponseTests.swift rename to Tests/AnthropicSwiftSDKTests/Network/Response/BatchResultResponseTests.swift diff --git a/Tests/AnthropicSwiftSDKTests/Network/MessagesResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/MessagesResponseTests.swift similarity index 100% rename from Tests/AnthropicSwiftSDKTests/Network/MessagesResponseTests.swift rename to Tests/AnthropicSwiftSDKTests/Network/Response/MessagesResponseTests.swift diff --git a/Tests/AnthropicSwiftSDKTests/Network/BatchListResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/ObjectListResponseTests.swift similarity index 95% rename from Tests/AnthropicSwiftSDKTests/Network/BatchListResponseTests.swift rename to Tests/AnthropicSwiftSDKTests/Network/Response/ObjectListResponseTests.swift index 3d024f4..88203aa 100644 --- a/Tests/AnthropicSwiftSDKTests/Network/BatchListResponseTests.swift +++ b/Tests/AnthropicSwiftSDKTests/Network/Response/ObjectListResponseTests.swift @@ -1,5 +1,5 @@ // -// BatchListResponseTests.swift +// ObjectListResponseTests.swift // AnthropicSwiftSDK // // Created by 伊藤史 on 2024/10/18. @@ -8,7 +8,7 @@ import XCTest @testable import AnthropicSwiftSDK -final class BatchListResponseTests: XCTestCase { +final class ObjectListResponseTests: XCTestCase { func testDecodeBatchListResponse() throws { let json = """ { @@ -56,7 +56,7 @@ final class BatchListResponseTests: XCTestCase { let jsonData = json.data(using: .utf8)! - let response = try anthropicJSONDecoder.decode(BatchListResponse.self, from: jsonData) + let response = try anthropicJSONDecoder.decode(ObjectListResponse.self, from: jsonData) XCTAssertEqual(response.data.count, 2) @@ -96,4 +96,4 @@ final class BatchListResponseTests: XCTestCase { XCTAssertEqual(response.firstId, "batch_123") XCTAssertEqual(response.lastId, "batch_456") } -} \ No newline at end of file +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Response/OrganizationInviteResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/OrganizationInviteResponseTests.swift new file mode 100644 index 0000000..98a2024 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Response/OrganizationInviteResponseTests.swift @@ -0,0 +1,51 @@ +// +// OrganizationInviteResponseTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/06. +// + +import XCTest +import AnthropicSwiftSDK + +final class OrganizationInviteResponseTests: XCTestCase { + func testDecodeOrganizationInviteResponse() throws { + let json = """ + { + "id": "invite_015gWxCN9Hfg2QhZwTK7Mdeu", + "type": "invite", + "email": "user@emaildomain.com", + "role": "user", + "invited_at": "2024-10-30T23:58:27.427722Z", + "expires_at": "2024-11-20T23:58:27.427722Z", + "status": "pending" + } + """ + + let jsonData = json.data(using: .utf8)! + let response = try anthropicJSONDecoder.decode(InvitationResponse.self, from: jsonData) + + XCTAssertEqual(response.id, "invite_015gWxCN9Hfg2QhZwTK7Mdeu") + XCTAssertEqual(response.type, .invite) + XCTAssertEqual(response.email, "user@emaildomain.com") + XCTAssertEqual(response.role, .user) + XCTAssertEqual(response.invitedAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.expiresAt, "2024-11-20T23:58:27.427722Z") + XCTAssertEqual(response.status, .pending) + } + + func testDecodeOrganizationInviteRemoveResponse() throws { + let json = """ + { + "id": "invite_015gWxCN9Hfg2QhZwTK7Mdeu", + "type": "invite_deleted" + } + """ + + let jsonData = json.data(using: .utf8)! + let response = try anthropicJSONDecoder.decode(InvitationRemoveResponse.self, from: jsonData) + + XCTAssertEqual(response.id, "invite_015gWxCN9Hfg2QhZwTK7Mdeu") + XCTAssertEqual(response.type, .deleted) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Response/OrganizationMemberResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/OrganizationMemberResponseTests.swift new file mode 100644 index 0000000..5c5cdb3 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Response/OrganizationMemberResponseTests.swift @@ -0,0 +1,49 @@ +// +// OrganizationMemberResponseTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/06. +// + +import XCTest +import AnthropicSwiftSDK + +final class OrganizationMemberResponseTests: XCTestCase { + func testDecodeOrganizationMemberResponse() throws { + let json = """ + { + "id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "type": "user", + "email": "user@emaildomain.com", + "name": "Jane Doe", + "role": "user", + "added_at": "2024-10-30T23:58:27.427722Z" + } + """ + + let jsonData = json.data(using: .utf8)! + let response = try anthropicJSONDecoder.decode(OrganizationMemberResponse.self, from: jsonData) + + XCTAssertEqual(response.id, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.type, .user) + XCTAssertEqual(response.email, "user@emaildomain.com") + XCTAssertEqual(response.name, "Jane Doe") + XCTAssertEqual(response.role, .user) + XCTAssertEqual(response.addedAt, "2024-10-30T23:58:27.427722Z") + } + + func testDecodeOrganizationMemberRemoveResponse() throws { + let json = """ + { + "id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "type": "user_deleted" + } + """ + + let jsonData = json.data(using: .utf8)! + let response = try anthropicJSONDecoder.decode(OrganizationMemberRemoveResponse.self, from: jsonData) + + XCTAssertEqual(response.id, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.type, .deleted) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Response/WorkspaceMemberResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/WorkspaceMemberResponseTests.swift new file mode 100644 index 0000000..98eab2b --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Response/WorkspaceMemberResponseTests.swift @@ -0,0 +1,47 @@ +// +// WorkspaceMemberResponseTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/06. +// + +import XCTest +import AnthropicSwiftSDK + +final class WorkspaceMemberResponseTests: XCTestCase { + func testDecodeWorkspaceMemberResponse() throws { + let json = """ + { + "type": "workspace_member", + "user_id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "workspace_role": "workspace_user" + } + """ + + let jsonData = json.data(using: .utf8)! + let response = try anthropicJSONDecoder.decode(WorkspaceMemberResponse.self, from: jsonData) + + XCTAssertEqual(response.type, .workspaceMember) + XCTAssertEqual(response.userId, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.workspaceId, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.workspaceRole, .user) + } + + func testDecodeWorkspaceMemberRemoveResponse() throws { + let json = """ + { + "user_id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "type": "workspace_member_deleted" + } + """ + + let jsonData = json.data(using: .utf8)! + let response = try anthropicJSONDecoder.decode(WorkspaceMemberRemoveResponse.self, from: jsonData) + + XCTAssertEqual(response.userId, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.workspaceId, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.type, .deleted) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Response/WorkspaceResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/WorkspaceResponseTests.swift new file mode 100644 index 0000000..0b2fc25 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Response/WorkspaceResponseTests.swift @@ -0,0 +1,34 @@ +// +// WorkspaceResponseTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/06. +// + +import XCTest +import AnthropicSwiftSDK + +final class WorkspaceResponseTests: XCTestCase { + func testDecodeWorkspaceResponse() throws { + let json = """ + { + "id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "type": "workspace", + "name": "Workspace Name", + "created_at": "2024-10-30T23:58:27.427722Z", + "archived_at": "2024-11-01T23:59:27.427722Z", + "display_color": "#6C5BB9" + } + """ + + let jsonData = json.data(using: .utf8)! + let response = try anthropicJSONDecoder.decode(WorkspaceResponse.self, from: jsonData) + + XCTAssertEqual(response.id, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.type, .workspace) + XCTAssertEqual(response.name, "Workspace Name") + XCTAssertEqual(response.createdAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.archivedAt, "2024-11-01T23:59:27.427722Z") + XCTAssertEqual(response.displayColor, "#6C5BB9") + } +}