Project updates from Template #1
@@ -4,7 +4,8 @@ import Foundation
|
|||||||
///
|
///
|
||||||
/// A page carries it as an optional value so the ``Page`` scaffolding renders the tracker's deferred `<script>` in the document head, or omits it
|
/// A page carries it as an optional value so the ``Page`` scaffolding renders the tracker's deferred `<script>` in the document head, or omits it
|
||||||
/// when the page has none. The attribute names follow the Umami tracker convention. The three behavior flags default to on, and each renders its
|
/// when the page has none. The attribute names follow the Umami tracker convention. The three behavior flags default to on, and each renders its
|
||||||
/// `data-` attribute only when enabled, since the tracker treats an absent attribute as off.
|
/// `data-` attribute only when enabled, since the tracker treats an absent attribute as off. Recorder mode, by contrast, defaults to off; when
|
||||||
|
/// activated, the page embeds a second deferred script that loads the session recorder from the tracker's origin.
|
||||||
public struct Analytics: Sendable {
|
public struct Analytics: Sendable {
|
||||||
|
|
||||||
// MARK: Type aliases
|
// MARK: Type aliases
|
||||||
@@ -25,6 +26,9 @@ public struct Analytics: Sendable {
|
|||||||
/// Whether the tracker collects Core Web Vitals from visitors (requires an Umami instance at v3.1 or newer).
|
/// Whether the tracker collects Core Web Vitals from visitors (requires an Umami instance at v3.1 or newer).
|
||||||
public let performance: Bool
|
public let performance: Bool
|
||||||
|
|
||||||
|
/// Whether the tracker also records visitor sessions, loading the session recorder script alongside the tracker.
|
||||||
|
public let recorder: Bool
|
||||||
|
|
||||||
/// The URL the tracker script is loaded from.
|
/// The URL the tracker script is loaded from.
|
||||||
public let scriptURL: String
|
public let scriptURL: String
|
||||||
|
|
||||||
@@ -41,13 +45,15 @@ public struct Analytics: Sendable {
|
|||||||
/// - excludeHash: whether the tracker drops the URL fragment from reported pageviews; defaults to `true`.
|
/// - excludeHash: whether the tracker drops the URL fragment from reported pageviews; defaults to `true`.
|
||||||
/// - doNotTrack: whether the tracker honors the visitor's browser Do Not Track preference; defaults to `true`.
|
/// - doNotTrack: whether the tracker honors the visitor's browser Do Not Track preference; defaults to `true`.
|
||||||
/// - performance: whether the tracker collects Core Web Vitals (requires Umami v3.1 or newer); defaults to `true`.
|
/// - performance: whether the tracker collects Core Web Vitals (requires Umami v3.1 or newer); defaults to `true`.
|
||||||
|
/// - recorder: whether the tracker also records visitor sessions, loading the session recorder script alongside the tracker; defaults to `false`.
|
||||||
public init(
|
public init(
|
||||||
scriptURL: String,
|
scriptURL: String,
|
||||||
websiteID: String,
|
websiteID: String,
|
||||||
domains: String,
|
domains: String,
|
||||||
excludeHash: Bool = true,
|
excludeHash: Bool = true,
|
||||||
doNotTrack: Bool = true,
|
doNotTrack: Bool = true,
|
||||||
performance: Bool = true
|
performance: Bool = true,
|
||||||
|
recorder: Bool = false
|
||||||
) {
|
) {
|
||||||
self.scriptURL = scriptURL
|
self.scriptURL = scriptURL
|
||||||
self.websiteID = websiteID
|
self.websiteID = websiteID
|
||||||
@@ -55,6 +61,7 @@ public struct Analytics: Sendable {
|
|||||||
self.excludeHash = excludeHash
|
self.excludeHash = excludeHash
|
||||||
self.doNotTrack = doNotTrack
|
self.doNotTrack = doNotTrack
|
||||||
self.performance = performance
|
self.performance = performance
|
||||||
|
self.recorder = recorder
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Computed
|
// MARK: Computed
|
||||||
@@ -114,4 +121,16 @@ public struct Analytics: Sendable {
|
|||||||
return "\(scheme)://\(host)\(port)"
|
return "\(scheme)://\(host)\(port)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The URL the session recorder script is loaded from, derived from the tracker's ``origin``, or `nil` when ``recorder`` mode is off
|
||||||
|
/// or no origin can be derived from the ``scriptURL``.
|
||||||
|
///
|
||||||
|
/// A page renders it as a second deferred script tag after the tracker script, carrying only the `data-website-id` attribute.
|
||||||
|
public var recorderScriptURL: String? {
|
||||||
|
guard recorder, let origin else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "\(origin)/recorder.js"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,41 @@ struct AnalyticsTests {
|
|||||||
#expect(analytics.origin == nil)
|
#expect(analytics.origin == nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
func `carries no recorder script URL by default`() {
|
||||||
|
let analytics = Analytics(
|
||||||
|
scriptURL: "https://analytics.example.com/script",
|
||||||
|
websiteID: "id-123",
|
||||||
|
domains: "example.com"
|
||||||
|
)
|
||||||
|
|
||||||
|
#expect(analytics.recorderScriptURL == nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
func `derives its recorder script URL from the origin when recorder mode is on`() {
|
||||||
|
let analytics = Analytics(
|
||||||
|
scriptURL: "https://analytics.example.com/script",
|
||||||
|
websiteID: "id-123",
|
||||||
|
domains: "example.com",
|
||||||
|
recorder: true
|
||||||
|
)
|
||||||
|
|
||||||
|
#expect(analytics.recorderScriptURL == "https://analytics.example.com/recorder.js")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
func `carries no recorder script URL when no origin can be derived`() {
|
||||||
|
let analytics = Analytics(
|
||||||
|
scriptURL: "/script",
|
||||||
|
websiteID: "id-123",
|
||||||
|
domains: "example.com",
|
||||||
|
recorder: true
|
||||||
|
)
|
||||||
|
|
||||||
|
#expect(analytics.recorderScriptURL == nil)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
func `omits the disabled behavior flags`() {
|
func `omits the disabled behavior flags`() {
|
||||||
let analytics = Analytics(
|
let analytics = Analytics(
|
||||||
|
|||||||
Reference in New Issue
Block a user