Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/chefnaphtha/xBlockOrigin/llms.txt

Use this file to discover all available pages before exploring further.

xBlockOrigin uses Chrome’s storage APIs for data persistence, with separation between synced and local storage.

Storage types

The extension uses two Chrome storage areas:
Synced across devices - Limited to 100KB total, 8KB per item
  • Country blacklist
  • User whitelist
  • Extension settings
All storage operations use Valibot schemas for runtime validation to ensure type safety and data integrity.

Synced storage (chrome.storage.sync)

Country blacklist

Storage key: blacklist Schema:
const blacklistSchema = v.array(v.string())

type Blacklist = string[] // e.g., ["United States", "Russia", "China"]
Example data:
{
  "blacklist": ["United States", "Antarctica", "Russia"]
}
Access pattern:
  • Read on every user processing to check if country is blacklisted
  • Write when user adds/removes countries via popup UI

User whitelist

Storage key: whitelist Schema:
const whitelistedUserSchema = v.object({
  username: v.string(),
  userId: v.string(),
  whitelistedAt: v.number() // Unix timestamp in milliseconds
})

type WhitelistedUser = {
  username: string
  userId: string
  whitelistedAt: number
}
Example data:
{
  "whitelist": [
    {
      "username": "elonmusk",
      "userId": "44196397",
      "whitelistedAt": 1709481600000
    },
    {
      "username": "TwitterDev",
      "userId": "2244994945",
      "whitelistedAt": 1709568000000
    }
  ]
}
Access pattern:
  • Read on every user processing to check if user is whitelisted
  • Write when user adds/removes users from whitelist
Functions:
getAllWhitelistedUsers
() => Promise<WhitelistedUser[]>
Returns all whitelisted users
isWhitelisted
(userId: string) => Promise<boolean>
Checks if a user ID is whitelisted
addToWhitelist
(userId: string, username: string) => Promise<void>
Adds a user to whitelist (prevents duplicates)
removeFromWhitelist
(userId: string) => Promise<void>
Removes a user from whitelist

Settings

Storage key: settings Schema:
const settingsSchema = v.object({
  showFlags: v.boolean(),
  muteFollowing: v.boolean()
})

type Settings = {
  showFlags: boolean      // Show country flags next to usernames
  muteFollowing: boolean  // Also mute users you are following
}
Default values:
{
  "settings": {
    "showFlags": false,
    "muteFollowing": false
  }
}
Access pattern:
  • Read when processing users (to check muteFollowing)
  • Read when injecting flags (to check showFlags)
  • Write when user changes settings in popup
Functions:
getSettings
() => Promise<Settings>
Returns current settings (merges with defaults)
updateSettings
(updates: Partial<Settings>) => Promise<void>
Updates settings (partial update supported)
getShowFlags
() => Promise<boolean>
Returns showFlags setting value
getMuteFollowing
() => Promise<boolean>
Returns muteFollowing setting value

Local storage (chrome.storage.local)

Muted users database

Storage key pattern: muted:{userId} Schema:
const mutedUserSchema = v.object({
  username: v.string(),
  userId: v.string(),
  country: v.string(),
  mutedAt: v.number() // Unix timestamp in milliseconds
})

type MutedUser = {
  username: string
  userId: string
  country: string
  mutedAt: number
}
Example data:
{
  "muted:1234567890": {
    "username": "badactor",
    "userId": "1234567890",
    "country": "Antarctica",
    "mutedAt": 1709481600000
  },
  "muted:9876543210": {
    "username": "spammer",
    "userId": "9876543210",
    "country": "United States",
    "mutedAt": 1709568000000
  }
}
Access pattern:
  • Write when a new user is muted via API
  • Read to display muted users in popup UI
  • Read to check if user is already muted (cache miss scenario)
Functions:
saveMutedUser
(user: MutedUser) => Promise<void>
Saves a muted user to database (validates with schema)
getAllMutedUsers
() => Promise<MutedUser[]>
Returns all muted users (filters keys with muted: prefix)
isUserMuted
(userId: string) => Promise<boolean>
Checks if a user ID exists in muted database
getMutedUsersByCountry
(country: string) => Promise<MutedUser[]>
Returns all muted users from a specific country

Persistent cache

The cache system stores time-limited data with automatic expiration. See Caching for details. Storage key patterns:
  • cache:country:{username} - Country lookup cache (24h TTL)
  • cache:user:{username} - User ID lookup cache (24h TTL)
  • cache:following:{userId} - Following status cache (5m TTL)
Schema:
type CacheEntry<T> = {
  value: T
  expiresAt: number // Unix timestamp in milliseconds
}
Example data:
{
  "cache:country:elonmusk": {
    "value": "United States",
    "expiresAt": 1709568000000
  },
  "cache:user:elonmusk": {
    "value": "44196397",
    "expiresAt": 1709568000000
  },
  "cache:following:44196397": {
    "value": true,
    "expiresAt": 1709482200000
  }
}
Access pattern:
  • Read before every API call to check if data is cached
  • Write after successful API responses
  • Lazy cleanup on read (expired entries deleted when accessed)

Storage limits

Be aware of Chrome storage quota limits:
Storage TypeTotal QuotaPer-Item Quota
chrome.storage.sync100 KB8 KB
chrome.storage.local (Chrome)10 MBN/A
chrome.storage.local (Firefox)UnlimitedN/A
Estimated storage usage:
  • Blacklist: ~100 bytes per country
  • Whitelist: ~100 bytes per user
  • Settings: ~50 bytes
  • Muted user: ~150 bytes per user
  • Cache entry: ~100-200 bytes per entry
With 10MB local storage quota, you can store approximately 50,000-70,000 muted users before hitting the limit.

Data migration

The extension does not currently implement data migration between versions. All schemas are validated on read using Valibot:
import * as v from 'valibot'

// Example: Reading validated data
const result = await chrome.storage.sync.get('settings')
const settings = v.parse(settingsSchema, result.settings)
If schema validation fails, the extension falls back to default values where applicable.

Build docs developers (and LLMs) love