From 25be07e2bc897e4a3cf8cf64752f96f88ce94cc3 Mon Sep 17 00:00:00 2001 From: William Date: Wed, 24 Sep 2025 19:17:28 +0200 Subject: [PATCH 01/11] fix: added comments for what must be refactored, small typo fix --- Backend/Package.resolved | 11 ++++++++++- Backend/Package.swift | 2 +- .../PrometheusController/PrometheusController.swift | 2 ++ .../PrometheusControllerError.swift | 3 +++ .../App/Services/MetricsService/MetricsService.swift | 2 ++ Backend/Sources/App/entrypoint.swift | 1 - .../PrometheusControllerIntegrationTests.swift | 3 +++ 7 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Backend/Package.resolved b/Backend/Package.resolved index 50cfb276..8325f03b 100644 --- a/Backend/Package.resolved +++ b/Backend/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "fd696153ea81efb825467272117f6b70b5b5fa52dfde9a8035d412d86626d6d3", + "originHash" : "1d8db4abc125868abd7c0e97eb84f6246d39ee42a10a5f1676c43785a2426b91", "pins" : [ { "identity" : "alamofire", @@ -28,6 +28,15 @@ "version" : "1.20.0" } }, + { + "identity" : "automautilities", + "kind" : "remoteSourceControl", + "location" : "https://github.com/GetAutomaApp/AutomaUtilities", + "state" : { + "branch" : "main", + "revision" : "5273b2cfe710b81ef52b44eba1b66c6e5cef85c4" + } + }, { "identity" : "console-kit", "kind" : "remoteSourceControl", diff --git a/Backend/Package.swift b/Backend/Package.swift index 42785c0d..086041ee 100644 --- a/Backend/Package.swift +++ b/Backend/Package.swift @@ -1,7 +1,7 @@ // swift-tools-version:6.0 import PackageDescription -/// INitializes Package +/// Initializes Package public let package = Package( name: "Backend", platforms: [ diff --git a/Backend/Sources/App/Controllers/PrometheusController/PrometheusController.swift b/Backend/Sources/App/Controllers/PrometheusController/PrometheusController.swift index 44a0ce1f..2fdbfff0 100644 --- a/Backend/Sources/App/Controllers/PrometheusController/PrometheusController.swift +++ b/Backend/Sources/App/Controllers/PrometheusController/PrometheusController.swift @@ -8,6 +8,8 @@ import Fluent import Prometheus import Vapor +// PrometheusController can be re-used between projects, no need to create a new implementation each time + /// Controller for handling Prometheus metrics requests. internal struct PrometheusController: RouteCollection { /// Registers routes for Prometheus operations. diff --git a/Backend/Sources/App/Controllers/PrometheusController/PrometheusControllerError.swift b/Backend/Sources/App/Controllers/PrometheusController/PrometheusControllerError.swift index 83ed3556..94866e45 100644 --- a/Backend/Sources/App/Controllers/PrometheusController/PrometheusControllerError.swift +++ b/Backend/Sources/App/Controllers/PrometheusController/PrometheusControllerError.swift @@ -3,6 +3,9 @@ // All source code and related assets are the property of GetAutomaApp. // All rights reserved. +// Errors along with controller can be re-used between projects, +// no need to create a new implementation each time + /// Represents errors that can occur in the Prometheus controller. internal enum PrometheusControllerError: Error { /// Error indicating failure to convert metrics data to a string. diff --git a/Backend/Sources/App/Services/MetricsService/MetricsService.swift b/Backend/Sources/App/Services/MetricsService/MetricsService.swift index 78ad740f..13c838f1 100644 --- a/Backend/Sources/App/Services/MetricsService/MetricsService.swift +++ b/Backend/Sources/App/Services/MetricsService/MetricsService.swift @@ -7,6 +7,8 @@ import Foundation import Metrics import Prometheus +// MetricsService can be re-used between projects, no need to create a new implementation each time + /// Service for managing and emitting metrics. internal struct MetricsService { /// Global instance of the `MetricsService`. diff --git a/Backend/Sources/App/entrypoint.swift b/Backend/Sources/App/entrypoint.swift index 4c3bdcee..1e204e22 100644 --- a/Backend/Sources/App/entrypoint.swift +++ b/Backend/Sources/App/entrypoint.swift @@ -4,7 +4,6 @@ // All rights reserved. import Logging -import Metrics import NIOCore import NIOPosix import Vapor diff --git a/Backend/Tests/AppTests/Controllers/PrometheusControllerTests/PrometheusControllerIntegrationTests.swift b/Backend/Tests/AppTests/Controllers/PrometheusControllerTests/PrometheusControllerIntegrationTests.swift index 86504856..09d33e7f 100644 --- a/Backend/Tests/AppTests/Controllers/PrometheusControllerTests/PrometheusControllerIntegrationTests.swift +++ b/Backend/Tests/AppTests/Controllers/PrometheusControllerTests/PrometheusControllerIntegrationTests.swift @@ -8,6 +8,9 @@ import AutomaUtilities import Testing import VaporTesting +// Since most prometheus implementation code (MetricsService and PrometheusController) will be re-used, +// the prometheus tests can placed in the package that contains the implementation code + /// Integration tests for the `PrometheusController`. /// These tests verify the controller's ability to handle requests and return metrics data. @Suite("PrometheusControllerIntegrationTests") From 9a48054bd19bc88b61fe9cab0f95c941da2a0228 Mon Sep 17 00:00:00 2001 From: William Date: Fri, 26 Sep 2025 11:34:55 +0200 Subject: [PATCH 02/11] refactor: prometheus controller, message service and metrics service to automa utilities package Need to merge automa utilities refactor branch to master, update packages in this repository, and build package and fix any small errors that might arise --- .../Sources/DataTypes/GenericErrors.swift | 6 +- .../PrometheusController.swift | 65 ------ .../PrometheusControllerError.swift | 16 -- .../BackendMetric.swift} | 53 +---- .../Foundation/TaskExtensions.swift | 38 --- .../RequestIsAuthenticatedMiddleware.swift | 1 + .../TransactionalMessageAsyncJob.swift | 4 +- .../AuthenticationService.swift | 13 +- .../UserLoginService.swift | 1 + .../UserRegistrationService.swift | 1 + .../MessageFormatterService.swift | 42 ---- .../DiscordWebhookMessage.swift | 109 --------- .../MessageService/MessageService.swift | 217 ------------------ .../App/Services/SNSService/SNSService.swift | 101 ++++++++ ...PrometheusControllerIntegrationTests.swift | 55 ----- 15 files changed, 116 insertions(+), 606 deletions(-) delete mode 100644 Backend/Sources/App/Controllers/PrometheusController/PrometheusController.swift delete mode 100644 Backend/Sources/App/Controllers/PrometheusController/PrometheusControllerError.swift rename Backend/Sources/App/{Services/MetricsService/MetricsService.swift => DataTypes/BackendMetric.swift} (83%) delete mode 100644 Backend/Sources/App/Extensions/Foundation/TaskExtensions.swift delete mode 100644 Backend/Sources/App/Services/Formatters/MessageFormatterService/MessageFormatterService.swift delete mode 100644 Backend/Sources/App/Services/MessageService/DiscordWebhookMessage.swift delete mode 100644 Backend/Sources/App/Services/MessageService/MessageService.swift create mode 100644 Backend/Sources/App/Services/SNSService/SNSService.swift delete mode 100644 Backend/Tests/AppTests/Controllers/PrometheusControllerTests/PrometheusControllerIntegrationTests.swift diff --git a/Backend/DataTypes/Sources/DataTypes/GenericErrors.swift b/Backend/DataTypes/Sources/DataTypes/GenericErrors.swift index d42d51bf..8c20eebf 100644 --- a/Backend/DataTypes/Sources/DataTypes/GenericErrors.swift +++ b/Backend/DataTypes/Sources/DataTypes/GenericErrors.swift @@ -13,8 +13,6 @@ public enum GenericErrors: String, Error, Decodable, Encodable { /// Error related to Alamofire networking operations case alamofireError /// Error when sending a Discord webhook message fails - case discordWebhookMessageFailed - /// Error when response decoding fails case failedToDecodeResponse /// Error when response encoding fails case failedToEncodeResponse @@ -61,12 +59,10 @@ public enum GenericErrors: String, Error, Decodable, Encodable { "You're Authentication Token is Invalid!" case .invalidUserId: "You're UserID isn't a valid UUID. We're Investigating" - case .discordWebhookMessageFailed: - "Sorry, We couldn't send a message through the discord webhook" case .smsMessageFailed: "We are having some technical difficulties sending sms messages!" case .missingImage: - "" + "Image generation was unsuccessful" case .failedToDecodeResponse: "An Invalid Response Object was sent down to the client!" case .failedToEncodeResponse: diff --git a/Backend/Sources/App/Controllers/PrometheusController/PrometheusController.swift b/Backend/Sources/App/Controllers/PrometheusController/PrometheusController.swift deleted file mode 100644 index 2fdbfff0..00000000 --- a/Backend/Sources/App/Controllers/PrometheusController/PrometheusController.swift +++ /dev/null @@ -1,65 +0,0 @@ -// PrometheusController.swift -// Copyright (c) 2025 GetAutomaApp -// All source code and related assets are the property of GetAutomaApp. -// All rights reserved. - -import AutomaUtilities -import Fluent -import Prometheus -import Vapor - -// PrometheusController can be re-used between projects, no need to create a new implementation each time - -/// Controller for handling Prometheus metrics requests. -internal struct PrometheusController: RouteCollection { - /// Registers routes for Prometheus operations. - /// - Parameter routes: The routes builder to register routes on. - public func boot(routes: RoutesBuilder) throws { - let prometheusRoute = routes.grouped("Prometheus") - - prometheusRoute.get("metrics", use: metrics) - } - - /// Retrieves Prometheus metrics. - /// - Parameter req: The request object. - /// - Returns: A string containing the metrics data. - /// - Throws: An error if metrics retrieval or conversion fails. - @Sendable - public func metrics(req: Request) throws -> String { - try validate(req: req) - guard - let metrics = String(data: MetricsService.global.emit(), encoding: .utf8) - else { - try MessageService().sendDiscordAlert( - alertTitle: "Could not convert metrics to string.", - error: PrometheusControllerError.couldNotConvertMetricsToData, - logger: req.logger - ) - throw PrometheusControllerError.couldNotConvertMetricsToData - } - return metrics - } - - /// Validates the request for Prometheus metrics. - /// - Parameter req: The request object. - /// - Throws: An error if the authentication token is invalid. - private func validate(req: Request) throws { - let query = try req.query.decode(PrometheusRouteQuery.self) - let token = try Environment.getOrThrow("FLY_METRICS_TOKEN") - - guard query.authToken == token else { - throw PrometheusControllerError.invalidAuthToken - } - } -} - -/// Represents the query parameters for Prometheus routes. -internal struct PrometheusRouteQuery: Content { - /// The authentication token for accessing Prometheus metrics. - public let authToken: String - - /// Coding keys to map the JSON keys to the struct properties. - public enum CodingKeys: String, CodingKey { - case authToken = "auth_token" - } -} diff --git a/Backend/Sources/App/Controllers/PrometheusController/PrometheusControllerError.swift b/Backend/Sources/App/Controllers/PrometheusController/PrometheusControllerError.swift deleted file mode 100644 index 94866e45..00000000 --- a/Backend/Sources/App/Controllers/PrometheusController/PrometheusControllerError.swift +++ /dev/null @@ -1,16 +0,0 @@ -// PrometheusControllerError.swift -// Copyright (c) 2025 GetAutomaApp -// All source code and related assets are the property of GetAutomaApp. -// All rights reserved. - -// Errors along with controller can be re-used between projects, -// no need to create a new implementation each time - -/// Represents errors that can occur in the Prometheus controller. -internal enum PrometheusControllerError: Error { - /// Error indicating failure to convert metrics data to a string. - case couldNotConvertMetricsToData - - /// Error indicating an invalid authentication token. - case invalidAuthToken -} diff --git a/Backend/Sources/App/Services/MetricsService/MetricsService.swift b/Backend/Sources/App/DataTypes/BackendMetric.swift similarity index 83% rename from Backend/Sources/App/Services/MetricsService/MetricsService.swift rename to Backend/Sources/App/DataTypes/BackendMetric.swift index 13c838f1..8dc33e97 100644 --- a/Backend/Sources/App/Services/MetricsService/MetricsService.swift +++ b/Backend/Sources/App/DataTypes/BackendMetric.swift @@ -1,61 +1,12 @@ -// MetricsService.swift +// BackendMetric.swift // Copyright (c) 2025 GetAutomaApp // All source code and related assets are the property of GetAutomaApp. // All rights reserved. +import AutomaUtilities import Foundation -import Metrics import Prometheus -// MetricsService can be re-used between projects, no need to create a new implementation each time - -/// Service for managing and emitting metrics. -internal struct MetricsService { - /// Global instance of the `MetricsService`. - public static let global = Self() - - /// Prometheus collector registry for managing metrics. - private var prometheus: PrometheusCollectorRegistry - - /// Initializes a new instance of `MetricsService`. - private init() { - let prometheusRegistry = PrometheusCollectorRegistry() - let myProm = PrometheusMetricsFactory(registry: prometheusRegistry) - MetricsSystem.bootstrap(myProm) - - prometheus = prometheusRegistry - } - - /// Emits metrics into a buffer and returns the data. - /// - Returns: A `Data` object containing the emitted metrics. - public func emit() -> Data { - var buffer = [UInt8]() - prometheus.emit(into: &buffer) - let data = String(decoding: buffer, as: Unicode.UTF8.self) - return Data(data.utf8) - } - - /// Creates a counter type metric. - /// - Parameters: - /// - name: The name of the counter. - /// - labels: Optional labels for the counter. - /// - Returns: A `Prometheus.Counter` object. - public func makeCounter(name: String, labels: [String: String] = [:]) -> Prometheus.Counter { - prometheus - .makeCounter( - name: name, - labels: convertStringDictionaryToStringMap(labels) - ) - } - - /// Converts a dictionary of strings to a tuple array. - /// - Parameter dictionary: The dictionary to convert. - /// - Returns: An array of tuples representing the dictionary. - private func convertStringDictionaryToStringMap(_ dictionary: [String: String]) -> [(String, String)] { - zip(dictionary.keys, dictionary.values).map { ($0.0, $0.1) } - } -} - /// Enum for managing backend metrics. internal enum BackendMetric { /// Counter for successful verification codes sent. diff --git a/Backend/Sources/App/Extensions/Foundation/TaskExtensions.swift b/Backend/Sources/App/Extensions/Foundation/TaskExtensions.swift deleted file mode 100644 index fbd543dc..00000000 --- a/Backend/Sources/App/Extensions/Foundation/TaskExtensions.swift +++ /dev/null @@ -1,38 +0,0 @@ -// TaskExtensions.swift -// Copyright (c) 2025 GetAutomaApp -// All source code and related assets are the property of GetAutomaApp. -// All rights reserved. - -import Vapor - -/// Extension on Task to start a detached task & log raw output -internal extension Task where Success == Void, Failure == any Error { - /// Executes & logs success / error on end - static func detachedLogOnError( - destination: String, - logger: Logger, - onError: @escaping @Sendable (Error) async throws -> Void = { _ in }, - onSuccess: @escaping @Sendable () async throws -> Void = {}, - method: @escaping @Sendable () async throws -> Void - ) { - Task.detached { - do { - try await method() - } catch { - logger.critical( - "Error occurred while running detached task", - metadata: [ - "destination": .array([ - .string(destination), - .string("Task.detachedLogOnError"), - .string(error.localizedDescription), - ]), - ] - ) - try await onError(error) - } - - try await onSuccess() - } - } -} diff --git a/Backend/Sources/App/Middleware/Authentication/RequestIsAuthenticatedMiddleware.swift b/Backend/Sources/App/Middleware/Authentication/RequestIsAuthenticatedMiddleware.swift index 422a985c..255c8126 100644 --- a/Backend/Sources/App/Middleware/Authentication/RequestIsAuthenticatedMiddleware.swift +++ b/Backend/Sources/App/Middleware/Authentication/RequestIsAuthenticatedMiddleware.swift @@ -3,6 +3,7 @@ // All source code and related assets are the property of GetAutomaApp. // All rights reserved. +import AutomaUtilities import DataTypes import Vapor diff --git a/Backend/Sources/App/Procs/Jobs/TransactionalMessageAsyncJob/TransactionalMessageAsyncJob.swift b/Backend/Sources/App/Procs/Jobs/TransactionalMessageAsyncJob/TransactionalMessageAsyncJob.swift index ee9a70b5..598ea6e9 100644 --- a/Backend/Sources/App/Procs/Jobs/TransactionalMessageAsyncJob/TransactionalMessageAsyncJob.swift +++ b/Backend/Sources/App/Procs/Jobs/TransactionalMessageAsyncJob/TransactionalMessageAsyncJob.swift @@ -25,10 +25,10 @@ internal struct TransactionalMessageAsyncJob: AsyncJob { /// - payload: The input payload containing message data. /// - Throws: Throws an error if the message sending fails. public func dequeue(_ context: QueueContext, _ payload: TransactionalMessageJobInput) async throws { - let messageService = MessageService() + let snsService = SNSService() // Send the SMS message - _ = try await messageService + _ = try await snsService .sendSmS( to: payload.toPhoneNumber, message: payload.content, diff --git a/Backend/Sources/App/Services/AuthenticationService/AuthenticationService.swift b/Backend/Sources/App/Services/AuthenticationService/AuthenticationService.swift index a0fe2f51..0cd29453 100644 --- a/Backend/Sources/App/Services/AuthenticationService/AuthenticationService.swift +++ b/Backend/Sources/App/Services/AuthenticationService/AuthenticationService.swift @@ -3,6 +3,7 @@ // All source code and related assets are the property of GetAutomaApp. // All rights reserved. +import AutomaUtilities import DataTypes import Fluent import JWT @@ -239,12 +240,12 @@ internal protocol AuthenticationService { } internal protocol AuthenticationServiceConfig { - /// Db w/ write access - var writeDb: Database { get } - /// Db w/ readonly access - var readDb: Database { get } - /// Logger - var logger: Logger { get } + /// Db w/ write access + var writeDb: Database { get } + /// Db w/ readonly access + var readDb: Database { get } + /// Logger + var logger: Logger { get } } internal struct RootAuthenticationServiceConfig: AuthenticationServiceConfig { diff --git a/Backend/Sources/App/Services/AuthenticationService/UserLoginService.swift b/Backend/Sources/App/Services/AuthenticationService/UserLoginService.swift index a815561c..546a2d19 100644 --- a/Backend/Sources/App/Services/AuthenticationService/UserLoginService.swift +++ b/Backend/Sources/App/Services/AuthenticationService/UserLoginService.swift @@ -3,6 +3,7 @@ // All source code and related assets are the property of GetAutomaApp. // All rights reserved. +import AutomaUtilities import DataTypes import Fluent import JWT diff --git a/Backend/Sources/App/Services/AuthenticationService/UserRegistrationService.swift b/Backend/Sources/App/Services/AuthenticationService/UserRegistrationService.swift index 96a79888..e0a44ece 100644 --- a/Backend/Sources/App/Services/AuthenticationService/UserRegistrationService.swift +++ b/Backend/Sources/App/Services/AuthenticationService/UserRegistrationService.swift @@ -3,6 +3,7 @@ // All source code and related assets are the property of GetAutomaApp. // All rights reserved. +import AutomaUtilities import DataTypes import Fluent import JWT diff --git a/Backend/Sources/App/Services/Formatters/MessageFormatterService/MessageFormatterService.swift b/Backend/Sources/App/Services/Formatters/MessageFormatterService/MessageFormatterService.swift deleted file mode 100644 index 28d40449..00000000 --- a/Backend/Sources/App/Services/Formatters/MessageFormatterService/MessageFormatterService.swift +++ /dev/null @@ -1,42 +0,0 @@ -// MessageFormatterService.swift -// Copyright (c) 2025 GetAutomaApp -// All source code and related assets are the property of GetAutomaApp. -// All rights reserved. - -import DataTypes -import Fluent -import Vapor - -/// Service for formatting messages. -internal enum MessageFormatterService { - /// Crafts a verification code message. - /// - Parameter code: The verification code to include in the message. - /// - Returns: A formatted string containing the verification code. - public static func craftVerificationCodeMessage( - code: String - ) -> String { - "your automa verification code is: \"\(code)\"" - } - - /// Crafts a Discord webhook message for user events. - /// - Parameters: - /// - input: The input string for the message. - /// - event: The event description. - /// - imageUrl: Optional URL for an image to include in the message. - /// - Returns: A `DiscordWebhookMessage` configured with the provided details. - public static func craftUserEventDiscordWebhookMessage( - input: String, - event: String, - imageUrl: String? = nil - ) -> DiscordWebhookMessage { - .init( - embeds: [ - .init( - title: "**[\(input)]**", - description: "\(event)", - image: .init(url: imageUrl) - ), - ] - ) - } -} diff --git a/Backend/Sources/App/Services/MessageService/DiscordWebhookMessage.swift b/Backend/Sources/App/Services/MessageService/DiscordWebhookMessage.swift deleted file mode 100644 index dd700361..00000000 --- a/Backend/Sources/App/Services/MessageService/DiscordWebhookMessage.swift +++ /dev/null @@ -1,109 +0,0 @@ -// DiscordWebhookMessage.swift -// Copyright (c) 2025 GetAutomaApp -// All source code and related assets are the property of GetAutomaApp. -// All rights reserved. - -import Foundation - -/// Represents a Discord webhook message. -internal struct DiscordWebhookMessage: Codable { - /// The content of the message. - public var content: String? - /// The username to display for the message. - public var username: String? - /// The URL of the avatar to display for the message. - public var avatarURL: String? - /// The embeds to include in the message. - public var embeds: [DiscordEmbed]? - - public enum CodingKeys: String, CodingKey { - case avatarURL = "avatar_url" - } -} - -/// Represents an embed in a Discord webhook message. -internal struct DiscordEmbed: Codable { - /// The title of the embed. - public var title: String? - /// The description of the embed. - public var description: String? - /// The URL associated with the embed. - public var url: String? - /// The timestamp of the embed. - public var timestamp: String? - /// The color of the embed. - public var color: Int? - /// The fields to include in the embed. - public var fields: [DiscordEmbedField]? - /// The footer of the embed. - public var footer: DiscordEmbedFooter? - /// The image to include in the embed. - public var image: DiscordEmbedImage? - /// The thumbnail to include in the embed. - public var thumbnail: DiscordEmbedImage? - /// The author of the embed. - public var author: DiscordEmbedAuthor? - /// The provider of the embed. - public var provider: DiscordEmbedProvider? - /// The video to include in the embed. - public var video: DiscordEmbedVideo? -} - -/// Represents a field in a Discord embed. -internal struct DiscordEmbedField: Codable { - /// The name of the field. - public var name: String - /// The value of the field. - public var value: String - /// Whether the field should be displayed inline. - public var inline: Bool -} - -/// Represents the footer of a Discord embed. -internal struct DiscordEmbedFooter: Codable { - /// The text of the footer. - public var text: String - /// The URL of the icon to display in the footer. - public var iconURL: String? - - public enum CodingKeys: String, CodingKey { - case iconURL = "icon_url" - case text - } -} - -/// Represents an image in a Discord embed. -internal struct DiscordEmbedImage: Codable { - /// The URL of the image. - public var url: String? -} - -/// Represents the author of a Discord embed. -internal struct DiscordEmbedAuthor: Codable { - /// The name of the author. - public var name: String - /// The URL associated with the author. - public var url: String? - /// The URL of the icon to display for the author. - public var iconURL: String? - - public enum CodingKeys: String, CodingKey { - case iconURL = "icon_url" - case url - case name - } -} - -/// Represents the provider of a Discord embed. -internal struct DiscordEmbedProvider: Codable { - /// The name of the provider. - public var name: String - /// The URL associated with the provider. - public var url: String -} - -/// Represents a video in a Discord embed. -internal struct DiscordEmbedVideo: Codable { - /// The URL of the video. - public var url: String -} diff --git a/Backend/Sources/App/Services/MessageService/MessageService.swift b/Backend/Sources/App/Services/MessageService/MessageService.swift deleted file mode 100644 index dc271ad0..00000000 --- a/Backend/Sources/App/Services/MessageService/MessageService.swift +++ /dev/null @@ -1,217 +0,0 @@ -// MessageService.swift -// Copyright (c) 2025 GetAutomaApp -// All source code and related assets are the property of GetAutomaApp. -// All rights reserved. - -import AutomaUtilities -import DataTypes -import Fluent -import Foundation -import SotoSNS -import Vapor - -#if canImport(FoundationNetworking) - import FoundationNetworking -#endif - -internal struct MessageService: Decodable { - // MARK: - Public API - - public func sendSmS( - to phoneNumber: String, - message: String, - logger: Logger - ) async throws -> String { - do { - let snsClient = try createSNSClient() - let output = try await snsClient.publish(.init(message: message, phoneNumber: phoneNumber)) - - try logSmsSentEvent(to: phoneNumber, message: message, logger: logger) - - return try extractMessageId(from: output, phoneNumber: phoneNumber, message: message, logger: logger) - } catch { - handleSmsError(error, to: phoneNumber, message: message, logger: logger) - throw error - } - } - - public func sendWebhookMessage( - webhookURL: URL, - message: DiscordWebhookMessage, - logger: Logger - ) async throws { - BackendMetric.totalDiscordWebhookMessagesSent.increment() - - guard try Environment.getOrThrow("ENVIRONMENT") != "local" else { return } - - do { - let request = try buildWebhookRequest(url: webhookURL, message: message) - let (data, response) = try await URLSession.shared.data(for: request) - - try validateWebhookResponse(response, data: data) - - logger.info("Sent Discord webhook message successfully", metadata: [ - "to": .string("MessageService.sendWebhookMessage"), - "webhook": .string(webhookURL.absoluteString), - "response": .string(String(data: data, encoding: .utf8) ?? "") - ]) - } catch { - logger.error("Failed to send Discord webhook message", metadata: [ - "to": .string("MessageService.sendWebhookMessage"), - "webhook": .string(webhookURL.absoluteString), - "error": .string(error.localizedDescription) - ]) - throw GenericErrors.discordWebhookMessageFailed - } - } - - public func sendDiscordWebhookAppEvent( - input: String, - event: String, - imageUrl: String? = nil, - logger: Logger, - withUrl: URL? = nil - ) throws { - guard let url = try resolveWebhookURL(override: withUrl, logger: logger, input: input, event: event) else { - return - } - - Task.detachedLogOnError(destination: "MessageService.sendDiscordWebhookAppEvent", logger: logger) { - try await sendWebhookMessage( - webhookURL: url, - message: MessageFormatterService.craftUserEventDiscordWebhookMessage( - input: input, - event: event, - imageUrl: imageUrl - ), - logger: logger - ) - } - } - - public func sendDiscordAlert( - alertTitle: String, - error: Error, - logger: Logger - ) throws { - guard - let webhookUrl = try URL(string: Environment.getOrThrow("DISCORD_AUTOMA_ALERTS_WEBHOOK_URL")) - else { - throwWebhookURLError(logger: logger, title: alertTitle) - } - - try sendDiscordWebhookAppEvent( - input: "Critical Error Occurred - \(alertTitle)", - event: "\(error) - \(error.localizedDescription)", - logger: logger, - withUrl: webhookUrl - ) - } - - // MARK: - Private Helpers - - private func createSNSClient() throws -> SNS { - let clientAuth = try AWSClient( - credentialProvider: .static( - accessKeyId: Environment.getOrThrow("AWS_ACCESS_KEY_ID"), - secretAccessKey: Environment.getOrThrow("AWS_SECRET_ACCESS_KEY") - ) - ) - let region = try Environment.getOrThrow("AWS_DEFAULT_REGION") - return SNS(client: clientAuth, region: .other(region)) - } - - private func extractMessageId( - from output: SNS.PublishResponse, - phoneNumber: String, - message: String, - logger: Logger - ) throws -> String { - guard let messageId = output.messageId else { - logger.error("Failed to send message to user", metadata: [ - "to": .string("MessageService.sendSmS"), - "phoneNumber": .string(phoneNumber), - "message": .string(message), - ]) - throw GenericErrors.smsMessageFailed - } - - logger.info("Sent SMS message to user", metadata: [ - "to": .string("MessageService.sendSmS"), - "messageId": .string(messageId), - "phoneNumber": .string(phoneNumber), - "message": .string(message), - "sequenceNumber": .string(output.sequenceNumber ?? "") - ]) - BackendMetric.totalTextMessagesSent.increment() - - return messageId - } - - private func handleSmsError( - _ error: Error, - to phoneNumber: String, - message: String, - logger: Logger - ) { - logger.error("Failed to send message", metadata: [ - "to": .string("MessageService.sendSmS"), - "phoneNumber": .string(phoneNumber), - "message": .string(message), - "error": .string(error.localizedDescription) - ]) - BackendMetric.totalTextMessagesSentFailed.increment() - } - - private func buildWebhookRequest(url: URL, message: DiscordWebhookMessage) throws -> URLRequest { - var request = URLRequest(url: url) - request.httpMethod = "POST" - request.setValue("application/json", forHTTPHeaderField: "Content-Type") - request.httpBody = try JSONEncoder().encode(message) - return request - } - - private func validateWebhookResponse(_ response: URLResponse, data _: Data) throws { - if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode != 204 { - throw GenericErrors.discordWebhookMessageFailed - } - } - - private func resolveWebhookURL( - override: URL?, - logger: Logger, - input: String, - event: String - ) throws -> URL? { - if let url = override { - return url - } - - guard let fallbackUrl = try? URL(string: Environment.getOrThrow("DISCORD_APP_EVENTS_URL")) else { - logger.error("Could not resolve Discord webhook URL", metadata: [ - "to": .string("MessageService.sendDiscordWebhookAppEvent"), - "event": .string(event), - "input": .string(input) - ]) - throw Abort(.internalServerError) - } - - return fallbackUrl - } - - private func throwWebhookURLError(logger: Logger, title: String) -> Never { - logger.error("Could not resolve Discord webhook URL", metadata: [ - "to": .string("MessageService.sendDiscordAlert"), - "alert_title": .string(title) - ]) - fatalError("Invalid webhook URL") // Or throw Abort(.internalServerError) - } - - private func logSmsSentEvent(to phoneNumber: String, message: String, logger: Logger) throws { - try sendDiscordWebhookAppEvent( - input: "random -> \(phoneNumber)", - event: "sending message: `\(message)`", - logger: logger - ) - } -} diff --git a/Backend/Sources/App/Services/SNSService/SNSService.swift b/Backend/Sources/App/Services/SNSService/SNSService.swift new file mode 100644 index 00000000..9e40110b --- /dev/null +++ b/Backend/Sources/App/Services/SNSService/SNSService.swift @@ -0,0 +1,101 @@ +// SNSService.swift +// Copyright (c) 2025 GetAutomaApp +// All source code and related assets are the property of GetAutomaApp. +// All rights reserved. + +import AutomaUtilities +import DataTypes +import Foundation +import SotoSNS +import Vapor + +#if canImport(FoundationNetworking) + import FoundationNetworking +#endif + +internal struct SNSService: Decodable { + private let messageService: MessageService + + public init() { + messageService = MessageService() + } + + public func sendSmS( + to phoneNumber: String, + message: String, + logger: Logger + ) async throws -> String { + do { + let snsClient = try createSNSClient() + let output = try await snsClient.publish(.init(message: message, phoneNumber: phoneNumber)) + + try logSmsSentEvent(to: phoneNumber, message: message, logger: logger) + + return try extractMessageId(from: output, phoneNumber: phoneNumber, message: message, logger: logger) + } catch { + handleSmsError(error, to: phoneNumber, message: message, logger: logger) + throw error + } + } + + private func createSNSClient() throws -> SNS { + let clientAuth = try AWSClient( + credentialProvider: .static( + accessKeyId: Environment.getOrThrow("AWS_ACCESS_KEY_ID"), + secretAccessKey: Environment.getOrThrow("AWS_SECRET_ACCESS_KEY") + ) + ) + let region = try Environment.getOrThrow("AWS_DEFAULT_REGION") + return SNS(client: clientAuth, region: .other(region)) + } + + private func extractMessageId( + from output: SNS.PublishResponse, + phoneNumber: String, + message: String, + logger: Logger + ) throws -> String { + guard let messageId = output.messageId else { + logger.error("Failed to send message to user", metadata: [ + "to": .string("MessageService.sendSmS"), + "phoneNumber": .string(phoneNumber), + "message": .string(message), + ]) + throw GenericErrors.smsMessageFailed + } + + logger.info("Sent SMS message to user", metadata: [ + "to": .string("MessageService.sendSmS"), + "messageId": .string(messageId), + "phoneNumber": .string(phoneNumber), + "message": .string(message), + "sequenceNumber": .string(output.sequenceNumber ?? "") + ]) + BackendMetric.totalTextMessagesSent.increment() + + return messageId + } + + private func handleSmsError( + _ error: Error, + to phoneNumber: String, + message: String, + logger: Logger + ) { + logger.error("Failed to send message", metadata: [ + "to": .string("MessageService.sendSmS"), + "phoneNumber": .string(phoneNumber), + "message": .string(message), + "error": .string(error.localizedDescription) + ]) + BackendMetric.totalTextMessagesSentFailed.increment() + } + + private func logSmsSentEvent(to phoneNumber: String, message: String, logger: Logger) throws { + try messageService.sendDiscordWebhookAppEvent( + input: "random -> \(phoneNumber)", + event: "sending message: `\(message)`", + logger: logger + ) + } +} diff --git a/Backend/Tests/AppTests/Controllers/PrometheusControllerTests/PrometheusControllerIntegrationTests.swift b/Backend/Tests/AppTests/Controllers/PrometheusControllerTests/PrometheusControllerIntegrationTests.swift deleted file mode 100644 index 09d33e7f..00000000 --- a/Backend/Tests/AppTests/Controllers/PrometheusControllerTests/PrometheusControllerIntegrationTests.swift +++ /dev/null @@ -1,55 +0,0 @@ -// PrometheusControllerIntegrationTests.swift -// Copyright (c) 2025 GetAutomaApp -// All source code and related assets are the property of GetAutomaApp. -// All rights reserved. - -@testable import App -import AutomaUtilities -import Testing -import VaporTesting - -// Since most prometheus implementation code (MetricsService and PrometheusController) will be re-used, -// the prometheus tests can placed in the package that contains the implementation code - -/// Integration tests for the `PrometheusController`. -/// These tests verify the controller's ability to handle requests and return metrics data. -@Suite("PrometheusControllerIntegrationTests") -internal struct PrometheusControllerIntegrationTests { - /// Helper method to create a test application instance for each test. - /// This method handles proper setup and teardown of the application. - /// - /// - Parameter test: A closure that takes an `Application` instance and performs test operations. - /// - Throws: Any errors that occur during test execution or application setup/teardown. - private func withApp(_ test: (Application) async throws -> Void) async throws { - let app = try await Application.make(.testing) - do { - // Register the `PrometheusController` with the application - try app.register(collection: PrometheusController()) - // Execute the test closure with the application instance - try await test(app) - } catch { - // Shut down the application in case of errors - try await app.asyncShutdown() - throw error - } - // Ensure proper cleanup by shutting down the application - try await app.asyncShutdown() - } - - /// Tests the ability to request metrics data from the Prometheus controller. - /// Verifies that the response status is OK and the metrics data is returned. - /// - /// - Throws: Any errors that occur during test execution or request handling. - @Test("Test Request") - public func request() async throws { - try await withApp { app in - // Retrieve the Fly metrics token from the environment - let token = try Environment.getOrThrow("FLY_METRICS_TOKEN") - // Send a GET request to the Prometheus metrics endpoint - try await app.testing().test(.GET, "Prometheus/metrics?auth_token=\(token)") { res async in - // Expect the response status to be OK - #expect(res.status == .ok) - } - } - } -} From 9dd2beb5d66a83f2fa0cdb5955024a6ab3e5909f Mon Sep 17 00:00:00 2001 From: William Date: Fri, 26 Sep 2025 17:03:15 +0200 Subject: [PATCH 03/11] fixup! refactor: prometheus controller, message service and metrics service to automa utilities package --- Backend/Package.resolved | 154 +++++++++--------- .../App/Services/SNSService/SNSService.swift | 2 +- 2 files changed, 78 insertions(+), 78 deletions(-) diff --git a/Backend/Package.resolved b/Backend/Package.resolved index 8325f03b..748ba0b9 100644 --- a/Backend/Package.resolved +++ b/Backend/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "1d8db4abc125868abd7c0e97eb84f6246d39ee42a10a5f1676c43785a2426b91", + "originHash" : "2639472734ac53292465423765530e979d16fad422d125c721d9d1414b211a46", "pins" : [ { "identity" : "alamofire", @@ -15,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swift-server/async-http-client.git", "state" : { - "revision" : "333f51104b75d1a5b94cb3b99e4c58a3b442c9f7", - "version" : "1.25.2" + "revision" : "7dc119c7edf3c23f52638faadb89182861dee853", + "version" : "1.28.0" } }, { @@ -24,8 +24,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/async-kit.git", "state" : { - "revision" : "e048c8ee94967e8d8a1c2ec0e1156d6f7fa34d31", - "version" : "1.20.0" + "revision" : "6f3615ccf2ac3c2ae0c8087d527546e9544a43dd", + "version" : "1.21.0" } }, { @@ -34,7 +34,7 @@ "location" : "https://github.com/GetAutomaApp/AutomaUtilities", "state" : { "branch" : "main", - "revision" : "5273b2cfe710b81ef52b44eba1b66c6e5cef85c4" + "revision" : "e5e39cef8cd774e0ef414ec380e74119a53d3e98" } }, { @@ -60,8 +60,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/nmdias/FeedKit.git", "state" : { - "revision" : "03ea968c7741f4feeeacbb6a82ff7320d0953edb", - "version" : "10.1.2" + "revision" : "7cd3569dac2a82118eb22d8bce48d040ef0d014d", + "version" : "10.1.3" } }, { @@ -69,8 +69,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/fluent.git", "state" : { - "revision" : "223b27d04ab2b51c25503c9922eecbcdf6c12f89", - "version" : "4.12.0" + "revision" : "2fe9e36daf4bdb5edcf193e0d0806ba2074d2864", + "version" : "4.13.0" } }, { @@ -78,8 +78,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/fluent-kit.git", "state" : { - "revision" : "1385c48f98e1e44335b251cc11dc11a0a50ab853", - "version" : "1.52.1" + "revision" : "8baacd7e8f7ebf68886c496b43bbe6cdcc5b57e0", + "version" : "1.52.2" } }, { @@ -87,14 +87,14 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/fluent-postgres-driver.git", "state" : { - "revision" : "095bc5a17ab3363167f4becb270b6f8eb790481c", - "version" : "2.10.1" + "revision" : "cd47a7042a529735e401bdfaa070823d151f7f94", + "version" : "2.11.0" } }, { "identity" : "jmespath.swift", "kind" : "remoteSourceControl", - "location" : "https://github.com/adam-fowler/jmespath.swift.git", + "location" : "https://github.com/jmespath/jmespath.swift.git", "state" : { "revision" : "3877a5060e85ae33e3b9fe51ab581784f65ec80e", "version" : "1.0.3" @@ -114,8 +114,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/jwt-kit.git", "state" : { - "revision" : "03f5013f0b547ce43abe45e7e90711303a3e5495", - "version" : "5.1.2" + "revision" : "2033b3e661238dda3d30e36a2d40987499d987de", + "version" : "5.2.0" } }, { @@ -123,8 +123,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/leaf.git", "state" : { - "revision" : "d469584b9186851c5a4012d11325fb9db3207ebb", - "version" : "4.5.0" + "revision" : "b70a6108e4917f338f6b8848407bf655aa7e405f", + "version" : "4.5.1" } }, { @@ -132,8 +132,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/leaf-kit.git", "state" : { - "revision" : "cf186d8f2ef33e16fd1dd78df36466c22c2e632f", - "version" : "1.13.1" + "revision" : "0c325fc46d42455914abd0105e88fe4561fc31a8", + "version" : "1.14.0" } }, { @@ -150,8 +150,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/MacPaw/OpenAI.git", "state" : { - "revision" : "bb283b2ac48c1e90121d73d6bfb45f961dc0b7a3", - "version" : "0.4.5" + "revision" : "80045fcda7ba727a327eb0a525e983fd7a796c70", + "version" : "0.4.6" } }, { @@ -159,8 +159,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/marmelroy/PhoneNumberKit", "state" : { - "revision" : "288b99e9e99926bc8be41220802df83c059fac9b", - "version" : "4.0.2" + "revision" : "8cba2258060e356d5fc4836d4ff8549faa2409dd", + "version" : "4.1.4" } }, { @@ -168,8 +168,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/postgres-kit.git", "state" : { - "revision" : "f4d4b9e8db9a907644d67d6a7ecb5f0314eec1ad", - "version" : "2.14.0" + "revision" : "d2fd3172c2e318bd292a4c1297e4c65a418cf6f3", + "version" : "2.14.1" } }, { @@ -177,8 +177,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/postgres-nio.git", "state" : { - "revision" : "5d817be55cae8b00003b7458944954558302d006", - "version" : "1.25.0" + "revision" : "8ee6118c03501196be183b0938d2ec4478c18954", + "version" : "1.27.0" } }, { @@ -204,8 +204,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/soto-project/soto.git", "state" : { - "revision" : "ab7bab78dbe6fd77722639a7f7f7521b1a79e900", - "version" : "7.6.1" + "revision" : "051706fdd526335a25ce3fb6b324ff627f3d36bd", + "version" : "7.9.0" } }, { @@ -213,8 +213,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/soto-project/soto-core.git", "state" : { - "revision" : "bfe6d6f94a82c9268b15ac636005ae57f4129de9", - "version" : "7.6.0" + "revision" : "b641a1b521c2674638325ca62aec126507e3cddd", + "version" : "7.8.0" } }, { @@ -222,8 +222,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/sql-kit.git", "state" : { - "revision" : "baf0d8684a43f16cd11ebcc67300c8ab5cb5d078", - "version" : "3.33.0" + "revision" : "1a9ab0523fb742d9629558cede64290165c4285b", + "version" : "3.33.2" } }, { @@ -240,8 +240,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-asn1.git", "state" : { - "revision" : "a54383ada6cecde007d374f58f864e29370ba5c3", - "version" : "1.3.2" + "revision" : "f70225981241859eb4aa1a18a75531d26637c8cc", + "version" : "1.4.0" } }, { @@ -258,8 +258,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-atomics.git", "state" : { - "revision" : "cd142fd2f64be2100422d658e7411e39489da985", - "version" : "1.2.0" + "revision" : "b601256eab081c0f92f059e12818ac1d4f178ff7", + "version" : "1.3.0" } }, { @@ -267,8 +267,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-certificates.git", "state" : { - "revision" : "999fd70c7803da89f3904d635a6815a2a7cd7585", - "version" : "1.10.0" + "revision" : "4b092f15164144c24554e0a75e080a960c5190a6", + "version" : "1.14.0" } }, { @@ -276,8 +276,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections.git", "state" : { - "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7", - "version" : "1.1.4" + "revision" : "8c0c0a8b49e080e54e5e328cc552821ff07cd341", + "version" : "1.2.1" } }, { @@ -285,8 +285,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-crypto.git", "state" : { - "revision" : "e8d6eba1fef23ae5b359c46b03f7d94be2f41fed", - "version" : "3.12.3" + "revision" : "95ba0316a9b733e92bb6b071255ff46263bbe7dc", + "version" : "3.15.1" } }, { @@ -294,8 +294,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-distributed-tracing.git", "state" : { - "revision" : "a64a0abc2530f767af15dd88dda7f64d5f1ff9de", - "version" : "1.2.0" + "revision" : "6600888f4cb5bbf1bcac51000f60b2cbd224c91b", + "version" : "1.3.0" } }, { @@ -303,8 +303,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-http-structured-headers.git", "state" : { - "revision" : "f280fc7676b9940ff2c6598642751ea333c6544f", - "version" : "1.2.2" + "revision" : "1625f271afb04375bf48737a5572613248d0e7a0", + "version" : "1.4.0" } }, { @@ -321,8 +321,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-log.git", "state" : { - "revision" : "3d8596ed08bd13520157f0355e35caed215ffbfa", - "version" : "1.6.3" + "revision" : "ce592ae52f982c847a4efc0dd881cc9eb32d29f2", + "version" : "1.6.4" } }, { @@ -330,8 +330,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-metrics.git", "state" : { - "revision" : "4c83e1cdf4ba538ef6e43a9bbd0bcc33a0ca46e3", - "version" : "2.7.0" + "revision" : "0743a9364382629da3bf5677b46a2c4b1ce5d2a6", + "version" : "2.7.1" } }, { @@ -339,8 +339,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio.git", "state" : { - "revision" : "0f54d58bb5db9e064f332e8524150de379d1e51c", - "version" : "2.82.1" + "revision" : "a18bddb0acf7a40d982b2f128ce73ce4ee31f352", + "version" : "2.86.2" } }, { @@ -348,8 +348,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-extras.git", "state" : { - "revision" : "f1f6f772198bee35d99dd145f1513d8581a54f2c", - "version" : "1.26.0" + "revision" : "a55c3dd3a81d035af8a20ce5718889c0dcab073d", + "version" : "1.29.0" } }, { @@ -357,8 +357,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-http2.git", "state" : { - "revision" : "4281466512f63d1bd530e33f4aa6993ee7864be0", - "version" : "1.36.0" + "revision" : "5e9e99ec96c53bc2c18ddd10c1e25a3cd97c55e5", + "version" : "1.38.0" } }, { @@ -366,8 +366,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-ssl.git", "state" : { - "revision" : "6df102a39c8da5fdc2eae29a0f63546d660866fc", - "version" : "2.30.0" + "revision" : "b2b043a8810ab6d51b3ff4df17f057d87ef1ec7c", + "version" : "2.34.1" } }, { @@ -375,8 +375,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-transport-services.git", "state" : { - "revision" : "cd1e89816d345d2523b11c55654570acd5cd4c56", - "version" : "1.24.0" + "revision" : "e645014baea2ec1c2db564410c51a656cf47c923", + "version" : "1.25.1" } }, { @@ -384,8 +384,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-numerics.git", "state" : { - "revision" : "e0ec0f5f3af6f3e4d5e7a19d2af26b481acb6ba8", - "version" : "1.0.3" + "revision" : "0c0290ff6b24942dadb83a929ffaaa1481df04a2", + "version" : "1.1.1" } }, { @@ -393,8 +393,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-openapi-runtime", "state" : { - "revision" : "8f33cc5dfe81169fb167da73584b9c72c3e8bc23", - "version" : "1.8.2" + "revision" : "7722cf8eac05c1f1b5b05895b04cfcc29576d9be", + "version" : "1.8.3" } }, { @@ -402,8 +402,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swift-server/swift-prometheus.git", "state" : { - "revision" : "54f18941e5f278f7f700f2188b7e21be563ca76f", - "version" : "2.1.0" + "revision" : "8a8ff47403444e16d8cdfa805a5e3cb8e2efe734", + "version" : "2.2.0" } }, { @@ -420,8 +420,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-service-context.git", "state" : { - "revision" : "8946c930cae601452149e45d31d8ddfac973c3c7", - "version" : "1.2.0" + "revision" : "1983448fefc717a2bc2ebde5490fe99873c5b8a6", + "version" : "1.2.1" } }, { @@ -438,8 +438,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-system.git", "state" : { - "revision" : "a34201439c74b53f0fd71ef11741af7e7caf01e1", - "version" : "1.4.2" + "revision" : "395a77f0aa927f0ff73941d7ac35f2b46d47c9db", + "version" : "1.6.3" } }, { @@ -456,8 +456,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/vapor.git", "state" : { - "revision" : "3636f443474769147828a5863e81a31f6f30e92c", - "version" : "4.115.1" + "revision" : "773ea6a63595ae4f6bc46a366d78769d4cb8b08c", + "version" : "4.117.0" } }, { @@ -474,8 +474,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/websocket-kit.git", "state" : { - "revision" : "014ccd52891b8c098d7e1033d5e72ed76fef7a86", - "version" : "2.16.0" + "revision" : "8666c92dbbb3c8eefc8008c9c8dcf50bfd302167", + "version" : "2.16.1" } } ], diff --git a/Backend/Sources/App/Services/SNSService/SNSService.swift b/Backend/Sources/App/Services/SNSService/SNSService.swift index 9e40110b..57aa369b 100644 --- a/Backend/Sources/App/Services/SNSService/SNSService.swift +++ b/Backend/Sources/App/Services/SNSService/SNSService.swift @@ -13,7 +13,7 @@ import Vapor import FoundationNetworking #endif -internal struct SNSService: Decodable { +internal struct SNSService { private let messageService: MessageService public init() { From 9bcd7fffb949674c22eed77c5933db2f85dcbd45 Mon Sep 17 00:00:00 2001 From: William Date: Tue, 30 Sep 2025 12:25:31 +0200 Subject: [PATCH 04/11] refactor(BackendMetric): removed message service metric MessageService is in AutomaUtilities package now. Metric removed in this commit is added in AutomaUtilities. --- Backend/Sources/App/DataTypes/BackendMetric.swift | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Backend/Sources/App/DataTypes/BackendMetric.swift b/Backend/Sources/App/DataTypes/BackendMetric.swift index 8dc33e97..ad950be5 100644 --- a/Backend/Sources/App/DataTypes/BackendMetric.swift +++ b/Backend/Sources/App/DataTypes/BackendMetric.swift @@ -89,14 +89,6 @@ internal enum BackendMetric { ] ) - /// Counter for Discord webhook messages sent. - public static let totalDiscordWebhookMessagesSent = MetricsService.global.makeCounter( - name: "total_discord_webhook_messages_sent", - labels: [ - "status": Self.MetricStatus.success.rawValue, - ] - ) - /// Counter for OpenAI image generation requests. public static let openAIImageGenerationRequests = MetricsService.global.makeCounter( name: "openai_image_generation_requests" From 8050b379b00e76b7211864a94f33010e4d6d455d Mon Sep 17 00:00:00 2001 From: William Date: Tue, 30 Sep 2025 19:29:42 +0200 Subject: [PATCH 05/11] feat(configure): use prometheus service instead of legacy prometheus controller from automa utilities This removes the need of an authentication token to prevent leaking metrics. It works, because `PrometheusService` starts up a separate HTTP server on a different port that is not exposed publicly. --- Backend/Package.resolved | 15 ++++++++++++--- Backend/Sources/App/configure.swift | 2 +- Backend/infra/fly/fly-jobs.toml | 4 ++-- Backend/infra/fly/fly.toml | 4 ++-- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Backend/Package.resolved b/Backend/Package.resolved index 748ba0b9..7c6136a4 100644 --- a/Backend/Package.resolved +++ b/Backend/Package.resolved @@ -34,7 +34,7 @@ "location" : "https://github.com/GetAutomaApp/AutomaUtilities", "state" : { "branch" : "main", - "revision" : "e5e39cef8cd774e0ef414ec380e74119a53d3e98" + "revision" : "91fa64dab446587a495c9508429408f9d40e1dda" } }, { @@ -91,6 +91,15 @@ "version" : "2.11.0" } }, + { + "identity" : "flyingfox", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swhitty/FlyingFox.git", + "state" : { + "revision" : "76b2d2d0eb54f0b53e8b661cc8007c487d94f8da", + "version" : "0.25.0" + } + }, { "identity" : "jmespath.swift", "kind" : "remoteSourceControl", @@ -276,8 +285,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections.git", "state" : { - "revision" : "8c0c0a8b49e080e54e5e328cc552821ff07cd341", - "version" : "1.2.1" + "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", + "version" : "1.3.0" } }, { diff --git a/Backend/Sources/App/configure.swift b/Backend/Sources/App/configure.swift index 4fb9ab64..ed45c8ee 100644 --- a/Backend/Sources/App/configure.swift +++ b/Backend/Sources/App/configure.swift @@ -49,6 +49,7 @@ internal struct AppConfigurator { private func configureWhenDatabaseURLsAvailable() async throws { try await DatabaseConfigurator(app: app).configureDatabases() try registerControllers() + try await PrometheusService().startServer() try await addAuthenticationJWTKey() configureQueues() addJobsToQueue() @@ -61,7 +62,6 @@ internal struct AppConfigurator { try app.register(collection: TwitterController()) try app.register(collection: ChatCompletionController()) try app.register(collection: FirecrawlTestController()) - try app.register(collection: PrometheusController()) } private func addAuthenticationJWTKey() async throws { diff --git a/Backend/infra/fly/fly-jobs.toml b/Backend/infra/fly/fly-jobs.toml index 3d05bd68..273fe1fb 100644 --- a/Backend/infra/fly/fly-jobs.toml +++ b/Backend/infra/fly/fly-jobs.toml @@ -18,5 +18,5 @@ cpus = 2 min_machines_running = 1 [metrics] -port = 8080 -path = "/Prometheus/metrics?auth_token=__FLY_METRICS_TOKEN__" +port = 6834 +path = "/metrics" diff --git a/Backend/infra/fly/fly.toml b/Backend/infra/fly/fly.toml index b8644bc4..8b12b29e 100644 --- a/Backend/infra/fly/fly.toml +++ b/Backend/infra/fly/fly.toml @@ -25,5 +25,5 @@ cpu_kind = 'shared' cpus = 4 [metrics] -port = 8080 -path = "/Prometheus/metrics?auth_token=__FLY_METRICS_TOKEN__" +port = 6834 +path = "/metrics" From 292242ce578c4a01a6658db146812cb14274719c Mon Sep 17 00:00:00 2001 From: William Date: Tue, 30 Sep 2025 20:08:07 +0200 Subject: [PATCH 06/11] fix(docker-compose): pass github_ssh_authentication_token to api_dev so that automa utilities package can be cloned --- Backend/.gitignore | 1 + Backend/DevDockerfile | 4 ++++ Backend/Dockerfile | 34 +++++++++++++++++++--------------- Backend/README.md | 2 ++ Backend/docker-compose.yml | 6 ++++++ 5 files changed, 32 insertions(+), 15 deletions(-) create mode 100644 Backend/README.md diff --git a/Backend/.gitignore b/Backend/.gitignore index 44272c4d..89af0c74 100644 --- a/Backend/.gitignore +++ b/Backend/.gitignore @@ -11,3 +11,4 @@ db.sqlite ! .env.example .vscode .fly.toml +infra/docker-secrets/* diff --git a/Backend/DevDockerfile b/Backend/DevDockerfile index 626a502c..2b7e9835 100644 --- a/Backend/DevDockerfile +++ b/Backend/DevDockerfile @@ -12,4 +12,8 @@ WORKDIR /app EXPOSE 8080 +RUN --mount=type=secret,id=GITHUB_SSH_AUTHENTICATION_TOKEN \ + TOKEN=$(cat /run/secrets/GITHUB_SSH_AUTHENTICATION_TOKEN) && \ + git config --global url."https://x-access-token:${TOKEN}@github.com/".insteadOf "https://github.com/" + CMD bash -c "nodemon -w ./ -w .env -e '.' --ignore ./.build --exec 'swift run App --env local $RUN_COMMAND'" diff --git a/Backend/Dockerfile b/Backend/Dockerfile index e9e9fa02..0518a6c3 100644 --- a/Backend/Dockerfile +++ b/Backend/Dockerfile @@ -5,10 +5,10 @@ FROM swift:6.1.0-jammy AS build # Install OS updates RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \ - && apt-get -q update \ - && apt-get -q dist-upgrade -y \ - && apt-get install -y libjemalloc-dev \ - && apt-get install -y openssl libssl-dev + && apt-get -q update \ + && apt-get -q dist-upgrade -y \ + && apt-get install -y libjemalloc-dev \ + && apt-get install -y openssl libssl-dev # Set up a build area WORKDIR /build @@ -18,6 +18,10 @@ WORKDIR /build # as long as your Package.swift/Package.resolved # files do not change. +RUN --mount=type=secret,id=GITHUB_SSH_AUTHENTICATION_TOKEN \ + TOKEN=$(cat /run/secrets/GITHUB_SSH_AUTHENTICATION_TOKEN) && \ + git config --global url."https://x-access-token:${TOKEN}@github.com/".insteadOf "https://github.com/" + COPY Package.swift . COPY Package.resolved . @@ -29,8 +33,8 @@ COPY . . # Build everything, with optimizations, with static linking, and using jemalloc # N.B.: The static version of jemalloc is incompatible with the static Swift runtime. RUN --mount=type=cache,target=/build/.build swift build -c release \ - --static-swift-stdlib \ - -Xlinker -ljemalloc + --static-swift-stdlib \ + -Xlinker -ljemalloc # Switch to the staging area WORKDIR /staging @@ -56,15 +60,15 @@ FROM ubuntu:jammy # Make sure all system packages are up to date, and install only essential packages. RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \ - && apt-get -q update \ - && apt-get -q dist-upgrade -y \ - && apt-get -q install -y \ - libjemalloc2 \ - ca-certificates \ - tzdata \ - && apt-get install bash \ - && apt-get install -y openssl libssl-dev libcurl4 libxml2 \ - && rm -r /var/lib/apt/lists/* + && apt-get -q update \ + && apt-get -q dist-upgrade -y \ + && apt-get -q install -y \ + libjemalloc2 \ + ca-certificates \ + tzdata \ + && apt-get install bash \ + && apt-get install -y openssl libssl-dev libcurl4 libxml2 \ + && rm -r /var/lib/apt/lists/* # Create a vapor user and group with /app as its home directory RUN useradd --user-group --create-home --system --skel /dev/null --home-dir /app vapor diff --git a/Backend/README.md b/Backend/README.md new file mode 100644 index 00000000..351eafa9 --- /dev/null +++ b/Backend/README.md @@ -0,0 +1,2 @@ +1. Create `./infra/docker-secrets/` directory with the following files and secrets: + 1. "GITHUB_SSH_AUTHENTICATION_TOKEN": A Github fine-grained token that allows cloning AutomaUtilities repository (private) diff --git a/Backend/docker-compose.yml b/Backend/docker-compose.yml index 5db77360..4f61fe9f 100644 --- a/Backend/docker-compose.yml +++ b/Backend/docker-compose.yml @@ -6,6 +6,8 @@ services: build: context: . dockerfile: ./DevDockerfile + secrets: + - GITHUB_SSH_AUTHENTICATION_TOKEN depends_on: postgres: condition: service_healthy @@ -68,3 +70,7 @@ volumes: driver: local worker_build: driver: local + +secrets: + GITHUB_SSH_AUTHENTICATION_TOKEN: + file: ./infra/docker-secrets/GITHUB_SSH_AUTHENTICATION_TOKEN From b52eacd596fc1d55aeea1f8368d1b49ffd60766d Mon Sep 17 00:00:00 2001 From: William Date: Wed, 1 Oct 2025 17:19:01 +0200 Subject: [PATCH 07/11] fix(package.json): set github token build secret when deploying to fly This is needed to clone AutomaUtilities, a private Github repository. This commit also exposes the metrics port in both dockerfiles --- Backend/DevDockerfile | 2 ++ Backend/Dockerfile | 3 +++ Backend/Package.resolved | 2 +- package.json | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Backend/DevDockerfile b/Backend/DevDockerfile index 2b7e9835..18136559 100644 --- a/Backend/DevDockerfile +++ b/Backend/DevDockerfile @@ -12,6 +12,8 @@ WORKDIR /app EXPOSE 8080 +EXPOSE 6834 + RUN --mount=type=secret,id=GITHUB_SSH_AUTHENTICATION_TOKEN \ TOKEN=$(cat /run/secrets/GITHUB_SSH_AUTHENTICATION_TOKEN) && \ git config --global url."https://x-access-token:${TOKEN}@github.com/".insteadOf "https://github.com/" diff --git a/Backend/Dockerfile b/Backend/Dockerfile index 0518a6c3..a2eeb6ed 100644 --- a/Backend/Dockerfile +++ b/Backend/Dockerfile @@ -88,4 +88,7 @@ USER vapor:vapor # Let Docker bind to port 8080 EXPOSE 8080 +# Expose PrometheusService server port +EXPOSE 6834 + CMD /bin/bash -c "eval './App $RUN_COMMAND'" diff --git a/Backend/Package.resolved b/Backend/Package.resolved index 7c6136a4..24d134b2 100644 --- a/Backend/Package.resolved +++ b/Backend/Package.resolved @@ -34,7 +34,7 @@ "location" : "https://github.com/GetAutomaApp/AutomaUtilities", "state" : { "branch" : "main", - "revision" : "91fa64dab446587a495c9508429408f9d40e1dda" + "revision" : "31dd29c0dc75df45c1c8c1d0b06d6301fb42c3d1" } }, { diff --git a/package.json b/package.json index 98c51e86..a8ea07b2 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "deploy:backend:sandbox": "npm run fly:config -- ../Backend/infra/fly/fly.toml sandbox | npm run deploy:to:fly", "deploy:backend:staging": "npm run fly:config -- ../Backend/infra/fly/fly.toml staging | npm run deploy:to:fly", "deploy:backend:production": "npm run fly:config -- ../Backend/infra/fly/fly.toml production | npm run deploy:to:fly", - "deploy:to:fly": "tail -n 1 | xargs -Ixx cp xx Backend/.fly.toml && cd Backend && flyctl deploy --config=.fly.toml", + "deploy:to:fly": "tail -n 1 | xargs -Ixx cp xx Backend/.fly.toml && cd Backend && flyctl deploy --config=.fly.toml --build-secret GITHUB_SSH_AUTHENTICATION_TOKEN=$(cat ../infra/docker-secrets/GITHUB_SSH_AUTHENTICATION_TOKEN)", "deploy:worker:sandbox": "npm run fly:config -- ../Backend/infra/fly/fly-jobs.toml sandbox | npm run deploy:to:fly", "deploy:worker:production": "npm run fly:config -- ../Backend/infra/fly/fly-jobs.toml production | npm run deploy:to:fly", "build:all": "npx npm-run-all --parallel build:ui-kit build:backend", From df33d01b5de1e89a8367d22b3e72600c4e4cd488 Mon Sep 17 00:00:00 2001 From: William Date: Thu, 2 Oct 2025 12:46:44 +0200 Subject: [PATCH 08/11] fix(BackendMetric): use metric status data type from automa utilities --- Backend/Package.resolved | 154 +++++++++--------- .../Sources/App/DataTypes/BackendMetric.swift | 54 +++--- 2 files changed, 98 insertions(+), 110 deletions(-) diff --git a/Backend/Package.resolved b/Backend/Package.resolved index b579a32a..b65a79ed 100644 --- a/Backend/Package.resolved +++ b/Backend/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "1d8db4abc125868abd7c0e97eb84f6246d39ee42a10a5f1676c43785a2426b91", + "originHash" : "2639472734ac53292465423765530e979d16fad422d125c721d9d1414b211a46", "pins" : [ { "identity" : "alamofire", @@ -15,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swift-server/async-http-client.git", "state" : { - "revision" : "333f51104b75d1a5b94cb3b99e4c58a3b442c9f7", - "version" : "1.25.2" + "revision" : "7dc119c7edf3c23f52638faadb89182861dee853", + "version" : "1.28.0" } }, { @@ -24,8 +24,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/async-kit.git", "state" : { - "revision" : "e048c8ee94967e8d8a1c2ec0e1156d6f7fa34d31", - "version" : "1.20.0" + "revision" : "6f3615ccf2ac3c2ae0c8087d527546e9544a43dd", + "version" : "1.21.0" } }, { @@ -34,7 +34,7 @@ "location" : "https://github.com/GetAutomaApp/AutomaUtilities", "state" : { "branch" : "main", - "revision" : "31dd29c0dc75df45c1c8c1d0b06d6301fb42c3d1" + "revision" : "c1b9a9e6930b66dc2139d62dff65578529b08334" } }, { @@ -60,8 +60,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/nmdias/FeedKit.git", "state" : { - "revision" : "03ea968c7741f4feeeacbb6a82ff7320d0953edb", - "version" : "10.1.2" + "revision" : "7cd3569dac2a82118eb22d8bce48d040ef0d014d", + "version" : "10.1.3" } }, { @@ -69,8 +69,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/fluent.git", "state" : { - "revision" : "223b27d04ab2b51c25503c9922eecbcdf6c12f89", - "version" : "4.12.0" + "revision" : "2fe9e36daf4bdb5edcf193e0d0806ba2074d2864", + "version" : "4.13.0" } }, { @@ -78,8 +78,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/fluent-kit.git", "state" : { - "revision" : "1385c48f98e1e44335b251cc11dc11a0a50ab853", - "version" : "1.52.1" + "revision" : "8baacd7e8f7ebf68886c496b43bbe6cdcc5b57e0", + "version" : "1.52.2" } }, { @@ -87,8 +87,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/fluent-postgres-driver.git", "state" : { - "revision" : "095bc5a17ab3363167f4becb270b6f8eb790481c", - "version" : "2.10.1" + "revision" : "cd47a7042a529735e401bdfaa070823d151f7f94", + "version" : "2.11.0" } }, { @@ -103,7 +103,7 @@ { "identity" : "jmespath.swift", "kind" : "remoteSourceControl", - "location" : "https://github.com/adam-fowler/jmespath.swift.git", + "location" : "https://github.com/jmespath/jmespath.swift.git", "state" : { "revision" : "3877a5060e85ae33e3b9fe51ab581784f65ec80e", "version" : "1.0.3" @@ -123,8 +123,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/jwt-kit.git", "state" : { - "revision" : "03f5013f0b547ce43abe45e7e90711303a3e5495", - "version" : "5.1.2" + "revision" : "2033b3e661238dda3d30e36a2d40987499d987de", + "version" : "5.2.0" } }, { @@ -132,8 +132,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/leaf.git", "state" : { - "revision" : "d469584b9186851c5a4012d11325fb9db3207ebb", - "version" : "4.5.0" + "revision" : "b70a6108e4917f338f6b8848407bf655aa7e405f", + "version" : "4.5.1" } }, { @@ -141,8 +141,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/leaf-kit.git", "state" : { - "revision" : "cf186d8f2ef33e16fd1dd78df36466c22c2e632f", - "version" : "1.13.1" + "revision" : "0c325fc46d42455914abd0105e88fe4561fc31a8", + "version" : "1.14.0" } }, { @@ -159,8 +159,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/MacPaw/OpenAI.git", "state" : { - "revision" : "bb283b2ac48c1e90121d73d6bfb45f961dc0b7a3", - "version" : "0.4.5" + "revision" : "80045fcda7ba727a327eb0a525e983fd7a796c70", + "version" : "0.4.6" } }, { @@ -168,8 +168,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/marmelroy/PhoneNumberKit", "state" : { - "revision" : "288b99e9e99926bc8be41220802df83c059fac9b", - "version" : "4.0.2" + "revision" : "8cba2258060e356d5fc4836d4ff8549faa2409dd", + "version" : "4.1.4" } }, { @@ -177,8 +177,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/postgres-kit.git", "state" : { - "revision" : "f4d4b9e8db9a907644d67d6a7ecb5f0314eec1ad", - "version" : "2.14.0" + "revision" : "d2fd3172c2e318bd292a4c1297e4c65a418cf6f3", + "version" : "2.14.1" } }, { @@ -186,8 +186,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/postgres-nio.git", "state" : { - "revision" : "5d817be55cae8b00003b7458944954558302d006", - "version" : "1.25.0" + "revision" : "8ee6118c03501196be183b0938d2ec4478c18954", + "version" : "1.27.0" } }, { @@ -213,8 +213,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/soto-project/soto.git", "state" : { - "revision" : "ab7bab78dbe6fd77722639a7f7f7521b1a79e900", - "version" : "7.6.1" + "revision" : "051706fdd526335a25ce3fb6b324ff627f3d36bd", + "version" : "7.9.0" } }, { @@ -222,8 +222,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/soto-project/soto-core.git", "state" : { - "revision" : "bfe6d6f94a82c9268b15ac636005ae57f4129de9", - "version" : "7.6.0" + "revision" : "b641a1b521c2674638325ca62aec126507e3cddd", + "version" : "7.8.0" } }, { @@ -231,8 +231,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/sql-kit.git", "state" : { - "revision" : "baf0d8684a43f16cd11ebcc67300c8ab5cb5d078", - "version" : "3.33.0" + "revision" : "1a9ab0523fb742d9629558cede64290165c4285b", + "version" : "3.33.2" } }, { @@ -249,8 +249,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-asn1.git", "state" : { - "revision" : "a54383ada6cecde007d374f58f864e29370ba5c3", - "version" : "1.3.2" + "revision" : "f70225981241859eb4aa1a18a75531d26637c8cc", + "version" : "1.4.0" } }, { @@ -267,8 +267,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-atomics.git", "state" : { - "revision" : "cd142fd2f64be2100422d658e7411e39489da985", - "version" : "1.2.0" + "revision" : "b601256eab081c0f92f059e12818ac1d4f178ff7", + "version" : "1.3.0" } }, { @@ -276,8 +276,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-certificates.git", "state" : { - "revision" : "999fd70c7803da89f3904d635a6815a2a7cd7585", - "version" : "1.10.0" + "revision" : "4b092f15164144c24554e0a75e080a960c5190a6", + "version" : "1.14.0" } }, { @@ -285,8 +285,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections.git", "state" : { - "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7", - "version" : "1.1.4" + "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", + "version" : "1.3.0" } }, { @@ -294,8 +294,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-crypto.git", "state" : { - "revision" : "e8d6eba1fef23ae5b359c46b03f7d94be2f41fed", - "version" : "3.12.3" + "revision" : "95ba0316a9b733e92bb6b071255ff46263bbe7dc", + "version" : "3.15.1" } }, { @@ -303,8 +303,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-distributed-tracing.git", "state" : { - "revision" : "a64a0abc2530f767af15dd88dda7f64d5f1ff9de", - "version" : "1.2.0" + "revision" : "6600888f4cb5bbf1bcac51000f60b2cbd224c91b", + "version" : "1.3.0" } }, { @@ -312,8 +312,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-http-structured-headers.git", "state" : { - "revision" : "f280fc7676b9940ff2c6598642751ea333c6544f", - "version" : "1.2.2" + "revision" : "1625f271afb04375bf48737a5572613248d0e7a0", + "version" : "1.4.0" } }, { @@ -330,8 +330,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-log.git", "state" : { - "revision" : "3d8596ed08bd13520157f0355e35caed215ffbfa", - "version" : "1.6.3" + "revision" : "ce592ae52f982c847a4efc0dd881cc9eb32d29f2", + "version" : "1.6.4" } }, { @@ -339,8 +339,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-metrics.git", "state" : { - "revision" : "4c83e1cdf4ba538ef6e43a9bbd0bcc33a0ca46e3", - "version" : "2.7.0" + "revision" : "0743a9364382629da3bf5677b46a2c4b1ce5d2a6", + "version" : "2.7.1" } }, { @@ -348,8 +348,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio.git", "state" : { - "revision" : "0f54d58bb5db9e064f332e8524150de379d1e51c", - "version" : "2.82.1" + "revision" : "a18bddb0acf7a40d982b2f128ce73ce4ee31f352", + "version" : "2.86.2" } }, { @@ -357,8 +357,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-extras.git", "state" : { - "revision" : "f1f6f772198bee35d99dd145f1513d8581a54f2c", - "version" : "1.26.0" + "revision" : "a55c3dd3a81d035af8a20ce5718889c0dcab073d", + "version" : "1.29.0" } }, { @@ -366,8 +366,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-http2.git", "state" : { - "revision" : "4281466512f63d1bd530e33f4aa6993ee7864be0", - "version" : "1.36.0" + "revision" : "5e9e99ec96c53bc2c18ddd10c1e25a3cd97c55e5", + "version" : "1.38.0" } }, { @@ -375,8 +375,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-ssl.git", "state" : { - "revision" : "6df102a39c8da5fdc2eae29a0f63546d660866fc", - "version" : "2.30.0" + "revision" : "b2b043a8810ab6d51b3ff4df17f057d87ef1ec7c", + "version" : "2.34.1" } }, { @@ -384,8 +384,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-transport-services.git", "state" : { - "revision" : "cd1e89816d345d2523b11c55654570acd5cd4c56", - "version" : "1.24.0" + "revision" : "e645014baea2ec1c2db564410c51a656cf47c923", + "version" : "1.25.1" } }, { @@ -393,8 +393,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-numerics.git", "state" : { - "revision" : "e0ec0f5f3af6f3e4d5e7a19d2af26b481acb6ba8", - "version" : "1.0.3" + "revision" : "0c0290ff6b24942dadb83a929ffaaa1481df04a2", + "version" : "1.1.1" } }, { @@ -402,8 +402,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-openapi-runtime", "state" : { - "revision" : "8f33cc5dfe81169fb167da73584b9c72c3e8bc23", - "version" : "1.8.2" + "revision" : "7722cf8eac05c1f1b5b05895b04cfcc29576d9be", + "version" : "1.8.3" } }, { @@ -411,8 +411,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swift-server/swift-prometheus.git", "state" : { - "revision" : "54f18941e5f278f7f700f2188b7e21be563ca76f", - "version" : "2.1.0" + "revision" : "8a8ff47403444e16d8cdfa805a5e3cb8e2efe734", + "version" : "2.2.0" } }, { @@ -429,8 +429,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-service-context.git", "state" : { - "revision" : "8946c930cae601452149e45d31d8ddfac973c3c7", - "version" : "1.2.0" + "revision" : "1983448fefc717a2bc2ebde5490fe99873c5b8a6", + "version" : "1.2.1" } }, { @@ -447,8 +447,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-system.git", "state" : { - "revision" : "a34201439c74b53f0fd71ef11741af7e7caf01e1", - "version" : "1.4.2" + "revision" : "395a77f0aa927f0ff73941d7ac35f2b46d47c9db", + "version" : "1.6.3" } }, { @@ -465,8 +465,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/vapor.git", "state" : { - "revision" : "3636f443474769147828a5863e81a31f6f30e92c", - "version" : "4.115.1" + "revision" : "773ea6a63595ae4f6bc46a366d78769d4cb8b08c", + "version" : "4.117.0" } }, { @@ -483,8 +483,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/websocket-kit.git", "state" : { - "revision" : "014ccd52891b8c098d7e1033d5e72ed76fef7a86", - "version" : "2.16.0" + "revision" : "8666c92dbbb3c8eefc8008c9c8dcf50bfd302167", + "version" : "2.16.1" } } ], diff --git a/Backend/Sources/App/DataTypes/BackendMetric.swift b/Backend/Sources/App/DataTypes/BackendMetric.swift index ad950be5..d09d89f5 100644 --- a/Backend/Sources/App/DataTypes/BackendMetric.swift +++ b/Backend/Sources/App/DataTypes/BackendMetric.swift @@ -12,56 +12,56 @@ internal enum BackendMetric { /// Counter for successful verification codes sent. public static let totalSuccessfulVerificationCodesSent = MetricsService.global.makeCounter( name: "total_verification_codes_sent", - labels: ["status": Self.MetricStatus.success.rawValue] + labels: ["status": MetricStatus.success.rawValue] ) /// Counter for failed verification codes sent. public static let totalFailedVerificationCodesSent = MetricsService.global.makeCounter( name: "total_verification_codes_sent", - labels: ["status": Self.MetricStatus.fail.rawValue] + labels: ["status": MetricStatus.fail.rawValue] ) /// Counter for total users created. public static let totalUsersCreated = MetricsService.global.makeCounter( name: "total_users_created", - labels: ["status": Self.MetricStatus.success.rawValue] + labels: ["status": MetricStatus.success.rawValue] ) /// Counter for users that already exist. public static let totalUsersAlreadyExists = MetricsService.global.makeCounter( name: "total_users_created", - labels: ["status": Self.MetricStatus.alreadyExists.rawValue] + labels: ["status": MetricStatus.alreadyExists.rawValue] ) /// Counter for successful token refresh attempts. public static let totalSuccessfulTokensRefreshed = MetricsService.global.makeCounter( name: "total_token_refresh_attempts", - labels: ["status": Self.MetricStatus.success.rawValue] + labels: ["status": MetricStatus.success.rawValue] ) /// Counter for failed token refresh attempts. public static let totalFailedTokensRefreshed = MetricsService.global.makeCounter( name: "total_token_refresh_attempts", - labels: ["status": Self.MetricStatus.fail.rawValue] + labels: ["status": MetricStatus.fail.rawValue] ) /// Counter for logout attempts. public static let totalLogoutAttempted = MetricsService.global.makeCounter( name: "total_logout_attempts", - labels: ["status": Self.MetricStatus.success.rawValue] + labels: ["status": MetricStatus.success.rawValue] ) /// Counter for failed logout attempts. public static let totalFailedLogoutAttempted = MetricsService.global.makeCounter( name: "total_logout_attempts", - labels: ["status": Self.MetricStatus.fail.rawValue] + labels: ["status": MetricStatus.fail.rawValue] ) /// Counter for profile pictures generated. public static let totalProfilePicturesGenerated = MetricsService.global.makeCounter( name: "total_profile_pictures_generated", labels: [ - "status": Self.MetricStatus.success.rawValue, + "status": MetricStatus.success.rawValue, ] ) @@ -69,7 +69,7 @@ internal enum BackendMetric { public static let totalProfilePicturesGenerationFailed = MetricsService.global.makeCounter( name: "total_profile_pictures_generated", labels: [ - "status": Self.MetricStatus.fail.rawValue, + "status": MetricStatus.fail.rawValue, ] ) @@ -77,7 +77,7 @@ internal enum BackendMetric { public static let totalTextMessagesSent = MetricsService.global.makeCounter( name: "total_text_messages_sent", labels: [ - "status": Self.MetricStatus.success.rawValue, + "status": MetricStatus.success.rawValue, ] ) @@ -85,7 +85,7 @@ internal enum BackendMetric { public static let totalTextMessagesSentFailed = MetricsService.global.makeCounter( name: "total_text_messages_sent", labels: [ - "status": Self.MetricStatus.fail.rawValue, + "status": MetricStatus.fail.rawValue, ] ) @@ -98,7 +98,7 @@ internal enum BackendMetric { /// - Parameter status: The status of the request. /// - Returns: A `Prometheus.Counter` object. public static func openAIImageGenerationRequest( - status: Self.MetricStatus + status: MetricStatus ) -> Prometheus.Counter { MetricsService.global.makeCounter( name: "openai_image_generation_requests", @@ -112,7 +112,7 @@ internal enum BackendMetric { /// - Parameter status: The status of the OAuth request (success/fail/etc). /// - Returns: A Prometheus counter for Twitter OAuth requests with the given status. public static func twitterOAuthRequest( - status: Self.MetricStatus + status: MetricStatus ) -> Prometheus.Counter { MetricsService.global.makeCounter( name: "twitter_oauth_requests", @@ -126,7 +126,7 @@ internal enum BackendMetric { /// - Parameter status: The status of the token conversion (success/fail/etc). /// - Returns: A Prometheus counter for Twitter token conversions with the given status. public static func twitterUserTokensConverted( - status: Self.MetricStatus + status: MetricStatus ) -> Prometheus.Counter { MetricsService.global.makeCounter( name: "twitter_user_tokens_converted", @@ -140,7 +140,7 @@ internal enum BackendMetric { /// - Parameter status: The status of posting the tweet (success/fail/etc). /// - Returns: A Prometheus counter for tweet posts with the given status. public static func twitterPostTweet( - status: Self.MetricStatus + status: MetricStatus ) -> Prometheus.Counter { MetricsService.global.makeCounter( name: "twitter_post_tweet", @@ -158,7 +158,7 @@ internal enum BackendMetric { /// - didThrowOnFeedInitialization: Flag indicating if an error occurred during feed initialization. /// - Returns: A Prometheus counter for RSS feed reads with the given status. public static func rssFeedReaderMetric( - status: Self.MetricStatus, + status: MetricStatus, url: URL, isRSSFeed: Bool? = nil, didThrowOnFeedInitialization: Bool = false @@ -185,7 +185,7 @@ internal enum BackendMetric { public static func chatCompletionServiceCall( platform: ChatCompletionPlatform, model: ChatCompletionModel, - status: Self.MetricStatus + status: MetricStatus ) -> Prometheus.Counter { MetricsService.global.makeCounter( name: "chat_completion_service_call", @@ -201,7 +201,7 @@ internal enum BackendMetric { public static let totalMediaFilesUploadedToTigris = MetricsService.global.makeCounter( name: "total_media_files_uploaded_to_tigris", labels: [ - "status": Self.MetricStatus.success.rawValue, + "status": MetricStatus.success.rawValue, ] ) @@ -209,7 +209,7 @@ internal enum BackendMetric { public static let totalMediaFilesUploadedToTigrisFailed = MetricsService.global.makeCounter( name: "total_media_files_uploaded_to_tigris", labels: [ - "status": Self.MetricStatus.fail.rawValue, + "status": MetricStatus.fail.rawValue, ] ) @@ -219,7 +219,7 @@ internal enum BackendMetric { /// - url: The URL being scraped. /// - Returns: A Prometheus counter for Firecrawl markdown scraping with the given status. public static func firecrawlScrapeMarkdown( - status: Self.MetricStatus, + status: MetricStatus, url: String ) -> Prometheus.Counter { MetricsService.global.makeCounter( @@ -230,16 +230,4 @@ internal enum BackendMetric { ] ) } - - /// Enum representing the status of a metric. - public enum MetricStatus: String, Codable { - /// Indicates that the metric already exists. - case alreadyExists - /// Indicates a failure status for the metric. - case fail - /// Indicates a start status for the metric. - case start - /// Indicates a success status for the metric. - case success - } } From 657aaa3254f8674787f2ad965b58715927b3b7c2 Mon Sep 17 00:00:00 2001 From: William Date: Mon, 13 Oct 2025 06:28:53 +0200 Subject: [PATCH 09/11] feat(AutomaWebCoreClient): created client to interact with automa web core api Made method to get website html. Updated AutomaUtilities to have the web core api endpoint payload type. --- Backend/Package.resolved | 22 ++++++++-------- .../AutomaWebCoreClient.swift | 25 +++++++++++++++++++ package.json | 2 +- 3 files changed, 37 insertions(+), 12 deletions(-) create mode 100644 Backend/Sources/App/Clients/AutomaWebCoreClient/AutomaWebCoreClient.swift diff --git a/Backend/Package.resolved b/Backend/Package.resolved index b65a79ed..e75f05b3 100644 --- a/Backend/Package.resolved +++ b/Backend/Package.resolved @@ -15,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swift-server/async-http-client.git", "state" : { - "revision" : "7dc119c7edf3c23f52638faadb89182861dee853", - "version" : "1.28.0" + "revision" : "8430dd49d4e2b417f472141805c9691ec2923cb8", + "version" : "1.29.0" } }, { @@ -34,7 +34,7 @@ "location" : "https://github.com/GetAutomaApp/AutomaUtilities", "state" : { "branch" : "main", - "revision" : "c1b9a9e6930b66dc2139d62dff65578529b08334" + "revision" : "e9876286ece603e964a8ef1c9bdc9802d4f680ed" } }, { @@ -186,8 +186,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/postgres-nio.git", "state" : { - "revision" : "8ee6118c03501196be183b0938d2ec4478c18954", - "version" : "1.27.0" + "revision" : "312444ea512ac9ed77fe58dcf737265ee48503cf", + "version" : "1.28.0" } }, { @@ -303,8 +303,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-distributed-tracing.git", "state" : { - "revision" : "6600888f4cb5bbf1bcac51000f60b2cbd224c91b", - "version" : "1.3.0" + "revision" : "baa932c1336f7894145cbaafcd34ce2dd0b77c97", + "version" : "1.3.1" } }, { @@ -384,8 +384,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-transport-services.git", "state" : { - "revision" : "e645014baea2ec1c2db564410c51a656cf47c923", - "version" : "1.25.1" + "revision" : "df6c28355051c72c884574a6c858bc54f7311ff9", + "version" : "1.25.2" } }, { @@ -438,8 +438,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swift-server/swift-service-lifecycle.git", "state" : { - "revision" : "e7187309187695115033536e8fc9b2eb87fd956d", - "version" : "2.8.0" + "revision" : "0fcc4c9c2d58dd98504c06f7308c86de775396ff", + "version" : "2.9.0" } }, { diff --git a/Backend/Sources/App/Clients/AutomaWebCoreClient/AutomaWebCoreClient.swift b/Backend/Sources/App/Clients/AutomaWebCoreClient/AutomaWebCoreClient.swift new file mode 100644 index 00000000..f89b5803 --- /dev/null +++ b/Backend/Sources/App/Clients/AutomaWebCoreClient/AutomaWebCoreClient.swift @@ -0,0 +1,25 @@ +// AutomaWebCoreClient.swift +// Copyright (c) 2025 GetAutomaApp +// All source code and related assets are the property of GetAutomaApp. +// All rights reserved. + +import AutomaUtilities +import Vapor + +internal struct AutomaWebCoreClient { + private let client: any Client + private let baseURL: URL + + public init(client: any Client) throws { + self.client = client + let urlString = try Environment.getOrThrow("AUTOMA_WEB_CORE_API_BASE_URL") + baseURL = try URL.fromString(payload: .init(string: urlString)) + } + + public func getWebsiteHTML(payload: AutomaWebCoreAPIEndpointPayload) async throws -> String { + let res = try await client.get("\(baseURL.absoluteString)/api") { req in + try req.content.encode(payload) + } + return try res.content.decode(String.self) + } +} diff --git a/package.json b/package.json index 3c419de4..01da9961 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "deploy:backend:sandbox": "npm run fly:config -- fly sandbox | npm run deploy:to:fly", "deploy:backend:staging": "npm run fly:config -- fly staging | npm run deploy:to:fly", "deploy:backend:production": "npm run fly:config -- fly production | npm run deploy:to:fly", - "deploy:to:fly": "tail -n 1 | xargs -Ixx cp xx Backend/.fly.toml && cd Backend && flyctl deploy --config=.fly.toml --build-secret GITHUB_SSH_AUTHENTICATION_TOKEN=$(cat ./infra/docker-secrets/GITHUB_SSH_AUTHENTICATION_TOKEN)", + "deploy:to:fly": "tail -n 1 | xargs -Ixx cp xx Backend/.fly.toml && cd Backend && flyctl deploy --ha=false --config=.fly.toml --build-secret GITHUB_SSH_AUTHENTICATION_TOKEN=$(cat ./infra/docker-secrets/GITHUB_SSH_AUTHENTICATION_TOKEN)", "deploy:worker:sandbox": "npm run fly:config -- fly-jobs sandbox | npm run deploy:to:fly", "deploy:worker:production": "npm run fly:config -- fly-jobs production | npm run deploy:to:fly", "build:all": "npx npm-run-all --parallel build:ui-kit build:backend", From ebc76208291495a2b6aa607f39e148feb382530b Mon Sep 17 00:00:00 2001 From: William Date: Mon, 13 Oct 2025 07:24:58 +0200 Subject: [PATCH 10/11] fix(automa-backend-testing.yml): set gh_pat so that swift test opensource action can clone private repo - automautilities --- .github/workflows/automa-backend-testing.yml | 12 +- Backend/Package.resolved | 136 +++++++++---------- 2 files changed, 74 insertions(+), 74 deletions(-) diff --git a/.github/workflows/automa-backend-testing.yml b/.github/workflows/automa-backend-testing.yml index 8dbaaedf..3a2e8b0f 100644 --- a/.github/workflows/automa-backend-testing.yml +++ b/.github/workflows/automa-backend-testing.yml @@ -3,8 +3,7 @@ name: Run `AutomaBackend` Tests on: pull_request: paths: - - 'Backend/**/*.swift' - + - "Backend/**/*.swift" jobs: unit-tests: @@ -14,7 +13,7 @@ jobs: - uses: SwiftyLab/setup-swift@latest with: - swift-version: "6.1" + swift-version: "6.1" - uses: useblacksmith/cache@v5 with: @@ -22,11 +21,12 @@ jobs: key: ${{ runner.os }}-backend-unittests-${{ hashFiles('**/Package.resolved') }} - name: Run Unit Tests - uses: GetAutomaApp/opensource-actions/swifttesting@main + uses: GetAutomaApp/Fpensource-actions/swifttesting@main with: compose: "false" working-directory: "Backend" swift_test_extra_args: "--filter '.*UnitTests.*'" + gh_pat: ${{ secrets.GET_AUTOMA_UTILITIES_GH_PAT }} integration-tests: runs-on: blacksmith-4vcpu-ubuntu-2404 @@ -35,13 +35,12 @@ jobs: - uses: SwiftyLab/setup-swift@latest with: - swift-version: "6.1" + swift-version: "6.1" - uses: useblacksmith/cache@v5 with: path: Backend/.build key: ${{ runner.os }}-backend-integrationtests-${{ hashFiles('**/Package.resolved') }} - - name: Run Integration Tests uses: GetAutomaApp/opensource-actions/swifttesting@main with: @@ -50,6 +49,7 @@ jobs: swift_test_extra_args: "--filter '.*IntegrationTests.*'" required_healthy_services_docker_compose: '["postgres", "localstack"]' compose_services_to_startup: '["postgres", "localstack"]' + gh_pat: ${{ secrets.GET_AUTOMA_UTILITIES_GH_PAT }} env: OWNER: ${{ secrets.OWNER }} REPO: ${{ secrets.REPO }} diff --git a/Backend/Package.resolved b/Backend/Package.resolved index e75f05b3..6292837f 100644 --- a/Backend/Package.resolved +++ b/Backend/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "2639472734ac53292465423765530e979d16fad422d125c721d9d1414b211a46", + "originHash" : "1d8db4abc125868abd7c0e97eb84f6246d39ee42a10a5f1676c43785a2426b91", "pins" : [ { "identity" : "alamofire", @@ -60,8 +60,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/nmdias/FeedKit.git", "state" : { - "revision" : "7cd3569dac2a82118eb22d8bce48d040ef0d014d", - "version" : "10.1.3" + "revision" : "03ea968c7741f4feeeacbb6a82ff7320d0953edb", + "version" : "10.1.2" } }, { @@ -69,8 +69,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/fluent.git", "state" : { - "revision" : "2fe9e36daf4bdb5edcf193e0d0806ba2074d2864", - "version" : "4.13.0" + "revision" : "223b27d04ab2b51c25503c9922eecbcdf6c12f89", + "version" : "4.12.0" } }, { @@ -78,8 +78,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/fluent-kit.git", "state" : { - "revision" : "8baacd7e8f7ebf68886c496b43bbe6cdcc5b57e0", - "version" : "1.52.2" + "revision" : "1385c48f98e1e44335b251cc11dc11a0a50ab853", + "version" : "1.52.1" } }, { @@ -87,8 +87,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/fluent-postgres-driver.git", "state" : { - "revision" : "cd47a7042a529735e401bdfaa070823d151f7f94", - "version" : "2.11.0" + "revision" : "095bc5a17ab3363167f4becb270b6f8eb790481c", + "version" : "2.10.1" } }, { @@ -103,7 +103,7 @@ { "identity" : "jmespath.swift", "kind" : "remoteSourceControl", - "location" : "https://github.com/jmespath/jmespath.swift.git", + "location" : "https://github.com/adam-fowler/jmespath.swift.git", "state" : { "revision" : "3877a5060e85ae33e3b9fe51ab581784f65ec80e", "version" : "1.0.3" @@ -123,8 +123,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/jwt-kit.git", "state" : { - "revision" : "2033b3e661238dda3d30e36a2d40987499d987de", - "version" : "5.2.0" + "revision" : "03f5013f0b547ce43abe45e7e90711303a3e5495", + "version" : "5.1.2" } }, { @@ -132,8 +132,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/leaf.git", "state" : { - "revision" : "b70a6108e4917f338f6b8848407bf655aa7e405f", - "version" : "4.5.1" + "revision" : "d469584b9186851c5a4012d11325fb9db3207ebb", + "version" : "4.5.0" } }, { @@ -141,8 +141,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/leaf-kit.git", "state" : { - "revision" : "0c325fc46d42455914abd0105e88fe4561fc31a8", - "version" : "1.14.0" + "revision" : "cf186d8f2ef33e16fd1dd78df36466c22c2e632f", + "version" : "1.13.1" } }, { @@ -159,8 +159,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/MacPaw/OpenAI.git", "state" : { - "revision" : "80045fcda7ba727a327eb0a525e983fd7a796c70", - "version" : "0.4.6" + "revision" : "bb283b2ac48c1e90121d73d6bfb45f961dc0b7a3", + "version" : "0.4.5" } }, { @@ -168,8 +168,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/marmelroy/PhoneNumberKit", "state" : { - "revision" : "8cba2258060e356d5fc4836d4ff8549faa2409dd", - "version" : "4.1.4" + "revision" : "288b99e9e99926bc8be41220802df83c059fac9b", + "version" : "4.0.2" } }, { @@ -177,8 +177,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/postgres-kit.git", "state" : { - "revision" : "d2fd3172c2e318bd292a4c1297e4c65a418cf6f3", - "version" : "2.14.1" + "revision" : "f4d4b9e8db9a907644d67d6a7ecb5f0314eec1ad", + "version" : "2.14.0" } }, { @@ -213,8 +213,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/soto-project/soto.git", "state" : { - "revision" : "051706fdd526335a25ce3fb6b324ff627f3d36bd", - "version" : "7.9.0" + "revision" : "ab7bab78dbe6fd77722639a7f7f7521b1a79e900", + "version" : "7.6.1" } }, { @@ -222,8 +222,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/soto-project/soto-core.git", "state" : { - "revision" : "b641a1b521c2674638325ca62aec126507e3cddd", - "version" : "7.8.0" + "revision" : "bfe6d6f94a82c9268b15ac636005ae57f4129de9", + "version" : "7.6.0" } }, { @@ -231,8 +231,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/sql-kit.git", "state" : { - "revision" : "1a9ab0523fb742d9629558cede64290165c4285b", - "version" : "3.33.2" + "revision" : "baf0d8684a43f16cd11ebcc67300c8ab5cb5d078", + "version" : "3.33.0" } }, { @@ -249,8 +249,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-asn1.git", "state" : { - "revision" : "f70225981241859eb4aa1a18a75531d26637c8cc", - "version" : "1.4.0" + "revision" : "a54383ada6cecde007d374f58f864e29370ba5c3", + "version" : "1.3.2" } }, { @@ -267,8 +267,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-atomics.git", "state" : { - "revision" : "b601256eab081c0f92f059e12818ac1d4f178ff7", - "version" : "1.3.0" + "revision" : "cd142fd2f64be2100422d658e7411e39489da985", + "version" : "1.2.0" } }, { @@ -276,8 +276,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-certificates.git", "state" : { - "revision" : "4b092f15164144c24554e0a75e080a960c5190a6", - "version" : "1.14.0" + "revision" : "999fd70c7803da89f3904d635a6815a2a7cd7585", + "version" : "1.10.0" } }, { @@ -285,8 +285,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections.git", "state" : { - "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", - "version" : "1.3.0" + "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7", + "version" : "1.1.4" } }, { @@ -294,8 +294,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-crypto.git", "state" : { - "revision" : "95ba0316a9b733e92bb6b071255ff46263bbe7dc", - "version" : "3.15.1" + "revision" : "e8d6eba1fef23ae5b359c46b03f7d94be2f41fed", + "version" : "3.12.3" } }, { @@ -312,8 +312,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-http-structured-headers.git", "state" : { - "revision" : "1625f271afb04375bf48737a5572613248d0e7a0", - "version" : "1.4.0" + "revision" : "f280fc7676b9940ff2c6598642751ea333c6544f", + "version" : "1.2.2" } }, { @@ -330,8 +330,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-log.git", "state" : { - "revision" : "ce592ae52f982c847a4efc0dd881cc9eb32d29f2", - "version" : "1.6.4" + "revision" : "3d8596ed08bd13520157f0355e35caed215ffbfa", + "version" : "1.6.3" } }, { @@ -339,8 +339,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-metrics.git", "state" : { - "revision" : "0743a9364382629da3bf5677b46a2c4b1ce5d2a6", - "version" : "2.7.1" + "revision" : "4c83e1cdf4ba538ef6e43a9bbd0bcc33a0ca46e3", + "version" : "2.7.0" } }, { @@ -348,8 +348,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio.git", "state" : { - "revision" : "a18bddb0acf7a40d982b2f128ce73ce4ee31f352", - "version" : "2.86.2" + "revision" : "0f54d58bb5db9e064f332e8524150de379d1e51c", + "version" : "2.82.1" } }, { @@ -357,8 +357,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-extras.git", "state" : { - "revision" : "a55c3dd3a81d035af8a20ce5718889c0dcab073d", - "version" : "1.29.0" + "revision" : "f1f6f772198bee35d99dd145f1513d8581a54f2c", + "version" : "1.26.0" } }, { @@ -366,8 +366,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-http2.git", "state" : { - "revision" : "5e9e99ec96c53bc2c18ddd10c1e25a3cd97c55e5", - "version" : "1.38.0" + "revision" : "4281466512f63d1bd530e33f4aa6993ee7864be0", + "version" : "1.36.0" } }, { @@ -375,8 +375,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-ssl.git", "state" : { - "revision" : "b2b043a8810ab6d51b3ff4df17f057d87ef1ec7c", - "version" : "2.34.1" + "revision" : "6df102a39c8da5fdc2eae29a0f63546d660866fc", + "version" : "2.30.0" } }, { @@ -384,8 +384,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-transport-services.git", "state" : { - "revision" : "df6c28355051c72c884574a6c858bc54f7311ff9", - "version" : "1.25.2" + "revision" : "cd1e89816d345d2523b11c55654570acd5cd4c56", + "version" : "1.24.0" } }, { @@ -393,8 +393,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-numerics.git", "state" : { - "revision" : "0c0290ff6b24942dadb83a929ffaaa1481df04a2", - "version" : "1.1.1" + "revision" : "e0ec0f5f3af6f3e4d5e7a19d2af26b481acb6ba8", + "version" : "1.0.3" } }, { @@ -402,8 +402,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-openapi-runtime", "state" : { - "revision" : "7722cf8eac05c1f1b5b05895b04cfcc29576d9be", - "version" : "1.8.3" + "revision" : "8f33cc5dfe81169fb167da73584b9c72c3e8bc23", + "version" : "1.8.2" } }, { @@ -411,8 +411,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swift-server/swift-prometheus.git", "state" : { - "revision" : "8a8ff47403444e16d8cdfa805a5e3cb8e2efe734", - "version" : "2.2.0" + "revision" : "54f18941e5f278f7f700f2188b7e21be563ca76f", + "version" : "2.1.0" } }, { @@ -429,8 +429,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-service-context.git", "state" : { - "revision" : "1983448fefc717a2bc2ebde5490fe99873c5b8a6", - "version" : "1.2.1" + "revision" : "8946c930cae601452149e45d31d8ddfac973c3c7", + "version" : "1.2.0" } }, { @@ -447,8 +447,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-system.git", "state" : { - "revision" : "395a77f0aa927f0ff73941d7ac35f2b46d47c9db", - "version" : "1.6.3" + "revision" : "a34201439c74b53f0fd71ef11741af7e7caf01e1", + "version" : "1.4.2" } }, { @@ -465,8 +465,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/vapor.git", "state" : { - "revision" : "773ea6a63595ae4f6bc46a366d78769d4cb8b08c", - "version" : "4.117.0" + "revision" : "3636f443474769147828a5863e81a31f6f30e92c", + "version" : "4.115.1" } }, { @@ -483,8 +483,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/websocket-kit.git", "state" : { - "revision" : "8666c92dbbb3c8eefc8008c9c8dcf50bfd302167", - "version" : "2.16.1" + "revision" : "014ccd52891b8c098d7e1033d5e72ed76fef7a86", + "version" : "2.16.0" } } ], From 2514b416e48c621ad44225dbf4f10b0b9190dad6 Mon Sep 17 00:00:00 2001 From: William Date: Mon, 13 Oct 2025 07:26:05 +0200 Subject: [PATCH 11/11] fixup! fix(automa-backend-testing.yml): set gh_pat so that swift test opensource action can clone private repo - automautilities --- .github/workflows/automa-backend-testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/automa-backend-testing.yml b/.github/workflows/automa-backend-testing.yml index 3a2e8b0f..20b76ec5 100644 --- a/.github/workflows/automa-backend-testing.yml +++ b/.github/workflows/automa-backend-testing.yml @@ -21,7 +21,7 @@ jobs: key: ${{ runner.os }}-backend-unittests-${{ hashFiles('**/Package.resolved') }} - name: Run Unit Tests - uses: GetAutomaApp/Fpensource-actions/swifttesting@main + uses: GetAutomaApp/opensource-actions/swifttesting@main with: compose: "false" working-directory: "Backend"