- 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.
- 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)
- 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)
- 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)
- 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)
docs: update CLAUDE.md to reflect completed async error handling fixes
- 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)
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.
feat: add comprehensive environment variable validation at startup
- 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.
feat: Add workflow guidelines and project documentation
This commit introduces new files that provide comprehensive guidelines for contributing to the project. The updated documentation enhances maintainability and clarity for all contributors.
feat(language-detection): replace lande with franc for improved language detection
- 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)
test: add comprehensive tests for franc language detection
- 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)
- 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 )
$(cat <<'EOF' feat(language-detection): restore franc implementation
- 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.
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.
feat: Add check to avoid duplicate account age labels
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.
src/types.ts:68 - added optional expires?: string field to AccountAgeCheck interface 2. src/rules/account/age.ts:117-128 - added logic to skip expired checks by comparing current date against expires date 3. src/rules/account/ageConstants.ts:24 - updated example to show how to use the new field 4. added 3 tests to verify: - expired checks are skipped - non-expired checks still work - checks without expires field work (backward compatible)
src/types.ts:63-64 - added optional monitoredPostURIs field, made monitoredDIDs optional (at least one must be provided) 2. src/rules/account/age.ts:13 - added optional replyToPostURI to ReplyContext interface 3. src/rules/account/age.ts:113-123 - updated logic to check both monitoredDIDs and monitoredPostURIs (matches if either condition is true) 4. src/rules/account/ageConstants.ts:27-38 - added example showing how to monitor specific post URIs 5. added 4 tests covering: - monitoring post URIs - ignoring non-matching post URIs - matching either DIDs OR post URIs - backward compatibility (works without replyToPostURI)
src/rules/account/age.ts:8-22 - renamed ReplyContext โ InteractionContext, added quotedDid and quotedPostURI fields for quote posts, actorDid as the common actor field 2. src/rules/account/age.ts:123-149 - updated matching logic to check both replies (replyToDid/replyToPostURI) AND quotes (quotedDid/quotedPostURI) 3. src/rules/account/ageConstants.ts:3-12 - updated documentation to reflect reply/quote monitoring 4. added 4 new tests covering: - labeling when quoting monitored DID - labeling when quoting monitored post URI - not labeling when quoting different DID - matching either reply OR quote to monitored target
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.
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 upgrades project dependencies, including: - @types/node to v22.18.0 - @vitest/coverage-v8 to v1.6.0 - Other dependencies for bug fixes and improvements
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.
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.
fix: eliminate fire-and-forget async patterns in moderation actions
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>
fix(auth): convert isLoggedIn to lazy initialization
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>