Raccoglie eventi aggregati dietro consenso cookie, senza PII né tracking su admin/regia/live/replay; GA4 resta invariato. Co-authored-by: Cursor <cursoragent@cursor.com>
43 lines
1.3 KiB
Ruby
43 lines
1.3 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Analytics
|
|
class PathNormalizer
|
|
UUID_RE = /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/i
|
|
NUMERIC_RE = /\A\d{6,}\z/
|
|
TOKENISH_RE = /\A[A-Za-z0-9_\-]{22,}\z/
|
|
|
|
EXCLUDED_PREFIXES = %w[/admin /regia /analytics /cable /api /webhooks /internal].freeze
|
|
|
|
class << self
|
|
def normalize(raw_path)
|
|
path = raw_path.to_s.split("?", 2).first.to_s
|
|
path = "/" if path.blank?
|
|
path = "/#{path}" unless path.start_with?("/")
|
|
path = path.gsub(%r{/{2,}}, "/").chomp("/")
|
|
path = "/" if path.blank?
|
|
|
|
parts = path.split("/").map do |segment|
|
|
next segment if segment.blank?
|
|
next ":id" if UUID_RE.match?(segment)
|
|
next ":id" if NUMERIC_RE.match?(segment)
|
|
next ":token" if TOKENISH_RE.match?(segment) && segment.match?(/[A-Z]/)
|
|
|
|
segment
|
|
end
|
|
normalized = parts.join("/")
|
|
normalized = "/" if normalized.blank?
|
|
normalized
|
|
end
|
|
|
|
def excluded?(raw_or_normalized)
|
|
path = normalize(raw_or_normalized)
|
|
return true if EXCLUDED_PREFIXES.any? { |p| path == p || path.start_with?("#{p}/") }
|
|
return true if path.match?(%r{\A/live/[^/]+})
|
|
return true if path.match?(%r{\A/replay/[^/]+})
|
|
|
|
false
|
|
end
|
|
end
|
|
end
|
|
end
|