-
New starter pack threshold monitoring system for detecting follow-farming - Account label negation support (remove labels when criteria no longer match) - Login retry logic with configurable attempts - Configurable time window units (minutes, hours, days) for threshold labeling - Refactored profile checking into single unified function - Bug fixes for async error handling and authentication race conditions
## New Features ### Starter Pack Threshold System - New `src/starterPackThreshold.ts` module - Monitors starter pack creation per account within rolling time windows - Configurable threshold, window, and actions (label/report/comment) - Per-config allowlist support - 3 new Prometheus metrics for monitoring ### Label Negation - New `negateAccountLabel()` function in accountModeration - New `getAllAccountLabels()` to retrieve current labels - New `deleteAccountLabelClaim()` for Redis cache invalidation - Enables `unlabel: true` in check configs to auto-remove labels ### Configurable Window Units - Changed from `windowDays: number` to `window: number` + `windowUnit: WindowUnit` - Supports `"minutes"`, `"hours"`, `"days"` - Applies to both account threshold and starter pack threshold ### Login Retry - Agent now retries login up to 3 times with 2s delay - Graceful failure after exhausting retries ### Profile Check Refactor - Combined `checkDescription` + `checkDisplayName` into single `checkProfile` function - Cleaner event handling in main.ts ## Bug Fixes ### Fire-and-Forget Async Handling - Eliminated `void` keyword discarding promises from moderation actions - Added `ModerationResult` type for structured error tracking - Added `moderationActionsFailedCounter` metric for monitoring failures - Moderation functions now rethrow errors after logging - Updated `checkProfiles.ts`, `checkPosts.ts`, and `countStarterPacks.ts` with proper async/await and error aggregation - **Prevents phantom state where Redis succeeds but Ozone API fails** ### Authentication Race Condition - Converted `isLoggedIn` from eager evaluation to lazy initialization - Authentication now only starts when first awaited - Prevents race conditions during test setup or early module imports - Backward-compatible implementation using thenable object
Release 2.1.0 #5
expand 95 commits
hide 95 commits
- Rename `reportOnly` to `reportAcct` and `commentOnly` to `commentAcct`
for clarity.
- Introduce `toLabel` flag to explicitly manage item labeling.
These changes allow independent control over labeling an item,
reporting its author, or commenting on the author's account.
- Remove non-functional pre-check for existing labels before applying new ones in handle and profile checks.
- Add checks for starter pack content (name, description) and known vector authors.
- Implement `createPostReport` function for reporting specific posts.
- Update `checkHandle` signature for direct parameter passing.
- Populate predefined moderation lists.
Update to add a funding.yml
This reverts commit 367198d9b94fbbb10d177a0a2c37bd5e2b5c0ece.
- Added comprehensive error handling throughout the codebase to ensure
robustness. - Enhanced logging for improved debugging capabilities. -
Improved shutdown process with graceful exit and cleanup.
- Fixed unsafe type assertions on lines 152 and 158 where embed.external
could potentially be undefined
- Added proper type checking before accessing nested properties
- Improves type safety and prevents potential runtime errors when
processing external embeds
๐ค Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed unsafe type assertions for metricsServer variable
- Added proper type conversions for template literal expressions
- Replaced hasOwnProperty with Object.hasOwn for better practice
- Converted async event handlers to non-async with void for fire-and-forget
- Added comprehensive error type annotations throughout
- Used Promise.allSettled for concurrent operations
- Removed unused imports and applied destructuring
๐ค Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed return-await issues by properly awaiting emitEvent calls
- Replaced template literal expressions with nullish coalescing for agent.did
- Removed unused parameter from checkAccountLabels function
- Made checkAccountLabels function non-async since it only returns null
- Applied nullish coalescing operator for better type safety
๐ค Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Removed unused imports (login, langs)
- Fixed unnecessary optional chain conditions
- Added void operator to floating promises for fire-and-forget operations
- Fixed template literal expressions by converting number to string
- Improved code quality and type safety
๐ค Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed checkHandles.ts: removed require-await, added void for floating promises, fixed template literals, removed non-null assertions
- Fixed checkPosts.ts: removed unused imports, added void for floating promises, fixed template literals, removed non-null assertions
- Fixed checkStarterPack.ts: added correct imports for STARTERPACK_CHECKS, fixed floating promises, template literals, and logic issues
All three check modules now have zero linting errors and follow TypeScript best practices.
๐ค Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed unnecessary conditional check in getLanguage function
- Since parameter is typed as string, typeof check and null check are redundant
- Simplified to check for falsy values only
- Updated log message to be more accurate
๐ค Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Updated TODO section to show completed async error handling work
- Listed all resolved issues including type safety, error handling, and code quality
- Added status for all cleaned files (7 files with zero linting errors)
- Clarified remaining tasks are configuration-related, not code quality
- Fixed constants.ts.example to use type import and include knownVectors property
The codebase is now production-ready with robust error handling and modern TypeScript practices.
๐ค Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit introduces an ESLint configuration file to the project. It
includes recommended rules and best practices for TypeScript projects.
The configuration also sets up various plugins and specifies ignores to
prevent linting of certain files.
- Add validateEnv.ts with validation for all required and optional environment variables
- Validate DID format (must start with 'did:')
- Validate OZONE_URL and OZONE_PDS as domain names
- Validate BSKY_HANDLE format (must contain '.')
- Support arithmetic expressions for LABEL_LIMIT and LABEL_LIMIT_WAIT (e.g., "2900 * 1000")
- Validate numeric values for ports and intervals
- Validate LOG_LEVEL and NODE_ENV against allowed values
- Exit with code 1 and clear error messages if validation fails
- Integrated validation call at application startup in main.ts
This addresses the security concern of missing environment variable validation identified in the code review.
Includes tasks to validate environment and add files.
Adds a function to validate environment variables. This will catch any
issues early in the startup process.
This commit introduces new files that provide comprehensive guidelines
for contributing to the project. The updated documentation enhances
maintainability and clarity for all contributors.
- Replaced lande v1.0.10 with franc v6.2.0 for better maintenance and performance
- Simplified getLanguage function to use franc's simpler API
- Fixed redundant null check lint issue
- Removed invalid stylistic/comma-trailing package that was breaking npm install
- Updated implementation to handle franc's "und" (undetermined) response
๐ค Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add unit tests for getLanguage function with franc
- Test input validation, language detection for 10+ languages
- Add critical moderation tests for English vs French 'retard' disambiguation
- Verify franc can distinguish French 'delay' from English slur usage
- Include edge cases: emojis, special chars, mixed languages
- Add vitest configuration and test scripts
๐ค Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Revert language detection from franc back to lande
- Add label deduplication checks in moderation functions
- Improve type safety with explicit type assertions
- Simplify check iteration logic across handle/post/profile checks
- Remove unused monitor.ts and processJetstream.ts files
- Remove test files and vitest config
- Remove temporary PLAN.md and PRD.md files
- Add duration support for post labels
- Fix import ordering and formatting issues
- Add modTool metadata to moderation events
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
EOF
)
- Replace lande with franc for language detection
- Simplify API from probability map to single detection
- Handle "und" (undetermined) response by defaulting to "eng"
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
EOF
)
This adds a global allowlist to bypass moderation checks for specified
DIDs. This is to allow certain accounts to bypass checks for testing and
other use cases.
The allowlist is checked in checkHandles, checkPosts, checkProfiles, and
checkDisplayName functions.
- Renamed files and directories to the `rules` structure. - Added global
allowlist check.
This change updates the account age check to use a date window defined
by the anchor date and max age days. Instead of calculating the age, it
now checks if the account creation date falls within the specified
window. This simplifies the logic and makes it more readable.
Additionally, the test suite has been updated to reflect the new
behavior, and a more descriptive comment has been added.
This commit adds a check to the `checkAccountAge` function to prevent
duplicate labels from being applied to the same account. It uses the
`checkAccountLabels` function to determine if a label already exists
before attempting to create a new one. This prevents redundant labeling
and improves efficiency. Also includes unit tests for the
`checkAccountLabels` function to ensure correct behavior.
plc.directory and improve account age lookups
Use the correct PLC URL.
Improve account age lookup by fetching the audit log from the PLC and
using `createdAt` instead of `indexedAt` from the profile.
1. line 124: changed replyingDid โ actorDid (this was causing your
error) 2. line 126: added replyToPostURI to capture the full parent
URI 3. lines 133-158: added quote post monitoring - now detects when
someone quotes a monitored DID or post
the error should be gone now. the system will now: - monitor replies
to your configured government DIDs - monitor quote posts of those same
DIDs - monitor specific post URIs if you add them to monitoredPostURIs
- Removed an unused import statement in `src/tests/moderation.test.ts` -
Standardized formatting across several files to improve readability.
Fix: Remove unused imports and formatting
This commit removes an unused import and applies minor formatting
changes for improved code readability.
This commit adds eslint-config-prettier to the project.
Adds a type-checking script to package.json and updates tsconfig.json to
improve type checking and skip library checks.
feat: Add type checking and update tsconfig
Adds a type-check script to `package.json` and a pre-push hook to run
type checks before pushing. Updates the `tsconfig.json` to include
`vitest/globals` and `skipLibCheck`. Also, updates imports in test files
to include the `.js` extension.
This commit moves the account age related checks into the
`rules/account` folder, organizing the project structure.
feat: Add Prettier config and plugins
feat: Add ESLint config and plugins
fix: Fix missing import for Agent
feat: Implement metrics endpoint
refactor: Improve test organization
fix: Mock fetch in age.test.ts
fix: Add tests for countStarterPacks
refactor: Move account age checks to rules folder
feat: Add tests for facet spam detection
Use Bun to run the type check, tests, and coverage.
Provides examples of checks for spam and promotional content, including
regular expressions and actions to take when matches are found.
This commit upgrades project dependencies, including: - @types/node to
v22.18.0 - @vitest/coverage-v8 to v1.6.0 - Other dependencies for bug
fixes and improvements
Exclude test and example files from coverage
This commit introduces Redis caching to prevent redundant moderation
actions, reducing the load on the Bluesky API.
- Added the `redis` package as a dependency. - Implemented
`connectRedis` and `disconnectRedis` functions to manage the Redis
connection. - Added `tryClaimPostLabel`, `tryClaimAccountLabel`, and
`tryClaimAccountComment` functions to manage and claim resources for
caching purposes. - Modified `src/config.ts` to include the `REDIS_URL`
environment variable. - Added `src/redis.ts` which contains the Redis
client and connection management. - Integrated the caching logic into
moderation functions to ensure that actions are performed only once per
resource. - Added Redis healthcheck to compose.yaml. - Updated
package.json and bun.lock.
This commit introduces Redis caching to prevent redundant moderation
actions, reducing the load on the Bluesky API.
- Added the `redis` package as a dependency. - Implemented
`connectRedis` and `disconnectRedis` functions to manage the Redis
connection. - Added `tryClaimPostLabel`, `tryClaimAccountLabel`, and
`tryClaimAccountComment` functions to manage and claim resources for
caching purposes. - Modified `src/config.ts` to include the `REDIS_URL`
environment variable. - Added `src/redis.ts` which contains the Redis
client and connection management. - Integrated the caching logic into
moderation functions to ensure that actions are performed only once per
resource. - Added Redis healthcheck to compose.yaml. - Updated
package.json and bun.lock.
- Stores and restores session for persistent login - Implements dynamic
rate limiting from ATP headers - Adds Prometheus metrics for rate limit
state and waits - Refactors authentication flow for session persistence
- Added example configuration files for account age, account threshold,
global constants, handles, posts, and profiles. - Updated the CI build
to copy the example configuration files. - Removed the now redundant
rules/README.md. - Updated .gitignore to exclude all rules.
The example config files are no longer needed. The CI setup previously
copied the example files to the main config files. This is no longer
necessary, as the user will be expected to create the config files from
scratch.
Adds example configuration files for account age, account threshold,
global allowlist, handle checks, post checks, and profile checks. These
files contain example values and instructions for configuration.
This constant will hold a list of allowed link shorteners.
Move the `LINK_SHORTENER` constant from `rules/posts.ts` to
`rules/constants.ts` and remove the now duplicate declaration.
Update dependencies to address security vulnerabilities and improve
overall project health. This includes updates for eslint,
eslint-plugin-import, and others.
The authentication flow was updated to include retry logic. This ensures
that the application attempts to log in multiple times if the initial
attempts fail. This also addresses an issue where the app was exiting
before the Jetstream client was started.
- Add docs/common/starterPackThreshold.md for new module
- Update types.md with WindowUnit, StarterPackThresholdConfig
- Update redis.md with starter pack tracking functions and fixed signatures
- Update metrics.md with 3 new starter pack threshold metrics
- Update accountThreshold.md with corrected function signature (uri param)
- Update accountModeration.md with error handling clarification
- Update main.md with starter pack handler section
- Update developing_checks.md with starter pack threshold section
- Fix accountThreshold config examples (windowDays โ window + windowUnit)
- Update README.md with complete env vars and threshold system docs
- Improve rule file examples with comprehensive optional field coverage
- Add proper LINK_SHORTENER pattern to constants.ts
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Convert void-discarded promises to properly awaited calls with error
handling and aggregation. This prevents phantom state where Redis
succeeds but Ozone API fails.
Changes:
- Add ModerationResult type for structured error tracking
- Add moderationActionsFailedCounter metric for monitoring failures
- Modify moderation functions to rethrow errors after logging
- Update checkProfiles.ts ProfileChecker with async/await pattern
- Update checkPosts.ts to use for...of loop with proper awaiting
- Update countStarterPacks.ts with error handling
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change isLoggedIn from eager evaluation at module load time to lazy
initialization. Authentication now only starts when isLoggedIn is
first awaited, preventing race conditions during test setup or when
the module is imported before the application is ready.
The implementation uses a thenable object for backward compatibility,
allowing existing `await isLoggedIn` patterns to continue working.
๐ค Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>