refactor(audience): unify consent level checks via capability-query functions#2848
Merged
ImmutableJeffrey merged 10 commits intoApr 14, 2026
Merged
Conversation
|
View your CI Pipeline Execution ↗ for commit e526fa0
☁️ Nx Cloud last updated this comment at |
✅ Pixel Bundle Size — @imtbl/pixel
Budget: 10.00 KB gzipped (warn at 8.00 KB) |
nattb8
reviewed
Apr 13, 2026
nattb8
reviewed
Apr 13, 2026
Add canTrack(), canIdentify(), and includesUserId() to consent.ts as the single source of truth for what each consent level permits. Currently the behavioral rules (can I track at this level? can I identify? should I attach userId?) are expressed as raw string comparisons scattered across 21+ call sites in sdk, pixel, and autocapture. If consent levels or rules change, every call site needs updating. These three functions centralise the rules: - canTrack(level) — true for anonymous + full - canIdentify(level) — true for full only - includesUserId(level) — true for full only Subsequent commits will replace the scattered comparisons with calls to these functions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace 6 scattered consent string comparisons in sdk.ts with calls to canTrack(), canIdentify(), and includesUserId() from core: - constructor: consentLevel !== 'none' → canTrack(consentLevel) - isTrackingDisabled(): === 'none' → !canTrack(level) - effectiveUserId(): === 'full' → includesUserId(level) - identify(): !== 'full' → !canIdentify(level) - alias(): !== 'full' → !canIdentify(level) - setConsent upgrade detection: string comparison → canTrack() setConsent() transition-specific checks (→none stops queue, clears cookies; →anonymous from full clears userId) remain as direct comparisons — they're state transitions, not capability queries. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace 5 consent string comparisons in pixel.ts with calls to consentAllowsTracking() from core: - init(): level !== 'none' → consentAllowsTracking(level) - setConsent(): level !== 'none' → consentAllowsTracking(level) - startCmpDetection() onUpdate: level !== 'none' → consentAllowsTracking - startCmpDetection() onDetected: detector.level !== 'none' → same - canTrack(): level !== 'none' → consentAllowsTracking(level) The earlier version of pixel.ts had userId/identify checks that needed includesUserId() and canIdentify(), but those were removed in PR #2846 (pixel identify removal). Only canTrack() is needed now. Update pixel.test.ts mock to include the canTrack export. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ons type autocapture.ts — replace 3 consent string comparisons: - form submit guard: getConsent() === 'none' → !canTrack(getConsent()) - email hash gate: consent === 'full' → includesUserId(consent) - link click guard: getConsent() === 'none' → !canTrack(getConsent()) snippet.ts — replace inline literal union 'none' | 'anonymous' | 'full' with the ConsentLevel type from @imtbl/audience-core. This was the one place consent values were defined outside the single source of truth. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tity gates canIdentify() and includesUserId() had identical implementations (level === 'full'). Collapse to just canIdentify() — the name covers both "can I call identify/alias" and "should I attach userId or hash email", which are the same gate. Two functions is the right number: - canTrack(level) — can this level record events? - canIdentify(level) — can this level use identity features? Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Consumer apps (e.g. Play) import from @imtbl/audience, not @imtbl/audience-core. Re-export the two consent capability functions so consumers can use them without adding a direct core dependency. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Convert the 3 remaining raw consent string comparisons in sdk.ts setConsent() to use the capability functions: - level === 'none' (queue stop) → !canTrack(level) - level === 'none' (cookie delete) → !canTrack(level) - level === 'anonymous' && previous === 'full' (userId clear) → canIdentify(previous) && !canIdentify(level) These were left as raw comparisons in the initial refactor because they're state transitions, but they gate the same capabilities as the query functions. If a future consent level blocks tracking (like 'none' does), these would silently diverge without this change. Also fix canTrack mock in pixel.test.ts from a bare arrow to jest.fn().mockImplementation() so it can be overridden per-test. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment referenced the 'none' level specifically, but the check now delegates to canTrack(), which is the capability source of truth. Describe the predicate in the same terms so the comment doesn't rot if another non-tracking level is added. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous commit aliased the imported canTrack to avoid colliding with pixel's pre-existing private method of the same name. Invert that choice: rename the private method, drop the import alias. The imported canTrack now reads the same as in autocapture.ts and every other call site, and isTrackingAllowed better describes the private method (it also checks isReady, not just consent). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
8d86957 to
769986e
Compare
The section header and doc comments restated what the function names already convey. Removed per the project's preference to comment only when the reason is non-obvious. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
nattb8
approved these changes
Apr 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
@imtbl/audience-core:canTrack(level)— true if the level allows event recordingcanIdentify(level)— true if the level allows identity features (identify, alias, userId, email hashing)@imtbl/audience-coreand@imtbl/audience=== 'none'/=== 'full'comparisons in@imtbl/audience(sdk.ts) and@imtbl/pixel(pixel.ts,autocapture.ts) with calls to these helpersSnippetOptions.consentfrom'none' | 'anonymous' | 'full'toConsentLevelcanTrack()method toisTrackingAllowed()LInear: SDK-122
Tests
pnpm typecheckandpnpm lintclean across all three packages