Radish alpha
r
rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5
Radicle web interface
Radicle
Git
Update eslint config to flat config
Merged did:key:z6MkkfM3...sVz5 opened 1 year ago

Since the legacy config is being deprecated at some point, we should start moving to the eslint flat config.

I avoided the tseslint config helper function so we avoid wrapping magic.

The configs are being merged from top to bottom.

  1. Are the recommended configs from eslint, svelte, prettier, etc.
  2. Then come the svelte configs that apply only to svelte files
  3. Followed by everything typescript
  4. And lastly there are the rules that apply to all files, followed by the ignored folders for all checking.

This seems to have triggered more checking since any checks in svelte files have appeared and the $$Generic type that is being deprecated had to be rewritten.

check check-visual check-unit-test check-httpd-api-unit-test check-e2e check-build

πŸ‘‰ Preview πŸ‘‰ Workflow runs πŸ‘‰ Branch on GitHub

22 files changed +370 -276 ffd49e82 β†’ 0c7ea70c
deleted .eslintignore
@@ -1,3 +0,0 @@
-
node_modules
-
build
-
public
deleted .eslintrc.cjs
@@ -1,121 +0,0 @@
-
module.exports = {
-
  env: {
-
    es6: true,
-
    browser: true,
-
    node: true,
-
  },
-
  extends: [
-
    "eslint:recommended",
-
    "plugin:@typescript-eslint/recommended",
-
    "plugin:svelte/recommended",
-
    "prettier",
-
  ],
-
  parser: "@typescript-eslint/parser",
-
  parserOptions: {
-
    ecmaVersion: 2020,
-
    sourceType: "module",
-
    project: ["./tsconfig.json"],
-
    tsconfigRootDir: __dirname,
-
    extraFileExtensions: [".svelte"],
-
  },
-
  overrides: [
-
    {
-
      files: ["*.svelte"],
-
      parser: "svelte-eslint-parser",
-
      parserOptions: {
-
        parser: "@typescript-eslint/parser",
-
      },
-
    },
-
  ],
-
  settings: {
-
    svelte: {
-
      ignoreWarnings: ["svelte/no-at-html-tags"],
-
    },
-
  },
-
  // Workaround until $$Generic is supported:
-
  // https://github.com/sveltejs/svelte-eslint-parser/issues/306#issuecomment-1480844814
-
  globals: {
-
    $$Generic: "readonly",
-
  },
-
  plugins: ["@typescript-eslint", "no-only-tests"],
-
  rules: {
-
    "no-only-tests/no-only-tests": "warn",
-
    "no-implicit-globals": ["error"],
-
    "no-restricted-globals": [
-
      "error",
-
      "name",
-
      "event",
-
      "frames",
-
      "history",
-
      "length",
-
      "content",
-
      "origin",
-
      "status",
-
    ],
-
    "@typescript-eslint/no-floating-promises": "warn",
-
    "@typescript-eslint/naming-convention": [
-
      "warn",
-
      {
-
        selector: "enumMember",
-
        format: ["PascalCase"],
-
      },
-
      {
-
        selector: "objectLiteralProperty",
-
        format: ["PascalCase", "camelCase"],
-
      },
-
      {
-
        selector: "default",
-
        format: ["camelCase"],
-
        leadingUnderscore: "allow",
-
        trailingUnderscore: "allow",
-
      },
-
      {
-
        selector: "variable",
-
        modifiers: ["const"],
-
        format: ["camelCase", "PascalCase", "UPPER_CASE"],
-
        leadingUnderscore: "allow",
-
        trailingUnderscore: "allow",
-
      },
-
      {
-
        selector: "typeLike",
-
        format: ["PascalCase"],
-
      },
-
      // Disable @typescript-eslint/naming-convention format for imports
-
      // https://github.com/typescript-eslint/typescript-eslint/pull/7269#issuecomment-1777628591
-
      // https://github.com/typescript-eslint/typescript-eslint/issues/7892
-
      { selector: "import", format: null },
-
      {
-
        selector: ["objectLiteralProperty"],
-
        modifiers: ["requiresQuotes"],
-
        format: null,
-
      },
-
    ],
-
    "@typescript-eslint/no-explicit-any": "off",
-
    "@typescript-eslint/no-namespace": ["error", { allowDeclarations: true }],
-
    "@typescript-eslint/member-ordering": [
-
      "warn",
-
      { default: ["field", "signature", "constructor", "method"] },
-
    ],
-

-
    "@typescript-eslint/no-invalid-void-type": ["warn"],
-
    // Disallow Unused Variables.
-
    // https://eslint.org/docs/rules/no-unused-vars
-
    "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
-
    // Require using arrow functions as callbacks.
-
    // https://eslint.org/docs/rules/prefer-arrow-callback
-
    "prefer-arrow-callback": "warn",
-
    // Require using const for variables that are never modified after declared.
-
    // https://eslint.org/docs/rules/prefer-const
-
    "prefer-const": "warn",
-
    // Disallow modifying variables that are declared using const.
-
    // https://eslint.org/docs/rules/no-const-assign
-
    "no-const-assign": "error",
-
    // Require let or const instead of var.
-
    // https://eslint.org/docs/rules/no-var
-
    "no-var": "warn",
-
    // Require `===` and `!==` comparisons.
-
    eqeqeq: "warn",
-
    // Allow explict type annotations for additional clarity.
-
    "@typescript-eslint/no-inferrable-types": "off",
-
  },
-
};
added eslint.config.js
@@ -0,0 +1,138 @@
+
import globals from "globals";
+
import js from "@eslint/js";
+
import prettier from "eslint-config-prettier";
+
import svelte from "eslint-plugin-svelte";
+
import svelteParser from "svelte-eslint-parser";
+
import ts from "typescript-eslint";
+

+
export default [
+
  ...[
+
    js.configs.recommended,
+
    ...ts.configs.recommended,
+
    prettier,
+
    {
+
      languageOptions: {
+
        parser: ts.parser,
+
        parserOptions: {
+
          project: "./tsconfig.json",
+
          tsconfigRootDir: import.meta.dirname,
+
          extraFileExtensions: [".svelte"],
+
        },
+
        globals: { ...globals.browser, ...globals.node },
+
      },
+
      rules: {
+
        "no-implicit-globals": "error",
+
        "no-restricted-globals": [
+
          "error",
+
          "name",
+
          "event",
+
          "frames",
+
          "history",
+
          "length",
+
          "content",
+
          "origin",
+
          "status",
+
        ],
+
        // Require using arrow functions as callbacks.
+
        // https://eslint.org/docs/rules/prefer-arrow-callback
+
        "prefer-arrow-callback": "warn",
+
        // Require using const for variables that are never modified after declared.
+
        // https://eslint.org/docs/rules/prefer-const
+
        "prefer-const": "warn",
+
        // Disallow modifying variables that are declared using const.
+
        // https://eslint.org/docs/rules/no-const-assign
+
        "no-const-assign": "error",
+
        // Require let or const instead of var.
+
        // https://eslint.org/docs/rules/no-var
+
        "no-var": "warn",
+
        // Require `===` and `!==` comparisons.
+
        eqeqeq: "warn",
+
        "@typescript-eslint/no-floating-promises": "warn",
+
        "@typescript-eslint/no-empty-function": "warn",
+
        "@typescript-eslint/naming-convention": [
+
          "warn",
+
          {
+
            selector: "enumMember",
+
            format: ["PascalCase"],
+
          },
+
          {
+
            selector: "objectLiteralProperty",
+
            format: ["PascalCase", "camelCase"],
+
          },
+
          {
+
            selector: "default",
+
            format: ["camelCase"],
+
            leadingUnderscore: "allow",
+
            trailingUnderscore: "allow",
+
          },
+
          {
+
            selector: "variable",
+
            modifiers: ["const"],
+
            format: ["camelCase", "PascalCase", "UPPER_CASE"],
+
            leadingUnderscore: "allow",
+
            trailingUnderscore: "allow",
+
          },
+
          {
+
            selector: "typeLike",
+
            format: ["PascalCase"],
+
          },
+
          // Disable @typescript-eslint/naming-convention format for imports
+
          // https://github.com/typescript-eslint/typescript-eslint/pull/7269#issuecomment-1777628591
+
          // https://github.com/typescript-eslint/typescript-eslint/issues/7892
+
          { selector: "import", format: null },
+
          {
+
            selector: ["objectLiteralProperty"],
+
            modifiers: ["requiresQuotes"],
+
            format: null,
+
          },
+
        ],
+
        "@typescript-eslint/no-namespace": [
+
          "error",
+
          { allowDeclarations: true },
+
        ],
+
        "@typescript-eslint/member-ordering": [
+
          "warn",
+
          { default: ["field", "signature", "constructor", "method"] },
+
        ],
+
        // Allow explict type annotations for additional clarity.
+
        "@typescript-eslint/no-inferrable-types": "off",
+
        "@typescript-eslint/no-invalid-void-type": ["warn"],
+
        // Disallow Unused Variables.
+
        // https://eslint.org/docs/rules/no-unused-vars
+
        "@typescript-eslint/no-unused-vars": [
+
          "warn",
+
          { argsIgnorePattern: "^_" },
+
        ],
+
      },
+
    },
+
  ].map(conf => ({
+
    ...conf,
+
    linterOptions: {
+
      reportUnusedDisableDirectives: "error",
+
    },
+
    files: ["**/*.js", "**/*.ts", "**/*.svelte"],
+
  })),
+
  ...svelte.configs["flat/recommended"],
+
  ...svelte.configs["flat/prettier"],
+
  {
+
    files: ["*.svelte", "**/*.svelte"],
+
    languageOptions: {
+
      parser: svelteParser,
+
      parserOptions: {
+
        parser: ts.parser,
+
        project: "./tsconfig.json",
+
        tsconfigRootDir: import.meta.dirname,
+
        svelteFeatures: {
+
          experimentalGenerics: true,
+
        },
+
      },
+
    },
+
    rules: {
+
      "svelte/no-at-html-tags": "off",
+
      "@typescript-eslint/no-explicit-any": "error",
+
    },
+
  },
+
  {
+
    ignores: ["node_modules/**/*", "build/**/*", "public/**/*"],
+
  },
+
];
modified httpd-client/lib/fetcher.ts
@@ -20,10 +20,11 @@ export class ResponseError extends Error {
  public body: unknown;

  public constructor(method: string, response: Response, body_: unknown) {
-
    const body: any = body_;
+
    const body: unknown = body_;
    if (
      typeof body === "object" &&
      body !== null &&
+
      "message" in body &&
      typeof body.message === "string"
    ) {
      super(body.message);
modified httpd-client/tests/support/support.ts
@@ -38,7 +38,7 @@ export async function createPatchToBeModified(
}
export async function assertIssue(
  oid: string,
-
  change: Record<string, any>,
+
  change: Record<string, unknown>,
  api: HttpdClient,
) {
  expect(
@@ -49,7 +49,7 @@ export async function assertIssue(

export async function assertPatch(
  oid: string,
-
  change: Record<string, any>,
+
  change: Record<string, unknown>,
  api: HttpdClient,
) {
  expect(
modified package-lock.json
@@ -31,6 +31,7 @@
        "zod": "^3.22.4"
      },
      "devDependencies": {
+
        "@eslint/js": "^9.3.0",
        "@playwright/test": "^1.42.1",
        "@sveltejs/vite-plugin-svelte": "^3.0.2",
        "@tsconfig/svelte": "^5.0.3",
@@ -42,21 +43,23 @@
        "@types/node": "^20.11.30",
        "@types/sinon": "^17.0.3",
        "@types/wait-on": "^5.3.4",
-
        "@typescript-eslint/eslint-plugin": "^7.4.0",
+
        "@typescript-eslint/parser": "^7.10.0",
        "chalk": "^5.3.0",
        "config": "^3.3.11",
        "eslint": "^8.57.0",
        "eslint-config-prettier": "^9.1.0",
-
        "eslint-plugin-no-only-tests": "^3.1.0",
-
        "eslint-plugin-svelte": "^2.35.1",
+
        "eslint-plugin-svelte": "^2.39.0",
        "execa": "^9.0.0",
        "get-port": "^7.1.0",
+
        "globals": "^15.3.0",
        "happy-dom": "^14.3.8",
        "prettier": "^3.2.5",
        "prettier-plugin-svelte": "^3.2.2",
        "sinon": "^17.0.1",
        "svelte-check": "^3.6.8",
+
        "svelte-eslint-parser": "^0.36.0",
        "typescript": "^5.4.3",
+
        "typescript-eslint": "^7.10.0",
        "vite": "^5.2.6",
        "vite-plugin-virtual": "^0.3.0",
        "vitest": "^1.4.0",
@@ -529,6 +532,21 @@
        "concat-map": "0.0.1"
      }
    },
+
    "node_modules/@eslint/eslintrc/node_modules/globals": {
+
      "version": "13.24.0",
+
      "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+
      "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+
      "dev": true,
+
      "dependencies": {
+
        "type-fest": "^0.20.2"
+
      },
+
      "engines": {
+
        "node": ">=8"
+
      },
+
      "funding": {
+
        "url": "https://github.com/sponsors/sindresorhus"
+
      }
+
    },
    "node_modules/@eslint/eslintrc/node_modules/minimatch": {
      "version": "3.1.2",
      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -542,12 +560,12 @@
      }
    },
    "node_modules/@eslint/js": {
-
      "version": "8.57.0",
-
      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
-
      "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
+
      "version": "9.3.0",
+
      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.3.0.tgz",
+
      "integrity": "sha512-niBqk8iwv96+yuTwjM6bWg8ovzAPF9qkICsGtcoa5/dmqcEMfdwNAX7+/OHcJHc7wj7XqPxH98oAHytFYlw6Sw==",
      "dev": true,
      "engines": {
-
        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+
        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
      }
    },
    "node_modules/@hapi/hoek": {
@@ -1070,12 +1088,6 @@
        "@types/unist": "*"
      }
    },
-
    "node_modules/@types/json-schema": {
-
      "version": "7.0.15",
-
      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
-
      "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
-
      "dev": true
-
    },
    "node_modules/@types/katex": {
      "version": "0.16.7",
      "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.7.tgz",
@@ -1121,12 +1133,6 @@
      "integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==",
      "dev": true
    },
-
    "node_modules/@types/semver": {
-
      "version": "7.5.8",
-
      "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
-
      "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
-
      "dev": true
-
    },
    "node_modules/@types/sinon": {
      "version": "17.0.3",
      "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.3.tgz",
@@ -1163,22 +1169,20 @@
      }
    },
    "node_modules/@typescript-eslint/eslint-plugin": {
-
      "version": "7.4.0",
-
      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz",
-
      "integrity": "sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==",
+
      "version": "7.10.0",
+
      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.10.0.tgz",
+
      "integrity": "sha512-PzCr+a/KAef5ZawX7nbyNwBDtM1HdLIT53aSA2DDlxmxMngZ43O8SIePOeX8H5S+FHXeI6t97mTt/dDdzY4Fyw==",
      "dev": true,
      "dependencies": {
-
        "@eslint-community/regexpp": "^4.5.1",
-
        "@typescript-eslint/scope-manager": "7.4.0",
-
        "@typescript-eslint/type-utils": "7.4.0",
-
        "@typescript-eslint/utils": "7.4.0",
-
        "@typescript-eslint/visitor-keys": "7.4.0",
-
        "debug": "^4.3.4",
+
        "@eslint-community/regexpp": "^4.10.0",
+
        "@typescript-eslint/scope-manager": "7.10.0",
+
        "@typescript-eslint/type-utils": "7.10.0",
+
        "@typescript-eslint/utils": "7.10.0",
+
        "@typescript-eslint/visitor-keys": "7.10.0",
        "graphemer": "^1.4.0",
-
        "ignore": "^5.2.4",
+
        "ignore": "^5.3.1",
        "natural-compare": "^1.4.0",
-
        "semver": "^7.5.4",
-
        "ts-api-utils": "^1.0.1"
+
        "ts-api-utils": "^1.3.0"
      },
      "engines": {
        "node": "^18.18.0 || >=20.0.0"
@@ -1198,16 +1202,15 @@
      }
    },
    "node_modules/@typescript-eslint/parser": {
-
      "version": "7.4.0",
-
      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.4.0.tgz",
-
      "integrity": "sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==",
+
      "version": "7.10.0",
+
      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.10.0.tgz",
+
      "integrity": "sha512-2EjZMA0LUW5V5tGQiaa2Gys+nKdfrn2xiTIBLR4fxmPmVSvgPcKNW+AE/ln9k0A4zDUti0J/GZXMDupQoI+e1w==",
      "dev": true,
-
      "peer": true,
      "dependencies": {
-
        "@typescript-eslint/scope-manager": "7.4.0",
-
        "@typescript-eslint/types": "7.4.0",
-
        "@typescript-eslint/typescript-estree": "7.4.0",
-
        "@typescript-eslint/visitor-keys": "7.4.0",
+
        "@typescript-eslint/scope-manager": "7.10.0",
+
        "@typescript-eslint/types": "7.10.0",
+
        "@typescript-eslint/typescript-estree": "7.10.0",
+
        "@typescript-eslint/visitor-keys": "7.10.0",
        "debug": "^4.3.4"
      },
      "engines": {
@@ -1227,13 +1230,13 @@
      }
    },
    "node_modules/@typescript-eslint/scope-manager": {
-
      "version": "7.4.0",
-
      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.4.0.tgz",
-
      "integrity": "sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==",
+
      "version": "7.10.0",
+
      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.10.0.tgz",
+
      "integrity": "sha512-7L01/K8W/VGl7noe2mgH0K7BE29Sq6KAbVmxurj8GGaPDZXPr8EEQ2seOeAS+mEV9DnzxBQB6ax6qQQ5C6P4xg==",
      "dev": true,
      "dependencies": {
-
        "@typescript-eslint/types": "7.4.0",
-
        "@typescript-eslint/visitor-keys": "7.4.0"
+
        "@typescript-eslint/types": "7.10.0",
+
        "@typescript-eslint/visitor-keys": "7.10.0"
      },
      "engines": {
        "node": "^18.18.0 || >=20.0.0"
@@ -1244,15 +1247,15 @@
      }
    },
    "node_modules/@typescript-eslint/type-utils": {
-
      "version": "7.4.0",
-
      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.4.0.tgz",
-
      "integrity": "sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==",
+
      "version": "7.10.0",
+
      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.10.0.tgz",
+
      "integrity": "sha512-D7tS4WDkJWrVkuzgm90qYw9RdgBcrWmbbRkrLA4d7Pg3w0ttVGDsvYGV19SH8gPR5L7OtcN5J1hTtyenO9xE9g==",
      "dev": true,
      "dependencies": {
-
        "@typescript-eslint/typescript-estree": "7.4.0",
-
        "@typescript-eslint/utils": "7.4.0",
+
        "@typescript-eslint/typescript-estree": "7.10.0",
+
        "@typescript-eslint/utils": "7.10.0",
        "debug": "^4.3.4",
-
        "ts-api-utils": "^1.0.1"
+
        "ts-api-utils": "^1.3.0"
      },
      "engines": {
        "node": "^18.18.0 || >=20.0.0"
@@ -1271,9 +1274,9 @@
      }
    },
    "node_modules/@typescript-eslint/types": {
-
      "version": "7.4.0",
-
      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.4.0.tgz",
-
      "integrity": "sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==",
+
      "version": "7.10.0",
+
      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.10.0.tgz",
+
      "integrity": "sha512-7fNj+Ya35aNyhuqrA1E/VayQX9Elwr8NKZ4WueClR3KwJ7Xx9jcCdOrLW04h51de/+gNbyFMs+IDxh5xIwfbNg==",
      "dev": true,
      "engines": {
        "node": "^18.18.0 || >=20.0.0"
@@ -1284,19 +1287,19 @@
      }
    },
    "node_modules/@typescript-eslint/typescript-estree": {
-
      "version": "7.4.0",
-
      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.4.0.tgz",
-
      "integrity": "sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==",
+
      "version": "7.10.0",
+
      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.10.0.tgz",
+
      "integrity": "sha512-LXFnQJjL9XIcxeVfqmNj60YhatpRLt6UhdlFwAkjNc6jSUlK8zQOl1oktAP8PlWFzPQC1jny/8Bai3/HPuvN5g==",
      "dev": true,
      "dependencies": {
-
        "@typescript-eslint/types": "7.4.0",
-
        "@typescript-eslint/visitor-keys": "7.4.0",
+
        "@typescript-eslint/types": "7.10.0",
+
        "@typescript-eslint/visitor-keys": "7.10.0",
        "debug": "^4.3.4",
        "globby": "^11.1.0",
        "is-glob": "^4.0.3",
-
        "minimatch": "9.0.3",
-
        "semver": "^7.5.4",
-
        "ts-api-utils": "^1.0.1"
+
        "minimatch": "^9.0.4",
+
        "semver": "^7.6.0",
+
        "ts-api-utils": "^1.3.0"
      },
      "engines": {
        "node": "^18.18.0 || >=20.0.0"
@@ -1312,18 +1315,15 @@
      }
    },
    "node_modules/@typescript-eslint/utils": {
-
      "version": "7.4.0",
-
      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.4.0.tgz",
-
      "integrity": "sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==",
+
      "version": "7.10.0",
+
      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.10.0.tgz",
+
      "integrity": "sha512-olzif1Fuo8R8m/qKkzJqT7qwy16CzPRWBvERS0uvyc+DHd8AKbO4Jb7kpAvVzMmZm8TrHnI7hvjN4I05zow+tg==",
      "dev": true,
      "dependencies": {
        "@eslint-community/eslint-utils": "^4.4.0",
-
        "@types/json-schema": "^7.0.12",
-
        "@types/semver": "^7.5.0",
-
        "@typescript-eslint/scope-manager": "7.4.0",
-
        "@typescript-eslint/types": "7.4.0",
-
        "@typescript-eslint/typescript-estree": "7.4.0",
-
        "semver": "^7.5.4"
+
        "@typescript-eslint/scope-manager": "7.10.0",
+
        "@typescript-eslint/types": "7.10.0",
+
        "@typescript-eslint/typescript-estree": "7.10.0"
      },
      "engines": {
        "node": "^18.18.0 || >=20.0.0"
@@ -1337,13 +1337,13 @@
      }
    },
    "node_modules/@typescript-eslint/visitor-keys": {
-
      "version": "7.4.0",
-
      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.4.0.tgz",
-
      "integrity": "sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==",
+
      "version": "7.10.0",
+
      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.10.0.tgz",
+
      "integrity": "sha512-9ntIVgsi6gg6FIq9xjEO4VQJvwOqA3jaBFQJ/6TK5AvEup2+cECI6Fh7QiBxmfMHXU0V0J4RyPeOU1VDNzl9cg==",
      "dev": true,
      "dependencies": {
-
        "@typescript-eslint/types": "7.4.0",
-
        "eslint-visitor-keys": "^3.4.1"
+
        "@typescript-eslint/types": "7.10.0",
+
        "eslint-visitor-keys": "^3.4.3"
      },
      "engines": {
        "node": "^18.18.0 || >=20.0.0"
@@ -2232,10 +2232,13 @@
      }
    },
    "node_modules/eslint-compat-utils": {
-
      "version": "0.1.2",
-
      "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.1.2.tgz",
-
      "integrity": "sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==",
+
      "version": "0.5.0",
+
      "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.0.tgz",
+
      "integrity": "sha512-dc6Y8tzEcSYZMHa+CMPLi/hyo1FzNeonbhJL7Ol0ccuKQkwopJcJBA9YL/xmMTLU1eKigXo9vj9nALElWYSowg==",
      "dev": true,
+
      "dependencies": {
+
        "semver": "^7.5.4"
+
      },
      "engines": {
        "node": ">=12"
      },
@@ -2255,33 +2258,24 @@
        "eslint": ">=7.0.0"
      }
    },
-
    "node_modules/eslint-plugin-no-only-tests": {
-
      "version": "3.1.0",
-
      "resolved": "https://registry.npmjs.org/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-3.1.0.tgz",
-
      "integrity": "sha512-Lf4YW/bL6Un1R6A76pRZyE1dl1vr31G/ev8UzIc/geCgFWyrKil8hVjYqWVKGB/UIGmb6Slzs9T0wNezdSVegw==",
-
      "dev": true,
-
      "engines": {
-
        "node": ">=5.0.0"
-
      }
-
    },
    "node_modules/eslint-plugin-svelte": {
-
      "version": "2.35.1",
-
      "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.35.1.tgz",
-
      "integrity": "sha512-IF8TpLnROSGy98Z3NrsKXWDSCbNY2ReHDcrYTuXZMbfX7VmESISR78TWgO9zdg4Dht1X8coub5jKwHzP0ExRug==",
+
      "version": "2.39.0",
+
      "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.39.0.tgz",
+
      "integrity": "sha512-FXktBLXsrxbA+6ZvJK2z/sQOrUKyzSg3fNWK5h0reSCjr2fjAsc9ai/s/JvSl4Hgvz3nYVtTIMwarZH5RcB7BA==",
      "dev": true,
      "dependencies": {
-
        "@eslint-community/eslint-utils": "^4.2.0",
-
        "@jridgewell/sourcemap-codec": "^1.4.14",
-
        "debug": "^4.3.1",
-
        "eslint-compat-utils": "^0.1.2",
+
        "@eslint-community/eslint-utils": "^4.4.0",
+
        "@jridgewell/sourcemap-codec": "^1.4.15",
+
        "debug": "^4.3.4",
+
        "eslint-compat-utils": "^0.5.0",
        "esutils": "^2.0.3",
-
        "known-css-properties": "^0.29.0",
-
        "postcss": "^8.4.5",
+
        "known-css-properties": "^0.31.0",
+
        "postcss": "^8.4.38",
        "postcss-load-config": "^3.1.4",
        "postcss-safe-parser": "^6.0.0",
-
        "postcss-selector-parser": "^6.0.11",
-
        "semver": "^7.5.3",
-
        "svelte-eslint-parser": ">=0.33.0 <1.0.0"
+
        "postcss-selector-parser": "^6.0.16",
+
        "semver": "^7.6.0",
+
        "svelte-eslint-parser": ">=0.36.0 <1.0.0"
      },
      "engines": {
        "node": "^14.17.0 || >=16.0.0"
@@ -2290,8 +2284,8 @@
        "url": "https://github.com/sponsors/ota-meshi"
      },
      "peerDependencies": {
-
        "eslint": "^7.0.0 || ^8.0.0-0",
-
        "svelte": "^3.37.0 || ^4.0.0"
+
        "eslint": "^7.0.0 || ^8.0.0-0 || ^9.0.0-0",
+
        "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0-next.112"
      },
      "peerDependenciesMeta": {
        "svelte": {
@@ -2327,6 +2321,15 @@
        "url": "https://opencollective.com/eslint"
      }
    },
+
    "node_modules/eslint/node_modules/@eslint/js": {
+
      "version": "8.57.0",
+
      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
+
      "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
+
      "dev": true,
+
      "engines": {
+
        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+
      }
+
    },
    "node_modules/eslint/node_modules/ansi-styles": {
      "version": "4.3.0",
      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -2368,6 +2371,21 @@
        "url": "https://github.com/chalk/chalk?sponsor=1"
      }
    },
+
    "node_modules/eslint/node_modules/globals": {
+
      "version": "13.24.0",
+
      "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+
      "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+
      "dev": true,
+
      "dependencies": {
+
        "type-fest": "^0.20.2"
+
      },
+
      "engines": {
+
        "node": ">=8"
+
      },
+
      "funding": {
+
        "url": "https://github.com/sponsors/sindresorhus"
+
      }
+
    },
    "node_modules/eslint/node_modules/minimatch": {
      "version": "3.1.2",
      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -2781,15 +2799,12 @@
      }
    },
    "node_modules/globals": {
-
      "version": "13.24.0",
-
      "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
-
      "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+
      "version": "15.3.0",
+
      "resolved": "https://registry.npmjs.org/globals/-/globals-15.3.0.tgz",
+
      "integrity": "sha512-cCdyVjIUVTtX8ZsPkq1oCsOsLmGIswqnjZYMJJTGaNApj1yHtLSymKhwH51ttirREn75z3p4k051clwg7rvNKA==",
      "dev": true,
-
      "dependencies": {
-
        "type-fest": "^0.20.2"
-
      },
      "engines": {
-
        "node": ">=8"
+
        "node": ">=18"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
@@ -3323,9 +3338,9 @@
      }
    },
    "node_modules/known-css-properties": {
-
      "version": "0.29.0",
-
      "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.29.0.tgz",
-
      "integrity": "sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==",
+
      "version": "0.31.0",
+
      "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.31.0.tgz",
+
      "integrity": "sha512-sBPIUGTNF0czz0mwGGUoKKJC8Q7On1GPbCSFPfyEsfHb2DyBG0Y4QtV+EVWpINSaiGKZblDNuF5AezxSgOhesQ==",
      "dev": true
    },
    "node_modules/levn": {
@@ -3656,9 +3671,9 @@
      }
    },
    "node_modules/minimatch": {
-
      "version": "9.0.3",
-
      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
-
      "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+
      "version": "9.0.4",
+
      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
+
      "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
      "dev": true,
      "dependencies": {
        "brace-expansion": "^2.0.1"
@@ -4691,16 +4706,16 @@
      }
    },
    "node_modules/svelte-eslint-parser": {
-
      "version": "0.33.1",
-
      "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.33.1.tgz",
-
      "integrity": "sha512-vo7xPGTlKBGdLH8T5L64FipvTrqv3OQRx9d2z5X05KKZDlF4rQk8KViZO4flKERY+5BiVdOh7zZ7JGJWo5P0uA==",
+
      "version": "0.36.0",
+
      "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.36.0.tgz",
+
      "integrity": "sha512-/6YmUSr0FAVxW8dXNdIMydBnddPMHzaHirAZ7RrT21XYdgGGZMh0LQG6CZsvAFS4r2Y4ItUuCQc8TQ3urB30mQ==",
      "dev": true,
      "dependencies": {
-
        "eslint-scope": "^7.0.0",
-
        "eslint-visitor-keys": "^3.0.0",
-
        "espree": "^9.0.0",
-
        "postcss": "^8.4.29",
-
        "postcss-scss": "^4.0.8"
+
        "eslint-scope": "^7.2.2",
+
        "eslint-visitor-keys": "^3.4.3",
+
        "espree": "^9.6.1",
+
        "postcss": "^8.4.38",
+
        "postcss-scss": "^4.0.9"
      },
      "engines": {
        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -4709,7 +4724,7 @@
        "url": "https://github.com/sponsors/ota-meshi"
      },
      "peerDependencies": {
-
        "svelte": "^3.37.0 || ^4.0.0"
+
        "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0-next.115"
      },
      "peerDependenciesMeta": {
        "svelte": {
@@ -4922,6 +4937,32 @@
        "node": ">=14.17"
      }
    },
+
    "node_modules/typescript-eslint": {
+
      "version": "7.10.0",
+
      "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.10.0.tgz",
+
      "integrity": "sha512-thO8nyqptXdfWHQrMJJiJyftpW8aLmwRNs11xA8pSrXneoclFPstQZqXvDWuH1WNL4CHffqHvYUeCHTit6yfhQ==",
+
      "dev": true,
+
      "dependencies": {
+
        "@typescript-eslint/eslint-plugin": "7.10.0",
+
        "@typescript-eslint/parser": "7.10.0",
+
        "@typescript-eslint/utils": "7.10.0"
+
      },
+
      "engines": {
+
        "node": "^18.18.0 || >=20.0.0"
+
      },
+
      "funding": {
+
        "type": "opencollective",
+
        "url": "https://opencollective.com/typescript-eslint"
+
      },
+
      "peerDependencies": {
+
        "eslint": "^8.56.0"
+
      },
+
      "peerDependenciesMeta": {
+
        "typescript": {
+
          "optional": true
+
        }
+
      }
+
    },
    "node_modules/uc.micro": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
modified package.json
@@ -18,6 +18,7 @@
    "node": ">=18.17.1"
  },
  "devDependencies": {
+
    "@eslint/js": "^9.3.0",
    "@playwright/test": "^1.42.1",
    "@sveltejs/vite-plugin-svelte": "^3.0.2",
    "@tsconfig/svelte": "^5.0.3",
@@ -29,21 +30,23 @@
    "@types/node": "^20.11.30",
    "@types/sinon": "^17.0.3",
    "@types/wait-on": "^5.3.4",
-
    "@typescript-eslint/eslint-plugin": "^7.4.0",
+
    "@typescript-eslint/parser": "^7.10.0",
    "chalk": "^5.3.0",
    "config": "^3.3.11",
    "eslint": "^8.57.0",
    "eslint-config-prettier": "^9.1.0",
-
    "eslint-plugin-no-only-tests": "^3.1.0",
-
    "eslint-plugin-svelte": "^2.35.1",
+
    "eslint-plugin-svelte": "^2.39.0",
    "execa": "^9.0.0",
    "get-port": "^7.1.0",
+
    "globals": "^15.3.0",
    "happy-dom": "^14.3.8",
    "prettier": "^3.2.5",
    "prettier-plugin-svelte": "^3.2.2",
    "sinon": "^17.0.1",
    "svelte-check": "^3.6.8",
+
    "svelte-eslint-parser": "^0.36.0",
    "typescript": "^5.4.3",
+
    "typescript-eslint": "^7.10.0",
    "vite": "^5.2.6",
    "vite-plugin-virtual": "^0.3.0",
    "vitest": "^1.4.0",
modified src/components/DropdownList.svelte
@@ -1,6 +1,4 @@
-
<script lang="ts">
-
  type T = $$Generic;
-

+
<script lang="ts" generics="T">
  export let items: T[];
  export let styleDropdownMinWidth: string | undefined = undefined;
</script>
modified src/components/HoverPopover.svelte
@@ -1,6 +1,7 @@
<script lang="ts">
  import debounce from "lodash/debounce";

+
  // eslint-disable-next-line @typescript-eslint/no-empty-function
  export let onShow: () => void = () => {};
  export let stylePopoverPositionLeft: string | undefined = undefined;
  export let stylePopoverPositionRight: string | undefined = undefined;
modified src/components/List.svelte
@@ -1,6 +1,4 @@
-
<script lang="ts">
-
  type T = $$Generic;
-

+
<script lang="ts" generics="T">
  export let items: T[];
</script>

modified src/components/Markdown.svelte
@@ -32,6 +32,7 @@
  export let breaks: boolean = false;

  let container: HTMLElement;
+
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  let frontMatter: [string, any][] | undefined = undefined;

  $: {
modified src/lib/utils.ts
@@ -286,10 +286,12 @@ export function twemoji(
  { exclude }: { exclude: string[] } = { exclude: [] },
) {
  twemojiModule.parse(node, {
-
    callback: (icon, options: Record<string, any>) => {
-
      return exclude.includes(icon)
-
        ? false
-
        : "".concat(options.base, options.size, "/", icon, options.ext);
+
    callback: (icon, options) => {
+
      const { base, size, ext } = options as Record<string, string>;
+
      if (!exclude.includes(icon)) {
+
        return `${base}${size}/${icon}${ext}`;
+
      }
+
      return false;
    },
    base: "/",
    folder: "twemoji",
modified src/views/nodes/router.ts
@@ -1,10 +1,12 @@
import type { BaseUrl, NodeStats, Policy, Scope } from "@httpd-client";
import type { ErrorRoute, NotFoundRoute } from "@app/lib/router/definitions";

-
import { HttpdClient } from "@httpd-client";
import config from "virtual:config";
+
import { HttpdClient } from "@httpd-client";
+
import { ResponseError, ResponseParseError } from "@httpd-client/lib/fetcher";
import { baseUrlToString } from "@app/lib/utils";
import { handleError } from "@app/views/nodes/error";
+
import { unreachableError } from "@app/views/projects/error";

export interface NodesRouteParams {
  baseUrl: BaseUrl;
@@ -58,7 +60,15 @@ export async function loadNodeRoute(
        scope: node.config?.scope,
      },
    };
-
  } catch (error: any) {
-
    return handleError(error, baseUrlToString(api.baseUrl));
+
  } catch (error) {
+
    if (
+
      error instanceof Error ||
+
      error instanceof ResponseError ||
+
      error instanceof ResponseParseError
+
    ) {
+
      return handleError(error, baseUrlToString(api.baseUrl));
+
    } else {
+
      return unreachableError();
+
    }
  }
}
modified src/views/projects/Cob/CobStateButton.svelte
@@ -1,4 +1,4 @@
-
<script lang="ts">
+
<script lang="ts" generics="CobState">
  import IconSmall from "@app/components/IconSmall.svelte";

  import isEqual from "lodash/isEqual";
@@ -11,8 +11,6 @@
  import Icon from "@app/components/Icon.svelte";
  import Button from "@app/components/Button.svelte";

-
  type CobState = $$Generic;
-

  export let state: CobState;
  export let selectedItem: [string, CobState];
  export let items: [string, CobState][];
modified src/views/projects/Cob/Revision.svelte
@@ -122,6 +122,7 @@
  type State = "read" | "submit" | "edit";

  let response: DiffResponse | undefined = undefined;
+
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  let error: any | undefined = undefined;
  let loading: boolean = false;
  let revisionState: State = "read";
@@ -135,6 +136,7 @@
    try {
      loading = true;
      response = await api.project.getDiff(projectId, fromCommit, revisionOid);
+
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
    } catch (err: any) {
      error = err;
    } finally {
modified src/views/projects/History.svelte
@@ -35,6 +35,7 @@

  const api = new HttpdClient(baseUrl);

+
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  let error: any;
  let page = 0;
  let loading = false;
modified src/views/projects/Issues.svelte
@@ -30,6 +30,7 @@

  let loading = false;
  let page = 0;
+
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  let error: any;
  let allIssues: Issue[];

modified src/views/projects/Patches.svelte
@@ -31,6 +31,7 @@

  let loading = false;
  let page = 0;
+
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  let error: any;
  let allPatches: Patch[];

modified src/views/projects/error.ts
@@ -73,3 +73,15 @@ export function handleError(
    };
  }
}
+

+
export function unreachableError(): NotFoundRoute | ErrorRoute {
+
  return {
+
    resource: "error",
+
    params: {
+
      error: undefined,
+
      title: "Could not load this route",
+
      description:
+
        "You stumbled on an unknown error, we aren't exactly sure what happened.",
+
    },
+
  };
+
}
modified src/views/projects/router.ts
@@ -23,12 +23,12 @@ import type {
import * as Syntax from "@app/lib/syntax";
import * as httpd from "@app/lib/httpd";
import { HttpdClient } from "@httpd-client";
-
import { ResponseError } from "@httpd-client/lib/fetcher";
-
import { handleError } from "@app/views/projects/error";
+
import { ResponseError, ResponseParseError } from "@httpd-client/lib/fetcher";
+
import { experimental } from "@app/lib/appearance";
+
import { get } from "svelte/store";
+
import { handleError, unreachableError } from "@app/views/projects/error";
import { nodePath } from "@app/views/nodes/router";
import { unreachable } from "@app/lib/utils";
-
import { get } from "svelte/store";
-
import { experimental } from "@app/lib/appearance";

export const COMMITS_PER_PAGE = 30;
export const PATCHES_PER_PAGE = 10;
@@ -315,8 +315,16 @@ export async function loadProjectRoute(
    } else {
      return unreachable(route);
    }
-
  } catch (error: any) {
-
    return handleError(error, route);
+
  } catch (error) {
+
    if (
+
      error instanceof Error ||
+
      error instanceof ResponseError ||
+
      error instanceof ResponseParseError
+
    ) {
+
      return handleError(error, route);
+
    } else {
+
      return unreachableError();
+
    }
  }
}

modified tests/support/peerManager.ts
@@ -331,6 +331,7 @@ export class RadiclePeer {

  public async stopNode() {
    // Don’t leak unhandled rejections when forcefully killing the process
+
    // eslint-disable-next-line @typescript-eslint/no-empty-function
    this.#nodeProcess?.catch(() => {});
    this.#nodeProcess?.kill("SIGTERM");

@@ -350,6 +351,7 @@ export class RadiclePeer {
    // processes are running anymore.
    this.#childProcesses.forEach(p => {
      // Don’t leak unhandled rejections when forcefully killing the process
+
      // eslint-disable-next-line @typescript-eslint/no-empty-function
      p.catch(() => {});
      p.kill("SIGKILL");
    });
modified tests/unit/mutexExecutor.test.ts
@@ -95,7 +95,7 @@ describe("worker", () => {
    });

    const outputs: number[] = [];
-
    w.output.onValue((value: any) => outputs.push(value));
+
    w.output.onValue((value: never) => outputs.push(value));

    await w.submit(1);
    await w.submit(2);