@noctcore/eslint-plugin-async-safety 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # @noctcore/eslint-plugin-async-safety
2
+
3
+ Async-correctness rules TypeScript can't catch: unbounded `fetch`, dropped `AbortSignal`s, and
4
+ shared-state / concurrency races. Flat-config only, ESLint 9+.
5
+
6
+ ## Install
7
+
8
+ ```sh
9
+ bun add -D @noctcore/eslint-plugin-async-safety # or npm i -D / pnpm add -D
10
+ ```
11
+
12
+ ## Use
13
+
14
+ ```js
15
+ // eslint.config.js
16
+ import asyncSafety from '@noctcore/eslint-plugin-async-safety';
17
+
18
+ export default [
19
+ asyncSafety.configs.recommended,
20
+ ];
21
+ ```
22
+
23
+ Or wire rules individually:
24
+
25
+ ```js
26
+ import asyncSafety from '@noctcore/eslint-plugin-async-safety';
27
+
28
+ export default [
29
+ {
30
+ plugins: { 'noctcore-async-safety': asyncSafety },
31
+ rules: {
32
+ 'noctcore-async-safety/require-fetch-timeout': ['error', { callees: ['undici.request'] }],
33
+ // Off until you point it at server files:
34
+ 'noctcore-async-safety/no-shared-mutable-module-state': ['error', { include: ['**/server/**'] }],
35
+ },
36
+ },
37
+ ];
38
+ ```
39
+
40
+ ## Rules
41
+
42
+ | Rule | Description | 💡 |
43
+ | --- | --- | --- |
44
+ | [`require-fetch-timeout`](./docs/rules/require-fetch-timeout.md) | A `fetch` (or configured wrapper) call must carry a `signal`/`timeout` — an unbounded request can hang forever. | 💡 |
45
+ | [`forward-abort-signal`](./docs/rules/forward-abort-signal.md) | A function that accepts an `AbortSignal` but awaits a call without forwarding it leaves that work uncancellable. | |
46
+ | [`no-shared-mutable-module-state`](./docs/rules/no-shared-mutable-module-state.md) | A module-scoped mutable binding written from an exported async/handler function is shared across concurrent requests (opt in via `include`). | |
47
+ | [`prefer-parallel-awaits`](./docs/rules/prefer-parallel-awaits.md) | Consecutive independent awaits can run concurrently with `Promise.all`. | 💡 |
48
+ | [`no-concurrent-shared-mutation`](./docs/rules/no-concurrent-shared-mutation.md) | A read-modify-write of an outer binding inside a concurrent `Promise.all(map(async …))` callback can lose updates. | |
49
+
50
+ ## `recommended` preset
51
+
52
+ | Rule | Severity | Notes |
53
+ | --- | --- | --- |
54
+ | `require-fetch-timeout` | `error` | Precise and syntactic. |
55
+ | `no-shared-mutable-module-state` | `error` | Inert until you set `include` globs, so it ships enabled but off by default. |
56
+ | `forward-abort-signal` | `warn` | Heuristic — advisory. |
57
+ | `prefer-parallel-awaits` | `warn` | Heuristic — advisory suggestion. |
58
+ | `no-concurrent-shared-mutation` | `warn` | Heuristic — advisory. |
59
+
60
+ The 💡 rules provide editor suggestions (not autofixes) — parallelizing awaits and adding a timeout both change
61
+ runtime behavior, so they are never applied automatically.