Skip to content

Commit a251db3

Browse files
feat(*): Migrate from CommonJS to ESM (#19)
* feat(*): Migrate from CommonJS to ESM * test(*): Add NextJS example * feat(*): Add captchaAction setting Make nextjs example works * feat(logger): Remove pino-pretty and color * feat(build): Install tsup before build * test(e2e): Handle new log format without pino-pretty * style(*): Pass through code format tools * docs(*): Update doc for Nextjs * docs(*): Add note on specific nextjs constraint for implementation * refactor(examples): update nextjs examples to better align with last documentation * test(*): Mount a volume for crowdsec docker as it is required since 1.7.0 --------- Co-authored-by: Roussange Alexandre <[email protected]>
1 parent 9746329 commit a251db3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+10779
-3681
lines changed

.eslintrc.js

Lines changed: 0 additions & 60 deletions
This file was deleted.

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,9 @@ dist
129129
.yarn/build-state.yml
130130
.yarn/install-state.gz
131131
.pnp.*
132+
133+
# Claude
134+
.claude
135+
136+
# History
137+
.history

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@ The [public API](https://semver.org/spec/v2.0.0.html#spec-item-1) of this librar
1111
properties and constants belonging to the `src` folder.
1212

1313

14+
---
15+
16+
## [0.2.0](https://github.com/crowdsecurity/nodejs-cs-bouncer/releases/tag/v0.2.0) - 2025-??-??
17+
18+
[_Compare with previous release_](https://github.com/crowdsecurity/nodejs-cs-bouncer/compare/v0.1.0...v0.2.0)
19+
20+
### Changed
21+
22+
- **Breaking Change**: Migrate from CommonJS to ESM
23+
24+
### Added
25+
26+
- Add optional `captchaAction` configuration to set the action attribute of the captcha form
27+
1428
---
1529

1630
## [0.1.0](https://github.com/crowdsecurity/nodejs-cs-bouncer/releases/tag/v0.1.0) - 2025-03-28

docs/DEVELOPER.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ npm install -g doctoc
9090
Then, run it in the relevant folders:
9191

9292
```bash
93-
doctoc docs/* --maxlevel 4 && doctoc examples/express-server/README.md --maxlevel 4
93+
doctoc docs/* --maxlevel 4 && doctoc examples/express-server/README.md --maxlevel 4 && doctoc examples/nextjs/README.md --maxlevel 4
9494
```
9595

9696
## Release process

docs/USER_GUIDE.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,20 @@
1313
- [Features](#features)
1414
- [Usage](#usage)
1515
- [Configurations](#configurations)
16-
- [Bouncer behavior](#bouncer-behavior)
17-
- [Local API Connection](#local-api-connection)
18-
- [Cache](#cache)
19-
- [Captcha and Ban walls settings](#captcha-and-ban-walls-settings)
16+
- [Bouncer behavior](#bouncer-behavior)
17+
- [Local API Connection](#local-api-connection)
18+
- [Cache](#cache)
19+
- [Captcha and Ban walls settings](#captcha-and-ban-walls-settings)
2020
- [Implement your own bouncer](#implement-your-own-bouncer)
21-
- [Instantiation](#instantiation)
22-
- [Apply a remediation](#apply-a-remediation)
23-
- [Refresh decision cache](#refresh-decision-cache)
24-
- [Push usage metrics](#push-usage-metrics)
25-
- [Custom Captcha](#custom-captcha)
26-
- [Custom Cache Adapter](#custom-cache-adapter)
21+
- [Instantiation](#instantiation)
22+
- [Apply a remediation](#apply-a-remediation)
23+
- [Refresh decision cache](#refresh-decision-cache)
24+
- [Push usage metrics](#push-usage-metrics)
25+
- [Custom Captcha](#custom-captcha)
26+
- [Custom Cache Adapter](#custom-cache-adapter)
2727
- [Examples](#examples)
28-
- [Basics](#basics)
29-
- [Express server](#express-server)
28+
- [Basics](#basics)
29+
- [Express server](#express-server)
3030

3131
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
3232

@@ -161,6 +161,7 @@ Below is the list of available settings (see also `CrowdSecBouncerConfigurations
161161
},
162162
"captcha": {
163163
"captchaImageTag": "Generated with svg-captcha-fixed",
164+
"captchaAction": "Optional action of the captcha form (e.g. '/crowdsec-captcha'). Empty by default.",
164165
"texts": {
165166
"tabTitle": "CrowdSec | Captcha Wall",
166167
"title": "Access Denied",

eslint.config.mjs

Lines changed: 97 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,92 @@ import { FlatCompat } from '@eslint/eslintrc';
33
import js from '@eslint/js';
44
import typescriptEslint from '@typescript-eslint/eslint-plugin';
55
import tsParser from '@typescript-eslint/parser';
6-
import _import from 'eslint-plugin-import';
7-
import noRelativeImportPaths from 'eslint-plugin-no-relative-import-paths';
6+
import eslintImport from 'eslint-plugin-import';
87
import preferArrowFunctions from 'eslint-plugin-prefer-arrow-functions';
8+
import jestPlugin from 'eslint-plugin-jest';
99
import globals from 'globals';
10-
1110
import path from 'node:path';
12-
import process from 'node:process';
1311
import { fileURLToPath } from 'node:url';
1412

1513
const __filename = fileURLToPath(import.meta.url);
1614
const __dirname = path.dirname(__filename);
15+
16+
const jestGlobals = jestPlugin.envs?.['jest/globals']?.globals ?? jestPlugin.environments?.['jest/globals']?.globals ?? {};
17+
1718
const compat = new FlatCompat({
1819
baseDirectory: __dirname,
1920
recommendedConfig: js.configs.recommended,
2021
allConfig: js.configs.all,
2122
});
2223

24+
const shared = {
25+
plugins: {
26+
'@typescript-eslint': fixupPluginRules(typescriptEslint),
27+
'prefer-arrow-functions': preferArrowFunctions,
28+
import: fixupPluginRules(eslintImport),
29+
},
30+
31+
languageOptions: {
32+
parser: tsParser,
33+
ecmaVersion: 'latest',
34+
sourceType: 'module',
35+
globals: { ...globals.node },
36+
parserOptions: {
37+
project: path.join(__dirname, 'tsconfig.json'),
38+
tsconfigRootDir: __dirname,
39+
},
40+
},
41+
42+
settings: {
43+
'import/resolver': {
44+
node: { extensions: ['.js', '.mjs', '.ts'] },
45+
typescript: {
46+
project: [path.join(__dirname, 'tsconfig.json'), path.join(__dirname, 'tsconfig.spec.json')],
47+
alwaysTryTypes: true,
48+
},
49+
},
50+
'import/parsers': {
51+
'@typescript-eslint/parser': ['.ts', '.tsx'],
52+
},
53+
},
54+
55+
rules: {
56+
'import/no-unresolved': 'error',
57+
'import/extensions': ['error', 'ignorePackages', { ts: 'never', tsx: 'never', js: 'never', mjs: 'never' }],
58+
'import/order': [
59+
'error',
60+
{
61+
groups: ['external', ['builtin', 'index', 'sibling', 'parent', 'internal'], 'object', 'type'],
62+
alphabetize: { order: 'asc', caseInsensitive: true },
63+
'newlines-between': 'always',
64+
},
65+
],
66+
'prefer-arrow-functions/prefer-arrow-functions': [
67+
'error',
68+
{
69+
allowNamedFunctions: false,
70+
classPropertiesAllowed: false,
71+
disallowPrototype: false,
72+
returnStyle: 'unchanged',
73+
singleReturnOnly: false,
74+
},
75+
],
76+
'prefer-template': 'error',
77+
'no-nested-ternary': 'error',
78+
'no-implicit-coercion': ['error', { boolean: true }],
79+
'@typescript-eslint/naming-convention': [
80+
'error',
81+
{ selector: 'typeLike', format: ['PascalCase'] },
82+
{ selector: 'enum', format: ['UPPER_CASE'] },
83+
],
84+
},
85+
};
86+
2387
export default [
2488
{
25-
ignores: process.env.CI ? ['**/*.ejs', '**/dist/', '**/examples'] : ['**/*.ejs', '**/dist/'],
89+
ignores: ['**/*.ejs', '**/dist/**', '**/examples/**', 'eslint.config.mjs', 'jest.config.mjs'],
2690
},
91+
2792
...fixupConfigRules(
2893
compat.extends(
2994
'eslint:recommended',
@@ -32,97 +97,45 @@ export default [
3297
'plugin:import/typescript',
3398
),
3499
),
100+
35101
{
36-
plugins: {
37-
'@typescript-eslint': fixupPluginRules(typescriptEslint),
38-
'prefer-arrow-functions': preferArrowFunctions,
39-
import: fixupPluginRules(_import),
40-
'no-relative-import-paths': noRelativeImportPaths,
41-
},
102+
files: ['**/*.ts', '**/*.tsx'],
103+
...shared,
104+
},
42105

106+
{
107+
files: ['tests/**/*.{ts,tsx}', '**/*.test.{ts,tsx}', '**/*.spec.{ts,tsx}'],
108+
plugins: { ...shared.plugins, jest: jestPlugin },
43109
languageOptions: {
44-
globals: {
45-
...globals.browser,
46-
},
47-
48-
parser: tsParser,
49-
ecmaVersion: 'latest',
50-
sourceType: 'module',
110+
...shared.languageOptions,
111+
globals: { ...shared.languageOptions.globals, ...jestGlobals },
51112
},
52-
53-
settings: {
54-
'import/resolver': {
55-
typescript: {
56-
alwaysTryTypes: true,
57-
project: './tsconfig.json',
58-
},
59-
},
60-
61-
'import/parsers': {
62-
'@typescript-eslint/parser': ['.ts', '.tsx'],
63-
},
64-
},
65-
113+
settings: shared.settings,
66114
rules: {
67-
'import/no-unresolved': 'error',
68-
69-
'import/order': [
70-
'error',
71-
{
72-
groups: ['external', ['builtin', 'index', 'sibling', 'parent', 'internal'], 'object', 'type'],
73-
'newlines-between': 'always',
74-
alphabetize: {
75-
order: 'asc',
76-
caseInsensitive: true,
77-
},
78-
},
79-
],
80-
81-
'no-relative-import-paths/no-relative-import-paths': [
82-
'error',
83-
{
84-
allowSameFolder: false,
85-
},
86-
],
87-
88-
'prefer-arrow-functions/prefer-arrow-functions': [
89-
'error',
90-
{
91-
allowNamedFunctions: false,
92-
classPropertiesAllowed: false,
93-
disallowPrototype: false,
94-
returnStyle: 'unchanged',
95-
singleReturnOnly: false,
96-
},
97-
],
98-
99-
'prefer-template': 'error',
100-
'no-nested-ternary': 'error',
101-
'no-implicit-coercion': ['error', { boolean: true }],
102-
103-
'@typescript-eslint/naming-convention': [
104-
'error',
105-
{
106-
selector: 'typeLike',
107-
format: ['PascalCase'],
108-
},
109-
{
110-
selector: 'enum',
111-
format: ['UPPER_CASE'],
112-
},
113-
],
115+
...shared.rules,
116+
'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
114117
},
115118
},
119+
116120
{
117-
files: ['**/.eslintrc.js'],
121+
files: ['*.config.{ts,js,mjs,cjs}'],
122+
languageOptions: {
123+
...shared.languageOptions,
124+
parserOptions: { project: null },
125+
},
126+
rules: { 'import/no-unresolved': 'off' },
127+
},
118128

129+
{
130+
files: ['jest-ejs-transform.cjs'],
119131
languageOptions: {
132+
sourceType: 'script',
120133
globals: {
121-
...globals.node,
134+
module: 'readonly',
135+
exports: 'readonly',
136+
require: 'readonly',
122137
},
123-
124-
ecmaVersion: 5,
125-
sourceType: 'commonjs',
126138
},
139+
rules: { 'no-undef': 'off' },
127140
},
128141
];

examples/basics/fetch-decisions-stream.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import CrowdSecBouncer from 'src/lib/bouncer';
2-
import { CrowdSecBouncerConfigurations } from 'src/lib/bouncer/types';
1+
import { CrowdSecBouncer, CrowdSecBouncerConfigurations } from '../../src';
32

43
/**
54
* Example usage of fetching decisions stream.

examples/basics/get-ip-remediation.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import CrowdSecBouncer from 'src/lib/bouncer';
2-
import { CrowdSecBouncerConfigurations } from 'src/lib/bouncer/types';
3-
import { BOUNCER_KEYS } from 'src/lib/constants';
1+
import { CrowdSecBouncer, CrowdSecBouncerConfigurations } from '../../src';
2+
import { BOUNCER_KEYS } from '../../src/lib/constants';
43

54
/**
65
* Example of basic usage of the CrowdSec Bouncer.

examples/express-server/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const { origin, remediation } = remediationData;
3535

3636
- Depending on the value of the remediation, we apply it:
3737

38-
- let the process continue with `next()`if there is no remediation (bypass)
38+
- let the process continue with `next()` if there is no remediation (bypass)
3939

4040
- block the user with a ban or captcha wall remediation:
4141

0 commit comments

Comments
 (0)