Name Description Size Coverage
ExtensionWidgetsFeed.sys.mjs @import {Store} from "resource://newtab/lib/Store.sys.mjs" 3722 -
ListsFeed.sys.mjs @import {Store} from "resource://newtab/lib/Store.sys.mjs" 4704 -
PictureOfTheDayFeed.sys.mjs @import {Store} from "resource://newtab/lib/Store.sys.mjs" 16373 -
PrivacyFeed.sys.mjs @import {Store} from "resource://newtab/lib/Store.sys.mjs" 23709 -
PrivacyMessages.sys.mjs Privacy widget message scheduling — catalog + selector. The widget always shows today's tracker count. Below it, it shows ONE secondary message — or nothing ("blank"). This module owns the catalog of messages and the pure logic that picks which one to show on each new tab. `PrivacyFeed` gathers the inputs (counts, streak, feature flags, persisted state), calls `selectPrivacyMessage`, persists the returned state, and broadcasts the decision to the component (Bug 2050954). ───────────────────────────── BUSINESS RULES ───────────────────────────── ZERO STATE No trackers blocked today → the empty state (shield icon, no count, no tip). A zero *site* count is not a zero state; the component drops that line instead. MESSAGE FAMILIES (the `category` field) info Education about tracking / Firefox protections. shield/planet/ bolt icon by sub-theme. promo Suggest adopting another Firefox feature (passwords, VPN, Relay masks, sign-in, Monitor). star icon. `feature` tags it so we can suppress promos for features already in use. firstProtection / dailyCap / streak / milestone{Week,Month,Year,Total} Earned "celebration" moments. kit icon. CELEBRATIONS firstProtection The very first time the count goes above zero (once ever). dailyCap Today's count reaches the display cap (the "100+" ceiling). streak Protected 3, 5, or 7 days in a row (count-block layout, like blank but with a message + kit icon). Each of 3/5/7 fires once per streak; a broken streak re-arms them. milestone* Cumulative total crosses a tier (see MILESTONE_TIERS): week 100 month 250 / 500 / 1K / 2K year 5K / 10K / 25K total 10K / 25K Fires on the next new tab after crossing, at most once per day. The highest crossed tier wins; the watermark prevents re-firing until the calendar period rolls (week/month/year) or never (total). FREQUENCY (ordinary info + promo only — celebrations bypass all of this) Normal profile: ≤ 5/day, ≤ 1/hour. (day = UTC day, see below) New profile (< 48h): ≤ 10/day, ≤ 1/15min. Anchored to profile age. Over a limit → blank. A blank never consumes a slot (only real messages do). "Seen" = rendered: a message counts the moment it is selected for a new tab. BLANK CHANCE Even when an info message is eligible, show blank `blankChance` of the time (default 0.4, pref-controlled) for a calm, high-signal experience. Promos are not subject to the random blank. PROMO LIMITS (on top of the frequency rules) ≤ 1 promo/day; the same promo repeats ≤ once/month; and promos are skipped for features the user already uses (sign-in/Sync, saved logins, Relay masks are detectable; VPN and Monitor have no local signal so they still rotate). PRECEDENCE (when several qualify on the same new tab) 1. empty (count 0) 2. firstProtection (once ever) 3. streak (3/5/7) 4. milestone (≤ once/day) 5. dailyCap (100+) 6. otherwise an ordinary info/promo message subject to the limits — or blank DAY BOUNDARIES are UTC (matching how the tracker count is stored; same as about:protections), so week/month/year totals reset on UTC boundaries. NOTE (Bug 2048389): the catalog `id`s are real Fluent message ids; the component resolves each as an l10n id with `countArg`. The scheduling logic keys off `category`/`icon`/`countSource`, never the id. 24795 -
RecentSearchesFeed.sys.mjs @import {Store} from "resource://newtab/lib/Store.sys.mjs" 10934 -
StocksFeed.sys.mjs @import {Store} from "resource://newtab/lib/Store.sys.mjs" 19740 -
TimerFeed.sys.mjs @import {Store} from "resource://newtab/lib/Store.sys.mjs" 5410 -
TravelFeed.sys.mjs @import {Store} from "resource://newtab/lib/Store.sys.mjs" 1746 -