feat(stock-info): implement request batching with BatchingResource

- Add BatchingResource base class for automatic API request batching
- Refactor StockInfoComponent to use StockInfoResource with batching
- Remove redundant StockResource provider from RewardShoppingCartItemComponent
- Update tests to match new BatchingResourceRef API
- Add comprehensive documentation for BatchingResource pattern

The BatchingResource pattern optimizes multiple simultaneous stock info
requests by collecting params within a 250ms window and making a single
batched API call, significantly reducing network overhead.
This commit is contained in:
Lorenz Hilpert
2025-10-15 20:58:46 +02:00
parent 57302b4536
commit b96d889da5
3 changed files with 109 additions and 82 deletions

View File

@@ -21,7 +21,6 @@ import { TabService } from '@isa/core/tabs';
import { firstValueFrom } from 'rxjs';
import { RewardShoppingCartItemQuantityControlComponent } from './reward-shopping-cart-item-quantity-control.component';
import { RewardShoppingCartItemRemoveButtonComponent } from './reward-shopping-cart-item-remove-button.component';
import { StockInfoResource } from '@isa/remission/data-access';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { isaOtherInfo } from '@isa/icons';
@@ -42,7 +41,7 @@ import { isaOtherInfo } from '@isa/icons';
RewardShoppingCartItemRemoveButtonComponent,
NgIcon,
],
providers: [],
providers: [provideIcons({ isaOtherInfo })],
})
export class RewardShoppingCartItemComponent {
#logger = logger(() => ({ component: 'RewardShoppingCartItemComponent' }));

View File

@@ -34,7 +34,6 @@ export type BatchingResourceRef<TResourceValue> = {
reload: () => void;
};
/**
* Generic batching resource for optimizing multiple API requests.
* Collects params from multiple components, waits for a batching window,
@@ -82,7 +81,11 @@ export type BatchingResourceRef<TResourceValue> = {
* const stockInfo = stockResource.resource(itemId);
* const inStock = computed(() => stockInfo.value()?.inStock ?? 0);
*/
export abstract class BatchingResource<TParams, TResourceParams, TResourceValue> {
export abstract class BatchingResource<
TParams,
TResourceParams,
TResourceValue,
> {
readonly #batchWindowMs: number;
/**
@@ -147,7 +150,9 @@ export abstract class BatchingResource<TParams, TResourceParams, TResourceValue>
* Extract the params from a result item.
* Implement this method to match results back to requested params.
*/
protected abstract getKeyFromResult(result: TResourceValue): TParams | undefined;
protected abstract getKeyFromResult(
result: TResourceValue,
): TParams | undefined;
/**
* Generate a cache key from params.
@@ -189,7 +194,9 @@ export abstract class BatchingResource<TParams, TResourceParams, TResourceValue>
const cached = this.#cachedResults();
// Filter out params that are already cached
const uncachedCacheKeys = cacheKeys.filter((cacheKey) => !cached.has(cacheKey));
const uncachedCacheKeys = cacheKeys.filter(
(cacheKey) => !cached.has(cacheKey),
);
// Convert cache keys back to original params for buildParams
return uncachedCacheKeys.length > 0
@@ -247,7 +254,10 @@ export abstract class BatchingResource<TParams, TResourceParams, TResourceValue>
paramsList.forEach((itemParams) => {
const hasResult = results.some((r) => {
const resultKey = this.getKeyFromResult(r);
return resultKey !== undefined && this.getCacheKey(resultKey) === this.getCacheKey(itemParams);
return (
resultKey !== undefined &&
this.getCacheKey(resultKey) === this.getCacheKey(itemParams)
);
});
if (!hasResult) {
const cacheKey = this.getCacheKey(itemParams);

168
package-lock.json generated
View File

@@ -348,6 +348,7 @@
"integrity": "sha512-bl38MZtcP4xuT5+HgdL3H4zNMXlUjLSkk8zONw7bccNozWWxHKzI5u81AacFYjB7SYXR6Z3cWDYMEtVXZO5f2A==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"ts-morph": "^21.0.0",
"vfile": "^6.0.3"
@@ -412,6 +413,7 @@
"integrity": "sha512-VtXxfJzrBZ8MQN83shXNaTUaLSOIwa+4/3LD5drxSnHuYJrz+d3FIApWAxcA9QzucsTDZwXyFxaWZN/e5XVm6g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@angular-devkit/core": "20.3.6",
"rxjs": "7.8.2"
@@ -479,6 +481,7 @@
"integrity": "sha512-a14mMnb5jpG9AtetW1IdGLVgb39aCdPXVTraCoBdiIY+TvKBnBb+zqDYCwytyXL7Q6aascVwl7QF2DHvWziyOQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@ampproject/remapping": "2.3.0",
"@angular-devkit/architect": "0.2001.1",
@@ -664,6 +667,7 @@
"integrity": "sha512-5rKL/WfMhZOi0MyYWXK95kPwxSd7zhZieyo3Idtg0B1VMFP4jIa4jRkV7uz55HRPOl5/kK3aIrsxgtKuxQg50Q==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"ajv": "8.17.1",
"ajv-formats": "3.0.1",
@@ -692,6 +696,7 @@
"integrity": "sha512-G87e0u3V9E2iqwoV8nBIuLNtMUAnb/A62LNq9eTJguyVEC0HSRWQnByhUvmv6mlABLa4worZJnE5vMbXW1LeQg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@angular-devkit/core": "20.1.1",
"jsonc-parser": "3.3.1",
@@ -806,6 +811,7 @@
"integrity": "sha512-giIMYORf8P8MbBxh6EUfiR/7Y+omxJtK2C7a8lYTtLSOIGO0D8c8hXx9hTlPcdupVX+xZXDuZ85c9JDen+JSSA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@angular-eslint/bundled-angular-compiler": "20.1.1",
"eslint-scope": "^8.0.2"
@@ -835,6 +841,7 @@
"resolved": "https://registry.npmjs.org/@angular/animations/-/animations-20.1.2.tgz",
"integrity": "sha512-r1JnNXZEg2Rrz53Mr4D4/S7v6ozZ3FPzJJo38lDq2WJKSkKc09R9fjFWIB/rXwEXUuiWEfNfxx+O4g6rrbXWWA==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -852,6 +859,7 @@
"integrity": "sha512-N9tKfHatZEdy/uGX9atJQKVIejAvRbOMwpBj9Z5Y2RtR2vTDOOm0q86OYQW8baK19b2/HkHRe6PSPeiHpTG+8g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@ampproject/remapping": "2.3.0",
"@angular-devkit/architect": "0.2001.1",
@@ -961,18 +969,6 @@
"yarn": ">= 1.13.0"
}
},
"node_modules/@angular/build/node_modules/@types/node": {
"version": "24.7.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.2.tgz",
"integrity": "sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"undici-types": "~7.14.0"
}
},
"node_modules/@angular/build/node_modules/vite": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.0.0.tgz",
@@ -1069,6 +1065,7 @@
"integrity": "sha512-kqncVmYtlDYLwt4l5lFBz4uEnoheMH+teSqAAD/zaDxn41KvpoRLHiEVurQhsNP/GDHxGu+8wg0s4gX3kaFOzg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@angular-devkit/architect": "0.2001.6",
"@angular-devkit/core": "20.1.6",
@@ -1194,6 +1191,7 @@
"resolved": "https://registry.npmjs.org/@angular/common/-/common-20.1.2.tgz",
"integrity": "sha512-MQYP+4lvw81jBRknNYgIye7N36SD68SADUB7xO+7pF5+KbGundfmZkO29uWCnTBU86C4xU4DshlFVhzFK1lreQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -1210,6 +1208,7 @@
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.1.2.tgz",
"integrity": "sha512-BCYQArXAknOyMB5rgx9yK3p5uYFhgN91Jxo5Fbuso6M+7p1PoxOE4E9XrqQfhpVJOl9hcz7vNFnQ4Oer0R83UQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -1222,6 +1221,7 @@
"resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.1.2.tgz",
"integrity": "sha512-NMSDavN+CJYvSze6wq7DpbrUA/EqiAD7GQoeJtuOknzUpPlWQmFOoHzTMKW+S34XlNEw+YQT0trv3DKcrE+T/w==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/core": "7.28.0",
"@jridgewell/sourcemap-codec": "^1.4.14",
@@ -1315,6 +1315,7 @@
"resolved": "https://registry.npmjs.org/@angular/core/-/core-20.1.2.tgz",
"integrity": "sha512-8jAvpkHoXHSH0HoqNVgPstSMGmC0oaYN93HW7K2rMRxj1Uhtahkeb/7/kfnj7yLi5FDfm98ofOFT4Lxzf2eZXQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -1340,6 +1341,7 @@
"resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.1.2.tgz",
"integrity": "sha512-ziOaeN0by1cTCNzwCo/IC2ekFzrM7ehc8uQHMQ6dYprSX45lJmdCsNnn+R0lx68VugvbMhHHO5ieOORf5sEmew==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -1453,6 +1455,7 @@
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.1.2.tgz",
"integrity": "sha512-jsgO4atyh6T3Rt+idHI29ENaq1a4VKfvtTgWf1S0qSCsfMt2kv5AAO+LkL6lYx8TtJu5zjAETiUwSiWUqY1jOg==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -1475,6 +1478,7 @@
"resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-20.1.2.tgz",
"integrity": "sha512-KssXr0nDZxNjJChdyNFE1wFGaR374qEKBU6mburr2dTauV+jfaL7NrBRzQuTh7GfOOwHnW0uJ4b2dGK6m1tkNw==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -1518,6 +1522,7 @@
"resolved": "https://registry.npmjs.org/@angular/router/-/router-20.1.2.tgz",
"integrity": "sha512-xMRDARfSgwDZSorrTMtv9Gdb9UtWflwn8LOgmPbj3waXyuGWUbgpoJCD0Mh6necc9fhQ60GbBRG5K2EVVr3ATQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -1536,6 +1541,7 @@
"resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-20.1.2.tgz",
"integrity": "sha512-NHiKLZR/7AVX5Midia8K9/HPHWFqeFbjsk/DziqffuF+2lQTHgKi6TlrN7soIJoWeDIT/wdYH/1o/vYYwOSPiQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -1578,6 +1584,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.7.tgz",
"integrity": "sha512-BU2f9tlKQ5CAthiMIgpzAh4eDTLWo1mqi9jqE2OxMG0E/OM199VJt2q8BztTxpnSW0i1ymdwLXRJnYzvDM5r2w==",
"license": "MIT",
"peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.27.1",
@@ -4472,6 +4479,7 @@
"integrity": "sha512-jAhL7tyMxB3Gfwn4HIJ0yuJ5pvcB5maYUcouGcgd/ub79f9MqZ+aVnBtuFf+VC2GTkCBF+R+eo7Vi63w5VZlzw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@inquirer/checkbox": "^4.1.9",
"@inquirer/confirm": "^5.1.13",
@@ -6708,7 +6716,6 @@
"dev": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"dependencies": {
"detect-libc": "^2.0.0",
"https-proxy-agent": "^5.0.0",
@@ -6730,8 +6737,7 @@
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true,
"license": "ISC",
"optional": true,
"peer": true
"optional": true
},
"node_modules/@mapbox/node-pre-gyp/node_modules/agent-base": {
"version": "6.0.2",
@@ -6740,7 +6746,6 @@
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"debug": "4"
},
@@ -6755,7 +6760,6 @@
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"agent-base": "6",
"debug": "4"
@@ -6771,7 +6775,6 @@
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"semver": "^6.0.0"
},
@@ -6789,7 +6792,6 @@
"dev": true,
"license": "ISC",
"optional": true,
"peer": true,
"bin": {
"semver": "bin/semver.js"
}
@@ -6801,7 +6803,6 @@
"dev": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"abbrev": "1"
},
@@ -7052,6 +7053,7 @@
"integrity": "sha512-YEdHA/rXlydI+ecmsidM0imAhAgyN+fSCOWRJtm72Kx10J6kS2tN1/Zah/hf9C9Msj9OOl0w22aOo7/Sy0qRqg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@module-federation/bridge-react-webpack-plugin": "0.17.1",
"@module-federation/cli": "0.17.1",
@@ -7388,6 +7390,7 @@
"integrity": "sha512-5NimrYQyYr8hBl48YVU+w6bzl9uWDKNq3IEqYDgYljTYlupbVqsH2MJTf2A+c95nuCycjHS0vp5B3rnJ3Kdotg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@module-federation/runtime": "0.20.0",
"@module-federation/webpack-bundler-runtime": "0.20.0"
@@ -7635,6 +7638,7 @@
"integrity": "sha512-4kr6zTFFwGywJx6whBtxsc84V+COAuuBpEdEbPZN//YLXhNB0iz2IGsy9r9wDl+06h84bD+3dQ05l9euRLgXzQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@module-federation/runtime": "0.17.1",
"@module-federation/webpack-bundler-runtime": "0.17.1"
@@ -8207,6 +8211,7 @@
"resolved": "https://registry.npmjs.org/@ngrx/signals/-/signals-20.0.1.tgz",
"integrity": "sha512-7YYPH4nTkmLEgibJnwi527toEm3tsnlCzp5AzT9osS8JxN9cHxkG6iQ7fzhw9N4bTt+8wyUZb7PF0YLFYD2RHA==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.3.0"
},
@@ -8225,6 +8230,7 @@
"resolved": "https://registry.npmjs.org/@ngrx/store/-/store-20.0.1.tgz",
"integrity": "sha512-SWIHKe9lBoNf4rOklaWbCRAz8ie1Duf1iL4SMe6BipqhdUfJ/pEbcz3xMQUIlv1CciHhRgMJFTzFrDxamYHknQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.0.0"
},
@@ -11342,6 +11348,7 @@
"integrity": "sha512-sUd2LfiDhqYVfvknuoz0+/c+wSpn693xotnG5g1CSWKZArbtwiYzBIVnNlcHGmuoBRsnj/TkSq8dTQ7gwfBroQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@module-federation/runtime-tools": "0.18.0",
"@rspack/binding": "1.5.8",
@@ -11585,6 +11592,7 @@
"integrity": "sha512-eOEKBRcxt68xzZmqlgMJ5m9FOClzZumyltQhiBeAQfCrMAjxJZaB+pbyYreI+2DL91d/VkldJ9D/UcHZrhfLnQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@angular-devkit/core": "20.1.1",
"@angular-devkit/schematics": "20.1.1",
@@ -11852,6 +11860,7 @@
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -12267,6 +12276,7 @@
"dev": true,
"hasInstallScript": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@swc/counter": "^0.1.3",
"@swc/types": "^0.1.23"
@@ -12492,6 +12502,7 @@
"integrity": "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@swc/counter": "^0.1.3"
}
@@ -12850,6 +12861,7 @@
"integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "^4.17.33",
@@ -13060,7 +13072,8 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.9.tgz",
"integrity": "sha512-IeB32oIV4oGArLrd7znD2rkHQ6EDCM+2Sr76dJnrHwv9OHBTTM6nuDLK9bmikXzPa0ZlWMWtRGo/Uw4mrzQedA==",
"dev": true,
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/@types/node-forge": {
"version": "1.3.14",
@@ -13284,6 +13297,7 @@
"integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.46.1",
"@typescript-eslint/types": "8.46.1",
@@ -13391,6 +13405,7 @@
"integrity": "sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
@@ -13450,6 +13465,7 @@
"integrity": "sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.7.0",
"@typescript-eslint/scope-manager": "8.46.1",
@@ -13951,6 +13967,7 @@
"integrity": "sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vitest/utils": "3.2.4",
"fflate": "^0.8.2",
@@ -14184,6 +14201,7 @@
"integrity": "sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"argparse": "^2.0.1"
},
@@ -14241,6 +14259,7 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -14347,6 +14366,7 @@
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -14565,8 +14585,7 @@
"integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==",
"dev": true,
"license": "ISC",
"optional": true,
"peer": true
"optional": true
},
"node_modules/are-we-there-yet": {
"version": "2.0.0",
@@ -14576,7 +14595,6 @@
"dev": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"delegates": "^1.0.0",
"readable-stream": "^3.6.0"
@@ -15366,6 +15384,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.8.9",
"caniuse-lite": "^1.0.30001746",
@@ -15727,24 +15746,6 @@
],
"license": "CC-BY-4.0"
},
"node_modules/canvas": {
"version": "2.11.2",
"resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz",
"integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@mapbox/node-pre-gyp": "^1.0.0",
"nan": "^2.17.0",
"simple-get": "^3.0.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/case-sensitive-paths-webpack-plugin": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz",
@@ -15818,6 +15819,7 @@
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"license": "MIT",
"peer": true,
"dependencies": {
"readdirp": "^4.0.1"
},
@@ -16159,7 +16161,6 @@
"dev": true,
"license": "ISC",
"optional": true,
"peer": true,
"bin": {
"color-support": "bin.js"
}
@@ -16336,8 +16337,7 @@
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
"dev": true,
"license": "ISC",
"optional": true,
"peer": true
"optional": true
},
"node_modules/content-disposition": {
"version": "1.0.0",
@@ -17826,7 +17826,6 @@
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"mimic-response": "^2.0.0"
},
@@ -18613,6 +18612,7 @@
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"peer": true,
"bin": {
"esbuild": "bin/esbuild"
},
@@ -18653,6 +18653,7 @@
"integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"debug": "^4.3.4"
},
@@ -18741,6 +18742,7 @@
"integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -18802,6 +18804,7 @@
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"eslint-config-prettier": "bin/cli.js"
},
@@ -19190,6 +19193,7 @@
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"accepts": "^2.0.0",
"body-parser": "^2.2.0",
@@ -19807,6 +19811,7 @@
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -20158,7 +20163,6 @@
"dev": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"aproba": "^1.0.3 || ^2.0.0",
"color-support": "^1.1.2",
@@ -20180,8 +20184,7 @@
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true
"optional": true
},
"node_modules/gauge/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
@@ -20190,7 +20193,6 @@
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
@@ -20201,8 +20203,7 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true,
"license": "ISC",
"optional": true,
"peer": true
"optional": true
},
"node_modules/gauge/node_modules/string-width": {
"version": "4.2.3",
@@ -20211,7 +20212,6 @@
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -20709,8 +20709,7 @@
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
"dev": true,
"license": "ISC",
"optional": true,
"peer": true
"optional": true
},
"node_modules/hasown": {
"version": "2.0.2",
@@ -20902,6 +20901,7 @@
"integrity": "sha512-V/PZeWsqhfpE27nKeX9EO2sbR+D17A+tLf6qU+ht66jdUsN0QLKJN27Z+1+gHrVMKgndBahes0PU6rRihDgHTw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/html-minifier-terser": "^6.0.0",
"html-minifier-terser": "^6.0.2",
@@ -22144,6 +22144,7 @@
"integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@jest/core": "^29.7.0",
"@jest/types": "^29.6.3",
@@ -23803,6 +23804,7 @@
"integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@jest/environment": "^29.7.0",
"@jest/fake-timers": "^29.7.0",
@@ -27009,6 +27011,7 @@
"integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"jiti": "lib/jiti-cli.mjs"
}
@@ -27069,6 +27072,7 @@
"integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"abab": "^2.0.6",
"cssstyle": "^3.0.0",
@@ -27620,6 +27624,7 @@
"integrity": "sha512-X9RyH9fvemArzfdP8Pi3irr7lor2Ok4rOttDXBhlwDg+wKQsXOXgHWduAJE1EsF7JJx0w0bcO6BC6tCKKYnXKA==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"copy-anything": "^2.0.1",
"parse-node-version": "^1.0.1",
@@ -28531,7 +28536,6 @@
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
},
@@ -28900,8 +28904,7 @@
"integrity": "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true
"optional": true
},
"node_modules/nanoid": {
"version": "3.3.11",
@@ -29023,6 +29026,7 @@
"integrity": "sha512-objHk39HWnSSv54KD0Ct4A02rug6HiqbmXo1KJW39npzuVc37QWfiZy94afltH1zIx+mQqollmGaCmwibmagvQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@ampproject/remapping": "^2.3.0",
"@rollup/plugin-json": "^6.1.0",
@@ -29542,7 +29546,6 @@
"dev": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"are-we-there-yet": "^2.0.0",
"console-control-strings": "^1.1.0",
@@ -29577,6 +29580,7 @@
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@napi-rs/wasm-runtime": "0.2.4",
"@yarnpkg/lockfile": "^1.1.0",
@@ -30876,6 +30880,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -31770,6 +31775,7 @@
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -32122,6 +32128,7 @@
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -32132,6 +32139,7 @@
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -32832,7 +32840,6 @@
"dev": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"glob": "^7.1.3"
},
@@ -32850,7 +32857,6 @@
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -32864,7 +32870,6 @@
"dev": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@@ -32887,7 +32892,6 @@
"dev": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
@@ -32919,6 +32923,7 @@
"integrity": "sha512-x8H8aPvD+xbl0Do8oez5f5o8eMS3trfCghc4HhLAnCkj7Vl0d1JWGs0UF/D886zLW2rOj2QymV/JcSSsw+XDNg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/estree": "1.0.8"
},
@@ -33049,6 +33054,7 @@
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"tslib": "^2.1.0"
}
@@ -33611,6 +33617,7 @@
"resolved": "https://registry.npmjs.org/scandit-web-datacapture-core/-/scandit-web-datacapture-core-6.28.6.tgz",
"integrity": "sha512-D7rC+SWWG0XoZVo+LNlvpJi8+sxsylhn5zvzfDGhrDI6zTAT812HNgoGJDjNNZTZ8iaS5/dYg8LU5b+N4MLsZQ==",
"license": "SEE LICENSE IN LICENSE",
"peer": true,
"dependencies": {
"@types/howler": "^2.2.11",
"@types/js-cookie": "^2.2.6",
@@ -33946,8 +33953,7 @@
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"dev": true,
"license": "ISC",
"optional": true,
"peer": true
"optional": true
},
"node_modules/set-cookie-parser": {
"version": "2.7.1",
@@ -34187,7 +34193,6 @@
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"decompress-response": "^4.2.0",
"once": "^1.3.1",
@@ -34566,6 +34571,7 @@
"integrity": "sha512-shRR8GLKoa6qSVxgC37ojtON4n+ZCFbzxL3t69qrVmMpcKqxOyZRUI933Xoi6+RQMyzqRfgkib5dvoLIGO1V4Q==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@storybook/global": "^5.0.0",
"@testing-library/jest-dom": "^6.6.3",
@@ -34905,6 +34911,7 @@
"integrity": "sha512-ZIdT8eUv8tegmqy1tTIdJv9We2DumkNZFdCF5mz/Kpq3OcTaxSuCAYZge6HKK2CmNC02G1eJig2RV7XTw5hQrA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@adobe/css-tools": "~4.3.3",
"debug": "^4.3.2",
@@ -35105,6 +35112,7 @@
"integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2",
@@ -35181,6 +35189,7 @@
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"jiti": "bin/jiti.js"
}
@@ -35424,6 +35433,7 @@
"integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==",
"dev": true,
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.14.0",
@@ -36057,6 +36067,7 @@
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
@@ -36163,7 +36174,8 @@
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
"license": "0BSD",
"peer": true
},
"node_modules/tsscmp": {
"version": "1.0.6",
@@ -36277,6 +36289,7 @@
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"devOptional": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -36291,6 +36304,7 @@
"integrity": "sha512-VHgijW803JafdSsDO8I761r3SHrgk4T00IdyQ+/UsthtgPRsBWQLqoSxOolxTpxRKi1kGXK0bSz4CoAc9ObqJA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/eslint-plugin": "8.46.1",
"@typescript-eslint/parser": "8.46.1",
@@ -36355,8 +36369,7 @@
"integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true
"optional": true
},
"node_modules/unicode-canonical-property-names-ecmascript": {
"version": "2.0.1",
@@ -36727,6 +36740,7 @@
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.4",
@@ -36825,6 +36839,7 @@
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/chai": "^5.2.2",
"@vitest/expect": "3.2.4",
@@ -36979,6 +36994,7 @@
"integrity": "sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.7",
"@types/estree": "^1.0.6",
@@ -37099,6 +37115,7 @@
"integrity": "sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/bonjour": "^3.5.13",
"@types/connect-history-api-fallback": "^1.5.4",
@@ -37620,6 +37637,7 @@
"integrity": "sha512-khZGfAeJx6I8K9zKohEWWYN6KDlVw2DHownoe+6Vtwj1LP9WFgegXnVMSkZ/dBEBtXFwrkkydsaPFlB7f8wU2A==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"ansi-html-community": "0.0.8",
"html-entities": "^2.1.0",
@@ -37920,7 +37938,6 @@
"dev": true,
"license": "ISC",
"optional": true,
"peer": true,
"dependencies": {
"string-width": "^1.0.2 || 2 || 3 || 4"
}
@@ -37931,8 +37948,7 @@
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true
"optional": true
},
"node_modules/wide-align/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
@@ -37941,7 +37957,6 @@
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
@@ -37953,7 +37968,6 @@
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -38111,6 +38125,7 @@
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=8.3.0"
},
@@ -38182,6 +38197,7 @@
"integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
"dev": true,
"license": "ISC",
"peer": true,
"bin": {
"yaml": "bin.mjs"
},
@@ -38369,6 +38385,7 @@
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
"license": "MIT",
"peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
@@ -38387,7 +38404,8 @@
"version": "0.15.1",
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz",
"integrity": "sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==",
"license": "MIT"
"license": "MIT",
"peer": true
}
}
}