# @fedify/lint

> Fedify linting rules and plugins

Latest version **2.4.4** (published 2026-10-12) · MIT license · 3.3K weekly downloads

## Install

```sh
npm install @fedify/lint
pnpm add @fedify/lint
yarn add @fedify/lint
bun add @fedify/lint
```

## Health

**Score 85/100 (A)** — status: active.

Positive: has types; esm support; no vulnerabilities; has provenance; recently updated; high maintenance score; high quality score.

## Facts

| | |
|---|---|
| Version | 2.4.4 |
| Published | 2026-10-12 |
| First published | 2025-12-31 |
| Weekly downloads | 3.3K |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 3 |
| Unpacked size | 237.2 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 1026 |
| Author | Chanhaeng Lee |
| Maintainers | hongminhee, z9mb1, 2chanhaeng |
| Keywords | Fedify, ActivityPub, Fediverse, Lint, ESLint, ESLint Plugin, oxlint, oxc |

## Links

- npm: https://www.npmjs.com/package/@fedify/lint
- Repository: https://github.com/fedify-dev/fedify
- Homepage: https://fedify.dev/
- Issues: https://github.com/fedify-dev/fedify/issues
- Funding: https://opencollective.com/fedify
- npm.io page: https://npm.io/package/@fedify/lint

## Dependencies (3)

- [@fxts/core](https://npm.io/package/@fxts/core.md) ^1.21.1
- [@typescript-eslint/utils](https://npm.io/package/@typescript-eslint/utils.md) ^8.0.0
- [@typescript-eslint/parser](https://npm.io/package/@typescript-eslint/parser.md) ^8.49.0

## Alternatives

- [eslint-plugin-sonarjs](https://npm.io/package/eslint-plugin-sonarjs.md) — 2.9M weekly downloads
- [eslint-config-expo](https://npm.io/package/eslint-config-expo.md) — 1.5M weekly downloads
- [@matter/protocol](https://npm.io/package/@matter/protocol.md) — 63.5K weekly downloads
- [@eventcatalog/linter](https://npm.io/package/@eventcatalog/linter.md) — 24.8K weekly downloads
- [@pandacss/eslint-plugin](https://npm.io/package/@pandacss/eslint-plugin.md) — 18.7K weekly downloads

## Recent versions

- 2.4.4 (latest) — 2026-10-12
- 2.0.35-dev.2480 (dev) — 2026-10-22
- 2.4.0-pr.1006.44 (pr-1006) — 2026-09-18
- 2.4.0-pr.1020.43 (pr-1020) — 2026-09-02
- 2.4.0-pr.936.41 (pr-936) — 2026-07-12
- 2.4.0-pr.934.40 (pr-934) — 2026-07-11
- 2.3.0-pr.809.39 (pr-809) — 2026-06-18
- 2.2.0-pr.732.35 (pr-732) — 2026-04-27
- 2.2.0-pr.731.34 (pr-731) — 2026-04-27
- 2.2.0-pr.731.0.33 (pr-731.0) — 2026-04-27
- 2.2.0-pr.715.28 (pr-715) — 2026-04-23
- 2.2.0-pr.710.26 (pr-710) — 2026-04-23
- 2.2.0-pr.695.23 (pr-695) — 2026-04-22
- 2.2.0-pr.709.20 (pr-709) — 2026-04-22
- 2.2.0-pr.708.19 (pr-708) — 2026-04-21
- … 497 more at https://npm.io/package/@fedify/lint/versions

## README

<!-- deno-fmt-ignore-file -->

@fedify/lint: Lint plugins for Fedify
=====================================

[![JSR][JSR badge]][JSR]
[![npm][npm badge]][npm]
[![@fedify@hackers.pub][@fedify@hackers.pub badge]][@fedify@hackers.pub]

*This package is available since Fedify 2.0.0.*

This package provides [Deno Lint], [ESLint], and [Oxlint] plugins with lint
rules specifically designed for [Fedify] applications.  It helps you catch
common mistakes and enforce best practices when building federated server apps
with Fedify.

The plugin includes rules that check for:

 -  Proper actor ID configuration
 -  Required actor properties (inbox, outbox, followers, etc.)
 -  Correct URL patterns for actor collections
 -  Public key and assertion method requirements
 -  Collection filtering implementation

[JSR badge]: https://jsr.io/badges/@fedify/lint
[JSR]: https://jsr.io/@fedify/lint
[npm badge]: https://img.shields.io/npm/v/@fedify/lint?logo=npm
[npm]: https://www.npmjs.com/package/@fedify/lint
[@fedify@hackers.pub badge]: https://fedi-badge.minhee.org/@fedify@hackers.pub/followers.svg
[@fedify@hackers.pub]: https://hackers.pub/@fedify
[Deno Lint]: https://docs.deno.com/runtime/reference/lint_plugins/
[ESLint]: https://eslint.org/
[Oxlint]: https://oxc.rs/docs/guide/usage/linter/
[Fedify]: https://fedify.dev/

### Deno Lint configuration example

~~~~ typescript
// deno.json

{
  "lint": {
    "plugins": {
      "@fedify/lint": "jsr:@fedify/lint"
    },
    "rules": {
      "@fedify/lint/actor-id-required": "error",
      "@fedify/lint/actor-id-mismatch": "error",
      "@fedify/lint/actor-inbox-property-required": "warn"
      // ... other rules
    }
  }
}
~~~~

### ESLint configuration example

~~~~ typescript
// eslint.config.ts

import fedifyLint from "@fedify/lint";

export default fedifyLint;
~~~~

### Oxlint configuration example

~~~~ jsonc
// .oxlintrc.json

{
  "jsPlugins": ["@fedify/lint/oxlint"],
  "rules": {
    "@fedify/lint/actor-id-required": "error",
    "@fedify/lint/actor-id-mismatch": "error",
    "@fedify/lint/actor-inbox-property-required": "warn"
  }
}
~~~~


Features
--------

The `@fedify/lint` package provides comprehensive linting rules for Fedify
federation code:

### Actor validation rules

 -  **`actor-id-required`**: Ensures all actors have an `id` property
 -  **`actor-id-mismatch`**: Validates that actor IDs match the expected URI
    from `Context.getActorUri()`
 -  **`actor-public-key-required`**: Ensures actors have public keys for
    HTTP Signatures
 -  **`actor-assertion-method-required`**: Validates assertion methods for
    Object Integrity Proofs

### Collection property rules

 -  **`actor-inbox-property-required`**: Ensures inbox is defined when
    `setInboxListeners` is set
 -  **`actor-inbox-property-mismatch`**: Validates inbox URI from `getInboxUri`
 -  **`actor-outbox-property-required`**: Ensures outbox is defined when
    `setOutboxDispatcher` is set
 -  **`actor-outbox-property-mismatch`**: Validates outbox URI from
    `getOutboxUri`
 -  **`actor-followers-property-required`**: Ensures followers is defined when
    `setFollowersDispatcher` is set
 -  **`actor-followers-property-mismatch`**: Validates followers URI from
    `getFollowersUri`
 -  **`actor-following-property-required`**: Ensures following is defined when
    `setFollowingDispatcher` is set
 -  **`actor-following-property-mismatch`**: Validates following URI from
    `getFollowingUri`
 -  **`actor-liked-property-required`**: Ensures liked is defined when
    `setLikedDispatcher` is set
 -  **`actor-liked-property-mismatch`**: Validates liked URI from `getLikedUri`
 -  **`actor-featured-property-required`**: Ensures featured is defined when
    `setFeaturedDispatcher` is set
 -  **`actor-featured-property-mismatch`**: Validates featured URI from
    `getFeaturedUri`
 -  **`actor-featured-tags-property-required`**: Ensures featuredTags is defined
    when `setFeaturedTagsDispatcher` is set
 -  **`actor-featured-tags-property-mismatch`**: Validates featuredTags URI from
    `getFeaturedTagsUri`
 -  **`actor-shared-inbox-property-required`**: Ensures sharedInbox is defined
    when `setInboxListeners` is set
 -  **`actor-shared-inbox-property-mismatch`**: Validates sharedInbox URI from
    `getInboxUri`
 -  **`actor-upload-media-property-required`**: Ensures endpoints.uploadMedia is
    defined when `setMediaUploader` is set
 -  **`actor-upload-media-property-mismatch`**: Validates endpoints.uploadMedia
    URI from `getMediaUploaderUri`

The mismatch rules for actor `id`, `inbox`, `outbox`, `followers`, `following`,
`liked`, `featured`, and `featuredTags` also accept the corresponding
`getPortable*Uri()` method.  They accept an inline
`toCompatibleEf61Id(ctx.getPortable*Uri(identifier, did), gateway)` call for
gateway-compatible IDs.

### Other rules

 -  **`collection-filtering-not-implemented`**: Warns about missing collection
    filtering implementation (`setFollowersDispatcher` only for now)
 -  **`media-uploader-object-uri-required`**: Warns when a `setMediaUploader`
    callback does not derive its return value from `getObjectUri`
 -  **`media-uploader-authorization-required`**: Warns when `setMediaUploader`
    is registered without an `authorize` hook
 -  **`outbox-listener-delivery-not-awaited`**: Warns when an outbox listener
    calls `sendActivity` or `forwardActivity` and does not wait for the result
    (ESLint and Oxlint only)


Installation
------------

::: code-group

~~~~ sh [Deno]
deno add jsr:@fedify/lint
~~~~

~~~~ sh [npm]
npm add -D @fedify/lint
~~~~

~~~~ sh [pnpm]
pnpm add -D @fedify/lint
~~~~

~~~~ sh [Yarn]
yarn add -D @fedify/lint
~~~~

~~~~ sh [Bun]
bun add -D @fedify/lint
~~~~

:::


Usage (Deno Lint)
-----------------

### Basic setup

Add the plugin to your *deno.json* configuration file:

~~~~ json
{
  "lint": {
    "plugins": ["jsr:@fedify/lint"]
  }
}
~~~~

By default, this enables all recommended rules.

### Custom configuration

You can customize which rules to enable and their severity levels:

~~~~ json
{
  "lint": {
    "plugins": ["jsr:@fedify/lint"],
    "rules": {
      "tags": ["recommended"],
      "include": [
        "@fedify/lint/actor-id-required",
        "@fedify/lint/actor-id-mismatch"
      ],
      "exclude": [
        "@fedify/lint/actor-featured-property-required"
      ]
    }
  }
}
~~~~

### Running Deno Lint

After setting up the configuration, run Deno's linter:

~~~~ sh
deno lint
~~~~

You can also specify which files to lint:

~~~~ sh
deno lint federation.ts
deno lint src/federation/
~~~~


Usage (ESLint)
--------------

### Basic setup

Add the plugin to your ESLint configuration file (e.g., *eslint.config.ts*
or *eslint.config.js*):

~~~~ typescript
import fedifyLint from "@fedify/lint";

// If your `createFederation` code is in `federation.ts` or `federation/**.ts`
export default fedifyLint; 

// Or specify your own federation files
export default {
  ...fedifyLint,
  files: ["my-own-federation.ts"],
};

// If you use other ESLint configurations

export default [
  otherConfig,
  fedifyLint,
];
~~~~

The default configuration applies recommended rules to files that match
common federation-related patterns (e.g., *federation.ts*, _federation/\*.ts_).

### Custom configuration

You can customize which files to lint and which rules to enable:

~~~~ typescript
import { plugin } from "@fedify/lint";

export default [{
  files: ["src/federation/**/*.ts"],  // Your federation code location
  plugins: {
    "@fedify/lint": plugin,
  },
  rules: {
    "@fedify/lint/actor-id-required": "error",
    "@fedify/lint/actor-id-mismatch": "error",
    "@fedify/lint/actor-inbox-property-required": "warn",
    // ... other rules
  },
}];
~~~~

### Using configurations

The plugin provides two preset configurations:

#### Recommended (default)

Enables critical rules as errors and optional rules as warnings:

~~~~ typescript
import fedifyLint from "@fedify/lint";

export default fedifyLint;
~~~~

#### Strict

Enables all rules as errors:

~~~~ typescript
import { plugin } from "@fedify/lint";

export default [{
  files: ["**/*.ts"],
  ...plugin.configs.strict,
}];
~~~~


Example
-------

Here's an example of code that would trigger lint errors:

~~~~ typescript
// ❌ Wrong: Using relative URL for actor ID
import { createFederation, Person } from "@fedify/fedify";

const federation = createFederation({ /* ... */ });

federation.setActorDispatcher(
  "/{identifier}",
  (_ctx, identifier) => {
    return new Person({
      id: new URL(`/${identifier}`),  // ❌ Should use ctx.getActorUri()
      name: "Example User",
    });
  },
);
~~~~

Corrected version:

~~~~ typescript
// ✅ Correct: Using Context.getActorUri() for actor ID
import { createFederation, Person } from "@fedify/fedify";

const federation = createFederation({ /* ... */ });

federation.setActorDispatcher(
  "/{identifier}",
  (ctx, identifier) => {
    return new Person({
      id: ctx.getActorUri(identifier),  // ✅ Correct
      name: "Example User",
      inbox: ctx.getInboxUri(identifier),
      outbox: ctx.getOutboxUri(identifier),
      followers: ctx.getFollowersUri(identifier),
      // ... other required properties
    });
  },
);
~~~~


Running the linter
------------------

### Deno Lint

Run Deno's linter with the plugin enabled:

~~~~ sh
deno lint
~~~~

You can also specify which files or directories to lint:

~~~~ sh
deno lint federation.ts
deno lint src/federation/
~~~~

### ESLint

Set up your ESLint configuration as shown above and add a follwing script on
`package.json`:

~~~~ jsonc
{
  "scripts": {
    "lint": "eslint ."
  }
}
~~~~

After setting up the configuration, run ESLint on your codebase:

::: code-group

~~~~ sh [npm]
npm run lint
~~~~

~~~~ sh [pnpm]
pnpm lint
~~~~

~~~~ sh [Yarn]
yarn lint
~~~~

~~~~ sh [Bun]
bun lint
~~~~

:::

or run the linter directly via command line:

::: code-group

~~~~ sh [npm]
npx eslint .
~~~~

~~~~ sh [pnpm]
pnpx eslint .
~~~~

~~~~ sh [Yarn]
yarn eslint .
~~~~

~~~~ sh [Bun]
bunx eslint .
~~~~

:::


Usage (Oxlint)
--------------

[Oxlint] is a fast Rust-based linter that supports ESLint-compatible JS plugins.
The `@fedify/lint/oxlint` subpath export plugs the Fedify rules into Oxlint's
[JS plugin API].

> [!NOTE]
> Oxlint's JS plugin API is currently in alpha and not subject to semver.

[JS plugin API]: https://oxc.rs/docs/guide/usage/linter/writing-js-plugins.html

### Basic setup

Add the plugin and the rules you want to enable to your *.oxlintrc.json*:

~~~~ json
{
  "$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json",
  "jsPlugins": ["@fedify/lint/oxlint"],
  "rules": {
    "@fedify/lint/actor-id-required": "error",
    "@fedify/lint/actor-id-mismatch": "error"
  }
}
~~~~

Rule IDs are namespaced under `@fedify/lint/`, matching the ESLint
configuration above.

### Custom configuration

Enable any subset of the rules listed in the *Features* section above. Each
rule can be set to `"error"`, `"warn"`, or `"off"`:

~~~~ json
{
  "jsPlugins": ["@fedify/lint/oxlint"],
  "rules": {
    "@fedify/lint/actor-id-required": "error",
    "@fedify/lint/actor-id-mismatch": "error",
    "@fedify/lint/actor-inbox-property-required": "warn",
    "@fedify/lint/actor-outbox-property-required": "warn",
    "@fedify/lint/actor-followers-property-required": "warn",
    "@fedify/lint/actor-public-key-required": "warn",
    "@fedify/lint/actor-assertion-method-required": "warn",
    "@fedify/lint/collection-filtering-not-implemented": "warn"
  }
}
~~~~

### Running Oxlint

Add a script to *package.json*:

~~~~ jsonc
{
  "scripts": {
    "lint": "oxlint ."
  }
}
~~~~

Then run:

::: code-group

~~~~ sh [npm]
npm run lint
~~~~

~~~~ sh [pnpm]
pnpm lint
~~~~

~~~~ sh [Yarn]
yarn lint
~~~~

~~~~ sh [Bun]
bun lint
~~~~

:::

Or invoke Oxlint directly:

::: code-group

~~~~ sh [npm]
npx oxlint .
~~~~

~~~~ sh [pnpm]
pnpx oxlint .
~~~~

~~~~ sh [Yarn]
yarn oxlint .
~~~~

~~~~ sh [Bun]
bunx oxlint .
~~~~

:::


See also
--------

 -  [Fedify Documentation]
 -  [ESLint Documentation]
 -  [Example Project]

[Fedify Documentation]: https://fedify.dev/
[ESLint Documentation]: https://eslint.org/
[Example Project]: https://github.com/fedify-dev/fedify/tree/main/examples/lint

---
_Source: https://npm.io/package/@fedify/lint · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
