Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ jobs:
cache: 'npm'
- run: npm ci
- run: npm run build
- run: npm run lint
- run: npm test
- run: npm run check:edge
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Fastify** is unchanged. It already deferred to `request.ip`, which was the safe answer; it gains the `trustProxy` option for parity.
- `getIP` still overrides everything, and existing `getIP` implementations are untouched.

### Internal

- **Lint runs for the first time.** Every package declared `eslint` and `@typescript-eslint` as devDependencies and ran `eslint src/**/*.ts`, but no config file had ever existed in the tree, so `npm run lint` exited 2 in all five and had done since the repo was created. There is now one flat config at the root (ESLint 9, `typescript-eslint` 8), the duplicated per-package toolchain is gone, and CI runs lint so it cannot rot again. `no-explicit-any` is a warning under a per-package budget that CI does not let grow.

Two client-side changes fell out of it and are worth knowing about:
- `_measureJSExecution()` now accumulates its arithmetic loop into a recorded `mathSink` value, matching what the array loop already did with `arrayLen`. The loop previously discarded its result and could legally be optimised away entirely — which would drive `mathOps` toward zero and trip the "JS execution unusually fast" automation signal on an ordinary browser. It also reports `stringLen` for the same reason. Both are additive keys on an open record.
- The `HTMLFormElement.prototype.submit` interception uses rest parameters and a closure instead of `arguments` and a `this` alias. Behaviour is unchanged — `submit()` takes no arguments.

## [0.11.1] - 2026-08-20

### Added
Expand Down
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ Run linter:
npm run lint
```

One flat config at the repo root (`eslint.config.mjs`) covers every package — don't add a per-package one. The ruleset is deliberately narrow, because type checking is TypeScript's job and formatting is Prettier's; what's left is the class of thing neither catches.

`@typescript-eslint/no-explicit-any` is a **warning** under a per-package budget, set in each package's lint script (`eslint src --max-warnings N`). CI fails if the count grows, so a new `any` needs either a real type or a deliberate decision to raise the number. Lower it when you remove one.

Format code:

```bash
Expand Down
91 changes: 91 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// @ts-check
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import globals from 'globals';

/**
* One flat config for the whole workspace.
*
* Every package declared eslint and @typescript-eslint as devDependencies and
* ran `eslint src/**\/*.ts`, and there was no config file anywhere in the tree —
* so `npm run lint` exited 2 in all five, and had since the repo was created.
* Nothing was gating on it, so it went unnoticed.
*
* Rather than five copies of the same config, the toolchain lives at the root
* and each package's script points here. The ruleset is deliberately narrow:
* type checking is TypeScript's job and formatting is Prettier's, so what is
* left is the class of thing neither catches — an unhandled promise, a name
* that is defined and never used, a `case` that falls through.
*/
export default tseslint.config(
{
ignores: [
'**/dist/**',
'**/node_modules/**',
'**/coverage/**',
'**/.turbo/**',
// Generated from the Go agent registry (`pkg/cmd/export-agent-registry`).
// Lint findings here are not actionable: the fix belongs in the
// generator, and the file is overwritten on every regeneration.
'**/*.generated.ts',
],
},

js.configs.recommended,
...tseslint.configs.recommended,

{
files: ['**/*.ts'],
languageOptions: {
parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
globals: { ...globals.node, ...globals.browser },
},
rules: {
// An unused argument is usually a signature the runtime dictates —
// middleware `next`, a handler's `res`. Underscore marks it deliberate.
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrors: 'all',
caughtErrorsIgnorePattern: '^_',
},
],

// `any` is load-bearing in a few places where we accept whatever a
// framework hands us. It is still worth seeing, so: a warning, and CI
// does not allow the count to grow (see the --max-warnings budget in the
// lint script).
'@typescript-eslint/no-explicit-any': 'warn',

// `declare global { namespace Express { … } }` is the only way to augment
// a framework's types. The rule's real target is a namespace used as a
// module, which `allowDeclarations` still forbids.
'@typescript-eslint/no-namespace': ['error', { allowDeclarations: true }],

'no-console': 'off', // the SDK logs through console by design (`debug: true`)
eqeqeq: ['error', 'always', { null: 'ignore' }],
'no-fallthrough': 'error',
},
},

{
files: ['**/*.test.ts', '**/*.spec.ts'],
languageOptions: {
globals: { ...globals.jest },
},
rules: {
// Tests reach into internals and hand-build malformed input on purpose.
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
},
},

{
files: ['**/*.mjs', '**/*.js'],
languageOptions: {
globals: { ...globals.node },
},
},
);
Loading
Loading