From 40094fc88ea4459f1fa70eed428480444730b58a Mon Sep 17 00:00:00 2001
From: DoneDeal0 <ap.lanoe@outlook.com>
Date: Sat, 2 Nov 2024 18:05:23 +0100
Subject: [PATCH] feat: use workers for streamListDiff (#31)

---
 .gitignore                                    |    4 +-
 README.md                                     |   31 +-
 eslint.config.mjs                             |    2 +-
 index.ts                                      |    0
 jest.config.js => jest.config.ts              |   12 +-
 jest.setup.ts                                 |    5 +
 package-lock.json                             | 1564 ++++++++++-------
 package.json                                  |   41 +-
 scripts/transpile-node-worker.js              |   17 +
 src/lib/list-diff/index.ts                    |   36 +-
 src/lib/list-diff/list-diff.test.ts           |    8 +-
 src/lib/object-diff/index.ts                  |   52 +-
 src/lib/object-diff/object-diff.test.ts       |   26 +-
 src/lib/stream-list-diff/client/index.ts      |   93 +-
 .../client/stream-list-diff-client.test.ts    |  153 +-
 .../stream-list-diff-client.worker.test.ts    | 1116 ++++++++++++
 .../stream-list-diff/client/worker/utils.ts   |   78 +
 .../client/worker/web-worker.ts               |   30 +
 src/lib/stream-list-diff/server/index.ts      |   93 +-
 .../server/stream-list-diff.test.ts           |  149 +-
 .../server/stream-list-diff.worker.test.ts    | 1048 +++++++++++
 .../server/worker/node-worker.ts              |   38 +
 .../stream-list-diff/server/worker/utils.ts   |   78 +
 src/lib/stream-list-diff/utils.ts             |    8 +-
 .../emitter.ts => models/emitter/index.ts}    |   27 +-
 src/models/list/index.ts                      |   27 +-
 src/models/object/index.ts                    |   14 +-
 src/models/stream/index.ts                    |   36 +-
 src/models/worker/index.ts                    |   22 +
 tsconfig.json                                 |    5 +-
 tsup.config.ts                                |   28 +-
 31 files changed, 3875 insertions(+), 966 deletions(-)
 delete mode 100644 index.ts
 rename jest.config.js => jest.config.ts (62%)
 create mode 100644 jest.setup.ts
 create mode 100644 scripts/transpile-node-worker.js
 create mode 100644 src/lib/stream-list-diff/client/stream-list-diff-client.worker.test.ts
 create mode 100644 src/lib/stream-list-diff/client/worker/utils.ts
 create mode 100644 src/lib/stream-list-diff/client/worker/web-worker.ts
 create mode 100644 src/lib/stream-list-diff/server/stream-list-diff.worker.test.ts
 create mode 100644 src/lib/stream-list-diff/server/worker/node-worker.ts
 create mode 100644 src/lib/stream-list-diff/server/worker/utils.ts
 rename src/{lib/stream-list-diff/emitter.ts => models/emitter/index.ts} (67%)
 create mode 100644 src/models/worker/index.ts

diff --git a/.gitignore b/.gitignore
index 19e6239..640d792 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
 /node_modules
 dist
-.eslintcache
\ No newline at end of file
+.eslintcache
+# Ignore generated worker files
+src/lib/stream-list-diff/server/worker/node-worker.cjs
\ No newline at end of file
diff --git a/README.md b/README.md
index 5198e2f..0c871ef 100644
--- a/README.md
+++ b/README.md
@@ -104,12 +104,12 @@ type ObjectDiff = {
   diff: Diff[];
 };
 
-/** recursive diff in case of subproperties */
 type Diff = {
   property: string;
   previousValue: unknown;
   currentValue: unknown;
   status: "added" | "deleted" | "equal" | "updated";
+  // recursive diff in case of subproperties
   diff?: Diff[];
 };
 ```
@@ -307,13 +307,15 @@ getListDiff(
 
 ```js
 // If you are in a server environment
-import { streamListDiff } from "@donedeal0/superdiff/server";
+import { streamListDiff } from "@donedeal0/superdiff/server.cjs";
 // If you are in a browser environment
 import { streamListDiff } from "@donedeal0/superdiff/client";
 ```
 
 Streams the diff of two object lists, ideal for large lists and maximum performance.
 
+ℹ️ `streamListDiff` requires ESM support for browser usage. It will work out of the box if you use a modern bundler (Webpack, Rollup) or JavaScript framework (Next.js, Vue.js).
+
 #### FORMAT
 
 **Input**
@@ -330,6 +332,8 @@ Streams the diff of two object lists, ideal for large lists and maximum performa
   showOnly?: ("added" | "deleted" | "moved" | "updated" | "equal")[], // [] by default
   chunksSize?: number, // 0 by default
   considerMoveAsUpdate?: boolean; // false by default
+  useWorker?: boolean; // true by default
+  showWarnings?: boolean; // true by default
 }
 ```
 
@@ -345,6 +349,9 @@ Streams the diff of two object lists, ideal for large lists and maximum performa
   showOnly?: ("added" | "deleted" | "moved" | "updated" | "equal")[], // [] by default
   chunksSize?: number, // 0 by default
   considerMoveAsUpdate?: boolean; // false by default
+  useWorker?: boolean; // true by default
+  showWarnings?: boolean; // true by default
+
 }
 ```
 
@@ -355,6 +362,10 @@ Streams the diff of two object lists, ideal for large lists and maximum performa
   - `chunksSize` the number of object diffs returned by each streamed chunk. (e.g. `0` = 1 object diff per chunk, `10` = 10 object diffs per chunk).
   - `showOnly` gives you the option to return only the values whose status you are interested in (e.g. `["added", "equal"]`).
   - `considerMoveAsUpdate`: if set to `true` a `moved` value will be considered as `updated`.
+  - `useWorker`: if set to `true`, the diff will be run in a worker for maximum performance. Only recommended for large lists (e.g. +100,000 items).
+  - `showWarnings`: if set to `true`, potential warnings will be displayed in the console. 
+
+> ⚠️ Warning: using Readable streams may impact workers' performance since they need to be converted to arrays. Consider using arrays or files for optimal performance. Alternatively, you can turn the `useWorker` option off.
 
 **Output**
 
@@ -364,20 +375,12 @@ The objects diff are grouped into arrays - called `chunks` - and are consumed th
   - `error`: to be notified if an error occurs during the stream.
 
 ```ts
-interface StreamListener<T extends Record<string, unknown>> {
-  on<E extends keyof EmitterEvents<T>>(
-    event: E,
-    listener: Listener<EmitterEvents<T>[E]>,
-  ): this;
+interface StreamListener<T> {
+  on(event: "data", listener: (chunk: StreamListDiff<T>[]) => void);
+  on(event: "finish", listener: () => void);
+  on(event: "error", listener: (error: Error) => void);
 }
 
-type EmitterEvents<T extends Record<string, unknown>> = {
-  data: [StreamListDiff<T>[]];
-  error: [Error];
-  finish: [];
-};
-
-
 type StreamListDiff<T extends Record<string, unknown>> = {
   currentValue: T | null;
   previousValue: T | null;
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 769dd55..6c09409 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -3,7 +3,7 @@ import tseslint from "typescript-eslint";
 
 export default [
   { files: ["**/*.{js,mjs,cjs,ts}"] },
-  { ignores: ["dist", "jest.config.js"] },
+  { ignores: ["dist", "jest.config.js", "src/lib/stream-list-diff/server/worker/node-worker.cjs"] },
   { settings: { react: { version: "detect" } } },
   pluginJs.configs.recommended,
   ...tseslint.configs.recommended,
diff --git a/index.ts b/index.ts
deleted file mode 100644
index e69de29..0000000
diff --git a/jest.config.js b/jest.config.ts
similarity index 62%
rename from jest.config.js
rename to jest.config.ts
index 0dbaf11..9e801ee 100644
--- a/jest.config.js
+++ b/jest.config.ts
@@ -1,6 +1,8 @@
-module.exports = {
+import type { Config } from "jest";
+
+const config: Config = {
   transform: {
-   "^.+\\.(ts|js)$": [
+    "^.+\\.(ts|js)$": [
       "@swc/jest",
       {
         jsc: {
@@ -11,13 +13,17 @@ module.exports = {
             dynamicImport: true,
           },
           paths: {
+            "@mocks/*": ["./src/mocks/*"],
             "@models/*": ["./src/models/*"],
             "@lib/*": ["./src/lib/*"],
-            
           },
           target: "esnext",
         },
       },
     ],
   },
+  testEnvironment: "node",
+  setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"],
 };
+
+export default config;
diff --git a/jest.setup.ts b/jest.setup.ts
new file mode 100644
index 0000000..c8f8d7b
--- /dev/null
+++ b/jest.setup.ts
@@ -0,0 +1,5 @@
+import { TextEncoder, TextDecoder } from "util";
+
+global.TextEncoder = TextEncoder;
+//@ts-expect-error - the TextDecoder is valid
+global.TextDecoder = TextDecoder;
diff --git a/package-lock.json b/package-lock.json
index ef1fda1..472f9ed 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,32 +1,34 @@
 {
   "name": "@donedeal0/superdiff",
-  "version": "2.1.0",
+  "version": "3.0.0",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "@donedeal0/superdiff",
-      "version": "2.1.0",
+      "version": "3.0.0",
       "license": "ISC",
       "devDependencies": {
-        "@eslint/js": "^9.11.1",
+        "@eslint/js": "^9.14.0",
         "@semantic-release/exec": "^6.0.3",
         "@semantic-release/git": "^10.0.1",
         "@semantic-release/github": "^11.0.0",
         "@semantic-release/npm": "^12.0.1",
-        "@swc/core": "^1.7.26",
-        "@swc/jest": "^0.2.36",
-        "@types/jest": "^29.5.13",
+        "@swc/core": "^1.7.42",
+        "@swc/jest": "^0.2.37",
+        "@types/jest": "^29.5.14",
         "blob-polyfill": "^9.0.20240710",
-        "eslint": "^9.11.1",
+        "eslint": "^9.14.0",
         "husky": "^9.1.6",
         "jest": "^29.7.0",
         "jest-environment-jsdom": "^29.7.0",
+        "jsdom": "^25.0.1",
         "prettier": "^3.3.3",
         "swc-loader": "^0.2.6",
-        "tsup": "^8.3.0",
-        "typescript": "^5.6.2",
-        "typescript-eslint": "^8.7.0",
+        "ts-node": "^10.9.2",
+        "tsup": "^8.3.5",
+        "typescript": "^5.6.3",
+        "typescript-eslint": "^8.12.2",
         "web-streams-polyfill": "^4.0.0"
       },
       "funding": {
@@ -494,10 +496,32 @@
         "node": ">=0.1.90"
       }
     },
+    "node_modules/@cspotcode/source-map-support": {
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+      "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/trace-mapping": "0.3.9"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+      "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.0.3",
+        "@jridgewell/sourcemap-codec": "^1.4.10"
+      }
+    },
     "node_modules/@esbuild/aix-ppc64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz",
-      "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz",
+      "integrity": "sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==",
       "cpu": [
         "ppc64"
       ],
@@ -511,9 +535,9 @@
       }
     },
     "node_modules/@esbuild/android-arm": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz",
-      "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.0.tgz",
+      "integrity": "sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==",
       "cpu": [
         "arm"
       ],
@@ -527,9 +551,9 @@
       }
     },
     "node_modules/@esbuild/android-arm64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz",
-      "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.0.tgz",
+      "integrity": "sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==",
       "cpu": [
         "arm64"
       ],
@@ -543,9 +567,9 @@
       }
     },
     "node_modules/@esbuild/android-x64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz",
-      "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.0.tgz",
+      "integrity": "sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==",
       "cpu": [
         "x64"
       ],
@@ -559,9 +583,9 @@
       }
     },
     "node_modules/@esbuild/darwin-arm64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz",
-      "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz",
+      "integrity": "sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==",
       "cpu": [
         "arm64"
       ],
@@ -575,9 +599,9 @@
       }
     },
     "node_modules/@esbuild/darwin-x64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz",
-      "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.0.tgz",
+      "integrity": "sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==",
       "cpu": [
         "x64"
       ],
@@ -591,9 +615,9 @@
       }
     },
     "node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz",
-      "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.0.tgz",
+      "integrity": "sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==",
       "cpu": [
         "arm64"
       ],
@@ -607,9 +631,9 @@
       }
     },
     "node_modules/@esbuild/freebsd-x64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz",
-      "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.0.tgz",
+      "integrity": "sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==",
       "cpu": [
         "x64"
       ],
@@ -623,9 +647,9 @@
       }
     },
     "node_modules/@esbuild/linux-arm": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz",
-      "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.0.tgz",
+      "integrity": "sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==",
       "cpu": [
         "arm"
       ],
@@ -639,9 +663,9 @@
       }
     },
     "node_modules/@esbuild/linux-arm64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz",
-      "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.0.tgz",
+      "integrity": "sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==",
       "cpu": [
         "arm64"
       ],
@@ -655,9 +679,9 @@
       }
     },
     "node_modules/@esbuild/linux-ia32": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz",
-      "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.0.tgz",
+      "integrity": "sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==",
       "cpu": [
         "ia32"
       ],
@@ -671,9 +695,9 @@
       }
     },
     "node_modules/@esbuild/linux-loong64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz",
-      "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.0.tgz",
+      "integrity": "sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==",
       "cpu": [
         "loong64"
       ],
@@ -687,9 +711,9 @@
       }
     },
     "node_modules/@esbuild/linux-mips64el": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz",
-      "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.0.tgz",
+      "integrity": "sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==",
       "cpu": [
         "mips64el"
       ],
@@ -703,9 +727,9 @@
       }
     },
     "node_modules/@esbuild/linux-ppc64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz",
-      "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.0.tgz",
+      "integrity": "sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==",
       "cpu": [
         "ppc64"
       ],
@@ -719,9 +743,9 @@
       }
     },
     "node_modules/@esbuild/linux-riscv64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz",
-      "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.0.tgz",
+      "integrity": "sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==",
       "cpu": [
         "riscv64"
       ],
@@ -735,9 +759,9 @@
       }
     },
     "node_modules/@esbuild/linux-s390x": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz",
-      "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.0.tgz",
+      "integrity": "sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==",
       "cpu": [
         "s390x"
       ],
@@ -751,9 +775,9 @@
       }
     },
     "node_modules/@esbuild/linux-x64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz",
-      "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz",
+      "integrity": "sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==",
       "cpu": [
         "x64"
       ],
@@ -767,9 +791,9 @@
       }
     },
     "node_modules/@esbuild/netbsd-x64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz",
-      "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz",
+      "integrity": "sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==",
       "cpu": [
         "x64"
       ],
@@ -783,9 +807,9 @@
       }
     },
     "node_modules/@esbuild/openbsd-arm64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz",
-      "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.0.tgz",
+      "integrity": "sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==",
       "cpu": [
         "arm64"
       ],
@@ -799,9 +823,9 @@
       }
     },
     "node_modules/@esbuild/openbsd-x64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz",
-      "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.0.tgz",
+      "integrity": "sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==",
       "cpu": [
         "x64"
       ],
@@ -815,9 +839,9 @@
       }
     },
     "node_modules/@esbuild/sunos-x64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz",
-      "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.0.tgz",
+      "integrity": "sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==",
       "cpu": [
         "x64"
       ],
@@ -831,9 +855,9 @@
       }
     },
     "node_modules/@esbuild/win32-arm64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz",
-      "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.0.tgz",
+      "integrity": "sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==",
       "cpu": [
         "arm64"
       ],
@@ -847,9 +871,9 @@
       }
     },
     "node_modules/@esbuild/win32-ia32": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz",
-      "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.0.tgz",
+      "integrity": "sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==",
       "cpu": [
         "ia32"
       ],
@@ -863,9 +887,9 @@
       }
     },
     "node_modules/@esbuild/win32-x64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz",
-      "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.0.tgz",
+      "integrity": "sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==",
       "cpu": [
         "x64"
       ],
@@ -906,9 +930,9 @@
       }
     },
     "node_modules/@eslint-community/regexpp": {
-      "version": "4.11.1",
-      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz",
-      "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==",
+      "version": "4.12.1",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+      "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
       "dev": true,
       "engines": {
         "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
@@ -929,9 +953,9 @@
       }
     },
     "node_modules/@eslint/core": {
-      "version": "0.6.0",
-      "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz",
-      "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==",
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz",
+      "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==",
       "dev": true,
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -991,9 +1015,9 @@
       }
     },
     "node_modules/@eslint/js": {
-      "version": "9.11.1",
-      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.11.1.tgz",
-      "integrity": "sha512-/qu+TWz8WwPWc7/HcIJKi+c+MOm46GdVaSlTTQcaqaL53+GsoA6MxWp5PtTx48qbSP7ylM1Kn7nhvkugfJvRSA==",
+      "version": "9.14.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz",
+      "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==",
       "dev": true,
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1020,6 +1044,41 @@
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       }
     },
+    "node_modules/@humanfs/core": {
+      "version": "0.19.1",
+      "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+      "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+      "dev": true,
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanfs/node": {
+      "version": "0.16.6",
+      "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz",
+      "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==",
+      "dev": true,
+      "dependencies": {
+        "@humanfs/core": "^0.19.1",
+        "@humanwhocodes/retry": "^0.3.0"
+      },
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
+      "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
+      "dev": true,
+      "engines": {
+        "node": ">=18.18"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
     "node_modules/@humanwhocodes/module-importer": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
@@ -1034,9 +1093,9 @@
       }
     },
     "node_modules/@humanwhocodes/retry": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz",
-      "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==",
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.0.tgz",
+      "integrity": "sha512-xnRgu9DxZbkWak/te3fcytNyp8MTbuiZIaueg2rgEvBuN55n04nwLYLU9TX/VVlusc9L2ZNXi99nUFNkHXtr5g==",
       "dev": true,
       "engines": {
         "node": ">=18.18"
@@ -2140,9 +2199,9 @@
       }
     },
     "node_modules/@rollup/rollup-android-arm-eabi": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.5.tgz",
-      "integrity": "sha512-SU5cvamg0Eyu/F+kLeMXS7GoahL+OoizlclVFX3l5Ql6yNlywJJ0OuqTzUx0v+aHhPHEB/56CT06GQrRrGNYww==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.3.tgz",
+      "integrity": "sha512-ufb2CH2KfBWPJok95frEZZ82LtDl0A6QKTa8MoM+cWwDZvVGl5/jNb79pIhRvAalUu+7LD91VYR0nwRD799HkQ==",
       "cpu": [
         "arm"
       ],
@@ -2153,9 +2212,9 @@
       ]
     },
     "node_modules/@rollup/rollup-android-arm64": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.5.tgz",
-      "integrity": "sha512-S4pit5BP6E5R5C8S6tgU/drvgjtYW76FBuG6+ibG3tMvlD1h9LHVF9KmlmaUBQ8Obou7hEyS+0w+IR/VtxwNMQ==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.3.tgz",
+      "integrity": "sha512-iAHpft/eQk9vkWIV5t22V77d90CRofgR2006UiCjHcHJFVI1E0oBkQIAbz+pLtthFw3hWEmVB4ilxGyBf48i2Q==",
       "cpu": [
         "arm64"
       ],
@@ -2166,9 +2225,9 @@
       ]
     },
     "node_modules/@rollup/rollup-darwin-arm64": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.5.tgz",
-      "integrity": "sha512-250ZGg4ipTL0TGvLlfACkIxS9+KLtIbn7BCZjsZj88zSg2Lvu3Xdw6dhAhfe/FjjXPVNCtcSp+WZjVsD3a/Zlw==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.3.tgz",
+      "integrity": "sha512-QPW2YmkWLlvqmOa2OwrfqLJqkHm7kJCIMq9kOz40Zo9Ipi40kf9ONG5Sz76zszrmIZZ4hgRIkez69YnTHgEz1w==",
       "cpu": [
         "arm64"
       ],
@@ -2179,9 +2238,9 @@
       ]
     },
     "node_modules/@rollup/rollup-darwin-x64": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.5.tgz",
-      "integrity": "sha512-D8brJEFg5D+QxFcW6jYANu+Rr9SlKtTenmsX5hOSzNYVrK5oLAEMTUgKWYJP+wdKyCdeSwnapLsn+OVRFycuQg==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.3.tgz",
+      "integrity": "sha512-KO0pN5x3+uZm1ZXeIfDqwcvnQ9UEGN8JX5ufhmgH5Lz4ujjZMAnxQygZAVGemFWn+ZZC0FQopruV4lqmGMshow==",
       "cpu": [
         "x64"
       ],
@@ -2191,10 +2250,36 @@
         "darwin"
       ]
     },
+    "node_modules/@rollup/rollup-freebsd-arm64": {
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.24.3.tgz",
+      "integrity": "sha512-CsC+ZdIiZCZbBI+aRlWpYJMSWvVssPuWqrDy/zi9YfnatKKSLFCe6fjna1grHuo/nVaHG+kiglpRhyBQYRTK4A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-x64": {
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.24.3.tgz",
+      "integrity": "sha512-F0nqiLThcfKvRQhZEzMIXOQG4EeX61im61VYL1jo4eBxv4aZRmpin6crnBJQ/nWnCsjH5F6J3W6Stdm0mBNqBg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
     "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.5.tgz",
-      "integrity": "sha512-PNqXYmdNFyWNg0ma5LdY8wP+eQfdvyaBAojAXgO7/gs0Q/6TQJVXAXe8gwW9URjbS0YAammur0fynYGiWsKlXw==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.3.tgz",
+      "integrity": "sha512-KRSFHyE/RdxQ1CSeOIBVIAxStFC/hnBgVcaiCkQaVC+EYDtTe4X7z5tBkFyRoBgUGtB6Xg6t9t2kulnX6wJc6A==",
       "cpu": [
         "arm"
       ],
@@ -2205,9 +2290,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm-musleabihf": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.5.tgz",
-      "integrity": "sha512-kSSCZOKz3HqlrEuwKd9TYv7vxPYD77vHSUvM2y0YaTGnFc8AdI5TTQRrM1yIp3tXCKrSL9A7JLoILjtad5t8pQ==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.3.tgz",
+      "integrity": "sha512-h6Q8MT+e05zP5BxEKz0vi0DhthLdrNEnspdLzkoFqGwnmOzakEHSlXfVyA4HJ322QtFy7biUAVFPvIDEDQa6rw==",
       "cpu": [
         "arm"
       ],
@@ -2218,9 +2303,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm64-gnu": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.5.tgz",
-      "integrity": "sha512-oTXQeJHRbOnwRnRffb6bmqmUugz0glXaPyspp4gbQOPVApdpRrY/j7KP3lr7M8kTfQTyrBUzFjj5EuHAhqH4/w==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.3.tgz",
+      "integrity": "sha512-fKElSyXhXIJ9pqiYRqisfirIo2Z5pTTve5K438URf08fsypXrEkVmShkSfM8GJ1aUyvjakT+fn2W7Czlpd/0FQ==",
       "cpu": [
         "arm64"
       ],
@@ -2231,9 +2316,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm64-musl": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.5.tgz",
-      "integrity": "sha512-qnOTIIs6tIGFKCHdhYitgC2XQ2X25InIbZFor5wh+mALH84qnFHvc+vmWUpyX97B0hNvwNUL4B+MB8vJvH65Fw==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.3.tgz",
+      "integrity": "sha512-YlddZSUk8G0px9/+V9PVilVDC6ydMz7WquxozToozSnfFK6wa6ne1ATUjUvjin09jp34p84milxlY5ikueoenw==",
       "cpu": [
         "arm64"
       ],
@@ -2244,9 +2329,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.5.tgz",
-      "integrity": "sha512-TMYu+DUdNlgBXING13rHSfUc3Ky5nLPbWs4bFnT+R6Vu3OvXkTkixvvBKk8uO4MT5Ab6lC3U7x8S8El2q5o56w==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.3.tgz",
+      "integrity": "sha512-yNaWw+GAO8JjVx3s3cMeG5Esz1cKVzz8PkTJSfYzE5u7A+NvGmbVFEHP+BikTIyYWuz0+DX9kaA3pH9Sqxp69g==",
       "cpu": [
         "ppc64"
       ],
@@ -2257,9 +2342,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-riscv64-gnu": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.5.tgz",
-      "integrity": "sha512-PTQq1Kz22ZRvuhr3uURH+U/Q/a0pbxJoICGSprNLAoBEkyD3Sh9qP5I0Asn0y0wejXQBbsVMRZRxlbGFD9OK4A==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.3.tgz",
+      "integrity": "sha512-lWKNQfsbpv14ZCtM/HkjCTm4oWTKTfxPmr7iPfp3AHSqyoTz5AgLemYkWLwOBWc+XxBbrU9SCokZP0WlBZM9lA==",
       "cpu": [
         "riscv64"
       ],
@@ -2270,9 +2355,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-s390x-gnu": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.5.tgz",
-      "integrity": "sha512-bR5nCojtpuMss6TDEmf/jnBnzlo+6n1UhgwqUvRoe4VIotC7FG1IKkyJbwsT7JDsF2jxR+NTnuOwiGv0hLyDoQ==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.3.tgz",
+      "integrity": "sha512-HoojGXTC2CgCcq0Woc/dn12wQUlkNyfH0I1ABK4Ni9YXyFQa86Fkt2Q0nqgLfbhkyfQ6003i3qQk9pLh/SpAYw==",
       "cpu": [
         "s390x"
       ],
@@ -2283,9 +2368,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-x64-gnu": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.5.tgz",
-      "integrity": "sha512-N0jPPhHjGShcB9/XXZQWuWBKZQnC1F36Ce3sDqWpujsGjDz/CQtOL9LgTrJ+rJC8MJeesMWrMWVLKKNR/tMOCA==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.3.tgz",
+      "integrity": "sha512-mnEOh4iE4USSccBOtcrjF5nj+5/zm6NcNhbSEfR3Ot0pxBwvEn5QVUXcuOwwPkapDtGZ6pT02xLoPaNv06w7KQ==",
       "cpu": [
         "x64"
       ],
@@ -2296,9 +2381,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-x64-musl": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.5.tgz",
-      "integrity": "sha512-uBa2e28ohzNNwjr6Uxm4XyaA1M/8aTgfF2T7UIlElLaeXkgpmIJ2EitVNQxjO9xLLLy60YqAgKn/AqSpCUkE9g==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.3.tgz",
+      "integrity": "sha512-rMTzawBPimBQkG9NKpNHvquIUTQPzrnPxPbCY1Xt+mFkW7pshvyIS5kYgcf74goxXOQk0CP3EoOC1zcEezKXhw==",
       "cpu": [
         "x64"
       ],
@@ -2309,9 +2394,9 @@
       ]
     },
     "node_modules/@rollup/rollup-win32-arm64-msvc": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.5.tgz",
-      "integrity": "sha512-RXT8S1HP8AFN/Kr3tg4fuYrNxZ/pZf1HemC5Tsddc6HzgGnJm0+Lh5rAHJkDuW3StI0ynNXukidROMXYl6ew8w==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.3.tgz",
+      "integrity": "sha512-2lg1CE305xNvnH3SyiKwPVsTVLCg4TmNCF1z7PSHX2uZY2VbUpdkgAllVoISD7JO7zu+YynpWNSKAtOrX3AiuA==",
       "cpu": [
         "arm64"
       ],
@@ -2322,9 +2407,9 @@
       ]
     },
     "node_modules/@rollup/rollup-win32-ia32-msvc": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.5.tgz",
-      "integrity": "sha512-ElTYOh50InL8kzyUD6XsnPit7jYCKrphmddKAe1/Ytt74apOxDq5YEcbsiKs0fR3vff3jEneMM+3I7jbqaMyBg==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.3.tgz",
+      "integrity": "sha512-9SjYp1sPyxJsPWuhOCX6F4jUMXGbVVd5obVpoVEi8ClZqo52ViZewA6eFz85y8ezuOA+uJMP5A5zo6Oz4S5rVQ==",
       "cpu": [
         "ia32"
       ],
@@ -2335,9 +2420,9 @@
       ]
     },
     "node_modules/@rollup/rollup-win32-x64-msvc": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.5.tgz",
-      "integrity": "sha512-+lvL/4mQxSV8MukpkKyyvfwhH266COcWlXE/1qxwN08ajovta3459zrjLghYMgDerlzNwLAcFpvU+WWE5y6nAQ==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.3.tgz",
+      "integrity": "sha512-HGZgRFFYrMrP3TJlq58nR1xy8zHKId25vhmm5S9jETEfDf6xybPxsavFTJaufe2zgOGYJBskGlj49CwtEuFhWQ==",
       "cpu": [
         "x64"
       ],
@@ -2851,14 +2936,14 @@
       }
     },
     "node_modules/@swc/core": {
-      "version": "1.7.26",
-      "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.26.tgz",
-      "integrity": "sha512-f5uYFf+TmMQyYIoxkn/evWhNGuUzC730dFwAKGwBVHHVoPyak1/GvJUm6i1SKl+2Hrj9oN0i3WSoWWZ4pgI8lw==",
+      "version": "1.7.42",
+      "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.42.tgz",
+      "integrity": "sha512-iQrRk3SKndQZ4ptJv1rzeQSiCYQIhMjiO97QXOlCcCoaazOLKPnLnXzU4Kv0FuBFyYfG2FE94BoR0XI2BN02qw==",
       "dev": true,
       "hasInstallScript": true,
       "dependencies": {
         "@swc/counter": "^0.1.3",
-        "@swc/types": "^0.1.12"
+        "@swc/types": "^0.1.13"
       },
       "engines": {
         "node": ">=10"
@@ -2868,16 +2953,16 @@
         "url": "https://opencollective.com/swc"
       },
       "optionalDependencies": {
-        "@swc/core-darwin-arm64": "1.7.26",
-        "@swc/core-darwin-x64": "1.7.26",
-        "@swc/core-linux-arm-gnueabihf": "1.7.26",
-        "@swc/core-linux-arm64-gnu": "1.7.26",
-        "@swc/core-linux-arm64-musl": "1.7.26",
-        "@swc/core-linux-x64-gnu": "1.7.26",
-        "@swc/core-linux-x64-musl": "1.7.26",
-        "@swc/core-win32-arm64-msvc": "1.7.26",
-        "@swc/core-win32-ia32-msvc": "1.7.26",
-        "@swc/core-win32-x64-msvc": "1.7.26"
+        "@swc/core-darwin-arm64": "1.7.42",
+        "@swc/core-darwin-x64": "1.7.42",
+        "@swc/core-linux-arm-gnueabihf": "1.7.42",
+        "@swc/core-linux-arm64-gnu": "1.7.42",
+        "@swc/core-linux-arm64-musl": "1.7.42",
+        "@swc/core-linux-x64-gnu": "1.7.42",
+        "@swc/core-linux-x64-musl": "1.7.42",
+        "@swc/core-win32-arm64-msvc": "1.7.42",
+        "@swc/core-win32-ia32-msvc": "1.7.42",
+        "@swc/core-win32-x64-msvc": "1.7.42"
       },
       "peerDependencies": {
         "@swc/helpers": "*"
@@ -2889,9 +2974,9 @@
       }
     },
     "node_modules/@swc/core-darwin-arm64": {
-      "version": "1.7.26",
-      "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.26.tgz",
-      "integrity": "sha512-FF3CRYTg6a7ZVW4yT9mesxoVVZTrcSWtmZhxKCYJX9brH4CS/7PRPjAKNk6kzWgWuRoglP7hkjQcd6EpMcZEAw==",
+      "version": "1.7.42",
+      "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.42.tgz",
+      "integrity": "sha512-fWhaCs2+8GDRIcjExVDEIfbptVrxDqG8oHkESnXgymmvqTWzWei5SOnPNMS8Q+MYsn/b++Y2bDxkcwmq35Bvxg==",
       "cpu": [
         "arm64"
       ],
@@ -2905,9 +2990,9 @@
       }
     },
     "node_modules/@swc/core-darwin-x64": {
-      "version": "1.7.26",
-      "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.7.26.tgz",
-      "integrity": "sha512-az3cibZdsay2HNKmc4bjf62QVukuiMRh5sfM5kHR/JMTrLyS6vSw7Ihs3UTkZjUxkLTT8ro54LI6sV6sUQUbLQ==",
+      "version": "1.7.42",
+      "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.7.42.tgz",
+      "integrity": "sha512-ZaVHD2bijrlkCyD7NDzLmSK849Jgcx+6DdL4x1dScoz1slJ8GTvLtEu0JOUaaScQwA+cVlhmrmlmi9ssjbRLGQ==",
       "cpu": [
         "x64"
       ],
@@ -2921,9 +3006,9 @@
       }
     },
     "node_modules/@swc/core-linux-arm-gnueabihf": {
-      "version": "1.7.26",
-      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.26.tgz",
-      "integrity": "sha512-VYPFVJDO5zT5U3RpCdHE5v1gz4mmR8BfHecUZTmD2v1JeFY6fv9KArJUpjrHEEsjK/ucXkQFmJ0jaiWXmpOV9Q==",
+      "version": "1.7.42",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.42.tgz",
+      "integrity": "sha512-iF0BJj7hVTbY/vmbvyzVTh/0W80+Q4fbOYschdUM3Bsud39TA+lSaPOefOHywkNH58EQ1z3EAxYcJOWNES7GFQ==",
       "cpu": [
         "arm"
       ],
@@ -2937,9 +3022,9 @@
       }
     },
     "node_modules/@swc/core-linux-arm64-gnu": {
-      "version": "1.7.26",
-      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.26.tgz",
-      "integrity": "sha512-YKevOV7abpjcAzXrhsl+W48Z9mZvgoVs2eP5nY+uoMAdP2b3GxC0Df1Co0I90o2lkzO4jYBpTMcZlmUXLdXn+Q==",
+      "version": "1.7.42",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.42.tgz",
+      "integrity": "sha512-xGu8j+DOLYTLkVmsfZPJbNPW1EkiWgSucT0nOlz77bLxImukt/0+HVm2hOwHSKuArQ8C3cjahAMY3b/s4VH2ww==",
       "cpu": [
         "arm64"
       ],
@@ -2953,9 +3038,9 @@
       }
     },
     "node_modules/@swc/core-linux-arm64-musl": {
-      "version": "1.7.26",
-      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.26.tgz",
-      "integrity": "sha512-3w8iZICMkQQON0uIcvz7+Q1MPOW6hJ4O5ETjA0LSP/tuKqx30hIniCGOgPDnv3UTMruLUnQbtBwVCZTBKR3Rkg==",
+      "version": "1.7.42",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.42.tgz",
+      "integrity": "sha512-qtW3JNO7i1yHEko59xxz+jY38+tYmB96JGzj6XzygMbYJYZDYbrOpXQvKbMGNG3YeTDan7Fp2jD0dlKf7NgDPA==",
       "cpu": [
         "arm64"
       ],
@@ -2969,9 +3054,9 @@
       }
     },
     "node_modules/@swc/core-linux-x64-gnu": {
-      "version": "1.7.26",
-      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.26.tgz",
-      "integrity": "sha512-c+pp9Zkk2lqb06bNGkR2Looxrs7FtGDMA4/aHjZcCqATgp348hOKH5WPvNLBl+yPrISuWjbKDVn3NgAvfvpH4w==",
+      "version": "1.7.42",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.42.tgz",
+      "integrity": "sha512-F9WY1TN+hhhtiEzZjRQziNLt36M5YprMeOBHjsLVNqwgflzleSI7ulgnlQECS8c8zESaXj3ksGduAoJYtPC1cA==",
       "cpu": [
         "x64"
       ],
@@ -2985,9 +3070,9 @@
       }
     },
     "node_modules/@swc/core-linux-x64-musl": {
-      "version": "1.7.26",
-      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.26.tgz",
-      "integrity": "sha512-PgtyfHBF6xG87dUSSdTJHwZ3/8vWZfNIXQV2GlwEpslrOkGqy+WaiiyE7Of7z9AvDILfBBBcJvJ/r8u980wAfQ==",
+      "version": "1.7.42",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.42.tgz",
+      "integrity": "sha512-7YMdOaYKLMQ8JGfnmRDwidpLFs/6ka+80zekeM0iCVO48yLrJR36G0QGXzMjKsXI0BPhq+mboZRRENK4JfQnEA==",
       "cpu": [
         "x64"
       ],
@@ -3001,9 +3086,9 @@
       }
     },
     "node_modules/@swc/core-win32-arm64-msvc": {
-      "version": "1.7.26",
-      "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.26.tgz",
-      "integrity": "sha512-9TNXPIJqFynlAOrRD6tUQjMq7KApSklK3R/tXgIxc7Qx+lWu8hlDQ/kVPLpU7PWvMMwC/3hKBW+p5f+Tms1hmA==",
+      "version": "1.7.42",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.42.tgz",
+      "integrity": "sha512-C5CYWaIZEyqPl5W/EwcJ/mLBJFHVoUEa/IwWi0b4q2fCXcSCktQGwKXOQ+d67GneiZoiq0HasgcdMmMpGS9YRQ==",
       "cpu": [
         "arm64"
       ],
@@ -3017,9 +3102,9 @@
       }
     },
     "node_modules/@swc/core-win32-ia32-msvc": {
-      "version": "1.7.26",
-      "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.26.tgz",
-      "integrity": "sha512-9YngxNcG3177GYdsTum4V98Re+TlCeJEP4kEwEg9EagT5s3YejYdKwVAkAsJszzkXuyRDdnHUpYbTrPG6FiXrQ==",
+      "version": "1.7.42",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.42.tgz",
+      "integrity": "sha512-3j47seZ5pO62mbrqvPe1iwhe2BXnM5q7iB+n2xgA38PCGYt0mnaJafqmpCXm/uYZOCMqSNynaoOWCMMZm4sqtA==",
       "cpu": [
         "ia32"
       ],
@@ -3033,9 +3118,9 @@
       }
     },
     "node_modules/@swc/core-win32-x64-msvc": {
-      "version": "1.7.26",
-      "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.26.tgz",
-      "integrity": "sha512-VR+hzg9XqucgLjXxA13MtV5O3C0bK0ywtLIBw/+a+O+Oc6mxFWHtdUeXDbIi5AiPbn0fjgVJMqYnyjGyyX8u0w==",
+      "version": "1.7.42",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.42.tgz",
+      "integrity": "sha512-FXl9MdeUogZLGDcLr6QIRdDVkpG0dkN4MLM4dwQ5kcAk+XfKPrQibX6M2kcfhsCx+jtBqtK7hRFReRXPWJZGbA==",
       "cpu": [
         "x64"
       ],
@@ -3055,9 +3140,9 @@
       "dev": true
     },
     "node_modules/@swc/jest": {
-      "version": "0.2.36",
-      "resolved": "https://registry.npmjs.org/@swc/jest/-/jest-0.2.36.tgz",
-      "integrity": "sha512-8X80dp81ugxs4a11z1ka43FPhP+/e+mJNXJSxiNYk8gIX/jPBtY4gQTrKu/KIoco8bzKuPI5lUxjfLiGsfvnlw==",
+      "version": "0.2.37",
+      "resolved": "https://registry.npmjs.org/@swc/jest/-/jest-0.2.37.tgz",
+      "integrity": "sha512-CR2BHhmXKGxTiFr21DYPRHQunLkX3mNIFGFkxBGji6r9uyIR5zftTOVYj1e0sFNMV2H7mf/+vpaglqaryBtqfQ==",
       "dev": true,
       "dependencies": {
         "@jest/create-cache-key-function": "^29.7.0",
@@ -3072,9 +3157,9 @@
       }
     },
     "node_modules/@swc/types": {
-      "version": "0.1.12",
-      "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.12.tgz",
-      "integrity": "sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==",
+      "version": "0.1.13",
+      "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.13.tgz",
+      "integrity": "sha512-JL7eeCk6zWCbiYQg2xQSdLXQJl8Qoc9rXmG2cEKvHe3CKwMHwHGpfOb8frzNLmbycOo6I51qxnLnn9ESf4I20Q==",
       "dev": true,
       "dependencies": {
         "@swc/counter": "^0.1.3"
@@ -3089,6 +3174,30 @@
         "node": ">= 10"
       }
     },
+    "node_modules/@tsconfig/node10": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
+      "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
+      "dev": true
+    },
+    "node_modules/@tsconfig/node12": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+      "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
+      "dev": true
+    },
+    "node_modules/@tsconfig/node14": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+      "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+      "dev": true
+    },
+    "node_modules/@tsconfig/node16": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
+      "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
+      "dev": true
+    },
     "node_modules/@types/babel__core": {
       "version": "7.20.5",
       "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -3170,9 +3279,9 @@
       }
     },
     "node_modules/@types/jest": {
-      "version": "29.5.13",
-      "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.13.tgz",
-      "integrity": "sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg==",
+      "version": "29.5.14",
+      "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz",
+      "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==",
       "dev": true,
       "dependencies": {
         "expect": "^29.0.0",
@@ -3255,16 +3364,16 @@
       "dev": true
     },
     "node_modules/@typescript-eslint/eslint-plugin": {
-      "version": "8.7.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.7.0.tgz",
-      "integrity": "sha512-RIHOoznhA3CCfSTFiB6kBGLQtB/sox+pJ6jeFu6FxJvqL8qRxq/FfGO/UhsGgQM9oGdXkV4xUgli+dt26biB6A==",
+      "version": "8.12.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.12.2.tgz",
+      "integrity": "sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==",
       "dev": true,
       "dependencies": {
         "@eslint-community/regexpp": "^4.10.0",
-        "@typescript-eslint/scope-manager": "8.7.0",
-        "@typescript-eslint/type-utils": "8.7.0",
-        "@typescript-eslint/utils": "8.7.0",
-        "@typescript-eslint/visitor-keys": "8.7.0",
+        "@typescript-eslint/scope-manager": "8.12.2",
+        "@typescript-eslint/type-utils": "8.12.2",
+        "@typescript-eslint/utils": "8.12.2",
+        "@typescript-eslint/visitor-keys": "8.12.2",
         "graphemer": "^1.4.0",
         "ignore": "^5.3.1",
         "natural-compare": "^1.4.0",
@@ -3288,15 +3397,15 @@
       }
     },
     "node_modules/@typescript-eslint/parser": {
-      "version": "8.7.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.7.0.tgz",
-      "integrity": "sha512-lN0btVpj2unxHlNYLI//BQ7nzbMJYBVQX5+pbNXvGYazdlgYonMn4AhhHifQ+J4fGRYA/m1DjaQjx+fDetqBOQ==",
+      "version": "8.12.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.12.2.tgz",
+      "integrity": "sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "8.7.0",
-        "@typescript-eslint/types": "8.7.0",
-        "@typescript-eslint/typescript-estree": "8.7.0",
-        "@typescript-eslint/visitor-keys": "8.7.0",
+        "@typescript-eslint/scope-manager": "8.12.2",
+        "@typescript-eslint/types": "8.12.2",
+        "@typescript-eslint/typescript-estree": "8.12.2",
+        "@typescript-eslint/visitor-keys": "8.12.2",
         "debug": "^4.3.4"
       },
       "engines": {
@@ -3316,13 +3425,13 @@
       }
     },
     "node_modules/@typescript-eslint/scope-manager": {
-      "version": "8.7.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz",
-      "integrity": "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==",
+      "version": "8.12.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz",
+      "integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "8.7.0",
-        "@typescript-eslint/visitor-keys": "8.7.0"
+        "@typescript-eslint/types": "8.12.2",
+        "@typescript-eslint/visitor-keys": "8.12.2"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3333,13 +3442,13 @@
       }
     },
     "node_modules/@typescript-eslint/type-utils": {
-      "version": "8.7.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.7.0.tgz",
-      "integrity": "sha512-tl0N0Mj3hMSkEYhLkjREp54OSb/FI6qyCzfiiclvJvOqre6hsZTGSnHtmFLDU8TIM62G7ygEa1bI08lcuRwEnQ==",
+      "version": "8.12.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.12.2.tgz",
+      "integrity": "sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/typescript-estree": "8.7.0",
-        "@typescript-eslint/utils": "8.7.0",
+        "@typescript-eslint/typescript-estree": "8.12.2",
+        "@typescript-eslint/utils": "8.12.2",
         "debug": "^4.3.4",
         "ts-api-utils": "^1.3.0"
       },
@@ -3357,9 +3466,9 @@
       }
     },
     "node_modules/@typescript-eslint/types": {
-      "version": "8.7.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz",
-      "integrity": "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==",
+      "version": "8.12.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz",
+      "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==",
       "dev": true,
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3370,13 +3479,13 @@
       }
     },
     "node_modules/@typescript-eslint/typescript-estree": {
-      "version": "8.7.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz",
-      "integrity": "sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg==",
+      "version": "8.12.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz",
+      "integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "8.7.0",
-        "@typescript-eslint/visitor-keys": "8.7.0",
+        "@typescript-eslint/types": "8.12.2",
+        "@typescript-eslint/visitor-keys": "8.12.2",
         "debug": "^4.3.4",
         "fast-glob": "^3.3.2",
         "is-glob": "^4.0.3",
@@ -3434,15 +3543,15 @@
       }
     },
     "node_modules/@typescript-eslint/utils": {
-      "version": "8.7.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.7.0.tgz",
-      "integrity": "sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==",
+      "version": "8.12.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.12.2.tgz",
+      "integrity": "sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.4.0",
-        "@typescript-eslint/scope-manager": "8.7.0",
-        "@typescript-eslint/types": "8.7.0",
-        "@typescript-eslint/typescript-estree": "8.7.0"
+        "@typescript-eslint/scope-manager": "8.12.2",
+        "@typescript-eslint/types": "8.12.2",
+        "@typescript-eslint/typescript-estree": "8.12.2"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3456,12 +3565,12 @@
       }
     },
     "node_modules/@typescript-eslint/visitor-keys": {
-      "version": "8.7.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz",
-      "integrity": "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==",
+      "version": "8.12.2",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz",
+      "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "8.7.0",
+        "@typescript-eslint/types": "8.12.2",
         "eslint-visitor-keys": "^3.4.3"
       },
       "engines": {
@@ -3667,9 +3776,9 @@
       "dev": true
     },
     "node_modules/acorn": {
-      "version": "8.12.1",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
-      "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
+      "version": "8.14.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
+      "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
       "dev": true,
       "bin": {
         "acorn": "bin/acorn"
@@ -3825,6 +3934,12 @@
         "node": ">= 8"
       }
     },
+    "node_modules/arg": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+      "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+      "dev": true
+    },
     "node_modules/argparse": {
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -4027,18 +4142,6 @@
       "integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==",
       "dev": true
     },
-    "node_modules/binary-extensions": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
-      "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
-      "dev": true,
-      "engines": {
-        "node": ">=8"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
     "node_modules/blob-polyfill": {
       "version": "9.0.20240710",
       "resolved": "https://registry.npmjs.org/blob-polyfill/-/blob-polyfill-9.0.20240710.tgz",
@@ -4206,39 +4309,18 @@
       }
     },
     "node_modules/chokidar": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
-      "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz",
+      "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==",
       "dev": true,
       "dependencies": {
-        "anymatch": "~3.1.2",
-        "braces": "~3.0.2",
-        "glob-parent": "~5.1.2",
-        "is-binary-path": "~2.1.0",
-        "is-glob": "~4.0.1",
-        "normalize-path": "~3.0.0",
-        "readdirp": "~3.6.0"
+        "readdirp": "^4.0.1"
       },
       "engines": {
-        "node": ">= 8.10.0"
+        "node": ">= 14.16.0"
       },
       "funding": {
         "url": "https://paulmillr.com/funding/"
-      },
-      "optionalDependencies": {
-        "fsevents": "~2.3.2"
-      }
-    },
-    "node_modules/chokidar/node_modules/glob-parent": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-      "dev": true,
-      "dependencies": {
-        "is-glob": "^4.0.1"
-      },
-      "engines": {
-        "node": ">= 6"
       }
     },
     "node_modules/chrome-trace-event": {
@@ -4768,6 +4850,12 @@
         "node": ">=8"
       }
     },
+    "node_modules/create-require": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+      "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+      "dev": true
+    },
     "node_modules/cross-spawn": {
       "version": "7.0.3",
       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -4816,47 +4904,40 @@
       "dev": true
     },
     "node_modules/cssstyle": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz",
-      "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==",
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz",
+      "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==",
       "dev": true,
       "dependencies": {
-        "cssom": "~0.3.6"
+        "rrweb-cssom": "^0.7.1"
       },
       "engines": {
-        "node": ">=8"
+        "node": ">=18"
       }
     },
-    "node_modules/cssstyle/node_modules/cssom": {
-      "version": "0.3.8",
-      "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
-      "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==",
-      "dev": true
-    },
     "node_modules/data-urls": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz",
-      "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
+      "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==",
       "dev": true,
       "dependencies": {
-        "abab": "^2.0.6",
-        "whatwg-mimetype": "^3.0.0",
-        "whatwg-url": "^11.0.0"
+        "whatwg-mimetype": "^4.0.0",
+        "whatwg-url": "^14.0.0"
       },
       "engines": {
-        "node": ">=12"
+        "node": ">=18"
       }
     },
     "node_modules/data-urls/node_modules/tr46": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
-      "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
+      "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
       "dev": true,
       "dependencies": {
-        "punycode": "^2.1.1"
+        "punycode": "^2.3.1"
       },
       "engines": {
-        "node": ">=12"
+        "node": ">=18"
       }
     },
     "node_modules/data-urls/node_modules/webidl-conversions": {
@@ -4869,16 +4950,16 @@
       }
     },
     "node_modules/data-urls/node_modules/whatwg-url": {
-      "version": "11.0.0",
-      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
-      "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz",
+      "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==",
       "dev": true,
       "dependencies": {
-        "tr46": "^3.0.0",
+        "tr46": "^5.0.0",
         "webidl-conversions": "^7.0.0"
       },
       "engines": {
-        "node": ">=12"
+        "node": ">=18"
       }
     },
     "node_modules/debug": {
@@ -4960,6 +5041,15 @@
         "node": ">=8"
       }
     },
+    "node_modules/diff": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+      "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.3.1"
+      }
+    },
     "node_modules/diff-sequences": {
       "version": "29.6.3",
       "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
@@ -5287,9 +5377,9 @@
       "peer": true
     },
     "node_modules/esbuild": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz",
-      "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==",
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz",
+      "integrity": "sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==",
       "dev": true,
       "hasInstallScript": true,
       "bin": {
@@ -5299,30 +5389,30 @@
         "node": ">=18"
       },
       "optionalDependencies": {
-        "@esbuild/aix-ppc64": "0.23.1",
-        "@esbuild/android-arm": "0.23.1",
-        "@esbuild/android-arm64": "0.23.1",
-        "@esbuild/android-x64": "0.23.1",
-        "@esbuild/darwin-arm64": "0.23.1",
-        "@esbuild/darwin-x64": "0.23.1",
-        "@esbuild/freebsd-arm64": "0.23.1",
-        "@esbuild/freebsd-x64": "0.23.1",
-        "@esbuild/linux-arm": "0.23.1",
-        "@esbuild/linux-arm64": "0.23.1",
-        "@esbuild/linux-ia32": "0.23.1",
-        "@esbuild/linux-loong64": "0.23.1",
-        "@esbuild/linux-mips64el": "0.23.1",
-        "@esbuild/linux-ppc64": "0.23.1",
-        "@esbuild/linux-riscv64": "0.23.1",
-        "@esbuild/linux-s390x": "0.23.1",
-        "@esbuild/linux-x64": "0.23.1",
-        "@esbuild/netbsd-x64": "0.23.1",
-        "@esbuild/openbsd-arm64": "0.23.1",
-        "@esbuild/openbsd-x64": "0.23.1",
-        "@esbuild/sunos-x64": "0.23.1",
-        "@esbuild/win32-arm64": "0.23.1",
-        "@esbuild/win32-ia32": "0.23.1",
-        "@esbuild/win32-x64": "0.23.1"
+        "@esbuild/aix-ppc64": "0.24.0",
+        "@esbuild/android-arm": "0.24.0",
+        "@esbuild/android-arm64": "0.24.0",
+        "@esbuild/android-x64": "0.24.0",
+        "@esbuild/darwin-arm64": "0.24.0",
+        "@esbuild/darwin-x64": "0.24.0",
+        "@esbuild/freebsd-arm64": "0.24.0",
+        "@esbuild/freebsd-x64": "0.24.0",
+        "@esbuild/linux-arm": "0.24.0",
+        "@esbuild/linux-arm64": "0.24.0",
+        "@esbuild/linux-ia32": "0.24.0",
+        "@esbuild/linux-loong64": "0.24.0",
+        "@esbuild/linux-mips64el": "0.24.0",
+        "@esbuild/linux-ppc64": "0.24.0",
+        "@esbuild/linux-riscv64": "0.24.0",
+        "@esbuild/linux-s390x": "0.24.0",
+        "@esbuild/linux-x64": "0.24.0",
+        "@esbuild/netbsd-x64": "0.24.0",
+        "@esbuild/openbsd-arm64": "0.24.0",
+        "@esbuild/openbsd-x64": "0.24.0",
+        "@esbuild/sunos-x64": "0.24.0",
+        "@esbuild/win32-arm64": "0.24.0",
+        "@esbuild/win32-ia32": "0.24.0",
+        "@esbuild/win32-x64": "0.24.0"
       }
     },
     "node_modules/escalade": {
@@ -5365,21 +5455,21 @@
       }
     },
     "node_modules/eslint": {
-      "version": "9.11.1",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.11.1.tgz",
-      "integrity": "sha512-MobhYKIoAO1s1e4VUrgx1l1Sk2JBR/Gqjjgw8+mfgoLE2xwsHur4gdfTxyTgShrhvdVFTaJSgMiQBl1jv/AWxg==",
+      "version": "9.14.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz",
+      "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.2.0",
-        "@eslint-community/regexpp": "^4.11.0",
+        "@eslint-community/regexpp": "^4.12.1",
         "@eslint/config-array": "^0.18.0",
-        "@eslint/core": "^0.6.0",
+        "@eslint/core": "^0.7.0",
         "@eslint/eslintrc": "^3.1.0",
-        "@eslint/js": "9.11.1",
+        "@eslint/js": "9.14.0",
         "@eslint/plugin-kit": "^0.2.0",
+        "@humanfs/node": "^0.16.6",
         "@humanwhocodes/module-importer": "^1.0.1",
-        "@humanwhocodes/retry": "^0.3.0",
-        "@nodelib/fs.walk": "^1.2.8",
+        "@humanwhocodes/retry": "^0.4.0",
         "@types/estree": "^1.0.6",
         "@types/json-schema": "^7.0.15",
         "ajv": "^6.12.4",
@@ -5387,9 +5477,9 @@
         "cross-spawn": "^7.0.2",
         "debug": "^4.3.2",
         "escape-string-regexp": "^4.0.0",
-        "eslint-scope": "^8.0.2",
-        "eslint-visitor-keys": "^4.0.0",
-        "espree": "^10.1.0",
+        "eslint-scope": "^8.2.0",
+        "eslint-visitor-keys": "^4.2.0",
+        "espree": "^10.3.0",
         "esquery": "^1.5.0",
         "esutils": "^2.0.2",
         "fast-deep-equal": "^3.1.3",
@@ -5399,13 +5489,11 @@
         "ignore": "^5.2.0",
         "imurmurhash": "^0.1.4",
         "is-glob": "^4.0.0",
-        "is-path-inside": "^3.0.3",
         "json-stable-stringify-without-jsonify": "^1.0.1",
         "lodash.merge": "^4.6.2",
         "minimatch": "^3.1.2",
         "natural-compare": "^1.4.0",
         "optionator": "^0.9.3",
-        "strip-ansi": "^6.0.1",
         "text-table": "^0.2.0"
       },
       "bin": {
@@ -5427,9 +5515,9 @@
       }
     },
     "node_modules/eslint-scope": {
-      "version": "8.1.0",
-      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz",
-      "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==",
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz",
+      "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==",
       "dev": true,
       "dependencies": {
         "esrecurse": "^4.3.0",
@@ -5443,9 +5531,9 @@
       }
     },
     "node_modules/eslint-visitor-keys": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz",
-      "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==",
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
+      "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
       "dev": true,
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -5583,14 +5671,14 @@
       }
     },
     "node_modules/espree": {
-      "version": "10.2.0",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz",
-      "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==",
+      "version": "10.3.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
+      "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
       "dev": true,
       "dependencies": {
-        "acorn": "^8.12.0",
+        "acorn": "^8.14.0",
         "acorn-jsx": "^5.3.2",
-        "eslint-visitor-keys": "^4.1.0"
+        "eslint-visitor-keys": "^4.2.0"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -6229,15 +6317,15 @@
       "dev": true
     },
     "node_modules/html-encoding-sniffer": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
-      "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
+      "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
       "dev": true,
       "dependencies": {
-        "whatwg-encoding": "^2.0.0"
+        "whatwg-encoding": "^3.1.1"
       },
       "engines": {
-        "node": ">=12"
+        "node": ">=18"
       }
     },
     "node_modules/html-escaper": {
@@ -6461,18 +6549,6 @@
       "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
       "dev": true
     },
-    "node_modules/is-binary-path": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
-      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
-      "dev": true,
-      "dependencies": {
-        "binary-extensions": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/is-core-module": {
       "version": "2.13.1",
       "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
@@ -6543,15 +6619,6 @@
         "node": ">=8"
       }
     },
-    "node_modules/is-path-inside": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
-      "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
-      "dev": true,
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/is-plain-obj": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
@@ -7228,80 +7295,320 @@
       "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
       "dev": true,
       "dependencies": {
-        "ansi-styles": "^4.1.0",
-        "supports-color": "^7.1.0"
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/jest-each/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/jest-each/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/jest-each/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-each/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-environment-jsdom": {
+      "version": "29.7.0",
+      "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz",
+      "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==",
+      "dev": true,
+      "dependencies": {
+        "@jest/environment": "^29.7.0",
+        "@jest/fake-timers": "^29.7.0",
+        "@jest/types": "^29.6.3",
+        "@types/jsdom": "^20.0.0",
+        "@types/node": "*",
+        "jest-mock": "^29.7.0",
+        "jest-util": "^29.7.0",
+        "jsdom": "^20.0.0"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      },
+      "peerDependencies": {
+        "canvas": "^2.5.0"
+      },
+      "peerDependenciesMeta": {
+        "canvas": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/jest-environment-jsdom/node_modules/agent-base": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+      "dev": true,
+      "dependencies": {
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6.0.0"
+      }
+    },
+    "node_modules/jest-environment-jsdom/node_modules/cssstyle": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz",
+      "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==",
+      "dev": true,
+      "dependencies": {
+        "cssom": "~0.3.6"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-environment-jsdom/node_modules/cssstyle/node_modules/cssom": {
+      "version": "0.3.8",
+      "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
+      "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==",
+      "dev": true
+    },
+    "node_modules/jest-environment-jsdom/node_modules/data-urls": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz",
+      "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==",
+      "dev": true,
+      "dependencies": {
+        "abab": "^2.0.6",
+        "whatwg-mimetype": "^3.0.0",
+        "whatwg-url": "^11.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/jest-environment-jsdom/node_modules/html-encoding-sniffer": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
+      "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
+      "dev": true,
+      "dependencies": {
+        "whatwg-encoding": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/jest-environment-jsdom/node_modules/http-proxy-agent": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
+      "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
+      "dev": true,
+      "dependencies": {
+        "@tootallnate/once": "2",
+        "agent-base": "6",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/jest-environment-jsdom/node_modules/https-proxy-agent": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "6",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/jest-environment-jsdom/node_modules/jsdom": {
+      "version": "20.0.3",
+      "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz",
+      "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==",
+      "dev": true,
+      "dependencies": {
+        "abab": "^2.0.6",
+        "acorn": "^8.8.1",
+        "acorn-globals": "^7.0.0",
+        "cssom": "^0.5.0",
+        "cssstyle": "^2.3.0",
+        "data-urls": "^3.0.2",
+        "decimal.js": "^10.4.2",
+        "domexception": "^4.0.0",
+        "escodegen": "^2.0.0",
+        "form-data": "^4.0.0",
+        "html-encoding-sniffer": "^3.0.0",
+        "http-proxy-agent": "^5.0.0",
+        "https-proxy-agent": "^5.0.1",
+        "is-potential-custom-element-name": "^1.0.1",
+        "nwsapi": "^2.2.2",
+        "parse5": "^7.1.1",
+        "saxes": "^6.0.0",
+        "symbol-tree": "^3.2.4",
+        "tough-cookie": "^4.1.2",
+        "w3c-xmlserializer": "^4.0.0",
+        "webidl-conversions": "^7.0.0",
+        "whatwg-encoding": "^2.0.0",
+        "whatwg-mimetype": "^3.0.0",
+        "whatwg-url": "^11.0.0",
+        "ws": "^8.11.0",
+        "xml-name-validator": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "peerDependencies": {
+        "canvas": "^2.5.0"
+      },
+      "peerDependenciesMeta": {
+        "canvas": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/jest-environment-jsdom/node_modules/parse5": {
+      "version": "7.2.1",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz",
+      "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==",
+      "dev": true,
+      "dependencies": {
+        "entities": "^4.5.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/jest-environment-jsdom/node_modules/tough-cookie": {
+      "version": "4.1.4",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
+      "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
+      "dev": true,
+      "dependencies": {
+        "psl": "^1.1.33",
+        "punycode": "^2.1.1",
+        "universalify": "^0.2.0",
+        "url-parse": "^1.5.3"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/jest-environment-jsdom/node_modules/tr46": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
+      "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
+      "dev": true,
+      "dependencies": {
+        "punycode": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/jest-environment-jsdom/node_modules/universalify": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
+      "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4.0.0"
+      }
+    },
+    "node_modules/jest-environment-jsdom/node_modules/w3c-xmlserializer": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
+      "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==",
+      "dev": true,
+      "dependencies": {
+        "xml-name-validator": "^4.0.0"
       },
       "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/chalk?sponsor=1"
+        "node": ">=14"
       }
     },
-    "node_modules/jest-each/node_modules/color-convert": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+    "node_modules/jest-environment-jsdom/node_modules/webidl-conversions": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
+      "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/jest-environment-jsdom/node_modules/whatwg-encoding": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
+      "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
       "dev": true,
       "dependencies": {
-        "color-name": "~1.1.4"
+        "iconv-lite": "0.6.3"
       },
       "engines": {
-        "node": ">=7.0.0"
+        "node": ">=12"
       }
     },
-    "node_modules/jest-each/node_modules/color-name": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-      "dev": true
-    },
-    "node_modules/jest-each/node_modules/has-flag": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+    "node_modules/jest-environment-jsdom/node_modules/whatwg-mimetype": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
+      "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
       "dev": true,
       "engines": {
-        "node": ">=8"
+        "node": ">=12"
       }
     },
-    "node_modules/jest-each/node_modules/supports-color": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+    "node_modules/jest-environment-jsdom/node_modules/whatwg-url": {
+      "version": "11.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
+      "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
       "dev": true,
       "dependencies": {
-        "has-flag": "^4.0.0"
+        "tr46": "^3.0.0",
+        "webidl-conversions": "^7.0.0"
       },
       "engines": {
-        "node": ">=8"
+        "node": ">=12"
       }
     },
-    "node_modules/jest-environment-jsdom": {
-      "version": "29.7.0",
-      "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz",
-      "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==",
+    "node_modules/jest-environment-jsdom/node_modules/xml-name-validator": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
+      "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
       "dev": true,
-      "dependencies": {
-        "@jest/environment": "^29.7.0",
-        "@jest/fake-timers": "^29.7.0",
-        "@jest/types": "^29.6.3",
-        "@types/jsdom": "^20.0.0",
-        "@types/node": "*",
-        "jest-mock": "^29.7.0",
-        "jest-util": "^29.7.0",
-        "jsdom": "^20.0.0"
-      },
       "engines": {
-        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-      },
-      "peerDependencies": {
-        "canvas": "^2.5.0"
-      },
-      "peerDependenciesMeta": {
-        "canvas": {
-          "optional": true
-        }
+        "node": ">=12"
       }
     },
     "node_modules/jest-environment-node": {
@@ -8368,43 +8675,38 @@
       }
     },
     "node_modules/jsdom": {
-      "version": "20.0.3",
-      "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz",
-      "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==",
+      "version": "25.0.1",
+      "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz",
+      "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==",
       "dev": true,
       "dependencies": {
-        "abab": "^2.0.6",
-        "acorn": "^8.8.1",
-        "acorn-globals": "^7.0.0",
-        "cssom": "^0.5.0",
-        "cssstyle": "^2.3.0",
-        "data-urls": "^3.0.2",
-        "decimal.js": "^10.4.2",
-        "domexception": "^4.0.0",
-        "escodegen": "^2.0.0",
+        "cssstyle": "^4.1.0",
+        "data-urls": "^5.0.0",
+        "decimal.js": "^10.4.3",
         "form-data": "^4.0.0",
-        "html-encoding-sniffer": "^3.0.0",
-        "http-proxy-agent": "^5.0.0",
-        "https-proxy-agent": "^5.0.1",
+        "html-encoding-sniffer": "^4.0.0",
+        "http-proxy-agent": "^7.0.2",
+        "https-proxy-agent": "^7.0.5",
         "is-potential-custom-element-name": "^1.0.1",
-        "nwsapi": "^2.2.2",
-        "parse5": "^7.1.1",
+        "nwsapi": "^2.2.12",
+        "parse5": "^7.1.2",
+        "rrweb-cssom": "^0.7.1",
         "saxes": "^6.0.0",
         "symbol-tree": "^3.2.4",
-        "tough-cookie": "^4.1.2",
-        "w3c-xmlserializer": "^4.0.0",
+        "tough-cookie": "^5.0.0",
+        "w3c-xmlserializer": "^5.0.0",
         "webidl-conversions": "^7.0.0",
-        "whatwg-encoding": "^2.0.0",
-        "whatwg-mimetype": "^3.0.0",
-        "whatwg-url": "^11.0.0",
-        "ws": "^8.11.0",
-        "xml-name-validator": "^4.0.0"
+        "whatwg-encoding": "^3.1.1",
+        "whatwg-mimetype": "^4.0.0",
+        "whatwg-url": "^14.0.0",
+        "ws": "^8.18.0",
+        "xml-name-validator": "^5.0.0"
       },
       "engines": {
-        "node": ">=14"
+        "node": ">=18"
       },
       "peerDependencies": {
-        "canvas": "^2.5.0"
+        "canvas": "^2.11.2"
       },
       "peerDependenciesMeta": {
         "canvas": {
@@ -8412,45 +8714,6 @@
         }
       }
     },
-    "node_modules/jsdom/node_modules/agent-base": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
-      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
-      "dev": true,
-      "dependencies": {
-        "debug": "4"
-      },
-      "engines": {
-        "node": ">= 6.0.0"
-      }
-    },
-    "node_modules/jsdom/node_modules/http-proxy-agent": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
-      "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
-      "dev": true,
-      "dependencies": {
-        "@tootallnate/once": "2",
-        "agent-base": "6",
-        "debug": "4"
-      },
-      "engines": {
-        "node": ">= 6"
-      }
-    },
-    "node_modules/jsdom/node_modules/https-proxy-agent": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
-      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
-      "dev": true,
-      "dependencies": {
-        "agent-base": "6",
-        "debug": "4"
-      },
-      "engines": {
-        "node": ">= 6"
-      }
-    },
     "node_modules/jsdom/node_modules/parse5": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.0.tgz",
@@ -8464,15 +8727,15 @@
       }
     },
     "node_modules/jsdom/node_modules/tr46": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
-      "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
+      "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
       "dev": true,
       "dependencies": {
-        "punycode": "^2.1.1"
+        "punycode": "^2.3.1"
       },
       "engines": {
-        "node": ">=12"
+        "node": ">=18"
       }
     },
     "node_modules/jsdom/node_modules/webidl-conversions": {
@@ -8485,16 +8748,16 @@
       }
     },
     "node_modules/jsdom/node_modules/whatwg-url": {
-      "version": "11.0.0",
-      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
-      "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz",
+      "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==",
       "dev": true,
       "dependencies": {
-        "tr46": "^3.0.0",
+        "tr46": "^5.0.0",
         "webidl-conversions": "^7.0.0"
       },
       "engines": {
-        "node": ">=12"
+        "node": ">=18"
       }
     },
     "node_modules/jsesc": {
@@ -8810,6 +9073,12 @@
       "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
       "dev": true
     },
+    "node_modules/make-error": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+      "dev": true
+    },
     "node_modules/makeerror": {
       "version": "1.0.12",
       "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
@@ -11958,9 +12227,9 @@
       }
     },
     "node_modules/picocolors": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
-      "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
       "dev": true
     },
     "node_modules/picomatch": {
@@ -11986,9 +12255,9 @@
       }
     },
     "node_modules/pirates": {
-      "version": "4.0.5",
-      "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
-      "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
+      "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
       "dev": true,
       "engines": {
         "node": ">= 6"
@@ -12233,9 +12502,9 @@
       "dev": true
     },
     "node_modules/punycode": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
-      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
       "dev": true,
       "engines": {
         "node": ">=6"
@@ -12419,15 +12688,16 @@
       }
     },
     "node_modules/readdirp": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
-      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz",
+      "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==",
       "dev": true,
-      "dependencies": {
-        "picomatch": "^2.2.1"
-      },
       "engines": {
-        "node": ">=8.10.0"
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://paulmillr.com/funding/"
       }
     },
     "node_modules/registry-auth-token": {
@@ -12515,9 +12785,9 @@
       }
     },
     "node_modules/rollup": {
-      "version": "4.22.5",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.5.tgz",
-      "integrity": "sha512-WoinX7GeQOFMGznEcWA1WrTQCd/tpEbMkc3nuMs9BT0CPjMdSjPMTVClwWd4pgSQwJdP65SK9mTCNvItlr5o7w==",
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.3.tgz",
+      "integrity": "sha512-HBW896xR5HGmoksbi3JBDtmVzWiPAYqp7wip50hjQ67JbDz61nyoMPdqu1DvVW9asYb2M65Z20ZHsyJCMqMyDg==",
       "dev": true,
       "dependencies": {
         "@types/estree": "1.0.6"
@@ -12530,25 +12800,33 @@
         "npm": ">=8.0.0"
       },
       "optionalDependencies": {
-        "@rollup/rollup-android-arm-eabi": "4.22.5",
-        "@rollup/rollup-android-arm64": "4.22.5",
-        "@rollup/rollup-darwin-arm64": "4.22.5",
-        "@rollup/rollup-darwin-x64": "4.22.5",
-        "@rollup/rollup-linux-arm-gnueabihf": "4.22.5",
-        "@rollup/rollup-linux-arm-musleabihf": "4.22.5",
-        "@rollup/rollup-linux-arm64-gnu": "4.22.5",
-        "@rollup/rollup-linux-arm64-musl": "4.22.5",
-        "@rollup/rollup-linux-powerpc64le-gnu": "4.22.5",
-        "@rollup/rollup-linux-riscv64-gnu": "4.22.5",
-        "@rollup/rollup-linux-s390x-gnu": "4.22.5",
-        "@rollup/rollup-linux-x64-gnu": "4.22.5",
-        "@rollup/rollup-linux-x64-musl": "4.22.5",
-        "@rollup/rollup-win32-arm64-msvc": "4.22.5",
-        "@rollup/rollup-win32-ia32-msvc": "4.22.5",
-        "@rollup/rollup-win32-x64-msvc": "4.22.5",
+        "@rollup/rollup-android-arm-eabi": "4.24.3",
+        "@rollup/rollup-android-arm64": "4.24.3",
+        "@rollup/rollup-darwin-arm64": "4.24.3",
+        "@rollup/rollup-darwin-x64": "4.24.3",
+        "@rollup/rollup-freebsd-arm64": "4.24.3",
+        "@rollup/rollup-freebsd-x64": "4.24.3",
+        "@rollup/rollup-linux-arm-gnueabihf": "4.24.3",
+        "@rollup/rollup-linux-arm-musleabihf": "4.24.3",
+        "@rollup/rollup-linux-arm64-gnu": "4.24.3",
+        "@rollup/rollup-linux-arm64-musl": "4.24.3",
+        "@rollup/rollup-linux-powerpc64le-gnu": "4.24.3",
+        "@rollup/rollup-linux-riscv64-gnu": "4.24.3",
+        "@rollup/rollup-linux-s390x-gnu": "4.24.3",
+        "@rollup/rollup-linux-x64-gnu": "4.24.3",
+        "@rollup/rollup-linux-x64-musl": "4.24.3",
+        "@rollup/rollup-win32-arm64-msvc": "4.24.3",
+        "@rollup/rollup-win32-ia32-msvc": "4.24.3",
+        "@rollup/rollup-win32-x64-msvc": "4.24.3",
         "fsevents": "~2.3.2"
       }
     },
+    "node_modules/rrweb-cssom": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz",
+      "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==",
+      "dev": true
+    },
     "node_modules/run-parallel": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -13689,13 +13967,19 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/tinyexec": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.1.tgz",
+      "integrity": "sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==",
+      "dev": true
+    },
     "node_modules/tinyglobby": {
-      "version": "0.2.6",
-      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.6.tgz",
-      "integrity": "sha512-NbBoFBpqfcgd1tCiO8Lkfdk+xrA7mlLR9zgvZcZWQQwU63XAfUePyd6wZBaU93Hqw347lHnwFzttAkemHzzz4g==",
+      "version": "0.2.10",
+      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.10.tgz",
+      "integrity": "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==",
       "dev": true,
       "dependencies": {
-        "fdir": "^6.3.0",
+        "fdir": "^6.4.2",
         "picomatch": "^4.0.2"
       },
       "engines": {
@@ -13703,9 +13987,9 @@
       }
     },
     "node_modules/tinyglobby/node_modules/fdir": {
-      "version": "6.3.0",
-      "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.3.0.tgz",
-      "integrity": "sha512-QOnuT+BOtivR77wYvCWHfGt9s4Pz1VIMbD463vegT5MLqNXy8rYFT/lPVEqf/bhYeT6qmqrNHhsX+rWwe3rOCQ==",
+      "version": "6.4.2",
+      "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.2.tgz",
+      "integrity": "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==",
       "dev": true,
       "peerDependencies": {
         "picomatch": "^3 || ^4"
@@ -13728,6 +14012,24 @@
         "url": "https://github.com/sponsors/jonschlinkert"
       }
     },
+    "node_modules/tldts": {
+      "version": "6.1.56",
+      "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.56.tgz",
+      "integrity": "sha512-2PT1oRZCxtsbLi5R2SQjE/v4vvgRggAtVcYj+3Rrcnu2nPZvu7m64+gDa/EsVSWd3QzEc0U0xN+rbEKsJC47kA==",
+      "dev": true,
+      "dependencies": {
+        "tldts-core": "^6.1.56"
+      },
+      "bin": {
+        "tldts": "bin/cli.js"
+      }
+    },
+    "node_modules/tldts-core": {
+      "version": "6.1.56",
+      "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.56.tgz",
+      "integrity": "sha512-Ihxv/Bwiyj73icTYVgBUkQ3wstlCglLoegSgl64oSrGUBX1hc7Qmf/CnrnJLaQdZrCnTaLqMYOwKMKlkfkFrxQ==",
+      "dev": true
+    },
     "node_modules/tmpl": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
@@ -13756,27 +14058,15 @@
       }
     },
     "node_modules/tough-cookie": {
-      "version": "4.1.4",
-      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
-      "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz",
+      "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==",
       "dev": true,
       "dependencies": {
-        "psl": "^1.1.33",
-        "punycode": "^2.1.1",
-        "universalify": "^0.2.0",
-        "url-parse": "^1.5.3"
+        "tldts": "^6.1.32"
       },
       "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/tough-cookie/node_modules/universalify": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
-      "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
-      "dev": true,
-      "engines": {
-        "node": ">= 4.0.0"
+        "node": ">=16"
       }
     },
     "node_modules/tr46": {
@@ -13811,9 +14101,9 @@
       }
     },
     "node_modules/ts-api-utils": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
-      "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz",
+      "integrity": "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==",
       "dev": true,
       "engines": {
         "node": ">=16"
@@ -13828,27 +14118,70 @@
       "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
       "dev": true
     },
+    "node_modules/ts-node": {
+      "version": "10.9.2",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
+      "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
+      "dev": true,
+      "dependencies": {
+        "@cspotcode/source-map-support": "^0.8.0",
+        "@tsconfig/node10": "^1.0.7",
+        "@tsconfig/node12": "^1.0.7",
+        "@tsconfig/node14": "^1.0.0",
+        "@tsconfig/node16": "^1.0.2",
+        "acorn": "^8.4.1",
+        "acorn-walk": "^8.1.1",
+        "arg": "^4.1.0",
+        "create-require": "^1.1.0",
+        "diff": "^4.0.1",
+        "make-error": "^1.1.1",
+        "v8-compile-cache-lib": "^3.0.1",
+        "yn": "3.1.1"
+      },
+      "bin": {
+        "ts-node": "dist/bin.js",
+        "ts-node-cwd": "dist/bin-cwd.js",
+        "ts-node-esm": "dist/bin-esm.js",
+        "ts-node-script": "dist/bin-script.js",
+        "ts-node-transpile-only": "dist/bin-transpile.js",
+        "ts-script": "dist/bin-script-deprecated.js"
+      },
+      "peerDependencies": {
+        "@swc/core": ">=1.2.50",
+        "@swc/wasm": ">=1.2.50",
+        "@types/node": "*",
+        "typescript": ">=2.7"
+      },
+      "peerDependenciesMeta": {
+        "@swc/core": {
+          "optional": true
+        },
+        "@swc/wasm": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/tsup": {
-      "version": "8.3.0",
-      "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.3.0.tgz",
-      "integrity": "sha512-ALscEeyS03IomcuNdFdc0YWGVIkwH1Ws7nfTbAPuoILvEV2hpGQAY72LIOjglGo4ShWpZfpBqP/jpQVCzqYQag==",
+      "version": "8.3.5",
+      "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.3.5.tgz",
+      "integrity": "sha512-Tunf6r6m6tnZsG9GYWndg0z8dEV7fD733VBFzFJ5Vcm1FtlXB8xBD/rtrBi2a3YKEV7hHtxiZtW5EAVADoe1pA==",
       "dev": true,
       "dependencies": {
         "bundle-require": "^5.0.0",
         "cac": "^6.7.14",
-        "chokidar": "^3.6.0",
+        "chokidar": "^4.0.1",
         "consola": "^3.2.3",
-        "debug": "^4.3.5",
-        "esbuild": "^0.23.0",
-        "execa": "^5.1.1",
+        "debug": "^4.3.7",
+        "esbuild": "^0.24.0",
         "joycon": "^3.1.1",
-        "picocolors": "^1.0.1",
+        "picocolors": "^1.1.1",
         "postcss-load-config": "^6.0.1",
         "resolve-from": "^5.0.0",
-        "rollup": "^4.19.0",
+        "rollup": "^4.24.0",
         "source-map": "0.8.0-beta.0",
         "sucrase": "^3.35.0",
-        "tinyglobby": "^0.2.1",
+        "tinyexec": "^0.3.1",
+        "tinyglobby": "^0.2.9",
         "tree-kill": "^1.2.2"
       },
       "bin": {
@@ -13925,9 +14258,9 @@
       }
     },
     "node_modules/typescript": {
-      "version": "5.6.2",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
-      "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
+      "version": "5.6.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
+      "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
       "dev": true,
       "bin": {
         "tsc": "bin/tsc",
@@ -13938,14 +14271,14 @@
       }
     },
     "node_modules/typescript-eslint": {
-      "version": "8.7.0",
-      "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.7.0.tgz",
-      "integrity": "sha512-nEHbEYJyHwsuf7c3V3RS7Saq+1+la3i0ieR3qP0yjqWSzVmh8Drp47uOl9LjbPANac4S7EFSqvcYIKXUUwIfIQ==",
+      "version": "8.12.2",
+      "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.12.2.tgz",
+      "integrity": "sha512-UbuVUWSrHVR03q9CWx+JDHeO6B/Hr9p4U5lRH++5tq/EbFq1faYZe50ZSBePptgfIKLEti0aPQ3hFgnPVcd8ZQ==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/eslint-plugin": "8.7.0",
-        "@typescript-eslint/parser": "8.7.0",
-        "@typescript-eslint/utils": "8.7.0"
+        "@typescript-eslint/eslint-plugin": "8.12.2",
+        "@typescript-eslint/parser": "8.12.2",
+        "@typescript-eslint/utils": "8.12.2"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -14091,6 +14424,12 @@
       "dev": true,
       "peer": true
     },
+    "node_modules/v8-compile-cache-lib": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+      "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
+      "dev": true
+    },
     "node_modules/v8-to-istanbul": {
       "version": "9.2.0",
       "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz",
@@ -14116,15 +14455,15 @@
       }
     },
     "node_modules/w3c-xmlserializer": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
-      "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
+      "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
       "dev": true,
       "dependencies": {
-        "xml-name-validator": "^4.0.0"
+        "xml-name-validator": "^5.0.0"
       },
       "engines": {
-        "node": ">=14"
+        "node": ">=18"
       }
     },
     "node_modules/walker": {
@@ -14254,24 +14593,24 @@
       "peer": true
     },
     "node_modules/whatwg-encoding": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
-      "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
+      "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
       "dev": true,
       "dependencies": {
         "iconv-lite": "0.6.3"
       },
       "engines": {
-        "node": ">=12"
+        "node": ">=18"
       }
     },
     "node_modules/whatwg-mimetype": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
-      "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+      "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
       "dev": true,
       "engines": {
-        "node": ">=12"
+        "node": ">=18"
       }
     },
     "node_modules/whatwg-url": {
@@ -14458,12 +14797,12 @@
       }
     },
     "node_modules/xml-name-validator": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
-      "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
+      "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
       "dev": true,
       "engines": {
-        "node": ">=12"
+        "node": ">=18"
       }
     },
     "node_modules/xmlchars": {
@@ -14524,6 +14863,15 @@
         "node": ">=12"
       }
     },
+    "node_modules/yn": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+      "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/yocto-queue": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/package.json b/package.json
index 37e1a83..ac1dee5 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,7 @@
 {
   "name": "@donedeal0/superdiff",
-  "version": "3.0.0",
+  "version": "3.1.0",
+  "type": "module",
   "description": "SuperDiff compares two arrays or objects and returns a full diff of their differences",
   "main": "dist/index.js",
   "module": "dist/index.mjs",
@@ -9,6 +10,18 @@
   "files": [
     "dist"
   ],
+  "exports": {
+    ".": {
+      "import": "./dist/index.mjs",
+      "require": "./dist/index.js"
+    },
+    "./client": {
+      "default": "./dist/client.mjs"
+    },
+    "./server": {
+      "default": "./dist/server.cjs"
+    }
+  },
   "author": "DoneDeal0",
   "license": "ISC",
   "repository": {
@@ -60,6 +73,11 @@
     "object",
     "diff",
     "deep-diff",
+    "json-diff",
+    "files diff",
+    "json",
+    "file",
+    "isobject",
     "comparison",
     "compare",
     "stream",
@@ -73,28 +91,31 @@
     "lint:dead-code": "npx -p typescript@latest -p knip knip",
     "lint": "eslint --cache --max-warnings=0 --fix",
     "prepare": "husky",
-    "test": "jest",
+    "transpile": "node scripts/transpile-node-worker.js",
+    "test": "npm run transpile && jest",
     "tsc": "tsc --noEmit --incremental"
   },
   "devDependencies": {
-    "@eslint/js": "^9.11.1",
+    "@eslint/js": "^9.14.0",
     "@semantic-release/exec": "^6.0.3",
     "@semantic-release/git": "^10.0.1",
     "@semantic-release/github": "^11.0.0",
     "@semantic-release/npm": "^12.0.1",
-    "@swc/core": "^1.7.26",
-    "@swc/jest": "^0.2.36",
-    "@types/jest": "^29.5.13",
+    "@swc/core": "^1.7.42",
+    "@swc/jest": "^0.2.37",
+    "@types/jest": "^29.5.14",
     "blob-polyfill": "^9.0.20240710",
-    "eslint": "^9.11.1",
+    "eslint": "^9.14.0",
     "husky": "^9.1.6",
     "jest": "^29.7.0",
     "jest-environment-jsdom": "^29.7.0",
+    "jsdom": "^25.0.1",
     "prettier": "^3.3.3",
     "swc-loader": "^0.2.6",
-    "tsup": "^8.3.0",
-    "typescript": "^5.6.2",
-    "typescript-eslint": "^8.7.0",
+    "ts-node": "^10.9.2",
+    "tsup": "^8.3.5",
+    "typescript": "^5.6.3",
+    "typescript-eslint": "^8.12.2",
     "web-streams-polyfill": "^4.0.0"
   }
 }
diff --git a/scripts/transpile-node-worker.js b/scripts/transpile-node-worker.js
new file mode 100644
index 0000000..fd2b12c
--- /dev/null
+++ b/scripts/transpile-node-worker.js
@@ -0,0 +1,17 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
+/* eslint-disable no-undef */
+import { execSync } from "child_process";
+import { existsSync } from "fs"
+
+// The src/lib/stream-list-diff/server/node-worker.ts file needs to be transpiled to a .cjs file to be used in the tests.
+const workerFile = "src/lib/stream-list-diff/server/worker/node-worker"
+
+try {
+  if(!existsSync(`${workerFile}.cjs`)){
+    execSync(`npx esbuild ${workerFile}.ts --bundle --platform=node --format=cjs --outfile=${workerFile}.cjs`, {
+      stdio: "inherit",
+    });
+  }
+} catch (_) {
+  process.exit(1);
+}
\ No newline at end of file
diff --git a/src/lib/list-diff/index.ts b/src/lib/list-diff/index.ts
index 065fde3..ae94065 100644
--- a/src/lib/list-diff/index.ts
+++ b/src/lib/list-diff/index.ts
@@ -1,10 +1,10 @@
+import { isEqual, isObject } from "@lib/utils";
 import {
   DEFAULT_LIST_DIFF_OPTIONS,
-  LIST_STATUS,
+  ListStatus,
   ListDiff,
   ListDiffOptions,
 } from "@models/list";
-import { isEqual, isObject } from "@lib/utils";
 
 function getLeanDiff(
   diff: ListDiff["diff"],
@@ -15,13 +15,13 @@ function getLeanDiff(
 
 function formatSingleListDiff<T>(
   listData: T[],
-  status: LIST_STATUS,
+  status: ListStatus,
   options: ListDiffOptions = { showOnly: [] },
 ): ListDiff {
   const diff = listData.map((data, i) => ({
     value: data,
-    prevIndex: status === LIST_STATUS.ADDED ? null : i,
-    newIndex: status === LIST_STATUS.ADDED ? i : null,
+    prevIndex: status === ListStatus.ADDED ? null : i,
+    newIndex: status === ListStatus.ADDED ? i : null,
     indexDiff: null,
     status,
   }));
@@ -39,10 +39,10 @@ function formatSingleListDiff<T>(
   };
 }
 
-function getListStatus(listDiff: ListDiff["diff"]): LIST_STATUS {
-  return listDiff.some((value) => value.status !== LIST_STATUS.EQUAL)
-    ? LIST_STATUS.UPDATED
-    : LIST_STATUS.EQUAL;
+function getListStatus(listDiff: ListDiff["diff"]): ListStatus {
+  return listDiff.some((value) => value.status !== ListStatus.EQUAL)
+    ? ListStatus.UPDATED
+    : ListStatus.EQUAL;
 }
 
 function isReferencedObject(
@@ -72,15 +72,15 @@ export const getListDiff = <T>(
   if (!prevList && !nextList) {
     return {
       type: "list",
-      status: LIST_STATUS.EQUAL,
+      status: ListStatus.EQUAL,
       diff: [],
     };
   }
   if (!prevList) {
-    return formatSingleListDiff(nextList as T[], LIST_STATUS.ADDED, options);
+    return formatSingleListDiff(nextList as T[], ListStatus.ADDED, options);
   }
   if (!nextList) {
-    return formatSingleListDiff(prevList as T[], LIST_STATUS.DELETED, options);
+    return formatSingleListDiff(prevList as T[], ListStatus.DELETED, options);
   }
   const diff: ListDiff["diff"] = [];
   const prevIndexMatches = new Set<number>();
@@ -106,10 +106,10 @@ export const getListDiff = <T>(
     }
     const indexDiff = prevIndex === -1 ? null : i - prevIndex;
     if (indexDiff === 0 || options.ignoreArrayOrder) {
-      let nextStatus = LIST_STATUS.EQUAL;
+      let nextStatus = ListStatus.EQUAL;
       if (isReferencedObject(nextValue, options.referenceProperty)) {
         if (!isEqual(prevList[prevIndex], nextValue)) {
-          nextStatus = LIST_STATUS.UPDATED;
+          nextStatus = ListStatus.UPDATED;
         }
       }
       return diff.push({
@@ -126,7 +126,7 @@ export const getListDiff = <T>(
         prevIndex: null,
         newIndex: i,
         indexDiff,
-        status: LIST_STATUS.ADDED,
+        status: ListStatus.ADDED,
       });
     }
     return diff.push({
@@ -135,8 +135,8 @@ export const getListDiff = <T>(
       newIndex: i,
       indexDiff,
       status: options.considerMoveAsUpdate
-        ? LIST_STATUS.UPDATED
-        : LIST_STATUS.MOVED,
+        ? ListStatus.UPDATED
+        : ListStatus.MOVED,
     });
   });
 
@@ -147,7 +147,7 @@ export const getListDiff = <T>(
         prevIndex: i,
         newIndex: null,
         indexDiff: null,
-        status: LIST_STATUS.DELETED,
+        status: ListStatus.DELETED,
       });
     }
   });
diff --git a/src/lib/list-diff/list-diff.test.ts b/src/lib/list-diff/list-diff.test.ts
index 94ed606..c8f90e6 100644
--- a/src/lib/list-diff/list-diff.test.ts
+++ b/src/lib/list-diff/list-diff.test.ts
@@ -1,5 +1,5 @@
+import { ListStatus } from "@models/list";
 import { getListDiff } from ".";
-import { LIST_STATUS } from "@models/list";
 
 describe("getListDiff", () => {
   it("returns an empty diff if no lists are provided", () => {
@@ -418,7 +418,7 @@ describe("getListDiff", () => {
           false,
           { name: "joe", age: 88 },
         ],
-        { showOnly: [LIST_STATUS.ADDED, LIST_STATUS.DELETED] },
+        { showOnly: [ListStatus.ADDED, ListStatus.DELETED] },
       ),
     ).toStrictEqual({
       type: "list",
@@ -463,7 +463,7 @@ describe("getListDiff", () => {
     });
     expect(
       getListDiff(["mbappe", "mendes", "verratti", "ruiz"], null, {
-        showOnly: [LIST_STATUS.MOVED, LIST_STATUS.UPDATED],
+        showOnly: [ListStatus.MOVED, ListStatus.UPDATED],
       }),
     ).toStrictEqual({
       type: "list",
@@ -474,7 +474,7 @@ describe("getListDiff", () => {
   it("returns all values if their status match the required statuses", () => {
     expect(
       getListDiff(null, ["mbappe", "mendes", "verratti", "ruiz"], {
-        showOnly: [LIST_STATUS.ADDED],
+        showOnly: [ListStatus.ADDED],
       }),
     ).toStrictEqual({
       type: "list",
diff --git a/src/lib/object-diff/index.ts b/src/lib/object-diff/index.ts
index af03b4b..b5acb23 100644
--- a/src/lib/object-diff/index.ts
+++ b/src/lib/object-diff/index.ts
@@ -1,13 +1,13 @@
+import { isEqual, isObject } from "@lib/utils";
 import {
-  GRANULARITY,
-  OBJECT_STATUS,
+  Granularity,
+  ObjectStatus,
   ObjectData,
   ObjectDiff,
   ObjectDiffOptions,
   Diff,
   DEFAULT_OBJECT_DIFF_OPTIONS,
 } from "@models/object";
-import { isEqual, isObject } from "@lib/utils";
 
 function getLeanDiff(
   diff: ObjectDiff["diff"],
@@ -17,7 +17,7 @@ function getLeanDiff(
   const res: ObjectDiff["diff"] = [];
   for (let i = 0; i < diff.length; i++) {
     const value = diff[i];
-    if (granularity === GRANULARITY.DEEP && value.diff) {
+    if (granularity === Granularity.DEEP && value.diff) {
       const leanDiff = getLeanDiff(value.diff, showOnly);
       if (leanDiff.length > 0) {
         res.push({ ...value, diff: leanDiff });
@@ -29,21 +29,21 @@ function getLeanDiff(
   return res;
 }
 
-function getObjectStatus(diff: ObjectDiff["diff"]): OBJECT_STATUS {
-  return diff.some((property) => property.status !== OBJECT_STATUS.EQUAL)
-    ? OBJECT_STATUS.UPDATED
-    : OBJECT_STATUS.EQUAL;
+function getObjectStatus(diff: ObjectDiff["diff"]): ObjectStatus {
+  return diff.some((property) => property.status !== ObjectStatus.EQUAL)
+    ? ObjectStatus.UPDATED
+    : ObjectStatus.EQUAL;
 }
 
 function formatSingleObjectDiff(
   data: ObjectData,
-  status: OBJECT_STATUS,
+  status: ObjectStatus,
   options: ObjectDiffOptions = DEFAULT_OBJECT_DIFF_OPTIONS,
 ): ObjectDiff {
   if (!data) {
     return {
       type: "object",
-      status: OBJECT_STATUS.EQUAL,
+      status: ObjectStatus.EQUAL,
       diff: [],
     };
   }
@@ -55,16 +55,16 @@ function formatSingleObjectDiff(
       for (const [subProperty, subValue] of Object.entries(value)) {
         subPropertiesDiff.push({
           property: subProperty,
-          previousValue: status === OBJECT_STATUS.ADDED ? undefined : subValue,
-          currentValue: status === OBJECT_STATUS.ADDED ? subValue : undefined,
+          previousValue: status === ObjectStatus.ADDED ? undefined : subValue,
+          currentValue: status === ObjectStatus.ADDED ? subValue : undefined,
           status,
         });
       }
       diff.push({
         property,
         previousValue:
-          status === OBJECT_STATUS.ADDED ? undefined : data[property],
-        currentValue: status === OBJECT_STATUS.ADDED ? value : undefined,
+          status === ObjectStatus.ADDED ? undefined : data[property],
+        currentValue: status === ObjectStatus.ADDED ? value : undefined,
         status,
         diff: subPropertiesDiff,
       });
@@ -72,8 +72,8 @@ function formatSingleObjectDiff(
       diff.push({
         property,
         previousValue:
-          status === OBJECT_STATUS.ADDED ? undefined : data[property],
-        currentValue: status === OBJECT_STATUS.ADDED ? value : undefined,
+          status === ObjectStatus.ADDED ? undefined : data[property],
+        currentValue: status === ObjectStatus.ADDED ? value : undefined,
         status,
       });
     }
@@ -97,11 +97,11 @@ function getValueStatus(
   previousValue: unknown,
   nextValue: unknown,
   options?: ObjectDiffOptions,
-): OBJECT_STATUS {
+): ObjectStatus {
   if (isEqual(previousValue, nextValue, options)) {
-    return OBJECT_STATUS.EQUAL;
+    return ObjectStatus.EQUAL;
   }
-  return OBJECT_STATUS.UPDATED;
+  return ObjectStatus.UPDATED;
 }
 
 function getDiff(
@@ -123,7 +123,7 @@ function getDiff(
         property,
         previousValue: prevSubValue,
         currentValue: undefined,
-        status: OBJECT_STATUS.DELETED,
+        status: ObjectStatus.DELETED,
       });
       continue;
     }
@@ -132,20 +132,20 @@ function getDiff(
         property,
         previousValue: undefined,
         currentValue: nextSubValue,
-        status: OBJECT_STATUS.ADDED,
+        status: ObjectStatus.ADDED,
       });
       continue;
     }
     if (isObject(nextSubValue) && isObject(prevSubValue)) {
       const subDiff = getDiff(prevSubValue, nextSubValue, options);
       const isUpdated = subDiff.some(
-        (entry) => entry.status !== OBJECT_STATUS.EQUAL,
+        (entry) => entry.status !== ObjectStatus.EQUAL,
       );
       diff.push({
         property,
         previousValue: prevSubValue,
         currentValue: nextSubValue,
-        status: isUpdated ? OBJECT_STATUS.UPDATED : OBJECT_STATUS.EQUAL,
+        status: isUpdated ? ObjectStatus.UPDATED : ObjectStatus.EQUAL,
         ...(isUpdated && { diff: subDiff }),
       });
     } else {
@@ -180,15 +180,15 @@ export function getObjectDiff(
   if (!prevData && !nextData) {
     return {
       type: "object",
-      status: OBJECT_STATUS.EQUAL,
+      status: ObjectStatus.EQUAL,
       diff: [],
     };
   }
   if (!prevData) {
-    return formatSingleObjectDiff(nextData, OBJECT_STATUS.ADDED, options);
+    return formatSingleObjectDiff(nextData, ObjectStatus.ADDED, options);
   }
   if (!nextData) {
-    return formatSingleObjectDiff(prevData, OBJECT_STATUS.DELETED, options);
+    return formatSingleObjectDiff(prevData, ObjectStatus.DELETED, options);
   }
   const diff: ObjectDiff["diff"] = getDiff(prevData, nextData, options);
   const status = getObjectStatus(diff);
diff --git a/src/lib/object-diff/object-diff.test.ts b/src/lib/object-diff/object-diff.test.ts
index 78fea53..6efef72 100644
--- a/src/lib/object-diff/object-diff.test.ts
+++ b/src/lib/object-diff/object-diff.test.ts
@@ -1,4 +1,4 @@
-import { GRANULARITY, OBJECT_STATUS } from "@models/object";
+import { Granularity, ObjectStatus } from "@models/object";
 import { getObjectDiff } from ".";
 
 describe("getObjectDiff", () => {
@@ -51,8 +51,8 @@ describe("getObjectDiff", () => {
         null,
         {
           showOnly: {
-            statuses: [OBJECT_STATUS.ADDED],
-            granularity: GRANULARITY.DEEP,
+            statuses: [ObjectStatus.ADDED],
+            granularity: Granularity.DEEP,
           },
         },
       ),
@@ -509,7 +509,7 @@ describe("getObjectDiff", () => {
             nickname: "super joe",
           },
         },
-        { showOnly: { statuses: [OBJECT_STATUS.ADDED] } },
+        { showOnly: { statuses: [ObjectStatus.ADDED] } },
       ),
     ).toStrictEqual({
       type: "object",
@@ -549,8 +549,8 @@ describe("getObjectDiff", () => {
         },
         {
           showOnly: {
-            statuses: [OBJECT_STATUS.ADDED, OBJECT_STATUS.DELETED],
-            granularity: GRANULARITY.DEEP,
+            statuses: [ObjectStatus.ADDED, ObjectStatus.DELETED],
+            granularity: Granularity.DEEP,
           },
         },
       ),
@@ -634,8 +634,8 @@ describe("getObjectDiff", () => {
         },
         {
           showOnly: {
-            statuses: [OBJECT_STATUS.UPDATED],
-            granularity: GRANULARITY.DEEP,
+            statuses: [ObjectStatus.UPDATED],
+            granularity: Granularity.DEEP,
           },
         },
       ),
@@ -742,8 +742,8 @@ describe("getObjectDiff", () => {
         },
         {
           showOnly: {
-            statuses: [OBJECT_STATUS.ADDED],
-            granularity: GRANULARITY.DEEP,
+            statuses: [ObjectStatus.ADDED],
+            granularity: Granularity.DEEP,
           },
         },
       ),
@@ -834,8 +834,8 @@ describe("getObjectDiff", () => {
         },
         {
           showOnly: {
-            statuses: [OBJECT_STATUS.DELETED],
-            granularity: GRANULARITY.DEEP,
+            statuses: [ObjectStatus.DELETED],
+            granularity: Granularity.DEEP,
           },
         },
       ),
@@ -850,7 +850,7 @@ describe("getObjectDiff", () => {
       getObjectDiff(
         { name: "joe", age: 54, hobbies: ["golf", "football"] },
         null,
-        { showOnly: { statuses: [OBJECT_STATUS.DELETED] } },
+        { showOnly: { statuses: [ObjectStatus.DELETED] } },
       ),
     ).toStrictEqual({
       type: "object",
diff --git a/src/lib/stream-list-diff/client/index.ts b/src/lib/stream-list-diff/client/index.ts
index d35ae98..7af43a2 100644
--- a/src/lib/stream-list-diff/client/index.ts
+++ b/src/lib/stream-list-diff/client/index.ts
@@ -1,24 +1,21 @@
+import { IEmitter, EmitterEvents, EventEmitter } from "@models/emitter";
 import {
   DataBuffer,
   DEFAULT_LIST_STREAM_OPTIONS,
   ListStreamOptions,
   ReferenceProperty,
-} from "@models/stream";
-import { LIST_STATUS } from "@models/list";
-import {
-  Emitter,
-  EmitterEvents,
-  EventEmitter,
-  StreamListener,
   StreamEvent,
-} from "../emitter";
+  StreamListener,
+} from "@models/stream";
+import { ListStatus, ListType } from "@models/list";
 import { isDataValid, isValidChunkSize, outputDiffChunk } from "../utils";
+import { generateWorker } from "./worker/utils";
 
 async function getDiffChunks<T extends Record<string, unknown>>(
   prevStream: ReadableStream<T>,
   nextStream: ReadableStream<T>,
   referenceProperty: ReferenceProperty<T>,
-  emitter: Emitter<T>,
+  emitter: IEmitter<T>,
   options: ListStreamOptions = DEFAULT_LIST_STREAM_OPTIONS,
 ): Promise<void> {
   if (!isValidChunkSize(options?.chunksSize)) {
@@ -42,7 +39,7 @@ async function getDiffChunks<T extends Record<string, unknown>>(
     const { isValid, message } = isDataValid(
       chunk,
       referenceProperty,
-      "prevList",
+      ListType.PREV,
     );
     if (!isValid) {
       emitter.emit(StreamEvent.Error, new Error(message));
@@ -67,10 +64,10 @@ async function getDiffChunks<T extends Record<string, unknown>>(
             indexDiff,
             status:
               indexDiff === 0
-                ? LIST_STATUS.EQUAL
+                ? ListStatus.EQUAL
                 : options.considerMoveAsUpdate
-                  ? LIST_STATUS.UPDATED
-                  : LIST_STATUS.MOVED,
+                  ? ListStatus.UPDATED
+                  : ListStatus.MOVED,
           },
           options,
         );
@@ -82,7 +79,7 @@ async function getDiffChunks<T extends Record<string, unknown>>(
             prevIndex: currentPrevIndex,
             newIndex: relatedChunk.index,
             indexDiff,
-            status: LIST_STATUS.UPDATED,
+            status: ListStatus.UPDATED,
           },
           options,
         );
@@ -97,7 +94,7 @@ async function getDiffChunks<T extends Record<string, unknown>>(
     const { isValid, message } = isDataValid(
       chunk,
       referenceProperty,
-      "nextList",
+      ListType.NEXT,
     );
     if (!isValid) {
       emitter.emit(StreamEvent.Error, new Error(message));
@@ -122,10 +119,10 @@ async function getDiffChunks<T extends Record<string, unknown>>(
             indexDiff,
             status:
               indexDiff === 0
-                ? LIST_STATUS.EQUAL
+                ? ListStatus.EQUAL
                 : options.considerMoveAsUpdate
-                  ? LIST_STATUS.UPDATED
-                  : LIST_STATUS.MOVED,
+                  ? ListStatus.UPDATED
+                  : ListStatus.MOVED,
           },
           options,
         );
@@ -137,7 +134,7 @@ async function getDiffChunks<T extends Record<string, unknown>>(
             prevIndex: relatedChunk.index,
             newIndex: currentNextIndex,
             indexDiff,
-            status: LIST_STATUS.UPDATED,
+            status: ListStatus.UPDATED,
           },
           options,
         );
@@ -175,7 +172,7 @@ async function getDiffChunks<T extends Record<string, unknown>>(
         prevIndex: chunk.index,
         newIndex: null,
         indexDiff: null,
-        status: LIST_STATUS.DELETED,
+        status: ListStatus.DELETED,
       },
       options,
     );
@@ -189,7 +186,7 @@ async function getDiffChunks<T extends Record<string, unknown>>(
         prevIndex: null,
         newIndex: chunk.index,
         indexDiff: null,
-        status: LIST_STATUS.ADDED,
+        status: ListStatus.ADDED,
       },
       options,
     );
@@ -202,7 +199,7 @@ async function getDiffChunks<T extends Record<string, unknown>>(
 
 async function getValidClientStream<T extends Record<string, unknown>>(
   input: ReadableStream<T> | T[] | File,
-  listType: "prevList" | "nextList",
+  listType: ListType,
 ): Promise<ReadableStream<T>> {
   if (Array.isArray(input)) {
     return new ReadableStream({
@@ -243,6 +240,25 @@ async function getValidClientStream<T extends Record<string, unknown>>(
   );
 }
 
+export async function generateStream<T extends Record<string, unknown>>(
+  prevList: ReadableStream<T> | File | T[],
+  nextList: ReadableStream<T> | File | T[],
+  referenceProperty: ReferenceProperty<T>,
+  options: ListStreamOptions,
+  emitter: IEmitter<T>,
+): Promise<void> {
+  try {
+    const [prevStream, nextStream] = await Promise.all([
+      getValidClientStream(prevList, ListType.PREV),
+      getValidClientStream(nextList, ListType.NEXT),
+    ]);
+
+    getDiffChunks(prevStream, nextStream, referenceProperty, emitter, options);
+  } catch (err) {
+    return emitter.emit(StreamEvent.Error, err as Error);
+  }
+}
+
 /**
  * Streams the diff of two object lists
  * @param {ReadableStream | File | Record<string, unknown>[]} prevList - The original object list.
@@ -250,8 +266,10 @@ async function getValidClientStream<T extends Record<string, unknown>>(
  * @param {string} referenceProperty - A common property in all the objects of your lists (e.g. `id`)
  * @param {ListStreamOptions} options - Options to refine your output.
     - `chunksSize`: the number of object diffs returned by each streamed chunk. (e.g. `0` = 1 object diff by chunk, `10` = 10 object diffs by chunk).
-    - `showOnly`: returns only the values whose status you are interested in. (e.g. `["added", "equal"]`)
-    - `considerMoveAsUpdate`: if set to `true` a `moved` object will be considered as `updated`
+    - `showOnly`: returns only the values whose status you are interested in. (e.g. `["added", "equal"]`).
+    - `considerMoveAsUpdate`: if set to `true` a `moved` object will be considered as `updated`.
+    - `useWorker`: if set to `true`, the diff will be run in a worker. Recommended for maximum performance, `true` by default.
+    - `showWarnings`: if set to `true`, potential warnings will be displayed in the console. 
  * @returns StreamListener
  */
 export function streamListDiff<T extends Record<string, unknown>>(
@@ -261,23 +279,16 @@ export function streamListDiff<T extends Record<string, unknown>>(
   options: ListStreamOptions = DEFAULT_LIST_STREAM_OPTIONS,
 ): StreamListener<T> {
   const emitter = new EventEmitter<EmitterEvents<T>>();
-  setTimeout(async () => {
-    try {
-      const [prevStream, nextStream] = await Promise.all([
-        getValidClientStream(prevList, "prevList"),
-        getValidClientStream(nextList, "nextList"),
-      ]);
 
-      getDiffChunks(
-        prevStream,
-        nextStream,
-        referenceProperty,
-        emitter,
-        options,
-      );
-    } catch (err) {
-      return emitter.emit(StreamEvent.Error, err as Error);
-    }
-  }, 0);
+  if (typeof Worker === "undefined" || !options.useWorker) {
+    setTimeout(
+      () =>
+        generateStream(prevList, nextList, referenceProperty, options, emitter),
+      0,
+    );
+  } else {
+    generateWorker(prevList, nextList, referenceProperty, options, emitter);
+  }
+
   return emitter as StreamListener<T>;
 }
diff --git a/src/lib/stream-list-diff/client/stream-list-diff-client.test.ts b/src/lib/stream-list-diff/client/stream-list-diff-client.test.ts
index fe5f1dd..efea10d 100644
--- a/src/lib/stream-list-diff/client/stream-list-diff-client.test.ts
+++ b/src/lib/stream-list-diff/client/stream-list-diff-client.test.ts
@@ -3,13 +3,13 @@
  */
 import "blob-polyfill";
 import { ReadableStream } from "web-streams-polyfill";
-import { LIST_STATUS } from "@models/list";
+import prevListFile from "@mocks/prevList.json";
+import nextListFile from "@mocks/nextList.json";
+import { ListStatus } from "@models/list";
 import { StreamListDiff } from "@models/stream";
 import { streamListDiff } from ".";
-import prevListFile from "../../../mocks/prevList.json";
-import nextListFile from "../../../mocks/nextList.json";
 
-//@ts-expect-error - the ReadableStream polyfill is necessary to test ReadableStream in a Node environment.
+// @ts-expect-error - the ReadableStream polyfill is necessary to test ReadableStream in a Node environment.
 global.ReadableStream = ReadableStream;
 
 describe("data emission", () => {
@@ -18,7 +18,10 @@ describe("data emission", () => {
       { id: 1, name: "Item 1" },
       { id: 2, name: "Item 2" },
     ];
-    const diff = streamListDiff([], nextList, "id", { chunksSize: 2 });
+    const diff = streamListDiff([], nextList, "id", {
+      chunksSize: 2,
+      useWorker: false,
+    });
 
     const expectedChunks = [
       {
@@ -27,7 +30,7 @@ describe("data emission", () => {
         prevIndex: null,
         newIndex: 0,
         indexDiff: null,
-        status: LIST_STATUS.ADDED,
+        status: ListStatus.ADDED,
       },
       {
         previousValue: null,
@@ -35,7 +38,7 @@ describe("data emission", () => {
         prevIndex: null,
         newIndex: 1,
         indexDiff: null,
-        status: LIST_STATUS.ADDED,
+        status: ListStatus.ADDED,
       },
     ];
     let chunkCount = 0;
@@ -53,7 +56,10 @@ describe("data emission", () => {
       { id: 1, name: "Item 1" },
       { id: 2, name: "Item 2" },
     ];
-    const diff = streamListDiff(prevList, [], "id", { chunksSize: 2 });
+    const diff = streamListDiff(prevList, [], "id", {
+      chunksSize: 2,
+      useWorker: false,
+    });
 
     const expectedChunks = [
       {
@@ -62,7 +68,7 @@ describe("data emission", () => {
         prevIndex: 0,
         newIndex: null,
         indexDiff: null,
-        status: LIST_STATUS.DELETED,
+        status: ListStatus.DELETED,
       },
       {
         previousValue: { id: 2, name: "Item 2" },
@@ -70,7 +76,7 @@ describe("data emission", () => {
         prevIndex: 1,
         newIndex: null,
         indexDiff: null,
-        status: LIST_STATUS.DELETED,
+        status: ListStatus.DELETED,
       },
     ];
     let chunkCount = 0;
@@ -78,7 +84,7 @@ describe("data emission", () => {
       expect(chunk).toStrictEqual(expectedChunks);
       chunkCount++;
     });
-    diff.on("error", (err) => console.error("shiiiite", err));
+    diff.on("error", (err) => console.error(err));
     diff.on("finish", () => {
       expect(chunkCount).toBe(1);
       done();
@@ -93,7 +99,7 @@ describe("data emission", () => {
       { id: 2, name: "Item 2" },
       { id: 3, name: "Item 3" },
     ];
-    const diff = streamListDiff(prevList, nextList, "id");
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: false });
 
     const expectedChunks = [
       [
@@ -103,7 +109,7 @@ describe("data emission", () => {
           prevIndex: 1,
           newIndex: 0,
           indexDiff: -1,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
       ],
       [
@@ -113,7 +119,7 @@ describe("data emission", () => {
           prevIndex: 0,
           newIndex: null,
           indexDiff: null,
-          status: LIST_STATUS.DELETED,
+          status: ListStatus.DELETED,
         },
       ],
       [
@@ -123,7 +129,7 @@ describe("data emission", () => {
           prevIndex: null,
           newIndex: 1,
           indexDiff: null,
-          status: LIST_STATUS.ADDED,
+          status: ListStatus.ADDED,
         },
       ],
     ];
@@ -166,6 +172,7 @@ describe("data emission", () => {
     ];
     const diff = streamListDiff(prevList, nextList, "id", {
       chunksSize: 5,
+      useWorker: false,
     });
 
     const expectedChunks = [
@@ -176,7 +183,7 @@ describe("data emission", () => {
           prevIndex: 0,
           newIndex: 0,
           indexDiff: 0,
-          status: LIST_STATUS.EQUAL,
+          status: ListStatus.EQUAL,
         },
         {
           previousValue: { id: 2, name: "Item 2" },
@@ -184,7 +191,7 @@ describe("data emission", () => {
           prevIndex: 1,
           newIndex: 1,
           indexDiff: 0,
-          status: LIST_STATUS.UPDATED,
+          status: ListStatus.UPDATED,
         },
         {
           previousValue: { id: 3, name: "Item 3" },
@@ -192,7 +199,7 @@ describe("data emission", () => {
           prevIndex: 2,
           newIndex: 2,
           indexDiff: 0,
-          status: LIST_STATUS.EQUAL,
+          status: ListStatus.EQUAL,
         },
         {
           previousValue: { id: 5, name: "Item 5" },
@@ -200,7 +207,7 @@ describe("data emission", () => {
           prevIndex: 4,
           newIndex: 3,
           indexDiff: -1,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
         {
           previousValue: { id: 6, name: "Item 6" },
@@ -208,7 +215,7 @@ describe("data emission", () => {
           prevIndex: 5,
           newIndex: 4,
           indexDiff: -1,
-          status: LIST_STATUS.UPDATED,
+          status: ListStatus.UPDATED,
         },
       ],
       [
@@ -218,7 +225,7 @@ describe("data emission", () => {
           prevIndex: 6,
           newIndex: 5,
           indexDiff: -1,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
         {
           previousValue: { id: 9, name: "Item 9" },
@@ -226,7 +233,7 @@ describe("data emission", () => {
           prevIndex: 8,
           newIndex: 8,
           indexDiff: 0,
-          status: LIST_STATUS.EQUAL,
+          status: ListStatus.EQUAL,
         },
         {
           previousValue: { id: 10, name: "Item 10" },
@@ -234,7 +241,7 @@ describe("data emission", () => {
           prevIndex: 9,
           newIndex: 6,
           indexDiff: -3,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
         {
           previousValue: { id: 8, name: "Item 8" },
@@ -242,7 +249,7 @@ describe("data emission", () => {
           prevIndex: 7,
           newIndex: 9,
           indexDiff: 2,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
         {
           previousValue: { id: 4, name: "Item 4" },
@@ -250,7 +257,7 @@ describe("data emission", () => {
           prevIndex: 3,
           newIndex: null,
           indexDiff: null,
-          status: LIST_STATUS.DELETED,
+          status: ListStatus.DELETED,
         },
       ],
       [
@@ -260,7 +267,7 @@ describe("data emission", () => {
           prevIndex: null,
           newIndex: 7,
           indexDiff: null,
-          status: LIST_STATUS.ADDED,
+          status: ListStatus.ADDED,
         },
       ],
     ];
@@ -293,6 +300,7 @@ describe("data emission", () => {
 
     const diff = streamListDiff(prevList, nextList, "id", {
       chunksSize: 150,
+      useWorker: false,
     });
 
     const expectedChunks = [
@@ -302,7 +310,7 @@ describe("data emission", () => {
         prevIndex: 0,
         newIndex: 0,
         indexDiff: 0,
-        status: LIST_STATUS.EQUAL,
+        status: ListStatus.EQUAL,
       },
       {
         previousValue: { id: 2, name: "Item 2" },
@@ -310,7 +318,7 @@ describe("data emission", () => {
         prevIndex: 1,
         newIndex: 1,
         indexDiff: 0,
-        status: LIST_STATUS.UPDATED,
+        status: ListStatus.UPDATED,
       },
       {
         previousValue: { id: 3, name: "Item 3" },
@@ -318,7 +326,7 @@ describe("data emission", () => {
         prevIndex: 2,
         newIndex: 2,
         indexDiff: 0,
-        status: LIST_STATUS.EQUAL,
+        status: ListStatus.EQUAL,
       },
       {
         previousValue: { id: 4, name: "Item 4" },
@@ -326,7 +334,7 @@ describe("data emission", () => {
         prevIndex: 3,
         newIndex: null,
         indexDiff: null,
-        status: LIST_STATUS.DELETED,
+        status: ListStatus.DELETED,
       },
       {
         previousValue: null,
@@ -334,7 +342,7 @@ describe("data emission", () => {
         prevIndex: null,
         newIndex: 3,
         indexDiff: null,
-        status: LIST_STATUS.ADDED,
+        status: ListStatus.ADDED,
       },
     ];
 
@@ -365,6 +373,7 @@ describe("data emission", () => {
     const diff = streamListDiff(prevList, nextList, "id", {
       chunksSize: 5,
       considerMoveAsUpdate: true,
+      useWorker: false,
     });
 
     const expectedChunks = [
@@ -374,7 +383,7 @@ describe("data emission", () => {
         prevIndex: 1,
         newIndex: 0,
         indexDiff: -1,
-        status: LIST_STATUS.UPDATED,
+        status: ListStatus.UPDATED,
       },
       {
         previousValue: { id: 1, name: "Item 1" },
@@ -382,7 +391,7 @@ describe("data emission", () => {
         prevIndex: 0,
         newIndex: 1,
         indexDiff: 1,
-        status: LIST_STATUS.UPDATED,
+        status: ListStatus.UPDATED,
       },
       {
         previousValue: { id: 3, name: "Item 3" },
@@ -390,7 +399,7 @@ describe("data emission", () => {
         prevIndex: 2,
         newIndex: 2,
         indexDiff: 0,
-        status: LIST_STATUS.EQUAL,
+        status: ListStatus.EQUAL,
       },
       {
         previousValue: { id: 4, name: "Item 4" },
@@ -398,7 +407,7 @@ describe("data emission", () => {
         prevIndex: 3,
         newIndex: null,
         indexDiff: null,
-        status: LIST_STATUS.DELETED,
+        status: ListStatus.DELETED,
       },
       {
         previousValue: null,
@@ -406,7 +415,7 @@ describe("data emission", () => {
         prevIndex: null,
         newIndex: 3,
         indexDiff: null,
-        status: LIST_STATUS.ADDED,
+        status: ListStatus.ADDED,
       },
     ];
 
@@ -437,6 +446,7 @@ describe("data emission", () => {
     const diff = streamListDiff(prevList, nextList, "id", {
       chunksSize: 5,
       showOnly: ["added", "deleted"],
+      useWorker: false,
     });
 
     const expectedChunks = [
@@ -446,7 +456,7 @@ describe("data emission", () => {
         prevIndex: 3,
         newIndex: null,
         indexDiff: null,
-        status: LIST_STATUS.DELETED,
+        status: ListStatus.DELETED,
       },
       {
         previousValue: null,
@@ -454,7 +464,7 @@ describe("data emission", () => {
         prevIndex: null,
         newIndex: 3,
         indexDiff: null,
-        status: LIST_STATUS.ADDED,
+        status: ListStatus.ADDED,
       },
     ];
 
@@ -524,6 +534,7 @@ describe("data emission", () => {
     ];
     const diff = streamListDiff(prevList, nextList, "id", {
       chunksSize: 5,
+      useWorker: false,
     });
 
     const expectedChunks = [
@@ -542,7 +553,7 @@ describe("data emission", () => {
           prevIndex: 0,
           newIndex: 0,
           indexDiff: 0,
-          status: LIST_STATUS.EQUAL,
+          status: ListStatus.EQUAL,
         },
         {
           previousValue: { id: 2, name: "Item 2" },
@@ -550,7 +561,7 @@ describe("data emission", () => {
           prevIndex: 1,
           newIndex: 1,
           indexDiff: 0,
-          status: LIST_STATUS.UPDATED,
+          status: ListStatus.UPDATED,
         },
         {
           previousValue: {
@@ -566,7 +577,7 @@ describe("data emission", () => {
           prevIndex: 2,
           newIndex: 2,
           indexDiff: 0,
-          status: LIST_STATUS.EQUAL,
+          status: ListStatus.EQUAL,
         },
         {
           previousValue: { id: 5, name: "Item 5" },
@@ -574,7 +585,7 @@ describe("data emission", () => {
           prevIndex: 4,
           newIndex: 3,
           indexDiff: -1,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
         {
           previousValue: {
@@ -590,7 +601,7 @@ describe("data emission", () => {
           prevIndex: 5,
           newIndex: 4,
           indexDiff: -1,
-          status: LIST_STATUS.UPDATED,
+          status: ListStatus.UPDATED,
         },
       ],
       [
@@ -600,7 +611,7 @@ describe("data emission", () => {
           prevIndex: 6,
           newIndex: 5,
           indexDiff: -1,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
         {
           previousValue: { id: 9, name: "Item 9" },
@@ -608,7 +619,7 @@ describe("data emission", () => {
           prevIndex: 8,
           newIndex: 8,
           indexDiff: 0,
-          status: LIST_STATUS.EQUAL,
+          status: ListStatus.EQUAL,
         },
         {
           previousValue: {
@@ -632,7 +643,7 @@ describe("data emission", () => {
           prevIndex: 9,
           newIndex: 6,
           indexDiff: -3,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
         {
           previousValue: { id: 8, name: "Item 8" },
@@ -640,7 +651,7 @@ describe("data emission", () => {
           prevIndex: 7,
           newIndex: 9,
           indexDiff: 2,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
         {
           previousValue: {
@@ -652,7 +663,7 @@ describe("data emission", () => {
           prevIndex: 3,
           newIndex: null,
           indexDiff: null,
-          status: LIST_STATUS.DELETED,
+          status: ListStatus.DELETED,
         },
       ],
       [
@@ -662,7 +673,7 @@ describe("data emission", () => {
           prevIndex: null,
           newIndex: 7,
           indexDiff: null,
-          status: LIST_STATUS.ADDED,
+          status: ListStatus.ADDED,
         },
       ],
     ];
@@ -701,7 +712,7 @@ describe("input handling", () => {
       prevIndex: 0,
       newIndex: 0,
       indexDiff: 0,
-      status: LIST_STATUS.EQUAL,
+      status: ListStatus.EQUAL,
     },
     {
       previousValue: { id: 2, name: "Item 2" },
@@ -709,7 +720,7 @@ describe("input handling", () => {
       prevIndex: 1,
       newIndex: 1,
       indexDiff: 0,
-      status: LIST_STATUS.UPDATED,
+      status: ListStatus.UPDATED,
     },
     {
       previousValue: { id: 3, name: "Item 3" },
@@ -717,7 +728,7 @@ describe("input handling", () => {
       prevIndex: 2,
       newIndex: 2,
       indexDiff: 0,
-      status: LIST_STATUS.EQUAL,
+      status: ListStatus.EQUAL,
     },
     {
       previousValue: { id: 4, name: "Item 4" },
@@ -725,7 +736,7 @@ describe("input handling", () => {
       prevIndex: 3,
       newIndex: null,
       indexDiff: null,
-      status: LIST_STATUS.DELETED,
+      status: ListStatus.DELETED,
     },
     {
       previousValue: null,
@@ -733,7 +744,7 @@ describe("input handling", () => {
       prevIndex: null,
       newIndex: 3,
       indexDiff: null,
-      status: LIST_STATUS.ADDED,
+      status: ListStatus.ADDED,
     },
   ];
 
@@ -753,6 +764,7 @@ describe("input handling", () => {
 
     const diff = streamListDiff(prevStream, nextStream, "id", {
       chunksSize: 5,
+      useWorker: false,
     });
 
     let chunkCount = 0;
@@ -760,7 +772,7 @@ describe("input handling", () => {
       expect(chunk).toStrictEqual(expectedChunks);
       chunkCount++;
     });
-    diff.on("error", (err) => console.error("sheeeet", err));
+    diff.on("error", (err) => console.error(err));
     diff.on("finish", () => {
       expect(chunkCount).toBe(1);
       done();
@@ -777,6 +789,7 @@ describe("input handling", () => {
 
     const diff = streamListDiff(prevFile, nextFile, "id", {
       chunksSize: 5,
+      useWorker: false,
     });
 
     let chunkCount = 0;
@@ -784,7 +797,7 @@ describe("input handling", () => {
       expect(chunk).toStrictEqual(expectedChunks);
       chunkCount++;
     });
-    diff.on("error", (err) => console.error("sheeeet", err));
+    diff.on("error", (err) => console.error(err));
     diff.on("finish", () => {
       expect(chunkCount).toBe(1);
       done();
@@ -803,6 +816,7 @@ describe("input handling", () => {
 
     const diff = streamListDiff(prevStream, nextFile, "id", {
       chunksSize: 5,
+      useWorker: false,
     });
 
     let chunkCount = 0;
@@ -810,7 +824,7 @@ describe("input handling", () => {
       expect(chunk).toStrictEqual(expectedChunks);
       chunkCount++;
     });
-    diff.on("error", (err) => console.error("sheeeet", err));
+    diff.on("error", (err) => console.error(err));
     diff.on("finish", () => {
       expect(chunkCount).toBe(1);
       done();
@@ -826,6 +840,7 @@ describe("input handling", () => {
 
     const diff = streamListDiff(prevStream, nextList, "id", {
       chunksSize: 5,
+      useWorker: false,
     });
 
     let chunkCount = 0;
@@ -833,7 +848,7 @@ describe("input handling", () => {
       expect(chunk).toStrictEqual(expectedChunks);
       chunkCount++;
     });
-    diff.on("error", (err) => console.error("sheeeet", err));
+    diff.on("error", (err) => console.error(err));
     diff.on("finish", () => {
       expect(chunkCount).toBe(1);
       done();
@@ -846,6 +861,7 @@ describe("input handling", () => {
 
     const diff = streamListDiff(prevFile, nextList, "id", {
       chunksSize: 5,
+      useWorker: false,
     });
 
     let chunkCount = 0;
@@ -853,7 +869,7 @@ describe("input handling", () => {
       expect(chunk).toStrictEqual(expectedChunks);
       chunkCount++;
     });
-    diff.on("error", (err) => console.error("sheeeet", err));
+    diff.on("error", (err) => console.error(err));
     diff.on("finish", () => {
       expect(chunkCount).toBe(1);
       done();
@@ -863,7 +879,7 @@ describe("input handling", () => {
 
 describe("finish event", () => {
   it("emits 'finish' event if no prevList nor nextList is provided", (done) => {
-    const diff = streamListDiff([], [], "id");
+    const diff = streamListDiff([], [], "id", { useWorker: false });
     diff.on("finish", () => done());
   });
   it("emits 'finish' event when all the chunks have been processed", (done) => {
@@ -875,7 +891,7 @@ describe("finish event", () => {
       { id: 2, name: "Item 2" },
       { id: 3, name: "Item 3" },
     ];
-    const diff = streamListDiff(prevList, nextList, "id");
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: false });
     diff.on("finish", () => done());
   });
 });
@@ -893,7 +909,7 @@ describe("error event", () => {
     ];
 
     // @ts-expect-error prevList is invalid by design for the test
-    const diff = streamListDiff(prevList, nextList, "id");
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: false });
 
     diff.on("error", (err) => {
       expect(err["message"]).toEqual(
@@ -915,7 +931,7 @@ describe("error event", () => {
     ];
 
     // @ts-expect-error nextList is invalid by design for the test
-    const diff = streamListDiff(prevList, nextList, "id");
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: false });
 
     diff.on("error", (err) => {
       expect(err["message"]).toEqual(
@@ -932,7 +948,7 @@ describe("error event", () => {
       { id: 2, name: "Item 2" },
     ];
 
-    const diff = streamListDiff(prevList, nextList, "id");
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: false });
 
     diff.on("error", (err) => {
       expect(err["message"]).toEqual(
@@ -949,7 +965,7 @@ describe("error event", () => {
     ];
     const nextList = [{ id: 1, name: "Item 1" }, { name: "Item 2" }];
 
-    const diff = streamListDiff(prevList, nextList, "id");
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: false });
 
     diff.on("error", (err) => {
       expect(err["message"]).toEqual(
@@ -968,6 +984,7 @@ describe("error event", () => {
 
     const diff = streamListDiff(prevList, nextList, "id", {
       chunksSize: -3,
+      useWorker: false,
     });
 
     diff.on("error", (err) => {
@@ -982,7 +999,9 @@ describe("error event", () => {
     const nextList = [{ id: 1, name: "Item 1" }, { name: "Item 2" }];
 
     // @ts-expect-error - prevList is invalid by design for the test
-    const diff = streamListDiff({ name: "hello" }, nextList, "id");
+    const diff = streamListDiff({ name: "hello" }, nextList, "id", {
+      useWorker: false,
+    });
 
     diff.on("error", (err) => {
       expect(err["message"]).toEqual(
@@ -995,7 +1014,7 @@ describe("error event", () => {
     const prevList = [{ id: 1, name: "Item 1" }, { name: "Item 2" }];
 
     // @ts-expect-error - nextList is invalid by design for the test
-    const diff = streamListDiff(prevList, null, "id");
+    const diff = streamListDiff(prevList, null, "id", { useWorker: false });
 
     diff.on("error", (err) => {
       expect(err["message"]).toEqual(
diff --git a/src/lib/stream-list-diff/client/stream-list-diff-client.worker.test.ts b/src/lib/stream-list-diff/client/stream-list-diff-client.worker.test.ts
new file mode 100644
index 0000000..57c70af
--- /dev/null
+++ b/src/lib/stream-list-diff/client/stream-list-diff-client.worker.test.ts
@@ -0,0 +1,1116 @@
+/**
+ * @jest-environment jsdom
+ */
+import "blob-polyfill";
+import "jsdom";
+import { ReadableStream } from "web-streams-polyfill";
+import prevListFile from "@mocks/prevList.json";
+import nextListFile from "@mocks/nextList.json";
+import { ListStatus } from "@models/list";
+import {
+  ListStreamOptions,
+  ReferenceProperty,
+  StreamEvent,
+  StreamListDiff,
+} from "@models/stream";
+import { workerDiff } from "./worker/utils";
+import { streamListDiff } from ".";
+
+class Worker {
+  onmessage: ((event: { data: unknown }) => void) | null = null;
+
+  postMessage<T extends Record<string, unknown>>(msg: {
+    prevList: File | T[];
+    nextList: File | T[];
+    referenceProperty: ReferenceProperty<T>;
+    options: ListStreamOptions;
+  }) {
+    if (msg) {
+      const { prevList, nextList, referenceProperty, options } = msg;
+      const listener = workerDiff(
+        prevList,
+        nextList,
+        referenceProperty,
+        options,
+      );
+
+      listener.on(StreamEvent.Data, (chunk) => {
+        this.onmessage!({
+          data: { event: StreamEvent.Data, chunk },
+        });
+      });
+
+      listener.on(StreamEvent.Finish, () => {
+        this.onmessage!({
+          data: { event: StreamEvent.Finish },
+        });
+      });
+
+      listener.on(StreamEvent.Error, (error) => {
+        this.onmessage!({
+          data: { event: StreamEvent.Error, error: error.message },
+        });
+      });
+    }
+  }
+
+  terminate() {}
+}
+
+// @ts-expect-error - a Worker polyfill is necessary to test a Web Worker in a Node environment.
+global.Worker = Worker;
+// @ts-expect-error - the ReadableStream polyfill is necessary to test ReadableStream in a Node environment.
+global.ReadableStream = ReadableStream;
+
+describe("data emission", () => {
+  it("emits 'data' event and consider the all the nextList added if no prevList is provided", (done) => {
+    const nextList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+    const diff = streamListDiff([], nextList, "id", {
+      chunksSize: 2,
+      showWarnings: false,
+    });
+
+    const expectedChunks = [
+      {
+        previousValue: null,
+        currentValue: { id: 1, name: "Item 1" },
+        prevIndex: null,
+        newIndex: 0,
+        indexDiff: null,
+        status: ListStatus.ADDED,
+      },
+      {
+        previousValue: null,
+        currentValue: { id: 2, name: "Item 2" },
+        prevIndex: null,
+        newIndex: 1,
+        indexDiff: null,
+        status: ListStatus.ADDED,
+      },
+    ];
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toStrictEqual(expectedChunks);
+      chunkCount++;
+    });
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("emits 'data' event and consider the all the prevList deleted if no nextList is provided", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+    const diff = streamListDiff(prevList, [], "id", { chunksSize: 2 });
+
+    const expectedChunks = [
+      {
+        previousValue: { id: 1, name: "Item 1" },
+        currentValue: null,
+        prevIndex: 0,
+        newIndex: null,
+        indexDiff: null,
+        status: ListStatus.DELETED,
+      },
+      {
+        previousValue: { id: 2, name: "Item 2" },
+        currentValue: null,
+        prevIndex: 1,
+        newIndex: null,
+        indexDiff: null,
+        status: ListStatus.DELETED,
+      },
+    ];
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toStrictEqual(expectedChunks);
+      chunkCount++;
+    });
+    diff.on("error", (err) => console.error(err));
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("emits 'data' event with one object diff by chunk if chunkSize is 0 or undefined", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+    const nextList = [
+      { id: 2, name: "Item 2" },
+      { id: 3, name: "Item 3" },
+    ];
+    const diff = streamListDiff(prevList, nextList, "id");
+
+    const expectedChunks = [
+      [
+        {
+          previousValue: { id: 2, name: "Item 2" },
+          currentValue: { id: 2, name: "Item 2" },
+          prevIndex: 1,
+          newIndex: 0,
+          indexDiff: -1,
+          status: ListStatus.MOVED,
+        },
+      ],
+      [
+        {
+          previousValue: { id: 1, name: "Item 1" },
+          currentValue: null,
+          prevIndex: 0,
+          newIndex: null,
+          indexDiff: null,
+          status: ListStatus.DELETED,
+        },
+      ],
+      [
+        {
+          previousValue: null,
+          currentValue: { id: 3, name: "Item 3" },
+          prevIndex: null,
+          newIndex: 1,
+          indexDiff: null,
+          status: ListStatus.ADDED,
+        },
+      ],
+    ];
+
+    let chunkCount = 0;
+
+    diff.on("data", (chunk) => {
+      expect(chunk).toStrictEqual(expectedChunks[chunkCount]);
+      chunkCount++;
+    });
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(3);
+      done();
+    });
+  });
+  it("emits 'data' event with 5 object diff by chunk and return the last object diff in a one entry chunk at the end", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+      { id: 3, name: "Item 3" },
+      { id: 4, name: "Item 4" },
+      { id: 5, name: "Item 5" },
+      { id: 6, name: "Item 6" },
+      { id: 7, name: "Item 7" },
+      { id: 8, name: "Item 8" },
+      { id: 9, name: "Item 9" },
+      { id: 10, name: "Item 10" },
+    ];
+    const nextList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item Two" },
+      { id: 3, name: "Item 3" },
+      { id: 5, name: "Item 5" },
+      { id: 6, name: "Item Six" },
+      { id: 7, name: "Item 7" },
+      { id: 10, name: "Item 10" },
+      { id: 11, name: "Item 11" },
+      { id: 9, name: "Item 9" },
+      { id: 8, name: "Item 8" },
+    ];
+    const diff = streamListDiff(prevList, nextList, "id", { chunksSize: 5 });
+
+    const expectedChunks = [
+      [
+        {
+          previousValue: { id: 1, name: "Item 1" },
+          currentValue: { id: 1, name: "Item 1" },
+          prevIndex: 0,
+          newIndex: 0,
+          indexDiff: 0,
+          status: ListStatus.EQUAL,
+        },
+        {
+          previousValue: { id: 2, name: "Item 2" },
+          currentValue: { id: 2, name: "Item Two" },
+          prevIndex: 1,
+          newIndex: 1,
+          indexDiff: 0,
+          status: ListStatus.UPDATED,
+        },
+        {
+          previousValue: { id: 3, name: "Item 3" },
+          currentValue: { id: 3, name: "Item 3" },
+          prevIndex: 2,
+          newIndex: 2,
+          indexDiff: 0,
+          status: ListStatus.EQUAL,
+        },
+        {
+          previousValue: { id: 5, name: "Item 5" },
+          currentValue: { id: 5, name: "Item 5" },
+          prevIndex: 4,
+          newIndex: 3,
+          indexDiff: -1,
+          status: ListStatus.MOVED,
+        },
+        {
+          previousValue: { id: 6, name: "Item 6" },
+          currentValue: { id: 6, name: "Item Six" },
+          prevIndex: 5,
+          newIndex: 4,
+          indexDiff: -1,
+          status: ListStatus.UPDATED,
+        },
+      ],
+      [
+        {
+          previousValue: { id: 7, name: "Item 7" },
+          currentValue: { id: 7, name: "Item 7" },
+          prevIndex: 6,
+          newIndex: 5,
+          indexDiff: -1,
+          status: ListStatus.MOVED,
+        },
+        {
+          previousValue: { id: 9, name: "Item 9" },
+          currentValue: { id: 9, name: "Item 9" },
+          prevIndex: 8,
+          newIndex: 8,
+          indexDiff: 0,
+          status: ListStatus.EQUAL,
+        },
+        {
+          previousValue: { id: 10, name: "Item 10" },
+          currentValue: { id: 10, name: "Item 10" },
+          prevIndex: 9,
+          newIndex: 6,
+          indexDiff: -3,
+          status: ListStatus.MOVED,
+        },
+        {
+          previousValue: { id: 8, name: "Item 8" },
+          currentValue: { id: 8, name: "Item 8" },
+          prevIndex: 7,
+          newIndex: 9,
+          indexDiff: 2,
+          status: ListStatus.MOVED,
+        },
+        {
+          previousValue: { id: 4, name: "Item 4" },
+          currentValue: null,
+          prevIndex: 3,
+          newIndex: null,
+          indexDiff: null,
+          status: ListStatus.DELETED,
+        },
+      ],
+      [
+        {
+          previousValue: null,
+          currentValue: { id: 11, name: "Item 11" },
+          prevIndex: null,
+          newIndex: 7,
+          indexDiff: null,
+          status: ListStatus.ADDED,
+        },
+      ],
+    ];
+
+    let chunkCount = 0;
+
+    diff.on("data", (chunk) => {
+      expect(chunk).toStrictEqual(expectedChunks[chunkCount]);
+      chunkCount++;
+    });
+
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(3);
+      done();
+    });
+  });
+  it("emits 'data' event with all the objects diff in a single chunk if the chunkSize is bigger than the provided lists ", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+      { id: 3, name: "Item 3" },
+      { id: 4, name: "Item 4" },
+    ];
+    const nextList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item Two" },
+      { id: 3, name: "Item 3" },
+      { id: 5, name: "Item 5" },
+    ];
+
+    const diff = streamListDiff(prevList, nextList, "id", {
+      chunksSize: 150,
+    });
+
+    const expectedChunks = [
+      {
+        previousValue: { id: 1, name: "Item 1" },
+        currentValue: { id: 1, name: "Item 1" },
+        prevIndex: 0,
+        newIndex: 0,
+        indexDiff: 0,
+        status: ListStatus.EQUAL,
+      },
+      {
+        previousValue: { id: 2, name: "Item 2" },
+        currentValue: { id: 2, name: "Item Two" },
+        prevIndex: 1,
+        newIndex: 1,
+        indexDiff: 0,
+        status: ListStatus.UPDATED,
+      },
+      {
+        previousValue: { id: 3, name: "Item 3" },
+        currentValue: { id: 3, name: "Item 3" },
+        prevIndex: 2,
+        newIndex: 2,
+        indexDiff: 0,
+        status: ListStatus.EQUAL,
+      },
+      {
+        previousValue: { id: 4, name: "Item 4" },
+        currentValue: null,
+        prevIndex: 3,
+        newIndex: null,
+        indexDiff: null,
+        status: ListStatus.DELETED,
+      },
+      {
+        previousValue: null,
+        currentValue: { id: 5, name: "Item 5" },
+        prevIndex: null,
+        newIndex: 3,
+        indexDiff: null,
+        status: ListStatus.ADDED,
+      },
+    ];
+
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toStrictEqual(expectedChunks);
+      chunkCount++;
+    });
+
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("emits 'data' event with moved objects considered as updated if considerMoveAsUpdate is true", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+      { id: 3, name: "Item 3" },
+      { id: 4, name: "Item 4" },
+    ];
+    const nextList = [
+      { id: 2, name: "Item Two" },
+      { id: 1, name: "Item 1" },
+      { id: 3, name: "Item 3" },
+      { id: 5, name: "Item 5" },
+    ];
+    const diff = streamListDiff(prevList, nextList, "id", {
+      chunksSize: 5,
+      considerMoveAsUpdate: true,
+    });
+
+    const expectedChunks = [
+      {
+        previousValue: { id: 2, name: "Item 2" },
+        currentValue: { id: 2, name: "Item Two" },
+        prevIndex: 1,
+        newIndex: 0,
+        indexDiff: -1,
+        status: ListStatus.UPDATED,
+      },
+      {
+        previousValue: { id: 1, name: "Item 1" },
+        currentValue: { id: 1, name: "Item 1" },
+        prevIndex: 0,
+        newIndex: 1,
+        indexDiff: 1,
+        status: ListStatus.UPDATED,
+      },
+      {
+        previousValue: { id: 3, name: "Item 3" },
+        currentValue: { id: 3, name: "Item 3" },
+        prevIndex: 2,
+        newIndex: 2,
+        indexDiff: 0,
+        status: ListStatus.EQUAL,
+      },
+      {
+        previousValue: { id: 4, name: "Item 4" },
+        currentValue: null,
+        prevIndex: 3,
+        newIndex: null,
+        indexDiff: null,
+        status: ListStatus.DELETED,
+      },
+      {
+        previousValue: null,
+        currentValue: { id: 5, name: "Item 5" },
+        prevIndex: null,
+        newIndex: 3,
+        indexDiff: null,
+        status: ListStatus.ADDED,
+      },
+    ];
+
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toStrictEqual(expectedChunks);
+      chunkCount++;
+    });
+
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("emits 'data' event only with objects diff whose status match with showOnly's", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+      { id: 3, name: "Item 3" },
+      { id: 4, name: "Item 4" },
+    ];
+    const nextList = [
+      { id: 2, name: "Item Two" },
+      { id: 1, name: "Item 1" },
+      { id: 3, name: "Item 3" },
+      { id: 5, name: "Item 5" },
+    ];
+    const diff = streamListDiff(prevList, nextList, "id", {
+      chunksSize: 5,
+      showOnly: ["added", "deleted"],
+    });
+
+    const expectedChunks = [
+      {
+        previousValue: { id: 4, name: "Item 4" },
+        currentValue: null,
+        prevIndex: 3,
+        newIndex: null,
+        indexDiff: null,
+        status: ListStatus.DELETED,
+      },
+      {
+        previousValue: null,
+        currentValue: { id: 5, name: "Item 5" },
+        prevIndex: null,
+        newIndex: 3,
+        indexDiff: null,
+        status: ListStatus.ADDED,
+      },
+    ];
+
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toStrictEqual(expectedChunks);
+      chunkCount++;
+    });
+
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("emits 'data' event with deep nested objects diff", (done) => {
+    const prevList = [
+      {
+        id: 1,
+        name: "Item 1",
+        user: { role: "admin", hobbies: ["golf", "football"] },
+      },
+      { id: 2, name: "Item 2" },
+      { id: 3, name: "Item 3", user: { role: "admin", hobbies: ["rugby"] } },
+      {
+        id: 4,
+        name: "Item 4",
+        user: { role: "reader", hobbies: ["video games", "fishing"] },
+      },
+      { id: 5, name: "Item 5" },
+      { id: 6, name: "Item 6", user: { role: "root", hobbies: ["coding"] } },
+      { id: 7, name: "Item 7" },
+      { id: 8, name: "Item 8" },
+      { id: 9, name: "Item 9" },
+      {
+        id: 10,
+        name: "Item 10",
+        user: {
+          role: "root",
+          hobbies: ["coding"],
+          skills: { driving: true, diving: false },
+        },
+      },
+    ];
+    const nextList = [
+      {
+        id: 1,
+        name: "Item 1",
+        user: { role: "admin", hobbies: ["golf", "football"] },
+      },
+      { id: 2, name: "Item Two" },
+      { id: 3, name: "Item 3", user: { role: "admin", hobbies: ["rugby"] } },
+      { id: 5, name: "Item 5" },
+      { id: 6, name: "Item 6", user: { role: "root", hobbies: ["farming"] } },
+      { id: 7, name: "Item 7" },
+      {
+        id: 10,
+        name: "Item 10",
+        user: {
+          role: "root",
+          hobbies: ["coding"],
+          skills: { driving: true, diving: false },
+        },
+      },
+      { id: 11, name: "Item 11" },
+      { id: 9, name: "Item 9" },
+      { id: 8, name: "Item 8" },
+    ];
+    const diff = streamListDiff(prevList, nextList, "id", {
+      chunksSize: 5,
+    });
+
+    const expectedChunks = [
+      [
+        {
+          previousValue: {
+            id: 1,
+            name: "Item 1",
+            user: { role: "admin", hobbies: ["golf", "football"] },
+          },
+          currentValue: {
+            id: 1,
+            name: "Item 1",
+            user: { role: "admin", hobbies: ["golf", "football"] },
+          },
+          prevIndex: 0,
+          newIndex: 0,
+          indexDiff: 0,
+          status: ListStatus.EQUAL,
+        },
+        {
+          previousValue: { id: 2, name: "Item 2" },
+          currentValue: { id: 2, name: "Item Two" },
+          prevIndex: 1,
+          newIndex: 1,
+          indexDiff: 0,
+          status: ListStatus.UPDATED,
+        },
+        {
+          previousValue: {
+            id: 3,
+            name: "Item 3",
+            user: { role: "admin", hobbies: ["rugby"] },
+          },
+          currentValue: {
+            id: 3,
+            name: "Item 3",
+            user: { role: "admin", hobbies: ["rugby"] },
+          },
+          prevIndex: 2,
+          newIndex: 2,
+          indexDiff: 0,
+          status: ListStatus.EQUAL,
+        },
+        {
+          previousValue: { id: 5, name: "Item 5" },
+          currentValue: { id: 5, name: "Item 5" },
+          prevIndex: 4,
+          newIndex: 3,
+          indexDiff: -1,
+          status: ListStatus.MOVED,
+        },
+        {
+          previousValue: {
+            id: 6,
+            name: "Item 6",
+            user: { role: "root", hobbies: ["coding"] },
+          },
+          currentValue: {
+            id: 6,
+            name: "Item 6",
+            user: { role: "root", hobbies: ["farming"] },
+          },
+          prevIndex: 5,
+          newIndex: 4,
+          indexDiff: -1,
+          status: ListStatus.UPDATED,
+        },
+      ],
+      [
+        {
+          previousValue: { id: 7, name: "Item 7" },
+          currentValue: { id: 7, name: "Item 7" },
+          prevIndex: 6,
+          newIndex: 5,
+          indexDiff: -1,
+          status: ListStatus.MOVED,
+        },
+        {
+          previousValue: { id: 9, name: "Item 9" },
+          currentValue: { id: 9, name: "Item 9" },
+          prevIndex: 8,
+          newIndex: 8,
+          indexDiff: 0,
+          status: ListStatus.EQUAL,
+        },
+        {
+          previousValue: {
+            id: 10,
+            name: "Item 10",
+            user: {
+              role: "root",
+              hobbies: ["coding"],
+              skills: { driving: true, diving: false },
+            },
+          },
+          currentValue: {
+            id: 10,
+            name: "Item 10",
+            user: {
+              role: "root",
+              hobbies: ["coding"],
+              skills: { driving: true, diving: false },
+            },
+          },
+          prevIndex: 9,
+          newIndex: 6,
+          indexDiff: -3,
+          status: ListStatus.MOVED,
+        },
+        {
+          previousValue: { id: 8, name: "Item 8" },
+          currentValue: { id: 8, name: "Item 8" },
+          prevIndex: 7,
+          newIndex: 9,
+          indexDiff: 2,
+          status: ListStatus.MOVED,
+        },
+        {
+          previousValue: {
+            id: 4,
+            name: "Item 4",
+            user: { role: "reader", hobbies: ["video games", "fishing"] },
+          },
+          currentValue: null,
+          prevIndex: 3,
+          newIndex: null,
+          indexDiff: null,
+          status: ListStatus.DELETED,
+        },
+      ],
+      [
+        {
+          previousValue: null,
+          currentValue: { id: 11, name: "Item 11" },
+          prevIndex: null,
+          newIndex: 7,
+          indexDiff: null,
+          status: ListStatus.ADDED,
+        },
+      ],
+    ];
+
+    let chunkCount = 0;
+
+    diff.on("data", (chunk) => {
+      expect(chunk).toStrictEqual(expectedChunks[chunkCount]);
+      chunkCount++;
+    });
+
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(3);
+      done();
+    });
+  });
+});
+
+describe("input handling", () => {
+  const prevList = [
+    { id: 1, name: "Item 1" },
+    { id: 2, name: "Item 2" },
+    { id: 3, name: "Item 3" },
+    { id: 4, name: "Item 4" },
+  ];
+  const nextList = [
+    { id: 1, name: "Item 1" },
+    { id: 2, name: "Item Two" },
+    { id: 3, name: "Item 3" },
+    { id: 5, name: "Item 5" },
+  ];
+  const expectedChunks = [
+    {
+      previousValue: { id: 1, name: "Item 1" },
+      currentValue: { id: 1, name: "Item 1" },
+      prevIndex: 0,
+      newIndex: 0,
+      indexDiff: 0,
+      status: ListStatus.EQUAL,
+    },
+    {
+      previousValue: { id: 2, name: "Item 2" },
+      currentValue: { id: 2, name: "Item Two" },
+      prevIndex: 1,
+      newIndex: 1,
+      indexDiff: 0,
+      status: ListStatus.UPDATED,
+    },
+    {
+      previousValue: { id: 3, name: "Item 3" },
+      currentValue: { id: 3, name: "Item 3" },
+      prevIndex: 2,
+      newIndex: 2,
+      indexDiff: 0,
+      status: ListStatus.EQUAL,
+    },
+    {
+      previousValue: { id: 4, name: "Item 4" },
+      currentValue: null,
+      prevIndex: 3,
+      newIndex: null,
+      indexDiff: null,
+      status: ListStatus.DELETED,
+    },
+    {
+      previousValue: null,
+      currentValue: { id: 5, name: "Item 5" },
+      prevIndex: null,
+      newIndex: 3,
+      indexDiff: null,
+      status: ListStatus.ADDED,
+    },
+  ];
+
+  it("handles two readable streams", (done) => {
+    const prevStream = new ReadableStream({
+      start(controller) {
+        prevList.forEach((item) => controller.enqueue(item));
+        controller.close();
+      },
+    });
+    const nextStream = new ReadableStream({
+      start(controller) {
+        nextList.forEach((item) => controller.enqueue(item));
+        controller.close();
+      },
+    });
+
+    const diff = streamListDiff(prevStream, nextStream, "id", {
+      chunksSize: 5,
+      showWarnings: false,
+    });
+
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toStrictEqual(expectedChunks);
+      chunkCount++;
+    });
+    diff.on("error", (err) => console.error(err));
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("handles two local files", (done) => {
+    const prevFile = new File([JSON.stringify(prevListFile)], "prevList.json", {
+      type: "application/json",
+    });
+
+    const nextFile = new File([JSON.stringify(nextListFile)], "nextList.json", {
+      type: "application/json",
+    });
+
+    const diff = streamListDiff(prevFile, nextFile, "id", {
+      chunksSize: 5,
+    });
+
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toStrictEqual(expectedChunks);
+      chunkCount++;
+    });
+    diff.on("error", (err) => console.error(err));
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("handles a readable stream against a local file", (done) => {
+    const prevStream = new ReadableStream({
+      start(controller) {
+        prevList.forEach((item) => controller.enqueue(item));
+        controller.close();
+      },
+    });
+    const nextFile = new File([JSON.stringify(nextListFile)], "nextList.json", {
+      type: "application/json",
+    });
+
+    const diff = streamListDiff(prevStream, nextFile, "id", {
+      chunksSize: 5,
+      showWarnings: false,
+    });
+
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toStrictEqual(expectedChunks);
+      chunkCount++;
+    });
+    diff.on("error", (err) => console.error(err));
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("handles a readable stream against an array", (done) => {
+    const prevStream = new ReadableStream({
+      start(controller) {
+        prevList.forEach((item) => controller.enqueue(item));
+        controller.close();
+      },
+    });
+
+    const diff = streamListDiff(prevStream, nextList, "id", {
+      chunksSize: 5,
+      showWarnings: false,
+    });
+
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toStrictEqual(expectedChunks);
+      chunkCount++;
+    });
+    diff.on("error", (err) => console.error(err));
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("handles a local file against an array", (done) => {
+    const prevFile = new File([JSON.stringify(prevListFile)], "prevList.json", {
+      type: "application/json",
+    });
+
+    const diff = streamListDiff(prevFile, nextList, "id", {
+      chunksSize: 5,
+    });
+
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toStrictEqual(expectedChunks);
+      chunkCount++;
+    });
+    diff.on("error", (err) => console.error(err));
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+});
+
+describe("finish event", () => {
+  it("emits 'finish' event if no prevList nor nextList is provided", (done) => {
+    const diff = streamListDiff([], [], "id");
+    diff.on("finish", () => done());
+  });
+  it("emits 'finish' event when all the chunks have been processed", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+    const nextList = [
+      { id: 2, name: "Item 2" },
+      { id: 3, name: "Item 3" },
+    ];
+    const diff = streamListDiff(prevList, nextList, "id");
+    diff.on("finish", () => done());
+  });
+});
+
+describe("error event", () => {
+  test("emits 'error' event when prevList has invalid data", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      "hello",
+      { id: 2, name: "Item 2" },
+    ];
+    const nextList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+
+    // @ts-expect-error prevList is invalid by design for the test
+    const diff = streamListDiff(prevList, nextList, "id");
+
+    diff.on("error", (err) => {
+      expect(err["message"]).toEqual(
+        `Your prevList must only contain valid objects. Found 'hello'`,
+      );
+      done();
+    });
+  });
+
+  test("emits 'error' event when nextList has invalid data", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+    const nextList = [
+      { id: 1, name: "Item 1" },
+      "hello",
+      { id: 2, name: "Item 2" },
+    ];
+
+    // @ts-expect-error nextList is invalid by design for the test
+    const diff = streamListDiff(prevList, nextList, "id");
+
+    diff.on("error", (err) => {
+      expect(err["message"]).toEqual(
+        `Your nextList must only contain valid objects. Found 'hello'`,
+      );
+      done();
+    });
+  });
+
+  test("emits 'error' event when all prevList ojects don't have the requested reference property", (done) => {
+    const prevList = [{ id: 1, name: "Item 1" }, { name: "Item 2" }];
+    const nextList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+
+    const diff = streamListDiff(prevList, nextList, "id");
+
+    diff.on("error", (err) => {
+      expect(err["message"]).toEqual(
+        `The reference property 'id' is not available in all the objects of your prevList.`,
+      );
+      done();
+    });
+  });
+
+  test("emits 'error' event when all nextList ojects don't have the requested reference property", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+    const nextList = [{ id: 1, name: "Item 1" }, { name: "Item 2" }];
+
+    const diff = streamListDiff(prevList, nextList, "id");
+
+    diff.on("error", (err) => {
+      expect(err["message"]).toEqual(
+        `The reference property 'id' is not available in all the objects of your nextList.`,
+      );
+      done();
+    });
+  });
+
+  test("emits 'error' event when the chunkSize option is negative", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+    const nextList = [{ id: 1, name: "Item 1" }, { name: "Item 2" }];
+
+    const diff = streamListDiff(prevList, nextList, "id", {
+      chunksSize: -3,
+    });
+
+    diff.on("error", (err) => {
+      expect(err["message"]).toEqual(
+        "The chunk size can't be negative. You entered the value '-3'",
+      );
+      done();
+    });
+  });
+
+  test("emits 'error' event when the prevList is not a valid type", (done) => {
+    const nextList = [{ id: 1, name: "Item 1" }, { name: "Item 2" }];
+
+    // @ts-expect-error - prevList is invalid by design for the test
+    const diff = streamListDiff({ name: "hello" }, nextList, "id");
+
+    diff.on("error", (err) => {
+      expect(err["message"]).toEqual(
+        "Invalid prevList. Expected ReadableStream, Array, or File.",
+      );
+      done();
+    });
+  });
+  test("emits 'error' event when the nextList is not a valid type", (done) => {
+    const prevList = [{ id: 1, name: "Item 1" }, { name: "Item 2" }];
+
+    // @ts-expect-error - nextList is invalid by design for the test
+    const diff = streamListDiff(prevList, null, "id");
+
+    diff.on("error", (err) => {
+      expect(err["message"]).toEqual(
+        "Invalid nextList. Expected ReadableStream, Array, or File.",
+      );
+      done();
+    });
+  });
+});
+
+const generateLargeDataset = (count: number) => {
+  const data: Array<{ id: number; value: string }> = [];
+  for (let i = 0; i < count; i++) {
+    data.push({ id: i, value: `value-${i}` });
+  }
+  return data;
+};
+
+describe("performance", () => {
+  it("process 100.000 in each stream", (done) => {
+    const numEntries = 100_000;
+
+    const prevList = generateLargeDataset(numEntries);
+    const nextList = generateLargeDataset(numEntries);
+
+    nextList[100].value = "updated-value-100"; // 1 updated entry
+    nextList[20_000].value = "updated-value-20000"; // Another updated entry
+    nextList.push({ id: numEntries, value: `new-value-${numEntries}` }); // 1 added entry
+
+    const diffListener = streamListDiff<{ id: number; value: string }>(
+      prevList,
+      nextList,
+      "id",
+      {
+        chunksSize: 10_000,
+      },
+    );
+
+    const diffs: StreamListDiff<{ id: number; value: string }>[] = [];
+
+    diffListener.on("data", (chunk) => {
+      diffs.push(...chunk);
+    });
+
+    diffListener.on("finish", () => {
+      try {
+        const updatedEntries = diffs.filter((d) => d.status === "updated");
+        const addedEntries = diffs.filter((d) => d.status === "added");
+        const deletedEntries = diffs.filter((d) => d.status === "deleted");
+        const equalEntries = diffs.filter((d) => d.status === "equal");
+
+        expect(updatedEntries.length).toBe(2);
+        expect(addedEntries.length).toBe(1);
+        expect(deletedEntries.length).toBe(0);
+        expect(equalEntries.length).toBe(99998);
+        done();
+      } catch (err) {
+        done(err);
+      }
+    });
+
+    diffListener.on("error", (err) => done(err));
+  });
+});
diff --git a/src/lib/stream-list-diff/client/worker/utils.ts b/src/lib/stream-list-diff/client/worker/utils.ts
new file mode 100644
index 0000000..114151b
--- /dev/null
+++ b/src/lib/stream-list-diff/client/worker/utils.ts
@@ -0,0 +1,78 @@
+import { IEmitter, EmitterEvents, EventEmitter } from "@models/emitter";
+import {
+  ListStreamOptions,
+  READABLE_STREAM_ALERT,
+  ReferenceProperty,
+  StreamEvent,
+  StreamListener,
+} from "@models/stream";
+import { WebWorkerMessage } from "@models/worker";
+import { generateStream } from "..";
+
+export function workerDiff<T extends Record<string, unknown>>(
+  prevList: File | T[],
+  nextList: File | T[],
+  referenceProperty: ReferenceProperty<T>,
+  options: ListStreamOptions,
+): StreamListener<T> {
+  const emitter = new EventEmitter<EmitterEvents<T>>();
+  setTimeout(
+    () =>
+      generateStream(prevList, nextList, referenceProperty, options, emitter),
+    0,
+  );
+  return emitter as StreamListener<T>;
+}
+
+async function getArrayFromStream<T>(
+  readableStream: ReadableStream<T>,
+  showWarnings: boolean = true,
+): Promise<T[]> {
+  if (showWarnings) {
+    console.warn(READABLE_STREAM_ALERT);
+  }
+  const reader = readableStream.getReader();
+  const chunks: T[] = [];
+  let result;
+  while (!(result = await reader.read()).done) {
+    chunks.push(result.value);
+  }
+  return chunks;
+}
+
+export async function generateWorker<T extends Record<string, unknown>>(
+  prevList: ReadableStream<T> | File | T[],
+  nextList: ReadableStream<T> | File | T[],
+  referenceProperty: ReferenceProperty<T>,
+  options: ListStreamOptions,
+  emitter: IEmitter<T>,
+) {
+  try {
+    if (prevList instanceof ReadableStream) {
+      prevList = await getArrayFromStream(prevList, options?.showWarnings);
+    }
+    if (nextList instanceof ReadableStream) {
+      nextList = await getArrayFromStream(nextList, options?.showWarnings);
+    }
+    const worker = new Worker(new URL("./web-worker.js", import.meta.url), {
+      type: "module",
+    });
+    worker.postMessage({ prevList, nextList, referenceProperty, options });
+    worker.onmessage = (e: WebWorkerMessage<T>) => {
+      const { event, chunk, error } = e.data;
+      if (event === StreamEvent.Data) {
+        emitter.emit(StreamEvent.Data, chunk);
+      } else if (event === StreamEvent.Finish) {
+        emitter.emit(StreamEvent.Finish);
+        worker.terminate();
+      } else if (event === StreamEvent.Error) {
+        emitter.emit(StreamEvent.Error, new Error(error));
+        worker.terminate();
+      }
+    };
+    worker.onerror = (err: ErrorEvent) =>
+      emitter.emit(StreamEvent.Error, new Error(err.message));
+  } catch (err) {
+    return emitter.emit(StreamEvent.Error, err as Error);
+  }
+}
diff --git a/src/lib/stream-list-diff/client/worker/web-worker.ts b/src/lib/stream-list-diff/client/worker/web-worker.ts
new file mode 100644
index 0000000..273cd94
--- /dev/null
+++ b/src/lib/stream-list-diff/client/worker/web-worker.ts
@@ -0,0 +1,30 @@
+import {
+  ListStreamOptions,
+  ReferenceProperty,
+  StreamEvent,
+} from "@models/stream";
+import { workerDiff } from "./utils";
+
+self.onmessage = async <T extends Record<string, unknown>>(
+  event: MessageEvent<{
+    prevList: File | T[];
+    nextList: File | T[];
+    referenceProperty: ReferenceProperty<T>;
+    options: ListStreamOptions;
+  }>,
+) => {
+  const { prevList, nextList, referenceProperty, options } = event.data;
+  const listener = workerDiff(prevList, nextList, referenceProperty, options);
+
+  listener.on(StreamEvent.Data, (chunk) => {
+    self.postMessage({ event: StreamEvent.Data, chunk });
+  });
+
+  listener.on(StreamEvent.Finish, () => {
+    self.postMessage({ event: StreamEvent.Finish });
+  });
+
+  listener.on(StreamEvent.Error, (error) => {
+    self.postMessage({ event: StreamEvent.Error, error: error.message });
+  });
+};
diff --git a/src/lib/stream-list-diff/server/index.ts b/src/lib/stream-list-diff/server/index.ts
index d4fbb3e..a7cce68 100644
--- a/src/lib/stream-list-diff/server/index.ts
+++ b/src/lib/stream-list-diff/server/index.ts
@@ -1,27 +1,25 @@
 import { createReadStream } from "fs";
 import { Readable, Transform } from "stream";
-import { LIST_STATUS } from "@models/list";
+import { Worker } from "worker_threads";
+import { IEmitter, EmitterEvents, EventEmitter } from "@models/emitter";
+import { ListStatus, ListType } from "@models/list";
 import {
   DataBuffer,
   DEFAULT_LIST_STREAM_OPTIONS,
   FilePath,
   ListStreamOptions,
   ReferenceProperty,
-} from "@models/stream";
-import {
-  Emitter,
-  EmitterEvents,
-  EventEmitter,
-  StreamListener,
   StreamEvent,
-} from "../emitter";
+  StreamListener,
+} from "@models/stream";
 import { isDataValid, isValidChunkSize, outputDiffChunk } from "../utils";
+import { generateWorker } from "./worker/utils";
 
 async function getDiffChunks<T extends Record<string, unknown>>(
   prevStream: Readable,
   nextStream: Readable,
   referenceProperty: ReferenceProperty<T>,
-  emitter: Emitter<T>,
+  emitter: IEmitter<T>,
   options: ListStreamOptions = DEFAULT_LIST_STREAM_OPTIONS,
 ): Promise<void> {
   if (!isValidChunkSize(options?.chunksSize)) {
@@ -42,7 +40,7 @@ async function getDiffChunks<T extends Record<string, unknown>>(
     const { isValid, message } = isDataValid(
       chunk,
       referenceProperty,
-      "prevList",
+      ListType.PREV,
     );
     if (!isValid) {
       emitter.emit(StreamEvent.Error, new Error(message));
@@ -67,10 +65,10 @@ async function getDiffChunks<T extends Record<string, unknown>>(
             indexDiff,
             status:
               indexDiff === 0
-                ? LIST_STATUS.EQUAL
+                ? ListStatus.EQUAL
                 : options.considerMoveAsUpdate
-                  ? LIST_STATUS.UPDATED
-                  : LIST_STATUS.MOVED,
+                  ? ListStatus.UPDATED
+                  : ListStatus.MOVED,
           },
           options,
         );
@@ -82,7 +80,7 @@ async function getDiffChunks<T extends Record<string, unknown>>(
             prevIndex: currentPrevIndex,
             newIndex: relatedChunk.index,
             indexDiff,
-            status: LIST_STATUS.UPDATED,
+            status: ListStatus.UPDATED,
           },
           options,
         );
@@ -97,7 +95,7 @@ async function getDiffChunks<T extends Record<string, unknown>>(
     const { isValid, message } = isDataValid(
       chunk,
       referenceProperty,
-      "nextList",
+      ListType.NEXT,
     );
     if (!isValid) {
       emitter.emit(StreamEvent.Error, new Error(message));
@@ -122,10 +120,10 @@ async function getDiffChunks<T extends Record<string, unknown>>(
             indexDiff,
             status:
               indexDiff === 0
-                ? LIST_STATUS.EQUAL
+                ? ListStatus.EQUAL
                 : options.considerMoveAsUpdate
-                  ? LIST_STATUS.UPDATED
-                  : LIST_STATUS.MOVED,
+                  ? ListStatus.UPDATED
+                  : ListStatus.MOVED,
           },
           options,
         );
@@ -137,7 +135,7 @@ async function getDiffChunks<T extends Record<string, unknown>>(
             prevIndex: relatedChunk.index,
             newIndex: currentNextIndex,
             indexDiff,
-            status: LIST_STATUS.UPDATED,
+            status: ListStatus.UPDATED,
           },
           options,
         );
@@ -169,7 +167,7 @@ async function getDiffChunks<T extends Record<string, unknown>>(
         prevIndex: chunk.index,
         newIndex: null,
         indexDiff: null,
-        status: LIST_STATUS.DELETED,
+        status: ListStatus.DELETED,
       },
       options,
     );
@@ -183,7 +181,7 @@ async function getDiffChunks<T extends Record<string, unknown>>(
         prevIndex: null,
         newIndex: chunk.index,
         indexDiff: null,
-        status: LIST_STATUS.ADDED,
+        status: ListStatus.ADDED,
       },
       options,
     );
@@ -195,7 +193,7 @@ async function getDiffChunks<T extends Record<string, unknown>>(
 
 function getValidStream<T>(
   input: Readable | FilePath | T[],
-  listType: "prevList" | "nextList",
+  listType: ListType,
 ): Readable {
   if (input instanceof Readable) {
     return input;
@@ -227,10 +225,27 @@ function getValidStream<T>(
       }),
     );
   }
-
   throw new Error(`Invalid ${listType}. Expected Readable, Array, or File.`);
 }
 
+export async function generateStream<T extends Record<string, unknown>>(
+  prevList: Readable | FilePath | T[],
+  nextList: Readable | FilePath | T[],
+  referenceProperty: ReferenceProperty<T>,
+  options: ListStreamOptions,
+  emitter: IEmitter<T>,
+): Promise<void> {
+  try {
+    const [prevStream, nextStream] = await Promise.all([
+      getValidStream(prevList, ListType.PREV),
+      getValidStream(nextList, ListType.NEXT),
+    ]);
+    getDiffChunks(prevStream, nextStream, referenceProperty, emitter, options);
+  } catch (err) {
+    return emitter.emit(StreamEvent.Error, err as Error);
+  }
+}
+
 /**
  * Streams the diff of two object lists
  * @param {Readable | FilePath | Record<string, unknown>[]} prevList - The original object list.
@@ -238,29 +253,27 @@ function getValidStream<T>(
  * @param {string} referenceProperty - A common property in all the objects of your lists (e.g. `id`)
  * @param {ListStreamOptions} options - Options to refine your output.
     - `chunksSize`: the number of object diffs returned by each streamed chunk. (e.g. `0` = 1 object diff by chunk, `10` = 10 object diffs by chunk).
-    - `showOnly`: returns only the values whose status you are interested in. (e.g. `["added", "equal"]`)
-    - `considerMoveAsUpdate`: if set to `true` a `moved` object will be considered as `updated`
+    - `showOnly`: returns only the values whose status you are interested in. (e.g. `["added", "equal"]`).
+    - `considerMoveAsUpdate`: if set to `true` a `moved` object will be considered as `updated`.
+    - `useWorker`: if set to `true`, the diff will be run in a worker. Recommended for maximum performance, `true` by default.
+    - `showWarnings`: if set to `true`, potential warnings will be displayed in the console. 
  * @returns StreamListener
  */
 export function streamListDiff<T extends Record<string, unknown>>(
-  prevStream: Readable | FilePath | T[],
-  nextStream: Readable | FilePath | T[],
+  prevList: Readable | FilePath | T[],
+  nextList: Readable | FilePath | T[],
   referenceProperty: ReferenceProperty<T>,
   options: ListStreamOptions = DEFAULT_LIST_STREAM_OPTIONS,
 ): StreamListener<T> {
   const emitter = new EventEmitter<EmitterEvents<T>>();
-  setTimeout(async () => {
-    try {
-      await getDiffChunks(
-        getValidStream(prevStream, "prevList"),
-        getValidStream(nextStream, "nextList"),
-        referenceProperty,
-        emitter,
-        options,
-      );
-    } catch (err) {
-      return emitter.emit(StreamEvent.Error, err as Error);
-    }
-  }, 0);
+  if (typeof Worker === "undefined" || !options.useWorker) {
+    setTimeout(
+      () =>
+        generateStream(prevList, nextList, referenceProperty, options, emitter),
+      0,
+    );
+  } else {
+    generateWorker(prevList, nextList, referenceProperty, options, emitter);
+  }
   return emitter as StreamListener<T>;
 }
diff --git a/src/lib/stream-list-diff/server/stream-list-diff.test.ts b/src/lib/stream-list-diff/server/stream-list-diff.test.ts
index f1751d0..3ae87dc 100644
--- a/src/lib/stream-list-diff/server/stream-list-diff.test.ts
+++ b/src/lib/stream-list-diff/server/stream-list-diff.test.ts
@@ -1,6 +1,6 @@
 import path from "path";
 import { Readable } from "stream";
-import { LIST_STATUS } from "@models/list";
+import { ListStatus } from "@models/list";
 import { StreamListDiff } from "@models/stream";
 import { streamListDiff } from ".";
 
@@ -10,7 +10,10 @@ describe("data emission", () => {
       { id: 1, name: "Item 1" },
       { id: 2, name: "Item 2" },
     ];
-    const diff = streamListDiff([], nextList, "id", { chunksSize: 2 });
+    const diff = streamListDiff([], nextList, "id", {
+      chunksSize: 2,
+      useWorker: false,
+    });
 
     const expectedChunks = [
       {
@@ -19,7 +22,7 @@ describe("data emission", () => {
         prevIndex: null,
         newIndex: 0,
         indexDiff: null,
-        status: LIST_STATUS.ADDED,
+        status: ListStatus.ADDED,
       },
       {
         previousValue: null,
@@ -27,7 +30,7 @@ describe("data emission", () => {
         prevIndex: null,
         newIndex: 1,
         indexDiff: null,
-        status: LIST_STATUS.ADDED,
+        status: ListStatus.ADDED,
       },
     ];
     let chunkCount = 0;
@@ -45,7 +48,10 @@ describe("data emission", () => {
       { id: 1, name: "Item 1" },
       { id: 2, name: "Item 2" },
     ];
-    const diff = streamListDiff(prevList, [], "id", { chunksSize: 2 });
+    const diff = streamListDiff(prevList, [], "id", {
+      chunksSize: 2,
+      useWorker: false,
+    });
 
     const expectedChunks = [
       {
@@ -54,7 +60,7 @@ describe("data emission", () => {
         prevIndex: 0,
         newIndex: null,
         indexDiff: null,
-        status: LIST_STATUS.DELETED,
+        status: ListStatus.DELETED,
       },
       {
         previousValue: { id: 2, name: "Item 2" },
@@ -62,7 +68,7 @@ describe("data emission", () => {
         prevIndex: 1,
         newIndex: null,
         indexDiff: null,
-        status: LIST_STATUS.DELETED,
+        status: ListStatus.DELETED,
       },
     ];
     let chunkCount = 0;
@@ -70,7 +76,7 @@ describe("data emission", () => {
       expect(chunk).toStrictEqual(expectedChunks);
       chunkCount++;
     });
-    diff.on("error", (err) => console.error("shiiiite", err));
+    diff.on("error", (err) => console.error(err));
     diff.on("finish", () => {
       expect(chunkCount).toBe(1);
       done();
@@ -85,7 +91,7 @@ describe("data emission", () => {
       { id: 2, name: "Item 2" },
       { id: 3, name: "Item 3" },
     ];
-    const diff = streamListDiff(prevList, nextList, "id");
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: false });
 
     const expectedChunks = [
       [
@@ -95,7 +101,7 @@ describe("data emission", () => {
           prevIndex: 1,
           newIndex: 0,
           indexDiff: -1,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
       ],
       [
@@ -105,7 +111,7 @@ describe("data emission", () => {
           prevIndex: 0,
           newIndex: null,
           indexDiff: null,
-          status: LIST_STATUS.DELETED,
+          status: ListStatus.DELETED,
         },
       ],
       [
@@ -115,7 +121,7 @@ describe("data emission", () => {
           prevIndex: null,
           newIndex: 1,
           indexDiff: null,
-          status: LIST_STATUS.ADDED,
+          status: ListStatus.ADDED,
         },
       ],
     ];
@@ -158,6 +164,7 @@ describe("data emission", () => {
     ];
     const diff = streamListDiff(prevList, nextList, "id", {
       chunksSize: 5,
+      useWorker: false,
     });
 
     const expectedChunks = [
@@ -168,7 +175,7 @@ describe("data emission", () => {
           prevIndex: 0,
           newIndex: 0,
           indexDiff: 0,
-          status: LIST_STATUS.EQUAL,
+          status: ListStatus.EQUAL,
         },
         {
           previousValue: { id: 2, name: "Item 2" },
@@ -176,7 +183,7 @@ describe("data emission", () => {
           prevIndex: 1,
           newIndex: 1,
           indexDiff: 0,
-          status: LIST_STATUS.UPDATED,
+          status: ListStatus.UPDATED,
         },
         {
           previousValue: { id: 3, name: "Item 3" },
@@ -184,7 +191,7 @@ describe("data emission", () => {
           prevIndex: 2,
           newIndex: 2,
           indexDiff: 0,
-          status: LIST_STATUS.EQUAL,
+          status: ListStatus.EQUAL,
         },
         {
           previousValue: { id: 5, name: "Item 5" },
@@ -192,7 +199,7 @@ describe("data emission", () => {
           prevIndex: 4,
           newIndex: 3,
           indexDiff: -1,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
         {
           previousValue: { id: 6, name: "Item 6" },
@@ -200,7 +207,7 @@ describe("data emission", () => {
           prevIndex: 5,
           newIndex: 4,
           indexDiff: -1,
-          status: LIST_STATUS.UPDATED,
+          status: ListStatus.UPDATED,
         },
       ],
       [
@@ -210,7 +217,7 @@ describe("data emission", () => {
           prevIndex: 6,
           newIndex: 5,
           indexDiff: -1,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
         {
           previousValue: { id: 9, name: "Item 9" },
@@ -218,7 +225,7 @@ describe("data emission", () => {
           prevIndex: 8,
           newIndex: 8,
           indexDiff: 0,
-          status: LIST_STATUS.EQUAL,
+          status: ListStatus.EQUAL,
         },
         {
           previousValue: { id: 10, name: "Item 10" },
@@ -226,7 +233,7 @@ describe("data emission", () => {
           prevIndex: 9,
           newIndex: 6,
           indexDiff: -3,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
         {
           previousValue: { id: 8, name: "Item 8" },
@@ -234,7 +241,7 @@ describe("data emission", () => {
           prevIndex: 7,
           newIndex: 9,
           indexDiff: 2,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
         {
           previousValue: { id: 4, name: "Item 4" },
@@ -242,7 +249,7 @@ describe("data emission", () => {
           prevIndex: 3,
           newIndex: null,
           indexDiff: null,
-          status: LIST_STATUS.DELETED,
+          status: ListStatus.DELETED,
         },
       ],
       [
@@ -252,7 +259,7 @@ describe("data emission", () => {
           prevIndex: null,
           newIndex: 7,
           indexDiff: null,
-          status: LIST_STATUS.ADDED,
+          status: ListStatus.ADDED,
         },
       ],
     ];
@@ -286,6 +293,7 @@ describe("data emission", () => {
 
     const diff = streamListDiff(prevList, nextList, "id", {
       chunksSize: 5,
+      useWorker: false,
     });
 
     const expectedChunks = [
@@ -295,7 +303,7 @@ describe("data emission", () => {
         prevIndex: 0,
         newIndex: 0,
         indexDiff: 0,
-        status: LIST_STATUS.EQUAL,
+        status: ListStatus.EQUAL,
       },
       {
         previousValue: { id: 2, name: "Item 2" },
@@ -303,7 +311,7 @@ describe("data emission", () => {
         prevIndex: 1,
         newIndex: 1,
         indexDiff: 0,
-        status: LIST_STATUS.UPDATED,
+        status: ListStatus.UPDATED,
       },
       {
         previousValue: { id: 3, name: "Item 3" },
@@ -311,7 +319,7 @@ describe("data emission", () => {
         prevIndex: 2,
         newIndex: 2,
         indexDiff: 0,
-        status: LIST_STATUS.EQUAL,
+        status: ListStatus.EQUAL,
       },
       {
         previousValue: { id: 4, name: "Item 4" },
@@ -319,7 +327,7 @@ describe("data emission", () => {
         prevIndex: 3,
         newIndex: null,
         indexDiff: null,
-        status: LIST_STATUS.DELETED,
+        status: ListStatus.DELETED,
       },
       {
         previousValue: null,
@@ -327,7 +335,7 @@ describe("data emission", () => {
         prevIndex: null,
         newIndex: 3,
         indexDiff: null,
-        status: LIST_STATUS.ADDED,
+        status: ListStatus.ADDED,
       },
     ];
 
@@ -336,7 +344,7 @@ describe("data emission", () => {
       expect(chunk).toStrictEqual(expectedChunks);
       chunkCount++;
     });
-    diff.on("error", (err) => console.error("sheeeet", err));
+    diff.on("error", (err) => console.error(err));
     diff.on("finish", () => {
       expect(chunkCount).toBe(1);
       done();
@@ -358,6 +366,7 @@ describe("data emission", () => {
     const diff = streamListDiff(prevList, nextList, "id", {
       chunksSize: 5,
       considerMoveAsUpdate: true,
+      useWorker: false,
     });
 
     const expectedChunks = [
@@ -367,7 +376,7 @@ describe("data emission", () => {
         prevIndex: 1,
         newIndex: 0,
         indexDiff: -1,
-        status: LIST_STATUS.UPDATED,
+        status: ListStatus.UPDATED,
       },
       {
         previousValue: { id: 1, name: "Item 1" },
@@ -375,7 +384,7 @@ describe("data emission", () => {
         prevIndex: 0,
         newIndex: 1,
         indexDiff: 1,
-        status: LIST_STATUS.UPDATED,
+        status: ListStatus.UPDATED,
       },
       {
         previousValue: { id: 3, name: "Item 3" },
@@ -383,7 +392,7 @@ describe("data emission", () => {
         prevIndex: 2,
         newIndex: 2,
         indexDiff: 0,
-        status: LIST_STATUS.EQUAL,
+        status: ListStatus.EQUAL,
       },
       {
         previousValue: { id: 4, name: "Item 4" },
@@ -391,7 +400,7 @@ describe("data emission", () => {
         prevIndex: 3,
         newIndex: null,
         indexDiff: null,
-        status: LIST_STATUS.DELETED,
+        status: ListStatus.DELETED,
       },
       {
         previousValue: null,
@@ -399,7 +408,7 @@ describe("data emission", () => {
         prevIndex: null,
         newIndex: 3,
         indexDiff: null,
-        status: LIST_STATUS.ADDED,
+        status: ListStatus.ADDED,
       },
     ];
 
@@ -430,6 +439,7 @@ describe("data emission", () => {
     const diff = streamListDiff(prevList, nextList, "id", {
       chunksSize: 5,
       showOnly: ["added", "deleted"],
+      useWorker: false,
     });
 
     const expectedChunks = [
@@ -439,7 +449,7 @@ describe("data emission", () => {
         prevIndex: 3,
         newIndex: null,
         indexDiff: null,
-        status: LIST_STATUS.DELETED,
+        status: ListStatus.DELETED,
       },
       {
         previousValue: null,
@@ -447,7 +457,7 @@ describe("data emission", () => {
         prevIndex: null,
         newIndex: 3,
         indexDiff: null,
-        status: LIST_STATUS.ADDED,
+        status: ListStatus.ADDED,
       },
     ];
 
@@ -517,6 +527,7 @@ describe("data emission", () => {
     ];
     const diff = streamListDiff(prevList, nextList, "id", {
       chunksSize: 5,
+      useWorker: false,
     });
 
     const expectedChunks = [
@@ -535,7 +546,7 @@ describe("data emission", () => {
           prevIndex: 0,
           newIndex: 0,
           indexDiff: 0,
-          status: LIST_STATUS.EQUAL,
+          status: ListStatus.EQUAL,
         },
         {
           previousValue: { id: 2, name: "Item 2" },
@@ -543,7 +554,7 @@ describe("data emission", () => {
           prevIndex: 1,
           newIndex: 1,
           indexDiff: 0,
-          status: LIST_STATUS.UPDATED,
+          status: ListStatus.UPDATED,
         },
         {
           previousValue: {
@@ -559,7 +570,7 @@ describe("data emission", () => {
           prevIndex: 2,
           newIndex: 2,
           indexDiff: 0,
-          status: LIST_STATUS.EQUAL,
+          status: ListStatus.EQUAL,
         },
         {
           previousValue: { id: 5, name: "Item 5" },
@@ -567,7 +578,7 @@ describe("data emission", () => {
           prevIndex: 4,
           newIndex: 3,
           indexDiff: -1,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
         {
           previousValue: {
@@ -583,7 +594,7 @@ describe("data emission", () => {
           prevIndex: 5,
           newIndex: 4,
           indexDiff: -1,
-          status: LIST_STATUS.UPDATED,
+          status: ListStatus.UPDATED,
         },
       ],
       [
@@ -593,7 +604,7 @@ describe("data emission", () => {
           prevIndex: 6,
           newIndex: 5,
           indexDiff: -1,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
         {
           previousValue: { id: 9, name: "Item 9" },
@@ -601,7 +612,7 @@ describe("data emission", () => {
           prevIndex: 8,
           newIndex: 8,
           indexDiff: 0,
-          status: LIST_STATUS.EQUAL,
+          status: ListStatus.EQUAL,
         },
         {
           previousValue: {
@@ -625,7 +636,7 @@ describe("data emission", () => {
           prevIndex: 9,
           newIndex: 6,
           indexDiff: -3,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
         {
           previousValue: { id: 8, name: "Item 8" },
@@ -633,7 +644,7 @@ describe("data emission", () => {
           prevIndex: 7,
           newIndex: 9,
           indexDiff: 2,
-          status: LIST_STATUS.MOVED,
+          status: ListStatus.MOVED,
         },
         {
           previousValue: {
@@ -645,7 +656,7 @@ describe("data emission", () => {
           prevIndex: 3,
           newIndex: null,
           indexDiff: null,
-          status: LIST_STATUS.DELETED,
+          status: ListStatus.DELETED,
         },
       ],
       [
@@ -655,7 +666,7 @@ describe("data emission", () => {
           prevIndex: null,
           newIndex: 7,
           indexDiff: null,
-          status: LIST_STATUS.ADDED,
+          status: ListStatus.ADDED,
         },
       ],
     ];
@@ -694,7 +705,7 @@ describe("input handling", () => {
       prevIndex: 0,
       newIndex: 0,
       indexDiff: 0,
-      status: LIST_STATUS.EQUAL,
+      status: ListStatus.EQUAL,
     },
     {
       previousValue: { id: 2, name: "Item 2" },
@@ -702,7 +713,7 @@ describe("input handling", () => {
       prevIndex: 1,
       newIndex: 1,
       indexDiff: 0,
-      status: LIST_STATUS.UPDATED,
+      status: ListStatus.UPDATED,
     },
     {
       previousValue: { id: 3, name: "Item 3" },
@@ -710,7 +721,7 @@ describe("input handling", () => {
       prevIndex: 2,
       newIndex: 2,
       indexDiff: 0,
-      status: LIST_STATUS.EQUAL,
+      status: ListStatus.EQUAL,
     },
     {
       previousValue: { id: 4, name: "Item 4" },
@@ -718,7 +729,7 @@ describe("input handling", () => {
       prevIndex: 3,
       newIndex: null,
       indexDiff: null,
-      status: LIST_STATUS.DELETED,
+      status: ListStatus.DELETED,
     },
     {
       previousValue: null,
@@ -726,7 +737,7 @@ describe("input handling", () => {
       prevIndex: null,
       newIndex: 3,
       indexDiff: null,
-      status: LIST_STATUS.ADDED,
+      status: ListStatus.ADDED,
     },
   ];
 
@@ -736,6 +747,7 @@ describe("input handling", () => {
 
     const diff = streamListDiff(prevStream, nextStream, "id", {
       chunksSize: 5,
+      useWorker: false,
     });
 
     let chunkCount = 0;
@@ -743,7 +755,7 @@ describe("input handling", () => {
       expect(chunk).toStrictEqual(expectedChunks);
       chunkCount++;
     });
-    diff.on("error", (err) => console.error("sheeeet", err));
+    diff.on("error", (err) => console.error(err));
     diff.on("finish", () => {
       expect(chunkCount).toBe(1);
       done();
@@ -755,6 +767,7 @@ describe("input handling", () => {
 
     const diff = streamListDiff(prevFile, nextFile, "id", {
       chunksSize: 5,
+      useWorker: false,
     });
 
     let chunkCount = 0;
@@ -762,7 +775,7 @@ describe("input handling", () => {
       expect(chunk).toStrictEqual(expectedChunks);
       chunkCount++;
     });
-    diff.on("error", (err) => console.error("sheeeet", err));
+    diff.on("error", (err) => console.error(err));
     diff.on("finish", () => {
       expect(chunkCount).toBe(1);
       done();
@@ -774,6 +787,7 @@ describe("input handling", () => {
 
     const diff = streamListDiff(prevStream, nextFile, "id", {
       chunksSize: 5,
+      useWorker: false,
     });
 
     let chunkCount = 0;
@@ -781,7 +795,7 @@ describe("input handling", () => {
       expect(chunk).toStrictEqual(expectedChunks);
       chunkCount++;
     });
-    diff.on("error", (err) => console.error("sheeeet", err));
+    diff.on("error", (err) => console.error(err));
     diff.on("finish", () => {
       expect(chunkCount).toBe(1);
       done();
@@ -792,6 +806,7 @@ describe("input handling", () => {
 
     const diff = streamListDiff(prevStream, nextList, "id", {
       chunksSize: 5,
+      useWorker: false,
     });
 
     let chunkCount = 0;
@@ -799,7 +814,7 @@ describe("input handling", () => {
       expect(chunk).toStrictEqual(expectedChunks);
       chunkCount++;
     });
-    diff.on("error", (err) => console.error("sheeeet", err));
+    diff.on("error", (err) => console.error(err));
     diff.on("finish", () => {
       expect(chunkCount).toBe(1);
       done();
@@ -810,6 +825,7 @@ describe("input handling", () => {
 
     const diff = streamListDiff(prevFile, nextList, "id", {
       chunksSize: 5,
+      useWorker: false,
     });
 
     let chunkCount = 0;
@@ -817,7 +833,7 @@ describe("input handling", () => {
       expect(chunk).toStrictEqual(expectedChunks);
       chunkCount++;
     });
-    diff.on("error", (err) => console.error("sheeeet", err));
+    diff.on("error", (err) => console.error(err));
     diff.on("finish", () => {
       expect(chunkCount).toBe(1);
       done();
@@ -827,7 +843,7 @@ describe("input handling", () => {
 
 describe("finish event", () => {
   it("emits 'finish' event if no prevList nor nextList is provided", (done) => {
-    const diff = streamListDiff([], [], "id");
+    const diff = streamListDiff([], [], "id", { useWorker: false });
     diff.on("finish", () => done());
   });
   it("emits 'finish' event when all the chunks have been processed", (done) => {
@@ -839,7 +855,7 @@ describe("finish event", () => {
       { id: 2, name: "Item 2" },
       { id: 3, name: "Item 3" },
     ];
-    const diff = streamListDiff(prevList, nextList, "id");
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: false });
     diff.on("finish", () => done());
   });
 });
@@ -857,7 +873,7 @@ describe("error event", () => {
     ];
 
     // @ts-expect-error prevList is invalid by design for the test
-    const diff = streamListDiff(prevList, nextList, "id");
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: false });
 
     diff.on("error", (err) => {
       expect(err["message"]).toEqual(
@@ -879,7 +895,7 @@ describe("error event", () => {
     ];
 
     // @ts-expect-error nextList is invalid by design for the test
-    const diff = streamListDiff(prevList, nextList, "id");
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: false });
 
     diff.on("error", (err) => {
       expect(err["message"]).toEqual(
@@ -896,7 +912,7 @@ describe("error event", () => {
       { id: 2, name: "Item 2" },
     ];
 
-    const diff = streamListDiff(prevList, nextList, "id");
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: false });
 
     diff.on("error", (err) => {
       expect(err["message"]).toEqual(
@@ -913,7 +929,7 @@ describe("error event", () => {
     ];
     const nextList = [{ id: 1, name: "Item 1" }, { name: "Item 2" }];
 
-    const diff = streamListDiff(prevList, nextList, "id");
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: false });
 
     diff.on("error", (err) => {
       expect(err["message"]).toEqual(
@@ -932,6 +948,7 @@ describe("error event", () => {
 
     const diff = streamListDiff(prevList, nextList, "id", {
       chunksSize: -3,
+      useWorker: false,
     });
 
     diff.on("error", (err) => {
@@ -946,7 +963,9 @@ describe("error event", () => {
     const nextList = [{ id: 1, name: "Item 1" }, { name: "Item 2" }];
 
     // @ts-expect-error - prevList is invalid by design for the test
-    const diff = streamListDiff({ name: "hello" }, nextList, "id");
+    const diff = streamListDiff({ name: "hello" }, nextList, "id", {
+      useWorker: false,
+    });
 
     diff.on("error", (err) => {
       expect(err["message"]).toEqual(
@@ -959,7 +978,7 @@ describe("error event", () => {
     const prevList = [{ id: 1, name: "Item 1" }, { name: "Item 2" }];
 
     // @ts-expect-error - nextList is invalid by design for the test
-    const diff = streamListDiff(prevList, null, "id");
+    const diff = streamListDiff(prevList, null, "id", { useWorker: false });
 
     diff.on("error", (err) => {
       expect(err["message"]).toEqual(
diff --git a/src/lib/stream-list-diff/server/stream-list-diff.worker.test.ts b/src/lib/stream-list-diff/server/stream-list-diff.worker.test.ts
new file mode 100644
index 0000000..690e1ff
--- /dev/null
+++ b/src/lib/stream-list-diff/server/stream-list-diff.worker.test.ts
@@ -0,0 +1,1048 @@
+import path from "path";
+import { Readable } from "stream";
+import { ListStatus } from "@models/list";
+import { StreamListDiff } from "@models/stream";
+import { streamListDiff } from ".";
+
+describe("data emission", () => {
+  it("emits 'data' event and consider the all the nextList added if no prevList is provided", (done) => {
+    const nextList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+    const diff = streamListDiff([], nextList, "id", {
+      chunksSize: 2,
+      useWorker: true,
+    });
+
+    const expectedChunks = [
+      {
+        previousValue: null,
+        currentValue: { id: 1, name: "Item 1" },
+        prevIndex: null,
+        newIndex: 0,
+        indexDiff: null,
+        status: ListStatus.ADDED,
+      },
+      {
+        previousValue: null,
+        currentValue: { id: 2, name: "Item 2" },
+        prevIndex: null,
+        newIndex: 1,
+        indexDiff: null,
+        status: ListStatus.ADDED,
+      },
+    ];
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toEqual(expectedChunks);
+      chunkCount++;
+    });
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("emits 'data' event and consider the all the prevList deleted if no nextList is provided", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+    const diff = streamListDiff(prevList, [], "id", {
+      chunksSize: 2,
+      useWorker: true,
+    });
+
+    const expectedChunks = [
+      {
+        previousValue: { id: 1, name: "Item 1" },
+        currentValue: null,
+        prevIndex: 0,
+        newIndex: null,
+        indexDiff: null,
+        status: ListStatus.DELETED,
+      },
+      {
+        previousValue: { id: 2, name: "Item 2" },
+        currentValue: null,
+        prevIndex: 1,
+        newIndex: null,
+        indexDiff: null,
+        status: ListStatus.DELETED,
+      },
+    ];
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toEqual(expectedChunks);
+      chunkCount++;
+    });
+    diff.on("error", (err) => console.error(err));
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("emits 'data' event with one object diff by chunk if chunkSize is 0 or undefined", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+    const nextList = [
+      { id: 2, name: "Item 2" },
+      { id: 3, name: "Item 3" },
+    ];
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: true });
+
+    const expectedChunks = [
+      [
+        {
+          previousValue: { id: 2, name: "Item 2" },
+          currentValue: { id: 2, name: "Item 2" },
+          prevIndex: 1,
+          newIndex: 0,
+          indexDiff: -1,
+          status: ListStatus.MOVED,
+        },
+      ],
+      [
+        {
+          previousValue: { id: 1, name: "Item 1" },
+          currentValue: null,
+          prevIndex: 0,
+          newIndex: null,
+          indexDiff: null,
+          status: ListStatus.DELETED,
+        },
+      ],
+      [
+        {
+          previousValue: null,
+          currentValue: { id: 3, name: "Item 3" },
+          prevIndex: null,
+          newIndex: 1,
+          indexDiff: null,
+          status: ListStatus.ADDED,
+        },
+      ],
+    ];
+
+    let chunkCount = 0;
+
+    diff.on("data", (chunk) => {
+      expect(chunk).toEqual(expectedChunks[chunkCount]);
+      chunkCount++;
+    });
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(3);
+      done();
+    });
+  });
+  it("emits 'data' event with 5 object diff by chunk and return the last object diff in a one entry chunk at the end", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+      { id: 3, name: "Item 3" },
+      { id: 4, name: "Item 4" },
+      { id: 5, name: "Item 5" },
+      { id: 6, name: "Item 6" },
+      { id: 7, name: "Item 7" },
+      { id: 8, name: "Item 8" },
+      { id: 9, name: "Item 9" },
+      { id: 10, name: "Item 10" },
+    ];
+    const nextList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item Two" },
+      { id: 3, name: "Item 3" },
+      { id: 5, name: "Item 5" },
+      { id: 6, name: "Item Six" },
+      { id: 7, name: "Item 7" },
+      { id: 10, name: "Item 10" },
+      { id: 11, name: "Item 11" },
+      { id: 9, name: "Item 9" },
+      { id: 8, name: "Item 8" },
+    ];
+    const diff = streamListDiff(prevList, nextList, "id", {
+      chunksSize: 5,
+      useWorker: true,
+    });
+
+    const expectedChunks = [
+      [
+        {
+          previousValue: { id: 1, name: "Item 1" },
+          currentValue: { id: 1, name: "Item 1" },
+          prevIndex: 0,
+          newIndex: 0,
+          indexDiff: 0,
+          status: ListStatus.EQUAL,
+        },
+        {
+          previousValue: { id: 2, name: "Item 2" },
+          currentValue: { id: 2, name: "Item Two" },
+          prevIndex: 1,
+          newIndex: 1,
+          indexDiff: 0,
+          status: ListStatus.UPDATED,
+        },
+        {
+          previousValue: { id: 3, name: "Item 3" },
+          currentValue: { id: 3, name: "Item 3" },
+          prevIndex: 2,
+          newIndex: 2,
+          indexDiff: 0,
+          status: ListStatus.EQUAL,
+        },
+        {
+          previousValue: { id: 5, name: "Item 5" },
+          currentValue: { id: 5, name: "Item 5" },
+          prevIndex: 4,
+          newIndex: 3,
+          indexDiff: -1,
+          status: ListStatus.MOVED,
+        },
+        {
+          previousValue: { id: 6, name: "Item 6" },
+          currentValue: { id: 6, name: "Item Six" },
+          prevIndex: 5,
+          newIndex: 4,
+          indexDiff: -1,
+          status: ListStatus.UPDATED,
+        },
+      ],
+      [
+        {
+          previousValue: { id: 7, name: "Item 7" },
+          currentValue: { id: 7, name: "Item 7" },
+          prevIndex: 6,
+          newIndex: 5,
+          indexDiff: -1,
+          status: ListStatus.MOVED,
+        },
+        {
+          previousValue: { id: 9, name: "Item 9" },
+          currentValue: { id: 9, name: "Item 9" },
+          prevIndex: 8,
+          newIndex: 8,
+          indexDiff: 0,
+          status: ListStatus.EQUAL,
+        },
+        {
+          previousValue: { id: 10, name: "Item 10" },
+          currentValue: { id: 10, name: "Item 10" },
+          prevIndex: 9,
+          newIndex: 6,
+          indexDiff: -3,
+          status: ListStatus.MOVED,
+        },
+        {
+          previousValue: { id: 8, name: "Item 8" },
+          currentValue: { id: 8, name: "Item 8" },
+          prevIndex: 7,
+          newIndex: 9,
+          indexDiff: 2,
+          status: ListStatus.MOVED,
+        },
+        {
+          previousValue: { id: 4, name: "Item 4" },
+          currentValue: null,
+          prevIndex: 3,
+          newIndex: null,
+          indexDiff: null,
+          status: ListStatus.DELETED,
+        },
+      ],
+      [
+        {
+          previousValue: null,
+          currentValue: { id: 11, name: "Item 11" },
+          prevIndex: null,
+          newIndex: 7,
+          indexDiff: null,
+          status: ListStatus.ADDED,
+        },
+      ],
+    ];
+
+    let chunkCount = 0;
+
+    diff.on("data", (chunk) => {
+      expect(chunk).toEqual(expectedChunks[chunkCount]);
+      chunkCount++;
+    });
+
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(3);
+      done();
+    });
+  });
+  it("emits 'data' event with all the objects diff in a single chunk if the chunkSize is bigger than the provided lists ", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+      { id: 3, name: "Item 3" },
+      { id: 4, name: "Item 4" },
+    ];
+
+    const nextList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item Two" },
+      { id: 3, name: "Item 3" },
+      { id: 5, name: "Item 5" },
+    ];
+
+    const diff = streamListDiff(prevList, nextList, "id", {
+      chunksSize: 5,
+      useWorker: true,
+    });
+
+    const expectedChunks = [
+      {
+        previousValue: { id: 1, name: "Item 1" },
+        currentValue: { id: 1, name: "Item 1" },
+        prevIndex: 0,
+        newIndex: 0,
+        indexDiff: 0,
+        status: ListStatus.EQUAL,
+      },
+      {
+        previousValue: { id: 2, name: "Item 2" },
+        currentValue: { id: 2, name: "Item Two" },
+        prevIndex: 1,
+        newIndex: 1,
+        indexDiff: 0,
+        status: ListStatus.UPDATED,
+      },
+      {
+        previousValue: { id: 3, name: "Item 3" },
+        currentValue: { id: 3, name: "Item 3" },
+        prevIndex: 2,
+        newIndex: 2,
+        indexDiff: 0,
+        status: ListStatus.EQUAL,
+      },
+      {
+        previousValue: { id: 4, name: "Item 4" },
+        currentValue: null,
+        prevIndex: 3,
+        newIndex: null,
+        indexDiff: null,
+        status: ListStatus.DELETED,
+      },
+      {
+        previousValue: null,
+        currentValue: { id: 5, name: "Item 5" },
+        prevIndex: null,
+        newIndex: 3,
+        indexDiff: null,
+        status: ListStatus.ADDED,
+      },
+    ];
+
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toEqual(expectedChunks);
+      chunkCount++;
+    });
+    diff.on("error", (err) => console.error(err));
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("emits 'data' event with moved objects considered as updated if considerMoveAsUpdate is true", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+      { id: 3, name: "Item 3" },
+      { id: 4, name: "Item 4" },
+    ];
+    const nextList = [
+      { id: 2, name: "Item Two" },
+      { id: 1, name: "Item 1" },
+      { id: 3, name: "Item 3" },
+      { id: 5, name: "Item 5" },
+    ];
+    const diff = streamListDiff(prevList, nextList, "id", {
+      chunksSize: 5,
+      considerMoveAsUpdate: true,
+      useWorker: true,
+    });
+
+    const expectedChunks = [
+      {
+        previousValue: { id: 2, name: "Item 2" },
+        currentValue: { id: 2, name: "Item Two" },
+        prevIndex: 1,
+        newIndex: 0,
+        indexDiff: -1,
+        status: ListStatus.UPDATED,
+      },
+      {
+        previousValue: { id: 1, name: "Item 1" },
+        currentValue: { id: 1, name: "Item 1" },
+        prevIndex: 0,
+        newIndex: 1,
+        indexDiff: 1,
+        status: ListStatus.UPDATED,
+      },
+      {
+        previousValue: { id: 3, name: "Item 3" },
+        currentValue: { id: 3, name: "Item 3" },
+        prevIndex: 2,
+        newIndex: 2,
+        indexDiff: 0,
+        status: ListStatus.EQUAL,
+      },
+      {
+        previousValue: { id: 4, name: "Item 4" },
+        currentValue: null,
+        prevIndex: 3,
+        newIndex: null,
+        indexDiff: null,
+        status: ListStatus.DELETED,
+      },
+      {
+        previousValue: null,
+        currentValue: { id: 5, name: "Item 5" },
+        prevIndex: null,
+        newIndex: 3,
+        indexDiff: null,
+        status: ListStatus.ADDED,
+      },
+    ];
+
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toEqual(expectedChunks);
+      chunkCount++;
+    });
+
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("emits 'data' event only with objects diff whose status match with showOnly's", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+      { id: 3, name: "Item 3" },
+      { id: 4, name: "Item 4" },
+    ];
+    const nextList = [
+      { id: 2, name: "Item Two" },
+      { id: 1, name: "Item 1" },
+      { id: 3, name: "Item 3" },
+      { id: 5, name: "Item 5" },
+    ];
+    const diff = streamListDiff(prevList, nextList, "id", {
+      chunksSize: 5,
+      showOnly: ["added", "deleted"],
+      useWorker: true,
+    });
+
+    const expectedChunks = [
+      {
+        previousValue: { id: 4, name: "Item 4" },
+        currentValue: null,
+        prevIndex: 3,
+        newIndex: null,
+        indexDiff: null,
+        status: ListStatus.DELETED,
+      },
+      {
+        previousValue: null,
+        currentValue: { id: 5, name: "Item 5" },
+        prevIndex: null,
+        newIndex: 3,
+        indexDiff: null,
+        status: ListStatus.ADDED,
+      },
+    ];
+
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toEqual(expectedChunks);
+      chunkCount++;
+    });
+
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("emits 'data' event with deep nested objects diff", (done) => {
+    const prevList = [
+      {
+        id: 1,
+        name: "Item 1",
+        user: { role: "admin", hobbies: ["golf", "football"] },
+      },
+      { id: 2, name: "Item 2" },
+      { id: 3, name: "Item 3", user: { role: "admin", hobbies: ["rugby"] } },
+      {
+        id: 4,
+        name: "Item 4",
+        user: { role: "reader", hobbies: ["video games", "fishing"] },
+      },
+      { id: 5, name: "Item 5" },
+      { id: 6, name: "Item 6", user: { role: "root", hobbies: ["coding"] } },
+      { id: 7, name: "Item 7" },
+      { id: 8, name: "Item 8" },
+      { id: 9, name: "Item 9" },
+      {
+        id: 10,
+        name: "Item 10",
+        user: {
+          role: "root",
+          hobbies: ["coding"],
+          skills: { driving: true, diving: false },
+        },
+      },
+    ];
+    const nextList = [
+      {
+        id: 1,
+        name: "Item 1",
+        user: { role: "admin", hobbies: ["golf", "football"] },
+      },
+      { id: 2, name: "Item Two" },
+      { id: 3, name: "Item 3", user: { role: "admin", hobbies: ["rugby"] } },
+      { id: 5, name: "Item 5" },
+      { id: 6, name: "Item 6", user: { role: "root", hobbies: ["farming"] } },
+      { id: 7, name: "Item 7" },
+      {
+        id: 10,
+        name: "Item 10",
+        user: {
+          role: "root",
+          hobbies: ["coding"],
+          skills: { driving: true, diving: false },
+        },
+      },
+      { id: 11, name: "Item 11" },
+      { id: 9, name: "Item 9" },
+      { id: 8, name: "Item 8" },
+    ];
+    const diff = streamListDiff(prevList, nextList, "id", {
+      chunksSize: 5,
+      useWorker: true,
+    });
+
+    const expectedChunks = [
+      [
+        {
+          previousValue: {
+            id: 1,
+            name: "Item 1",
+            user: { role: "admin", hobbies: ["golf", "football"] },
+          },
+          currentValue: {
+            id: 1,
+            name: "Item 1",
+            user: { role: "admin", hobbies: ["golf", "football"] },
+          },
+          prevIndex: 0,
+          newIndex: 0,
+          indexDiff: 0,
+          status: ListStatus.EQUAL,
+        },
+        {
+          previousValue: { id: 2, name: "Item 2" },
+          currentValue: { id: 2, name: "Item Two" },
+          prevIndex: 1,
+          newIndex: 1,
+          indexDiff: 0,
+          status: ListStatus.UPDATED,
+        },
+        {
+          previousValue: {
+            id: 3,
+            name: "Item 3",
+            user: { role: "admin", hobbies: ["rugby"] },
+          },
+          currentValue: {
+            id: 3,
+            name: "Item 3",
+            user: { role: "admin", hobbies: ["rugby"] },
+          },
+          prevIndex: 2,
+          newIndex: 2,
+          indexDiff: 0,
+          status: ListStatus.EQUAL,
+        },
+        {
+          previousValue: { id: 5, name: "Item 5" },
+          currentValue: { id: 5, name: "Item 5" },
+          prevIndex: 4,
+          newIndex: 3,
+          indexDiff: -1,
+          status: ListStatus.MOVED,
+        },
+        {
+          previousValue: {
+            id: 6,
+            name: "Item 6",
+            user: { role: "root", hobbies: ["coding"] },
+          },
+          currentValue: {
+            id: 6,
+            name: "Item 6",
+            user: { role: "root", hobbies: ["farming"] },
+          },
+          prevIndex: 5,
+          newIndex: 4,
+          indexDiff: -1,
+          status: ListStatus.UPDATED,
+        },
+      ],
+      [
+        {
+          previousValue: { id: 7, name: "Item 7" },
+          currentValue: { id: 7, name: "Item 7" },
+          prevIndex: 6,
+          newIndex: 5,
+          indexDiff: -1,
+          status: ListStatus.MOVED,
+        },
+        {
+          previousValue: { id: 9, name: "Item 9" },
+          currentValue: { id: 9, name: "Item 9" },
+          prevIndex: 8,
+          newIndex: 8,
+          indexDiff: 0,
+          status: ListStatus.EQUAL,
+        },
+        {
+          previousValue: {
+            id: 10,
+            name: "Item 10",
+            user: {
+              role: "root",
+              hobbies: ["coding"],
+              skills: { driving: true, diving: false },
+            },
+          },
+          currentValue: {
+            id: 10,
+            name: "Item 10",
+            user: {
+              role: "root",
+              hobbies: ["coding"],
+              skills: { driving: true, diving: false },
+            },
+          },
+          prevIndex: 9,
+          newIndex: 6,
+          indexDiff: -3,
+          status: ListStatus.MOVED,
+        },
+        {
+          previousValue: { id: 8, name: "Item 8" },
+          currentValue: { id: 8, name: "Item 8" },
+          prevIndex: 7,
+          newIndex: 9,
+          indexDiff: 2,
+          status: ListStatus.MOVED,
+        },
+        {
+          previousValue: {
+            id: 4,
+            name: "Item 4",
+            user: { role: "reader", hobbies: ["video games", "fishing"] },
+          },
+          currentValue: null,
+          prevIndex: 3,
+          newIndex: null,
+          indexDiff: null,
+          status: ListStatus.DELETED,
+        },
+      ],
+      [
+        {
+          previousValue: null,
+          currentValue: { id: 11, name: "Item 11" },
+          prevIndex: null,
+          newIndex: 7,
+          indexDiff: null,
+          status: ListStatus.ADDED,
+        },
+      ],
+    ];
+
+    let chunkCount = 0;
+
+    diff.on("data", (chunk) => {
+      expect(chunk).toEqual(expectedChunks[chunkCount]);
+      chunkCount++;
+    });
+
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(3);
+      done();
+    });
+  });
+});
+
+describe("input handling", () => {
+  const prevList = [
+    { id: 1, name: "Item 1" },
+    { id: 2, name: "Item 2" },
+    { id: 3, name: "Item 3" },
+    { id: 4, name: "Item 4" },
+  ];
+  const nextList = [
+    { id: 1, name: "Item 1" },
+    { id: 2, name: "Item Two" },
+    { id: 3, name: "Item 3" },
+    { id: 5, name: "Item 5" },
+  ];
+  const expectedChunks = [
+    {
+      previousValue: { id: 1, name: "Item 1" },
+      currentValue: { id: 1, name: "Item 1" },
+      prevIndex: 0,
+      newIndex: 0,
+      indexDiff: 0,
+      status: ListStatus.EQUAL,
+    },
+    {
+      previousValue: { id: 2, name: "Item 2" },
+      currentValue: { id: 2, name: "Item Two" },
+      prevIndex: 1,
+      newIndex: 1,
+      indexDiff: 0,
+      status: ListStatus.UPDATED,
+    },
+    {
+      previousValue: { id: 3, name: "Item 3" },
+      currentValue: { id: 3, name: "Item 3" },
+      prevIndex: 2,
+      newIndex: 2,
+      indexDiff: 0,
+      status: ListStatus.EQUAL,
+    },
+    {
+      previousValue: { id: 4, name: "Item 4" },
+      currentValue: null,
+      prevIndex: 3,
+      newIndex: null,
+      indexDiff: null,
+      status: ListStatus.DELETED,
+    },
+    {
+      previousValue: null,
+      currentValue: { id: 5, name: "Item 5" },
+      prevIndex: null,
+      newIndex: 3,
+      indexDiff: null,
+      status: ListStatus.ADDED,
+    },
+  ];
+
+  it("handles two readable streams", (done) => {
+    const prevStream = Readable.from(prevList, { objectMode: true });
+    const nextStream = Readable.from(nextList, { objectMode: true });
+
+    const diff = streamListDiff(prevStream, nextStream, "id", {
+      chunksSize: 5,
+      useWorker: true,
+      showWarnings: false,
+    });
+
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toEqual(expectedChunks);
+      chunkCount++;
+    });
+    diff.on("error", (err) => console.error(err));
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("handles two local files", (done) => {
+    const prevFile = path.resolve(__dirname, "../../../mocks/prevList.json");
+    const nextFile = path.resolve(__dirname, "../../../mocks/nextList.json");
+
+    const diff = streamListDiff(prevFile, nextFile, "id", {
+      chunksSize: 5,
+      useWorker: true,
+    });
+
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toEqual(expectedChunks);
+      chunkCount++;
+    });
+    diff.on("error", (err) => console.error(err));
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("handles a readable stream against a local file", (done) => {
+    const prevStream = Readable.from(prevList, { objectMode: true });
+    const nextFile = path.resolve(__dirname, "../../../mocks/nextList.json");
+
+    const diff = streamListDiff(prevStream, nextFile, "id", {
+      chunksSize: 5,
+      useWorker: true,
+      showWarnings: false,
+    });
+
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toEqual(expectedChunks);
+      chunkCount++;
+    });
+    diff.on("error", (err) => console.error(err));
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("handles a readable stream against an array", (done) => {
+    const prevStream = Readable.from(prevList, { objectMode: true });
+
+    const diff = streamListDiff(prevStream, nextList, "id", {
+      chunksSize: 5,
+      useWorker: true,
+      showWarnings: false,
+    });
+
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toEqual(expectedChunks);
+      chunkCount++;
+    });
+    diff.on("error", (err) => console.error(err));
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+  it("handles a local file against an array", (done) => {
+    const prevFile = path.resolve(__dirname, "../../../mocks/prevList.json");
+
+    const diff = streamListDiff(prevFile, nextList, "id", {
+      chunksSize: 5,
+      useWorker: true,
+    });
+
+    let chunkCount = 0;
+    diff.on("data", (chunk) => {
+      expect(chunk).toEqual(expectedChunks);
+      chunkCount++;
+    });
+    diff.on("error", (err) => console.error(err));
+    diff.on("finish", () => {
+      expect(chunkCount).toBe(1);
+      done();
+    });
+  });
+});
+
+describe("finish event", () => {
+  it("emits 'finish' event if no prevList nor nextList is provided", (done) => {
+    const diff = streamListDiff([], [], "id", { useWorker: true });
+    diff.on("finish", () => done());
+  });
+  it("emits 'finish' event when all the chunks have been processed", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+    const nextList = [
+      { id: 2, name: "Item 2" },
+      { id: 3, name: "Item 3" },
+    ];
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: true });
+    diff.on("finish", () => done());
+  });
+});
+
+describe("error event", () => {
+  test("emits 'error' event when prevList has invalid data", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      "hello",
+      { id: 2, name: "Item 2" },
+    ];
+    const nextList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+
+    // @ts-expect-error prevList is invalid by design for the test
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: true });
+
+    diff.on("error", (err) => {
+      expect(err["message"]).toEqual(
+        `Your prevList must only contain valid objects. Found 'hello'`,
+      );
+      done();
+    });
+  });
+
+  test("emits 'error' event when nextList has invalid data", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+    const nextList = [
+      { id: 1, name: "Item 1" },
+      "hello",
+      { id: 2, name: "Item 2" },
+    ];
+
+    // @ts-expect-error nextList is invalid by design for the test
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: true });
+
+    diff.on("error", (err) => {
+      expect(err["message"]).toEqual(
+        `Your nextList must only contain valid objects. Found 'hello'`,
+      );
+      done();
+    });
+  });
+
+  test("emits 'error' event when all prevList ojects don't have the requested reference property", (done) => {
+    const prevList = [{ id: 1, name: "Item 1" }, { name: "Item 2" }];
+    const nextList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: true });
+
+    diff.on("error", (err) => {
+      expect(err["message"]).toEqual(
+        `The reference property 'id' is not available in all the objects of your prevList.`,
+      );
+      done();
+    });
+  });
+
+  test("emits 'error' event when all nextList ojects don't have the requested reference property", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+    const nextList = [{ id: 1, name: "Item 1" }, { name: "Item 2" }];
+
+    const diff = streamListDiff(prevList, nextList, "id", { useWorker: true });
+
+    diff.on("error", (err) => {
+      expect(err["message"]).toEqual(
+        `The reference property 'id' is not available in all the objects of your nextList.`,
+      );
+      done();
+    });
+  });
+
+  test("emits 'error' event when the chunkSize option is negative", (done) => {
+    const prevList = [
+      { id: 1, name: "Item 1" },
+      { id: 2, name: "Item 2" },
+    ];
+    const nextList = [{ id: 1, name: "Item 1" }, { name: "Item 2" }];
+
+    const diff = streamListDiff(prevList, nextList, "id", {
+      chunksSize: -3,
+      useWorker: true,
+    });
+
+    diff.on("error", (err) => {
+      expect(err["message"]).toEqual(
+        "The chunk size can't be negative. You entered the value '-3'",
+      );
+      done();
+    });
+  });
+
+  test("emits 'error' event when the prevList is not a valid type", (done) => {
+    const nextList = [{ id: 1, name: "Item 1" }, { name: "Item 2" }];
+
+    // @ts-expect-error - prevList is invalid by design for the test
+    const diff = streamListDiff({ name: "hello" }, nextList, "id", {
+      useWorker: true,
+    });
+
+    diff.on("error", (err) => {
+      expect(err["message"]).toEqual(
+        "Invalid prevList. Expected Readable, Array, or File.",
+      );
+      done();
+    });
+  });
+  test("emits 'error' event when the nextList is not a valid type", (done) => {
+    const prevList = [{ id: 1, name: "Item 1" }, { name: "Item 2" }];
+
+    // @ts-expect-error - nextList is invalid by design for the test
+    const diff = streamListDiff(prevList, null, "id", { useWorker: true });
+
+    diff.on("error", (err) => {
+      expect(err["message"]).toEqual(
+        "Invalid nextList. Expected Readable, Array, or File.",
+      );
+      done();
+    });
+  });
+});
+
+const generateLargeDataset = (count: number) => {
+  const data: Array<{ id: number; value: string }> = [];
+  for (let i = 0; i < count; i++) {
+    data.push({ id: i, value: `value-${i}` });
+  }
+  return data;
+};
+
+describe("performance", () => {
+  it("process 100.000 in each stream", (done) => {
+    const numEntries = 100_000;
+
+    const prevList = generateLargeDataset(numEntries);
+    const nextList = generateLargeDataset(numEntries);
+
+    nextList[100].value = "updated-value-100"; // 1 updated entry
+    nextList[20_000].value = "updated-value-20000"; // Another updated entry
+    nextList.push({ id: numEntries, value: `new-value-${numEntries}` }); // 1 added entry
+
+    const diffListener = streamListDiff<{ id: number; value: string }>(
+      prevList,
+      nextList,
+      "id",
+      {
+        chunksSize: 10_000,
+      },
+    );
+
+    const diffs: StreamListDiff<{ id: number; value: string }>[] = [];
+
+    diffListener.on("data", (chunk) => {
+      diffs.push(...chunk);
+    });
+
+    diffListener.on("finish", () => {
+      try {
+        const updatedEntries = diffs.filter((d) => d.status === "updated");
+        const addedEntries = diffs.filter((d) => d.status === "added");
+        const deletedEntries = diffs.filter((d) => d.status === "deleted");
+        const equalEntries = diffs.filter((d) => d.status === "equal");
+
+        expect(updatedEntries.length).toBe(2);
+        expect(addedEntries.length).toBe(1);
+        expect(deletedEntries.length).toBe(0);
+        expect(equalEntries.length).toBe(99998);
+        done();
+      } catch (err) {
+        done(err);
+      }
+    });
+
+    diffListener.on("error", (err) => done(err));
+  });
+});
diff --git a/src/lib/stream-list-diff/server/worker/node-worker.ts b/src/lib/stream-list-diff/server/worker/node-worker.ts
new file mode 100644
index 0000000..0004a0a
--- /dev/null
+++ b/src/lib/stream-list-diff/server/worker/node-worker.ts
@@ -0,0 +1,38 @@
+import { parentPort } from "worker_threads";
+import {
+  FilePath,
+  ListStreamOptions,
+  ReferenceProperty,
+  StreamEvent,
+} from "@models/stream";
+import { WorkerEvent } from "@models/worker";
+import { workerDiff } from "./utils";
+
+parentPort?.on(
+  WorkerEvent.Message,
+  async <T extends Record<string, unknown>>(event: {
+    prevList: FilePath | T[];
+    nextList: FilePath | T[];
+    referenceProperty: ReferenceProperty<T>;
+    options: ListStreamOptions;
+  }) => {
+    const { prevList, nextList, referenceProperty, options } = event;
+
+    const listener = workerDiff(prevList, nextList, referenceProperty, options);
+
+    listener.on(StreamEvent.Data, (chunk) => {
+      parentPort?.postMessage({ event: StreamEvent.Data, chunk });
+    });
+
+    listener.on(StreamEvent.Finish, () => {
+      parentPort?.postMessage({ event: StreamEvent.Finish });
+    });
+
+    listener.on(StreamEvent.Error, (error) => {
+      parentPort?.postMessage({
+        event: StreamEvent.Error,
+        error: error.message,
+      });
+    });
+  },
+);
diff --git a/src/lib/stream-list-diff/server/worker/utils.ts b/src/lib/stream-list-diff/server/worker/utils.ts
new file mode 100644
index 0000000..92d6726
--- /dev/null
+++ b/src/lib/stream-list-diff/server/worker/utils.ts
@@ -0,0 +1,78 @@
+import path from "path";
+import { once, Readable } from "stream";
+import { Worker } from "worker_threads";
+import { IEmitter, EmitterEvents, EventEmitter } from "@models/emitter";
+import {
+  FilePath,
+  ListStreamOptions,
+  READABLE_STREAM_ALERT,
+  ReferenceProperty,
+  StreamEvent,
+  StreamListener,
+} from "@models/stream";
+import { NodeWorkerMessage, WorkerEvent } from "@models/worker";
+import { generateStream } from "..";
+
+async function getArrayFromStream<T>(
+  stream: Readable,
+  showWarnings: boolean = true,
+): Promise<T[]> {
+  if (showWarnings) {
+    console.warn(READABLE_STREAM_ALERT);
+  }
+  const data: T[] = [];
+  stream.on(StreamEvent.Data, (chunk) => data.push(chunk));
+  await once(stream, "end");
+  return data;
+}
+
+export async function generateWorker<T extends Record<string, unknown>>(
+  prevList: Readable | FilePath | T[],
+  nextList: Readable | FilePath | T[],
+  referenceProperty: ReferenceProperty<T>,
+  options: ListStreamOptions,
+  emitter: IEmitter<T>,
+) {
+  try {
+    if (prevList instanceof Readable) {
+      prevList = await getArrayFromStream(prevList, options?.showWarnings);
+    }
+    if (nextList instanceof Readable) {
+      nextList = await getArrayFromStream(nextList, options?.showWarnings);
+    }
+    const worker = new Worker(path.resolve(__dirname, "./node-worker.cjs"));
+    worker.postMessage({ prevList, nextList, referenceProperty, options });
+    worker.on(WorkerEvent.Message, (e: NodeWorkerMessage<T>) => {
+      const { event, chunk, error } = e;
+      if (event === StreamEvent.Data) {
+        emitter.emit(StreamEvent.Data, chunk);
+      } else if (event === StreamEvent.Finish) {
+        emitter.emit(StreamEvent.Finish);
+        worker.terminate();
+      } else if (event === StreamEvent.Error) {
+        emitter.emit(StreamEvent.Error, new Error(error));
+        worker.terminate();
+      }
+    });
+    worker.on(WorkerEvent.Error, (err) =>
+      emitter.emit(StreamEvent.Error, new Error(err.message)),
+    );
+  } catch (err) {
+    return emitter.emit(StreamEvent.Error, err as Error);
+  }
+}
+
+export function workerDiff<T extends Record<string, unknown>>(
+  prevList: FilePath | T[],
+  nextList: FilePath | T[],
+  referenceProperty: ReferenceProperty<T>,
+  options: ListStreamOptions,
+): StreamListener<T> {
+  const emitter = new EventEmitter<EmitterEvents<T>>();
+  setTimeout(
+    () =>
+      generateStream(prevList, nextList, referenceProperty, options, emitter),
+    0,
+  );
+  return emitter as StreamListener<T>;
+}
diff --git a/src/lib/stream-list-diff/utils.ts b/src/lib/stream-list-diff/utils.ts
index 8356343..d823c30 100644
--- a/src/lib/stream-list-diff/utils.ts
+++ b/src/lib/stream-list-diff/utils.ts
@@ -1,10 +1,12 @@
 import { isObject } from "@lib/utils";
+import { IEmitter } from "@models/emitter";
+import { ListType } from "@models/list";
 import {
   ListStreamOptions,
   ReferenceProperty,
+  StreamEvent,
   StreamListDiff,
 } from "@models/stream";
-import { Emitter, StreamEvent } from "./emitter";
 
 export function isValidChunkSize(
   chunksSize: ListStreamOptions["chunksSize"],
@@ -17,7 +19,7 @@ export function isValidChunkSize(
 export function isDataValid<T extends Record<string, unknown>>(
   data: T,
   referenceProperty: ReferenceProperty<T>,
-  listType: "prevList" | "nextList",
+  listType: ListType,
 ): { isValid: boolean; message?: string } {
   if (!isObject(data)) {
     return {
@@ -38,7 +40,7 @@ export function isDataValid<T extends Record<string, unknown>>(
 }
 
 export function outputDiffChunk<T extends Record<string, unknown>>(
-  emitter: Emitter<T>,
+  emitter: IEmitter<T>,
 ) {
   let chunks: StreamListDiff<T>[] = [];
 
diff --git a/src/lib/stream-list-diff/emitter.ts b/src/models/emitter/index.ts
similarity index 67%
rename from src/lib/stream-list-diff/emitter.ts
rename to src/models/emitter/index.ts
index b768784..feb8ef1 100644
--- a/src/lib/stream-list-diff/emitter.ts
+++ b/src/models/emitter/index.ts
@@ -1,14 +1,14 @@
 import { StreamListDiff } from "@models/stream";
 
-type Listener<T extends unknown[]> = (...args: T) => void;
+export type Listener<T extends unknown[]> = (...args: T) => void;
 
-export enum StreamEvent {
-  Data = "data",
-  Finish = "finish",
-  Error = "error",
-}
+export type EmitterEvents<T extends Record<string, unknown>> = {
+  data: [StreamListDiff<T>[]];
+  error: [Error];
+  finish: [];
+};
 
-export type Emitter<T extends Record<string, unknown>> = EventEmitter<{
+export type IEmitter<T extends Record<string, unknown>> = EventEmitter<{
   data: [StreamListDiff<T>[]];
   error: [Error];
   finish: [];
@@ -31,16 +31,3 @@ export class EventEmitter<Events extends Record<string, unknown[]>> {
     }
   }
 }
-
-export type EmitterEvents<T extends Record<string, unknown>> = {
-  data: [StreamListDiff<T>[]];
-  error: [Error];
-  finish: [];
-};
-
-export interface StreamListener<T extends Record<string, unknown>> {
-  on<E extends keyof EmitterEvents<T>>(
-    event: E,
-    listener: Listener<EmitterEvents<T>[E]>,
-  ): this;
-}
diff --git a/src/models/list/index.ts b/src/models/list/index.ts
index 8616faa..2f56730 100644
--- a/src/models/list/index.ts
+++ b/src/models/list/index.ts
@@ -1,4 +1,11 @@
-export enum LIST_STATUS {
+export const DEFAULT_LIST_DIFF_OPTIONS = {
+  showOnly: [],
+  referenceProperty: undefined,
+  considerMoveAsUpdate: false,
+  ignoreArrayOrder: false,
+};
+
+export enum ListStatus {
   ADDED = "added",
   EQUAL = "equal",
   DELETED = "deleted",
@@ -6,28 +13,26 @@ export enum LIST_STATUS {
   MOVED = "moved",
 }
 
+export enum ListType {
+  PREV = "prevList",
+  NEXT = "nextList",
+}
+
 export type ListDiffOptions = {
-  showOnly?: `${LIST_STATUS}`[];
+  showOnly?: `${ListStatus}`[];
   referenceProperty?: string;
   considerMoveAsUpdate?: boolean;
   ignoreArrayOrder?: boolean;
 };
 
-export const DEFAULT_LIST_DIFF_OPTIONS = {
-  showOnly: [],
-  referenceProperty: undefined,
-  considerMoveAsUpdate: false,
-  ignoreArrayOrder: false,
-};
-
 export type ListDiff = {
   type: "list";
-  status: LIST_STATUS;
+  status: `${ListStatus}`;
   diff: {
     value: unknown;
     prevIndex: number | null;
     newIndex: number | null;
     indexDiff: number | null;
-    status: LIST_STATUS;
+    status: ListStatus;
   }[];
 };
diff --git a/src/models/object/index.ts b/src/models/object/index.ts
index 86fa19e..7fa9874 100644
--- a/src/models/object/index.ts
+++ b/src/models/object/index.ts
@@ -1,11 +1,11 @@
-export enum OBJECT_STATUS {
+export enum ObjectStatus {
   ADDED = "added",
   EQUAL = "equal",
   DELETED = "deleted",
   UPDATED = "updated",
 }
 
-export enum GRANULARITY {
+export enum Granularity {
   BASIC = "basic",
   DEEP = "deep",
 }
@@ -15,14 +15,14 @@ export type ObjectData = Record<string, unknown> | undefined | null;
 export type ObjectDiffOptions = {
   ignoreArrayOrder?: boolean;
   showOnly?: {
-    statuses: `${OBJECT_STATUS}`[];
-    granularity?: `${GRANULARITY}`;
+    statuses: `${ObjectStatus}`[];
+    granularity?: `${Granularity}`;
   };
 };
 
 export const DEFAULT_OBJECT_DIFF_OPTIONS = {
   ignoreArrayOrder: false,
-  showOnly: { statuses: [], granularity: GRANULARITY.BASIC },
+  showOnly: { statuses: [], granularity: Granularity.BASIC },
 };
 
 /** recursive diff in case of subproperties */
@@ -30,12 +30,12 @@ export type Diff = {
   property: string;
   previousValue: unknown;
   currentValue: unknown;
-  status: OBJECT_STATUS;
+  status: `${ObjectStatus}`;
   diff?: Diff[];
 };
 
 export type ObjectDiff = {
   type: "object";
-  status: OBJECT_STATUS;
+  status: `${ObjectStatus}`;
   diff: Diff[];
 };
diff --git a/src/models/stream/index.ts b/src/models/stream/index.ts
index f62b50d..68b1c0f 100644
--- a/src/models/stream/index.ts
+++ b/src/models/stream/index.ts
@@ -1,4 +1,21 @@
-import { LIST_STATUS } from "@models/list";
+import { EmitterEvents, Listener } from "@models/emitter";
+import { ListStatus } from "@models/list";
+
+export const READABLE_STREAM_ALERT = `Warning: using Readable streams may impact workers' performance since they need to be converted to arrays.
+       Consider using arrays or files for optimal performance. Alternatively, you can turn the 'useWorker' option off.
+       To disable this warning, set 'showWarnings' to false in production.`;
+
+export const DEFAULT_LIST_STREAM_OPTIONS: ListStreamOptions = {
+  chunksSize: 0,
+  useWorker: true,
+  showWarnings: true,
+};
+
+export enum StreamEvent {
+  Data = "data",
+  Finish = "finish",
+  Error = "error",
+}
 
 export type StreamListDiff<T extends Record<string, unknown>> = {
   currentValue: T | null;
@@ -6,7 +23,7 @@ export type StreamListDiff<T extends Record<string, unknown>> = {
   prevIndex: number | null;
   newIndex: number | null;
   indexDiff: number | null;
-  status: LIST_STATUS;
+  status: `${ListStatus}`;
 };
 
 export type ReferenceProperty<T extends Record<string, unknown>> = keyof T;
@@ -26,12 +43,17 @@ export type DataBuffer<T extends Record<string, unknown>> = Map<
 
 export type ListStreamOptions = {
   chunksSize?: number; // 0 by default.
-  showOnly?: `${LIST_STATUS}`[];
+  showOnly?: `${ListStatus}`[];
   considerMoveAsUpdate?: boolean;
-};
-
-export const DEFAULT_LIST_STREAM_OPTIONS: ListStreamOptions = {
-  chunksSize: 0,
+  useWorker?: boolean; // true by default
+  showWarnings?: boolean; // true by default
 };
 
 export type FilePath = string;
+
+export interface StreamListener<T extends Record<string, unknown>> {
+  on<E extends keyof EmitterEvents<T>>(
+    event: E,
+    listener: Listener<EmitterEvents<T>[E]>,
+  ): this;
+}
diff --git a/src/models/worker/index.ts b/src/models/worker/index.ts
new file mode 100644
index 0000000..df9b261
--- /dev/null
+++ b/src/models/worker/index.ts
@@ -0,0 +1,22 @@
+import { StreamEvent, StreamListDiff } from "@models/stream";
+
+export enum WorkerEvent {
+  Message = "message",
+  Error = "error",
+}
+
+type WorkerData<T extends Record<string, unknown>> = {
+  chunk: StreamListDiff<T>[];
+  error: string;
+  event: StreamEvent;
+};
+
+type WorkerMessage<T extends Record<string, unknown>> = {
+  data: WorkerData<T>;
+};
+
+export type WebWorkerMessage<T extends Record<string, unknown>> =
+  WorkerMessage<T>;
+
+export type NodeWorkerMessage<T extends Record<string, unknown>> =
+  WorkerData<T>;
diff --git a/tsconfig.json b/tsconfig.json
index 9fb7612..cc140a0 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -18,10 +18,9 @@
     "skipLibCheck": true ,
     "baseUrl": ".",
     "paths": {
-      "@models/*": ["./src/models/*"],
       "@lib/*": ["./src/lib/*"],
-      
-
+      "@mocks/*": ["./src/mocks/*"],
+      "@models/*": ["./src/models/*"]
     }
   },
 }
diff --git a/tsup.config.ts b/tsup.config.ts
index 874abf3..9c6ce2d 100644
--- a/tsup.config.ts
+++ b/tsup.config.ts
@@ -15,17 +15,37 @@ export default defineConfig([
     format: ["cjs", "esm"],
     ...sharedConfig,
     platform: "neutral",
+    name: "MAIN",
+  },
+  {
+    entry: ["src/client.ts"],
+    format: ["esm"],
+    ...sharedConfig,
+    platform: "browser",
+    name: "CLIENT",
+  },
+  {
+    entry: ["src/lib/stream-list-diff/client/worker/web-worker.ts"],
+    format: ["esm"],
+    ...sharedConfig,
+    splitting: false,
+    platform: "browser",
+    name: "WEB WORKER",
   },
   {
     entry: ["src/server.ts"],
-    format: ["cjs", "esm"],
+    format: ["cjs"],
     ...sharedConfig,
     platform: "node",
+    name: "SERVER",
   },
   {
-    entry: ["src/client.ts"],
-    format: ["cjs", "esm"],
+    entry: ["src/lib/stream-list-diff/server/worker/node-worker.ts"],
+    format: ["cjs"],
     ...sharedConfig,
-    platform: "browser",
+    splitting: false,
+    shims: false,
+    platform: "node",
+    name: "NODEJS WORKER",
   },
 ]);