diff --git a/README.md b/README.md index bb0a60d..736742e 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ data is colored in relation to some metric (state, update count, skip count, cur "y":5321, "kit":"my-default-kit", "state":666, + "states": [...,664,665,666], "updatedAt":1711907506, "renderedAt":1711907506, "createdAt":1711302106, @@ -57,7 +58,7 @@ see [.env.production](/packages/frontend/config/.env.production) and [env.sh](/p ### redis search index creation: ``` FT.CREATE tileDetailsIdx ON JSON PREFIX 1 tile: -SCHEMA $.kit AS kit TEXT $.updatedAt AS updatedAt NUMERIC $.renderedAt AS renderedAt NUMERIC $.createdAt AS createdAt NUMERIC $.updateCount AS updateCount NUMERIC $.renderCount AS renderCount NUMERIC $.skipCount AS skipCount NUMERIC $.coordiantes AS coordinates GEO $.geoshape AS geoshape GEOSHAPE SPHERICAL $.state AS state NUMERIC $.z AS z NUMERIC $.x AS x NUMERIC $.y AS y NUMERIC +SCHEMA $.kit AS kit TEXT $.updatedAt AS updatedAt NUMERIC $.renderedAt AS renderedAt NUMERIC $.createdAt AS createdAt NUMERIC $.updateCount AS updateCount NUMERIC $.renderCount AS renderCount NUMERIC $.skipCount AS skipCount NUMERIC $.coordiantes AS coordinates GEO $.geoshape AS geoshape GEOSHAPE SPHERICAL $.state AS state NUMERIC $.states[*] AS states NUMERIC $.z AS z NUMERIC $.x AS x NUMERIC $.y AS y NUMERIC ``` ### redis post processing: diff --git a/package-lock.json b/package-lock.json index 86c2d8b..3202869 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,7 @@ } }, "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "11.6.4", + "version": "11.7.0", "license": "MIT", "dependencies": { "@jsdevtools/ono": "^7.1.3", @@ -77,7 +77,7 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.25.0", + "version": "7.25.4", "dev": true, "license": "MIT", "engines": { @@ -85,20 +85,20 @@ } }, "node_modules/@babel/core": { - "version": "7.24.9", + "version": "7.25.2", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.9", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-module-transforms": "^7.24.9", - "@babel/helpers": "^7.24.8", - "@babel/parser": "^7.24.8", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.9", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -113,6 +113,11 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "dev": true, @@ -155,10 +160,10 @@ } }, "node_modules/@babel/generator": { - "version": "7.25.0", + "version": "7.25.6", "license": "MIT", "dependencies": { - "@babel/types": "^7.25.0", + "@babel/types": "^7.25.6", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -191,11 +196,11 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.8", + "version": "7.25.2", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.24.8", + "@babel/compat-data": "^7.25.2", "@babel/helper-validator-option": "^7.24.8", "browserslist": "^4.23.1", "lru-cache": "^5.1.1", @@ -214,7 +219,7 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.25.0", + "version": "7.25.4", "dev": true, "license": "MIT", "dependencies": { @@ -223,7 +228,7 @@ "@babel/helper-optimise-call-expression": "^7.24.7", "@babel/helper-replace-supers": "^7.25.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/traverse": "^7.25.0", + "@babel/traverse": "^7.25.4", "semver": "^6.3.1" }, "engines": { @@ -242,7 +247,7 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.25.0", + "version": "7.25.2", "dev": true, "license": "MIT", "dependencies": { @@ -304,14 +309,14 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.25.0", + "version": "7.25.2", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.24.7", "@babel/helper-simple-access": "^7.24.7", "@babel/helper-validator-identifier": "^7.24.7", - "@babel/traverse": "^7.25.0" + "@babel/traverse": "^7.25.2" }, "engines": { "node": ">=6.9.0" @@ -431,12 +436,12 @@ } }, "node_modules/@babel/helpers": { - "version": "7.25.0", + "version": "7.25.6", "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/types": "^7.25.6" }, "engines": { "node": ">=6.9.0" @@ -513,8 +518,11 @@ } }, "node_modules/@babel/parser": { - "version": "7.25.0", + "version": "7.25.6", "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.6" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -523,12 +531,12 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.25.0", + "version": "7.25.3", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.8", - "@babel/traverse": "^7.25.0" + "@babel/traverse": "^7.25.3" }, "engines": { "node": ">=6.9.0" @@ -797,11 +805,11 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.7", + "version": "7.25.6", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -811,11 +819,11 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.7", + "version": "7.25.6", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -955,11 +963,11 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.24.7", + "version": "7.25.4", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -998,14 +1006,14 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.25.0", + "version": "7.25.4", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-remap-async-to-generator": "^7.25.0", "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/traverse": "^7.25.0" + "@babel/traverse": "^7.25.4" }, "engines": { "node": ">=6.9.0" @@ -1059,12 +1067,12 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.24.7", + "version": "7.25.4", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1090,15 +1098,15 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.25.0", + "version": "7.25.4", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-compilation-targets": "^7.25.2", "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-replace-supers": "^7.25.0", - "@babel/traverse": "^7.25.0", + "@babel/traverse": "^7.25.4", "globals": "^11.1.0" }, "engines": { @@ -1108,14 +1116,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/globals": { - "version": "11.12.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.24.7", "dev": true, @@ -1235,11 +1235,11 @@ } }, "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.24.7", + "version": "7.25.2", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", "@babel/plugin-syntax-flow": "^7.24.7" }, "engines": { @@ -1296,11 +1296,11 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.7", + "version": "7.25.2", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1538,12 +1538,12 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.24.7", + "version": "7.25.4", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1598,15 +1598,15 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.24.7", + "version": "7.25.2", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", "@babel/plugin-syntax-jsx": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.2" }, "engines": { "node": ">=6.9.0" @@ -1702,14 +1702,14 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.24.7", + "version": "7.25.4", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.1", + "babel-plugin-polyfill-corejs3": "^0.10.6", "babel-plugin-polyfill-regenerator": "^0.6.1", "semver": "^6.3.1" }, @@ -1800,7 +1800,7 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.25.0", + "version": "7.25.2", "dev": true, "license": "MIT", "dependencies": { @@ -1862,12 +1862,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.24.7", + "version": "7.25.4", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1877,15 +1877,15 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.25.0", + "version": "7.25.4", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.25.0", - "@babel/helper-compilation-targets": "^7.24.8", + "@babel/compat-data": "^7.25.4", + "@babel/helper-compilation-targets": "^7.25.2", "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-validator-option": "^7.24.8", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.0", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", @@ -1910,13 +1910,13 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.25.0", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoped-functions": "^7.24.7", "@babel/plugin-transform-block-scoping": "^7.25.0", - "@babel/plugin-transform-class-properties": "^7.24.7", + "@babel/plugin-transform-class-properties": "^7.25.4", "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.25.0", + "@babel/plugin-transform-classes": "^7.25.4", "@babel/plugin-transform-computed-properties": "^7.24.7", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-dotall-regex": "^7.24.7", @@ -1926,9 +1926,9 @@ "@babel/plugin-transform-exponentiation-operator": "^7.24.7", "@babel/plugin-transform-export-namespace-from": "^7.24.7", "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.25.0", + "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-json-strings": "^7.24.7", - "@babel/plugin-transform-literals": "^7.24.7", + "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-member-expression-literals": "^7.24.7", "@babel/plugin-transform-modules-amd": "^7.24.7", @@ -1944,7 +1944,7 @@ "@babel/plugin-transform-optional-catch-binding": "^7.24.7", "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", - "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.25.4", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-property-literals": "^7.24.7", "@babel/plugin-transform-regenerator": "^7.24.7", @@ -1957,10 +1957,10 @@ "@babel/plugin-transform-unicode-escapes": "^7.24.7", "@babel/plugin-transform-unicode-property-regex": "^7.24.7", "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.4", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-corejs3": "^0.10.6", "babel-plugin-polyfill-regenerator": "^0.6.1", "core-js-compat": "^3.37.1", "semver": "^6.3.1" @@ -2036,7 +2036,7 @@ "license": "MIT" }, "node_modules/@babel/runtime": { - "version": "7.25.0", + "version": "7.25.6", "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" @@ -2058,14 +2058,14 @@ } }, "node_modules/@babel/traverse": { - "version": "7.25.1", + "version": "7.25.6", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.0", + "@babel/generator": "^7.25.6", + "@babel/parser": "^7.25.6", "@babel/template": "^7.25.0", - "@babel/types": "^7.25.0", + "@babel/types": "^7.25.6", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2073,15 +2073,8 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/types": { - "version": "7.25.0", + "version": "7.25.6", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.24.8", @@ -2098,14 +2091,14 @@ "license": "MIT" }, "node_modules/@commitlint/cli": { - "version": "19.3.0", + "version": "19.4.1", "dev": true, "license": "MIT", "dependencies": { "@commitlint/format": "^19.3.0", - "@commitlint/lint": "^19.2.2", - "@commitlint/load": "^19.2.0", - "@commitlint/read": "^19.2.1", + "@commitlint/lint": "^19.4.1", + "@commitlint/load": "^19.4.0", + "@commitlint/read": "^19.4.0", "@commitlint/types": "^19.0.3", "execa": "^8.0.1", "yargs": "^17.0.0" @@ -2118,7 +2111,7 @@ } }, "node_modules/@commitlint/config-conventional": { - "version": "19.2.2", + "version": "19.4.1", "dev": true, "license": "MIT", "dependencies": { @@ -2190,13 +2183,13 @@ } }, "node_modules/@commitlint/lint": { - "version": "19.2.2", + "version": "19.4.1", "dev": true, "license": "MIT", "dependencies": { "@commitlint/is-ignored": "^19.2.2", "@commitlint/parse": "^19.0.3", - "@commitlint/rules": "^19.0.3", + "@commitlint/rules": "^19.4.1", "@commitlint/types": "^19.0.3" }, "engines": { @@ -2204,7 +2197,7 @@ } }, "node_modules/@commitlint/load": { - "version": "19.2.0", + "version": "19.4.0", "dev": true, "license": "MIT", "dependencies": { @@ -2245,7 +2238,7 @@ } }, "node_modules/@commitlint/read": { - "version": "19.2.1", + "version": "19.4.0", "dev": true, "license": "MIT", "dependencies": { @@ -2276,7 +2269,7 @@ } }, "node_modules/@commitlint/rules": { - "version": "19.0.3", + "version": "19.4.1", "dev": true, "license": "MIT", "dependencies": { @@ -2342,7 +2335,7 @@ } }, "node_modules/@deck.gl/aggregation-layers": { - "version": "9.0.24", + "version": "9.0.28", "license": "MIT", "dependencies": { "@luma.gl/constants": "^9.0.15", @@ -2358,7 +2351,7 @@ } }, "node_modules/@deck.gl/arcgis": { - "version": "9.0.24", + "version": "9.0.28", "license": "MIT", "dependencies": { "@luma.gl/constants": "^9.0.15", @@ -2372,7 +2365,7 @@ } }, "node_modules/@deck.gl/carto": { - "version": "9.0.24", + "version": "9.0.28", "license": "MIT", "dependencies": { "@loaders.gl/gis": "^4.2.0", @@ -2422,7 +2415,7 @@ "license": "MIT" }, "node_modules/@deck.gl/core": { - "version": "9.0.24", + "version": "9.0.28", "license": "MIT", "dependencies": { "@loaders.gl/core": "^4.2.0", @@ -2444,7 +2437,7 @@ } }, "node_modules/@deck.gl/extensions": { - "version": "9.0.24", + "version": "9.0.28", "license": "MIT", "dependencies": { "@luma.gl/constants": "^9.0.15", @@ -2458,7 +2451,7 @@ } }, "node_modules/@deck.gl/geo-layers": { - "version": "9.0.24", + "version": "9.0.28", "license": "MIT", "dependencies": { "@loaders.gl/3d-tiles": "^4.2.0", @@ -2496,7 +2489,7 @@ } }, "node_modules/@deck.gl/google-maps": { - "version": "9.0.24", + "version": "9.0.28", "license": "MIT", "dependencies": { "@luma.gl/constants": "^9.0.15", @@ -2509,7 +2502,7 @@ } }, "node_modules/@deck.gl/json": { - "version": "9.0.24", + "version": "9.0.28", "license": "MIT", "dependencies": { "expression-eval": "^5.0.0" @@ -2519,7 +2512,7 @@ } }, "node_modules/@deck.gl/layers": { - "version": "9.0.24", + "version": "9.0.28", "license": "MIT", "dependencies": { "@loaders.gl/images": "^4.2.0", @@ -2538,7 +2531,7 @@ } }, "node_modules/@deck.gl/mapbox": { - "version": "9.0.24", + "version": "9.0.28", "license": "MIT", "dependencies": { "@luma.gl/constants": "^9.0.15", @@ -2550,7 +2543,7 @@ } }, "node_modules/@deck.gl/mesh-layers": { - "version": "9.0.24", + "version": "9.0.28", "license": "MIT", "dependencies": { "@loaders.gl/gltf": "^4.2.0", @@ -2564,7 +2557,7 @@ } }, "node_modules/@deck.gl/react": { - "version": "9.0.24", + "version": "9.0.28", "license": "MIT", "peerDependencies": { "@deck.gl/core": "^9.0.0", @@ -2573,7 +2566,7 @@ } }, "node_modules/@deck.gl/widgets": { - "version": "9.0.24", + "version": "9.0.28", "license": "MIT", "dependencies": { "preact": "^10.17.0" @@ -2624,17 +2617,6 @@ "stylis": "4.2.0" } }, - "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { - "version": "1.9.0", - "license": "MIT" - }, - "node_modules/@emotion/babel-plugin/node_modules/source-map": { - "version": "0.5.7", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@emotion/cache": { "version": "11.13.1", "license": "MIT", @@ -2662,13 +2644,13 @@ "license": "MIT" }, "node_modules/@emotion/react": { - "version": "11.13.0", + "version": "11.13.3", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.12.0", "@emotion/cache": "^11.13.0", - "@emotion/serialize": "^1.3.0", + "@emotion/serialize": "^1.3.1", "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", "@emotion/utils": "^1.4.0", "@emotion/weak-memoize": "^0.4.0", @@ -2684,12 +2666,12 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.3.0", + "version": "1.3.1", "license": "MIT", "dependencies": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", - "@emotion/unitless": "^0.9.0", + "@emotion/unitless": "^0.10.0", "@emotion/utils": "^1.4.0", "csstype": "^3.0.2" } @@ -2720,7 +2702,7 @@ } }, "node_modules/@emotion/unitless": { - "version": "0.9.0", + "version": "0.10.0", "license": "MIT" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { @@ -2812,11 +2794,36 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { "version": "0.4.1", "dev": true, "license": "MIT" }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/js": { "version": "8.57.0", "dev": true, @@ -2842,20 +2849,23 @@ "peer": true }, "node_modules/@esri/calcite-components": { - "version": "2.10.1", + "version": "2.12.0", "license": "SEE LICENSE.md", "peer": true, "dependencies": { - "@floating-ui/dom": "1.6.5", - "@stencil/core": "4.18.3", + "@esri/calcite-ui-icons": "3.31.0", + "@floating-ui/dom": "1.6.10", + "@stencil/core": "4.20.0", "@types/color": "3.0.6", + "@types/sortablejs": "1.15.7", "color": "4.2.3", - "composed-offset-position": "0.0.4", - "dayjs": "1.11.11", + "composed-offset-position": "0.0.6", + "dayjs": "1.11.12", "focus-trap": "7.5.4", + "interactjs": "1.10.27", "lodash-es": "4.17.21", "sortablejs": "1.15.1", - "timezone-groups": "0.8.0", + "timezone-groups": "0.9.1", "type-fest": "4.18.2" } }, @@ -2875,25 +2885,33 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@esri/calcite-ui-icons": { + "version": "3.31.0", + "license": "SEE LICENSE.md", + "peer": true, + "bin": { + "spriter": "bin/spriter.js" + } + }, "node_modules/@floating-ui/core": { - "version": "1.6.5", + "version": "1.6.7", "license": "MIT", "peer": true, "dependencies": { - "@floating-ui/utils": "^0.2.5" + "@floating-ui/utils": "^0.2.7" } }, "node_modules/@floating-ui/dom": { - "version": "1.6.5", + "version": "1.6.10", "license": "MIT", "peer": true, "dependencies": { - "@floating-ui/core": "^1.0.0", - "@floating-ui/utils": "^0.2.0" + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.7" } }, "node_modules/@floating-ui/utils": { - "version": "0.2.5", + "version": "0.2.7", "license": "MIT", "peer": true }, @@ -3043,6 +3061,11 @@ "node": ">=6.9.0" } }, + "node_modules/@interactjs/types": { + "version": "1.10.27", + "license": "MIT", + "peer": true + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "dev": true, @@ -3600,6 +3623,11 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@jest/transform/node_modules/convert-source-map": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, "node_modules/@jest/types": { "version": "29.6.3", "dev": true, @@ -3696,11 +3724,11 @@ "license": "MIT" }, "node_modules/@lerna/create": { - "version": "8.1.7", + "version": "8.1.8", "dev": true, "license": "MIT", "dependencies": { - "@npmcli/arborist": "7.5.3", + "@npmcli/arborist": "7.5.4", "@npmcli/package-json": "5.2.0", "@npmcli/run-script": "8.1.0", "@nx/devkit": ">=17.1.2 < 20", @@ -4061,6 +4089,18 @@ "node": ">=6" } }, + "node_modules/@lerna/create/node_modules/uuid": { + "version": "10.0.0", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/@lerna/create/node_modules/write-file-atomic": { "version": "5.0.1", "dev": true, @@ -4085,7 +4125,7 @@ } }, "node_modules/@lit-labs/ssr-dom-shim": { - "version": "1.2.0", + "version": "1.2.1", "license": "BSD-3-Clause", "peer": true }, @@ -4359,11 +4399,11 @@ } }, "node_modules/@luma.gl/constants": { - "version": "9.0.16", + "version": "9.0.27", "license": "MIT" }, "node_modules/@luma.gl/core": { - "version": "9.0.16", + "version": "9.0.27", "license": "MIT", "dependencies": { "@math.gl/types": "^4.0.0", @@ -4374,10 +4414,10 @@ } }, "node_modules/@luma.gl/engine": { - "version": "9.0.16", + "version": "9.0.27", "license": "MIT", "dependencies": { - "@luma.gl/shadertools": "9.0.16", + "@luma.gl/shadertools": "9.0.27", "@math.gl/core": "^4.0.0", "@probe.gl/log": "^4.0.2", "@probe.gl/stats": "^4.0.2" @@ -4387,11 +4427,11 @@ } }, "node_modules/@luma.gl/gltf": { - "version": "9.0.16", + "version": "9.0.27", "license": "MIT", "dependencies": { "@loaders.gl/textures": "^4.2.0", - "@luma.gl/shadertools": "9.0.16", + "@luma.gl/shadertools": "9.0.27", "@math.gl/core": "^4.0.0" }, "peerDependencies": { @@ -4401,7 +4441,7 @@ } }, "node_modules/@luma.gl/shadertools": { - "version": "9.0.16", + "version": "9.0.27", "license": "MIT", "dependencies": { "@math.gl/core": "^4.0.0", @@ -4413,10 +4453,10 @@ } }, "node_modules/@luma.gl/webgl": { - "version": "9.0.16", + "version": "9.0.27", "license": "MIT", "dependencies": { - "@luma.gl/constants": "9.0.16", + "@luma.gl/constants": "9.0.27", "@probe.gl/env": "^4.0.2" }, "peerDependencies": { @@ -4666,7 +4706,7 @@ "license": "MIT" }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.16.5", + "version": "5.16.7", "license": "MIT", "funding": { "type": "opencollective", @@ -4674,7 +4714,7 @@ } }, "node_modules/@mui/icons-material": { - "version": "5.16.5", + "version": "5.16.7", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9" @@ -4698,14 +4738,14 @@ } }, "node_modules/@mui/material": { - "version": "5.16.5", + "version": "5.16.7", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/core-downloads-tracker": "^5.16.5", - "@mui/system": "^5.16.5", + "@mui/core-downloads-tracker": "^5.16.7", + "@mui/system": "^5.16.7", "@mui/types": "^7.2.15", - "@mui/utils": "^5.16.5", + "@mui/utils": "^5.16.6", "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.10", "clsx": "^2.1.0", @@ -4741,11 +4781,11 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.16.5", + "version": "5.16.6", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/utils": "^5.16.5", + "@mui/utils": "^5.16.6", "prop-types": "^15.8.1" }, "engines": { @@ -4766,7 +4806,7 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.16.4", + "version": "5.16.6", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", @@ -4796,14 +4836,14 @@ } }, "node_modules/@mui/system": { - "version": "5.16.5", + "version": "5.16.7", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/private-theming": "^5.16.5", - "@mui/styled-engine": "^5.16.4", + "@mui/private-theming": "^5.16.6", + "@mui/styled-engine": "^5.16.6", "@mui/types": "^7.2.15", - "@mui/utils": "^5.16.5", + "@mui/utils": "^5.16.6", "clsx": "^2.1.0", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -4834,10 +4874,10 @@ } }, "node_modules/@mui/types": { - "version": "7.2.15", + "version": "7.2.16", "license": "MIT", "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0" + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -4846,7 +4886,7 @@ } }, "node_modules/@mui/utils": { - "version": "5.16.5", + "version": "5.16.6", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", @@ -4964,7 +5004,7 @@ "license": "ISC" }, "node_modules/@npmcli/arborist": { - "version": "7.5.3", + "version": "7.5.4", "dev": true, "license": "ISC", "dependencies": { @@ -5353,19 +5393,19 @@ } }, "node_modules/@nrwl/devkit": { - "version": "19.5.3", + "version": "19.6.4", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "19.5.3" + "@nx/devkit": "19.6.4" } }, "node_modules/@nrwl/tao": { - "version": "19.5.3", + "version": "19.6.4", "dev": true, "license": "MIT", "dependencies": { - "nx": "19.5.3", + "nx": "19.6.4", "tslib": "^2.3.0" }, "bin": { @@ -5373,11 +5413,11 @@ } }, "node_modules/@nx/devkit": { - "version": "19.5.3", + "version": "19.6.4", "dev": true, "license": "MIT", "dependencies": { - "@nrwl/devkit": "19.5.3", + "@nrwl/devkit": "19.6.4", "ejs": "^3.1.7", "enquirer": "~2.3.6", "ignore": "^5.0.4", @@ -5422,7 +5462,7 @@ } }, "node_modules/@nx/nx-linux-x64-gnu": { - "version": "19.5.3", + "version": "19.6.4", "cpu": [ "x64" ], @@ -5437,7 +5477,7 @@ } }, "node_modules/@nx/nx-linux-x64-musl": { - "version": "19.5.3", + "version": "19.6.4", "cpu": [ "x64" ], @@ -5753,7 +5793,7 @@ } }, "node_modules/@opentelemetry/context-async-hooks": { - "version": "1.25.1", + "version": "1.26.0", "license": "Apache-2.0", "engines": { "node": ">=14" @@ -5763,10 +5803,10 @@ } }, "node_modules/@opentelemetry/core": { - "version": "1.25.1", + "version": "1.26.0", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/semantic-conventions": "1.25.1" + "@opentelemetry/semantic-conventions": "1.27.0" }, "engines": { "node": ">=14" @@ -6950,7 +6990,7 @@ } }, "node_modules/@opentelemetry/propagation-utils": { - "version": "0.30.10", + "version": "0.30.11", "license": "Apache-2.0", "engines": { "node": ">=14" @@ -6960,10 +7000,10 @@ } }, "node_modules/@opentelemetry/propagator-aws-xray": { - "version": "1.25.1", + "version": "1.26.0", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.25.1" + "@opentelemetry/core": "1.26.0" }, "engines": { "node": ">=14" @@ -6973,10 +7013,10 @@ } }, "node_modules/@opentelemetry/propagator-b3": { - "version": "1.25.1", + "version": "1.26.0", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.25.1" + "@opentelemetry/core": "1.26.0" }, "engines": { "node": ">=14" @@ -6986,10 +7026,10 @@ } }, "node_modules/@opentelemetry/propagator-jaeger": { - "version": "1.25.1", + "version": "1.26.0", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.25.1" + "@opentelemetry/core": "1.26.0" }, "engines": { "node": ">=14" @@ -7020,12 +7060,12 @@ } }, "node_modules/@opentelemetry/resource-detector-aws": { - "version": "1.5.2", + "version": "1.6.1", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "^1.0.0", - "@opentelemetry/resources": "^1.0.0", - "@opentelemetry/semantic-conventions": "^1.22.0" + "@opentelemetry/resources": "^1.10.0", + "@opentelemetry/semantic-conventions": "^1.27.0" }, "engines": { "node": ">=14" @@ -7049,12 +7089,12 @@ } }, "node_modules/@opentelemetry/resource-detector-gcp": { - "version": "0.29.10", + "version": "0.29.11", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "^1.0.0", "@opentelemetry/resources": "^1.0.0", - "@opentelemetry/semantic-conventions": "^1.22.0", + "@opentelemetry/semantic-conventions": "^1.27.0", "gcp-metadata": "^6.0.0" }, "engines": { @@ -7065,11 +7105,11 @@ } }, "node_modules/@opentelemetry/resources": { - "version": "1.25.1", + "version": "1.26.0", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.25.1", - "@opentelemetry/semantic-conventions": "1.25.1" + "@opentelemetry/core": "1.26.0", + "@opentelemetry/semantic-conventions": "1.27.0" }, "engines": { "node": ">=14" @@ -7128,12 +7168,11 @@ } }, "node_modules/@opentelemetry/sdk-metrics": { - "version": "1.25.1", + "version": "1.26.0", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.25.1", - "@opentelemetry/resources": "1.25.1", - "lodash.merge": "^4.6.2" + "@opentelemetry/core": "1.26.0", + "@opentelemetry/resources": "1.26.0" }, "engines": { "node": ">=14" @@ -7286,12 +7325,12 @@ } }, "node_modules/@opentelemetry/sdk-trace-base": { - "version": "1.25.1", + "version": "1.26.0", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.25.1", - "@opentelemetry/resources": "1.25.1", - "@opentelemetry/semantic-conventions": "1.25.1" + "@opentelemetry/core": "1.26.0", + "@opentelemetry/resources": "1.26.0", + "@opentelemetry/semantic-conventions": "1.27.0" }, "engines": { "node": ">=14" @@ -7301,14 +7340,14 @@ } }, "node_modules/@opentelemetry/sdk-trace-node": { - "version": "1.25.1", + "version": "1.26.0", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/context-async-hooks": "1.25.1", - "@opentelemetry/core": "1.25.1", - "@opentelemetry/propagator-b3": "1.25.1", - "@opentelemetry/propagator-jaeger": "1.25.1", - "@opentelemetry/sdk-trace-base": "1.25.1", + "@opentelemetry/context-async-hooks": "1.26.0", + "@opentelemetry/core": "1.26.0", + "@opentelemetry/propagator-b3": "1.26.0", + "@opentelemetry/propagator-jaeger": "1.26.0", + "@opentelemetry/sdk-trace-base": "1.26.0", "semver": "^7.5.2" }, "engines": { @@ -7319,7 +7358,7 @@ } }, "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.25.1", + "version": "1.27.0", "license": "Apache-2.0", "engines": { "node": ">=14" @@ -7430,7 +7469,7 @@ } }, "node_modules/@redis/client": { - "version": "1.5.17", + "version": "1.6.0", "license": "MIT", "dependencies": { "cluster-key-slot": "1.1.2", @@ -7453,21 +7492,21 @@ } }, "node_modules/@redis/json": { - "version": "1.0.6", + "version": "1.0.7", "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } }, "node_modules/@redis/search": { - "version": "1.1.6", + "version": "1.2.0", "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } }, "node_modules/@redis/time-series": { - "version": "1.0.5", + "version": "1.1.0", "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" @@ -7590,7 +7629,7 @@ } }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.19.1", + "version": "4.21.2", "cpu": [ "x64" ], @@ -7602,7 +7641,7 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.19.1", + "version": "4.21.2", "cpu": [ "x64" ], @@ -7723,7 +7762,7 @@ } }, "node_modules/@stencil/core": { - "version": "4.18.3", + "version": "4.20.0", "license": "MIT", "peer": true, "bin": { @@ -8249,7 +8288,7 @@ } }, "node_modules/@types/eslint": { - "version": "8.56.11", + "version": "8.56.12", "dev": true, "license": "MIT", "dependencies": { @@ -8296,7 +8335,7 @@ } }, "node_modules/@types/google.maps": { - "version": "3.55.12", + "version": "3.57.0", "license": "MIT" }, "node_modules/@types/graceful-fs": { @@ -8449,7 +8488,7 @@ } }, "node_modules/@types/mapbox-gl": { - "version": "3.1.0", + "version": "3.4.0", "license": "MIT", "dependencies": { "@types/geojson": "*" @@ -8491,7 +8530,7 @@ "license": "MIT" }, "node_modules/@types/multer": { - "version": "1.4.11", + "version": "1.4.12", "license": "MIT", "dependencies": { "@types/express": "*" @@ -8505,10 +8544,10 @@ } }, "node_modules/@types/node": { - "version": "20.14.13", + "version": "20.16.3", "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/@types/normalize-package-data": { @@ -8561,7 +8600,7 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.3", + "version": "18.3.5", "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -8585,7 +8624,7 @@ } }, "node_modules/@types/react-transition-group": { - "version": "4.4.10", + "version": "4.4.11", "license": "MIT", "dependencies": { "@types/react": "*" @@ -8641,13 +8680,18 @@ "version": "1.2.0", "license": "MIT" }, + "node_modules/@types/sortablejs": { + "version": "1.15.7", + "license": "MIT", + "peer": true + }, "node_modules/@types/stack-utils": { "version": "2.0.3", "dev": true, "license": "MIT" }, "node_modules/@types/superagent": { - "version": "8.1.8", + "version": "8.1.9", "dev": true, "license": "MIT", "dependencies": { @@ -8697,7 +8741,7 @@ "license": "MIT" }, "node_modules/@types/yargs": { - "version": "17.0.32", + "version": "17.0.33", "dev": true, "license": "MIT", "dependencies": { @@ -9029,34 +9073,34 @@ "license": "ISC" }, "node_modules/@vaadin/a11y-base": { - "version": "24.3.18", + "version": "24.3.21", "license": "Apache-2.0", "peer": true, "dependencies": { "@open-wc/dedupe-mixin": "^1.3.0", "@polymer/polymer": "^3.0.0", - "@vaadin/component-base": "~24.3.18", + "@vaadin/component-base": "~24.3.21", "lit": "^3.0.0" } }, "node_modules/@vaadin/checkbox": { - "version": "24.3.18", + "version": "24.3.21", "license": "Apache-2.0", "peer": true, "dependencies": { "@open-wc/dedupe-mixin": "^1.3.0", "@polymer/polymer": "^3.0.0", - "@vaadin/a11y-base": "~24.3.18", - "@vaadin/component-base": "~24.3.18", - "@vaadin/field-base": "~24.3.18", - "@vaadin/vaadin-lumo-styles": "~24.3.18", - "@vaadin/vaadin-material-styles": "~24.3.18", - "@vaadin/vaadin-themable-mixin": "~24.3.18", + "@vaadin/a11y-base": "~24.3.21", + "@vaadin/component-base": "~24.3.21", + "@vaadin/field-base": "~24.3.21", + "@vaadin/vaadin-lumo-styles": "~24.3.21", + "@vaadin/vaadin-material-styles": "~24.3.21", + "@vaadin/vaadin-themable-mixin": "~24.3.21", "lit": "^3.0.0" } }, "node_modules/@vaadin/component-base": { - "version": "24.3.18", + "version": "24.3.21", "license": "Apache-2.0", "peer": true, "dependencies": { @@ -9068,62 +9112,62 @@ } }, "node_modules/@vaadin/field-base": { - "version": "24.3.18", + "version": "24.3.21", "license": "Apache-2.0", "peer": true, "dependencies": { "@open-wc/dedupe-mixin": "^1.3.0", "@polymer/polymer": "^3.0.0", - "@vaadin/a11y-base": "~24.3.18", - "@vaadin/component-base": "~24.3.18", + "@vaadin/a11y-base": "~24.3.21", + "@vaadin/component-base": "~24.3.21", "lit": "^3.0.0" } }, "node_modules/@vaadin/grid": { - "version": "24.3.18", + "version": "24.3.21", "license": "Apache-2.0", "peer": true, "dependencies": { "@open-wc/dedupe-mixin": "^1.3.0", "@polymer/polymer": "^3.0.0", - "@vaadin/a11y-base": "~24.3.18", - "@vaadin/checkbox": "~24.3.18", - "@vaadin/component-base": "~24.3.18", - "@vaadin/lit-renderer": "~24.3.18", - "@vaadin/text-field": "~24.3.18", - "@vaadin/vaadin-lumo-styles": "~24.3.18", - "@vaadin/vaadin-material-styles": "~24.3.18", - "@vaadin/vaadin-themable-mixin": "~24.3.18" + "@vaadin/a11y-base": "~24.3.21", + "@vaadin/checkbox": "~24.3.21", + "@vaadin/component-base": "~24.3.21", + "@vaadin/lit-renderer": "~24.3.21", + "@vaadin/text-field": "~24.3.21", + "@vaadin/vaadin-lumo-styles": "~24.3.21", + "@vaadin/vaadin-material-styles": "~24.3.21", + "@vaadin/vaadin-themable-mixin": "~24.3.21" } }, "node_modules/@vaadin/icon": { - "version": "24.3.18", + "version": "24.3.21", "license": "Apache-2.0", "peer": true, "dependencies": { "@open-wc/dedupe-mixin": "^1.3.0", "@polymer/polymer": "^3.0.0", - "@vaadin/component-base": "~24.3.18", - "@vaadin/vaadin-lumo-styles": "~24.3.18", - "@vaadin/vaadin-themable-mixin": "~24.3.18", + "@vaadin/component-base": "~24.3.21", + "@vaadin/vaadin-lumo-styles": "~24.3.21", + "@vaadin/vaadin-themable-mixin": "~24.3.21", "lit": "^3.0.0" } }, "node_modules/@vaadin/input-container": { - "version": "24.3.18", + "version": "24.3.21", "license": "Apache-2.0", "peer": true, "dependencies": { "@polymer/polymer": "^3.0.0", - "@vaadin/component-base": "~24.3.18", - "@vaadin/vaadin-lumo-styles": "~24.3.18", - "@vaadin/vaadin-material-styles": "~24.3.18", - "@vaadin/vaadin-themable-mixin": "~24.3.18", + "@vaadin/component-base": "~24.3.21", + "@vaadin/vaadin-lumo-styles": "~24.3.21", + "@vaadin/vaadin-material-styles": "~24.3.21", + "@vaadin/vaadin-themable-mixin": "~24.3.21", "lit": "^3.0.0" } }, "node_modules/@vaadin/lit-renderer": { - "version": "24.3.18", + "version": "24.3.21", "license": "Apache-2.0", "peer": true, "dependencies": { @@ -9131,19 +9175,19 @@ } }, "node_modules/@vaadin/text-field": { - "version": "24.3.18", + "version": "24.3.21", "license": "Apache-2.0", "peer": true, "dependencies": { "@open-wc/dedupe-mixin": "^1.3.0", "@polymer/polymer": "^3.0.0", - "@vaadin/a11y-base": "~24.3.18", - "@vaadin/component-base": "~24.3.18", - "@vaadin/field-base": "~24.3.18", - "@vaadin/input-container": "~24.3.18", - "@vaadin/vaadin-lumo-styles": "~24.3.18", - "@vaadin/vaadin-material-styles": "~24.3.18", - "@vaadin/vaadin-themable-mixin": "~24.3.18", + "@vaadin/a11y-base": "~24.3.21", + "@vaadin/component-base": "~24.3.21", + "@vaadin/field-base": "~24.3.21", + "@vaadin/input-container": "~24.3.21", + "@vaadin/vaadin-lumo-styles": "~24.3.21", + "@vaadin/vaadin-material-styles": "~24.3.21", + "@vaadin/vaadin-themable-mixin": "~24.3.21", "lit": "^3.0.0" } }, @@ -9153,28 +9197,28 @@ "peer": true }, "node_modules/@vaadin/vaadin-lumo-styles": { - "version": "24.3.18", + "version": "24.3.21", "license": "Apache-2.0", "peer": true, "dependencies": { "@polymer/polymer": "^3.0.0", - "@vaadin/component-base": "~24.3.18", - "@vaadin/icon": "~24.3.18", - "@vaadin/vaadin-themable-mixin": "~24.3.18" + "@vaadin/component-base": "~24.3.21", + "@vaadin/icon": "~24.3.21", + "@vaadin/vaadin-themable-mixin": "~24.3.21" } }, "node_modules/@vaadin/vaadin-material-styles": { - "version": "24.3.18", + "version": "24.3.21", "license": "Apache-2.0", "peer": true, "dependencies": { "@polymer/polymer": "^3.0.0", - "@vaadin/component-base": "~24.3.18", - "@vaadin/vaadin-themable-mixin": "~24.3.18" + "@vaadin/component-base": "~24.3.21", + "@vaadin/vaadin-themable-mixin": "~24.3.21" } }, "node_modules/@vaadin/vaadin-themable-mixin": { - "version": "24.3.18", + "version": "24.3.21", "license": "Apache-2.0", "peer": true, "dependencies": { @@ -9183,7 +9227,7 @@ } }, "node_modules/@vaadin/vaadin-usage-statistics": { - "version": "2.1.2", + "version": "2.1.3", "hasInstallScript": true, "license": "Apache-2.0", "peer": true, @@ -9260,7 +9304,7 @@ "license": "BSD-3-Clause" }, "node_modules/@zip.js/zip.js": { - "version": "2.7.47", + "version": "2.7.52", "license": "BSD-3-Clause", "peer": true, "engines": { @@ -9722,7 +9766,7 @@ "license": "MIT" }, "node_modules/async": { - "version": "3.2.5", + "version": "3.2.6", "dev": true, "license": "MIT" }, @@ -9760,7 +9804,7 @@ } }, "node_modules/axe-core": { - "version": "4.9.1", + "version": "4.10.0", "dev": true, "license": "MPL-2.0", "engines": { @@ -9768,7 +9812,7 @@ } }, "node_modules/axios": { - "version": "1.7.2", + "version": "1.7.7", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -9942,12 +9986,12 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.4", + "version": "0.10.6", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.1", - "core-js-compat": "^3.36.1" + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -9970,22 +10014,25 @@ "license": "MIT" }, "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", + "version": "1.1.0", "dev": true, "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0" @@ -10115,6 +10162,19 @@ "readable-stream": "^3.4.0" } }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/body-parser": { "version": "1.20.2", "license": "MIT", @@ -10151,6 +10211,16 @@ "ms": "2.0.0" } }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "license": "MIT" @@ -10184,7 +10254,7 @@ } }, "node_modules/browserslist": { - "version": "4.23.2", + "version": "4.23.3", "dev": true, "funding": [ { @@ -10202,9 +10272,9 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001640", - "electron-to-chromium": "^1.4.820", - "node-releases": "^2.0.14", + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", "update-browserslist-db": "^1.1.0" }, "bin": { @@ -10431,7 +10501,7 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001643", + "version": "1.0.30001655", "dev": true, "funding": [ { @@ -10533,7 +10603,7 @@ } }, "node_modules/cjs-module-lexer": { - "version": "1.3.1", + "version": "1.4.0", "license": "MIT" }, "node_modules/clean-stack": { @@ -10783,11 +10853,11 @@ } }, "node_modules/commitlint": { - "version": "19.3.0", + "version": "19.4.1", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/cli": "^19.3.0", + "@commitlint/cli": "^19.4.1", "@commitlint/types": "^19.0.3" }, "bin": { @@ -10820,9 +10890,12 @@ } }, "node_modules/composed-offset-position": { - "version": "0.0.4", + "version": "0.0.6", "license": "MIT", - "peer": true + "peer": true, + "peerDependencies": { + "@floating-ui/utils": "^0.2.5" + } }, "node_modules/compressible": { "version": "2.0.18", @@ -10880,6 +10953,19 @@ "typedarray": "^0.0.6" } }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/config": { "version": "3.3.12", "license": "MIT", @@ -11264,6 +11350,19 @@ "node": ">=8" } }, + "node_modules/conventional-changelog-core/node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/conventional-changelog-core/node_modules/split2": { "version": "3.2.2", "dev": true, @@ -11962,6 +12061,19 @@ "node": ">=8" } }, + "node_modules/conventional-changelog/node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/conventional-changelog/node_modules/split2": { "version": "3.2.2", "dev": true, @@ -12302,10 +12414,23 @@ "node": ">=8" } }, - "node_modules/conventional-recommended-bump/node_modules/split2": { - "version": "3.2.2", + "node_modules/conventional-recommended-bump/node_modules/readable-stream": { + "version": "3.6.2", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/conventional-recommended-bump/node_modules/split2": { + "version": "3.2.2", + "dev": true, + "license": "ISC", "dependencies": { "readable-stream": "^3.0.0" } @@ -12343,8 +12468,7 @@ } }, "node_modules/convert-source-map": { - "version": "2.0.0", - "dev": true, + "version": "1.9.0", "license": "MIT" }, "node_modules/cookie": { @@ -12435,11 +12559,11 @@ } }, "node_modules/core-js-compat": { - "version": "3.37.1", + "version": "3.38.1", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.23.0" + "browserslist": "^4.23.3" }, "funding": { "type": "opencollective", @@ -12831,16 +12955,6 @@ "node": ">=12" } }, - "node_modules/d3-dsv/node_modules/iconv-lite": { - "version": "0.6.3", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/d3-ease": { "version": "3.0.1", "license": "BSD-3-Clause", @@ -13109,7 +13223,7 @@ } }, "node_modules/dayjs": { - "version": "1.11.11", + "version": "1.11.12", "license": "MIT", "peer": true }, @@ -13160,22 +13274,22 @@ } }, "node_modules/deck.gl": { - "version": "9.0.24", - "license": "MIT", - "dependencies": { - "@deck.gl/aggregation-layers": "9.0.24", - "@deck.gl/arcgis": "9.0.24", - "@deck.gl/carto": "9.0.24", - "@deck.gl/core": "9.0.24", - "@deck.gl/extensions": "9.0.24", - "@deck.gl/geo-layers": "9.0.24", - "@deck.gl/google-maps": "9.0.24", - "@deck.gl/json": "9.0.24", - "@deck.gl/layers": "9.0.24", - "@deck.gl/mapbox": "9.0.24", - "@deck.gl/mesh-layers": "9.0.24", - "@deck.gl/react": "9.0.24", - "@deck.gl/widgets": "9.0.24", + "version": "9.0.28", + "license": "MIT", + "dependencies": { + "@deck.gl/aggregation-layers": "9.0.28", + "@deck.gl/arcgis": "9.0.28", + "@deck.gl/carto": "9.0.28", + "@deck.gl/core": "9.0.28", + "@deck.gl/extensions": "9.0.28", + "@deck.gl/geo-layers": "9.0.28", + "@deck.gl/google-maps": "9.0.28", + "@deck.gl/json": "9.0.28", + "@deck.gl/layers": "9.0.28", + "@deck.gl/mapbox": "9.0.28", + "@deck.gl/mesh-layers": "9.0.28", + "@deck.gl/react": "9.0.28", + "@deck.gl/widgets": "9.0.28", "@loaders.gl/core": "^4.2.0", "@luma.gl/core": "^9.0.15", "@luma.gl/engine": "^9.0.15" @@ -13568,7 +13682,7 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.2", + "version": "1.5.13", "dev": true, "license": "ISC" }, @@ -13603,17 +13717,6 @@ "iconv-lite": "^0.6.2" } }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "license": "MIT", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/end-of-stream": { "version": "1.4.4", "license": "MIT", @@ -13875,7 +13978,7 @@ } }, "node_modules/escalade": { - "version": "3.1.2", + "version": "3.2.0", "license": "MIT", "engines": { "node": ">=6" @@ -14229,7 +14332,7 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.1", + "version": "2.8.2", "dev": true, "license": "MIT", "dependencies": { @@ -14797,6 +14900,20 @@ "node": ">=10.13.0" } }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", "dev": true, @@ -14838,6 +14955,17 @@ "node": ">=8" } }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/espree": { "version": "9.6.1", "dev": true, @@ -15048,12 +15176,12 @@ } }, "node_modules/express-openapi-validator": { - "version": "5.2.0", + "version": "5.3.4", "license": "MIT", "dependencies": { - "@apidevtools/json-schema-ref-parser": "^11.6.2", + "@apidevtools/json-schema-ref-parser": "^11.7.0", "@types/multer": "^1.4.11", - "ajv": "^8.14.0", + "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", "ajv-formats": "^2.1.1", "content-type": "^1.0.5", @@ -15150,6 +15278,17 @@ "node": ">=4" } }, + "node_modules/external-editor/node_modules/iconv-lite": { + "version": "0.4.24", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fast-copy": { "version": "3.0.2", "license": "MIT" @@ -15454,7 +15593,7 @@ } }, "node_modules/foreground-child": { - "version": "3.2.1", + "version": "3.3.0", "dev": true, "license": "ISC", "dependencies": { @@ -15609,14 +15748,14 @@ } }, "node_modules/gaxios": { - "version": "6.7.0", + "version": "6.7.1", "license": "Apache-2.0", "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", "node-fetch": "^2.6.9", - "uuid": "^10.0.0" + "uuid": "^9.0.1" }, "engines": { "node": ">=14" @@ -16207,7 +16346,7 @@ "node": ">=0.10.0" } }, - "node_modules/global-prefix": { + "node_modules/global-modules/node_modules/global-prefix": { "version": "1.0.2", "dev": true, "license": "MIT", @@ -16222,12 +16361,12 @@ "node": ">=0.10.0" } }, - "node_modules/global-prefix/node_modules/ini": { + "node_modules/global-modules/node_modules/ini": { "version": "1.3.8", "dev": true, "license": "ISC" }, - "node_modules/global-prefix/node_modules/which": { + "node_modules/global-modules/node_modules/which": { "version": "1.3.1", "dev": true, "license": "ISC", @@ -16238,29 +16377,37 @@ "which": "bin/which" } }, - "node_modules/globals": { - "version": "13.24.0", - "dev": true, + "node_modules/global-prefix": { + "version": "3.0.0", "license": "MIT", "dependencies": { - "type-fest": "^0.20.2" + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" }, "engines": { - "node": ">=8" + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/ini": { + "version": "1.3.8", + "license": "ISC" + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "bin": { + "which": "bin/which" } }, - "node_modules/globals/node_modules/type-fest": { - "version": "0.20.2", - "dev": true, - "license": "(MIT OR CC0-1.0)", + "node_modules/globals": { + "version": "11.12.0", + "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, "node_modules/globalthis": { @@ -16360,6 +16507,14 @@ "uglify-js": "^3.1.4" } }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/hard-rejection": { "version": "2.1.0", "dev": true, @@ -16567,10 +16722,10 @@ } }, "node_modules/iconv-lite": { - "version": "0.4.24", + "version": "0.6.3", "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" @@ -16595,7 +16750,7 @@ "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "5.3.1", + "version": "5.3.2", "dev": true, "license": "MIT", "engines": { @@ -16815,6 +16970,14 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/interactjs": { + "version": "1.10.27", + "license": "MIT", + "peer": true, + "dependencies": { + "@interactjs/types": "1.10.27" + } + }, "node_modules/internal-slot": { "version": "1.0.7", "dev": true, @@ -16966,7 +17129,7 @@ } }, "node_modules/is-core-module": { - "version": "2.15.0", + "version": "2.15.1", "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -17438,6 +17601,14 @@ "node": ">=10" } }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/istanbul-reports": { "version": "3.1.7", "dev": true, @@ -18911,30 +19082,6 @@ "setimmediate": "^1.0.5" } }, - "node_modules/jszip/node_modules/isarray": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/just-diff": { "version": "6.0.2", "dev": true, @@ -18993,12 +19140,12 @@ } }, "node_modules/lerna": { - "version": "8.1.7", + "version": "8.1.8", "dev": true, "license": "MIT", "dependencies": { - "@lerna/create": "8.1.7", - "@npmcli/arborist": "7.5.3", + "@lerna/create": "8.1.8", + "@npmcli/arborist": "7.5.4", "@npmcli/package-json": "5.2.0", "@npmcli/run-script": "8.1.0", "@nx/devkit": ">=17.1.2 < 20", @@ -19389,6 +19536,18 @@ "node": ">=6" } }, + "node_modules/lerna/node_modules/uuid": { + "version": "10.0.0", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/lerna/node_modules/write-file-atomic": { "version": "5.0.1", "dev": true, @@ -19492,27 +19651,27 @@ } }, "node_modules/lit": { - "version": "3.1.4", + "version": "3.2.0", "license": "BSD-3-Clause", "peer": true, "dependencies": { "@lit/reactive-element": "^2.0.4", - "lit-element": "^4.0.4", - "lit-html": "^3.1.2" + "lit-element": "^4.1.0", + "lit-html": "^3.2.0" } }, "node_modules/lit-element": { - "version": "4.0.6", + "version": "4.1.0", "license": "BSD-3-Clause", "peer": true, "dependencies": { "@lit-labs/ssr-dom-shim": "^1.2.0", "@lit/reactive-element": "^2.0.4", - "lit-html": "^3.1.2" + "lit-html": "^3.2.0" } }, "node_modules/lit-html": { - "version": "3.1.4", + "version": "3.2.0", "license": "BSD-3-Clause", "peer": true, "dependencies": { @@ -19827,32 +19986,6 @@ "vt-pbf": "^3.1.3" } }, - "node_modules/maplibre-gl/node_modules/global-prefix": { - "version": "3.0.0", - "license": "MIT", - "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/maplibre-gl/node_modules/ini": { - "version": "1.3.8", - "license": "ISC" - }, - "node_modules/maplibre-gl/node_modules/which": { - "version": "1.3.1", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, "node_modules/marked": { "version": "12.0.2", "license": "MIT", @@ -19921,7 +20054,7 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", + "version": "4.0.8", "dev": true, "license": "MIT", "dependencies": { @@ -20261,10 +20394,6 @@ "typedarray": "^0.0.6" } }, - "node_modules/multer/node_modules/isarray": { - "version": "1.0.0", - "license": "MIT" - }, "node_modules/multer/node_modules/mkdirp": { "version": "0.5.6", "license": "MIT", @@ -20275,26 +20404,6 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/multer/node_modules/readable-stream": { - "version": "2.3.8", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/multer/node_modules/string_decoder": { - "version": "1.1.1", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/multimatch": { "version": "5.0.0", "dev": true, @@ -20366,7 +20475,7 @@ "license": "MIT" }, "node_modules/nock": { - "version": "13.5.4", + "version": "13.5.5", "dev": true, "license": "MIT", "dependencies": { @@ -20702,17 +20811,17 @@ } }, "node_modules/nx": { - "version": "19.5.3", + "version": "19.6.4", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { "@napi-rs/wasm-runtime": "0.2.4", - "@nrwl/tao": "19.5.3", + "@nrwl/tao": "19.6.4", "@yarnpkg/lockfile": "^1.1.0", "@yarnpkg/parsers": "3.0.0-rc.46", "@zkochan/js-yaml": "0.0.7", - "axios": "^1.6.0", + "axios": "^1.7.4", "chalk": "^4.1.0", "cli-cursor": "3.1.0", "cli-spinners": "2.6.1", @@ -20748,16 +20857,16 @@ "nx-cloud": "bin/nx-cloud.js" }, "optionalDependencies": { - "@nx/nx-darwin-arm64": "19.5.3", - "@nx/nx-darwin-x64": "19.5.3", - "@nx/nx-freebsd-x64": "19.5.3", - "@nx/nx-linux-arm-gnueabihf": "19.5.3", - "@nx/nx-linux-arm64-gnu": "19.5.3", - "@nx/nx-linux-arm64-musl": "19.5.3", - "@nx/nx-linux-x64-gnu": "19.5.3", - "@nx/nx-linux-x64-musl": "19.5.3", - "@nx/nx-win32-arm64-msvc": "19.5.3", - "@nx/nx-win32-x64-msvc": "19.5.3" + "@nx/nx-darwin-arm64": "19.6.4", + "@nx/nx-darwin-x64": "19.6.4", + "@nx/nx-freebsd-x64": "19.6.4", + "@nx/nx-linux-arm-gnueabihf": "19.6.4", + "@nx/nx-linux-arm64-gnu": "19.6.4", + "@nx/nx-linux-arm64-musl": "19.6.4", + "@nx/nx-linux-x64-gnu": "19.6.4", + "@nx/nx-linux-x64-musl": "19.6.4", + "@nx/nx-win32-arm64-msvc": "19.6.4", + "@nx/nx-win32-x64-msvc": "19.6.4" }, "peerDependencies": { "@swc-node/register": "^1.8.0", @@ -21324,6 +21433,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-queue/node_modules/p-timeout": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/p-reduce": { "version": "2.1.0", "dev": true, @@ -21333,14 +21453,13 @@ } }, "node_modules/p-timeout": { - "version": "3.2.0", - "dev": true, + "version": "6.1.2", "license": "MIT", - "dependencies": { - "p-finally": "^1.0.0" - }, "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-try": { @@ -21681,20 +21800,45 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/pino-http": { - "version": "8.6.1", - "license": "MIT", - "dependencies": { - "get-caller-file": "^2.0.5", - "pino": "^8.17.1", - "pino-std-serializers": "^6.2.2", - "process-warning": "^3.0.0" - } - }, - "node_modules/pino-pretty": { - "version": "10.3.1", - "license": "MIT", - "dependencies": { + "node_modules/pino-abstract-transport/node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/pino-abstract-transport/node_modules/string_decoder": { + "version": "1.3.0", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/pino-http": { + "version": "8.6.1", + "license": "MIT", + "dependencies": { + "get-caller-file": "^2.0.5", + "pino": "^8.17.1", + "pino-std-serializers": "^6.2.2", + "process-warning": "^3.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "10.3.1", + "license": "MIT", + "dependencies": { "colorette": "^2.0.7", "dateformat": "^4.6.3", "fast-copy": "^3.0.0", @@ -21761,6 +21905,31 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/pino-pretty/node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/pino-pretty/node_modules/string_decoder": { + "version": "1.3.0", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/pino-std-serializers": { "version": "6.2.2", "license": "MIT" @@ -21897,7 +22066,7 @@ } }, "node_modules/postcss": { - "version": "8.4.40", + "version": "8.4.44", "dev": true, "funding": [ { @@ -21924,7 +22093,7 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.1.1", + "version": "6.1.2", "dev": true, "license": "MIT", "dependencies": { @@ -21971,7 +22140,7 @@ "license": "ISC" }, "node_modules/preact": { - "version": "10.23.1", + "version": "10.23.2", "license": "MIT", "funding": { "type": "opencollective", @@ -22324,7 +22493,7 @@ } }, "node_modules/protobufjs": { - "version": "7.3.2", + "version": "7.4.0", "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { @@ -22502,6 +22671,16 @@ "node": ">= 0.8" } }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react": { "version": "18.3.1", "license": "MIT", @@ -22785,18 +22964,22 @@ } }, "node_modules/readable-stream": { - "version": "3.6.2", - "dev": true, + "version": "2.3.8", "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, + "node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "license": "MIT" + }, "node_modules/readdirp": { "version": "3.6.0", "dev": true, @@ -22828,18 +23011,18 @@ } }, "node_modules/redis": { - "version": "4.6.15", + "version": "4.7.0", "license": "MIT", "workspaces": [ "./packages/*" ], "dependencies": { "@redis/bloom": "1.2.0", - "@redis/client": "1.5.17", + "@redis/client": "1.6.0", "@redis/graph": "1.1.1", - "@redis/json": "1.0.6", - "@redis/search": "1.1.6", - "@redis/time-series": "1.0.5" + "@redis/json": "1.0.7", + "@redis/search": "1.2.0", + "@redis/time-series": "1.1.0" } }, "node_modules/reflect-metadata": { @@ -23100,7 +23283,7 @@ } }, "node_modules/rimraf": { - "version": "5.0.9", + "version": "5.0.10", "dev": true, "license": "ISC", "dependencies": { @@ -23109,9 +23292,6 @@ "bin": { "rimraf": "dist/esm/bin.mjs" }, - "engines": { - "node": "14 >=14.20 || 16 >=16.20 || >=18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -23162,7 +23342,7 @@ "license": "Unlicense" }, "node_modules/rollup": { - "version": "4.19.1", + "version": "4.21.2", "dev": true, "license": "MIT", "dependencies": { @@ -23176,22 +23356,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.19.1", - "@rollup/rollup-android-arm64": "4.19.1", - "@rollup/rollup-darwin-arm64": "4.19.1", - "@rollup/rollup-darwin-x64": "4.19.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.19.1", - "@rollup/rollup-linux-arm-musleabihf": "4.19.1", - "@rollup/rollup-linux-arm64-gnu": "4.19.1", - "@rollup/rollup-linux-arm64-musl": "4.19.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.19.1", - "@rollup/rollup-linux-riscv64-gnu": "4.19.1", - "@rollup/rollup-linux-s390x-gnu": "4.19.1", - "@rollup/rollup-linux-x64-gnu": "4.19.1", - "@rollup/rollup-linux-x64-musl": "4.19.1", - "@rollup/rollup-win32-arm64-msvc": "4.19.1", - "@rollup/rollup-win32-ia32-msvc": "4.19.1", - "@rollup/rollup-win32-x64-msvc": "4.19.1", + "@rollup/rollup-android-arm-eabi": "4.21.2", + "@rollup/rollup-android-arm64": "4.21.2", + "@rollup/rollup-darwin-arm64": "4.21.2", + "@rollup/rollup-darwin-x64": "4.21.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.21.2", + "@rollup/rollup-linux-arm-musleabihf": "4.21.2", + "@rollup/rollup-linux-arm64-gnu": "4.21.2", + "@rollup/rollup-linux-arm64-musl": "4.21.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.21.2", + "@rollup/rollup-linux-riscv64-gnu": "4.21.2", + "@rollup/rollup-linux-s390x-gnu": "4.21.2", + "@rollup/rollup-linux-x64-gnu": "4.21.2", + "@rollup/rollup-linux-x64-musl": "4.21.2", + "@rollup/rollup-win32-arm64-msvc": "4.21.2", + "@rollup/rollup-win32-ia32-msvc": "4.21.2", + "@rollup/rollup-win32-x64-msvc": "4.21.2", "fsevents": "~2.3.2" } }, @@ -23275,7 +23455,7 @@ } }, "node_modules/safe-stable-stringify": { - "version": "2.4.3", + "version": "2.5.0", "license": "MIT", "engines": { "node": ">=10" @@ -23549,6 +23729,19 @@ "ws": "^7.4.2" } }, + "node_modules/simple-websocket/node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/sisteransi": { "version": "1.0.5", "dev": true, @@ -23649,13 +23842,12 @@ } }, "node_modules/sortablejs": { - "version": "1.15.2", + "version": "1.15.3", "license": "MIT", "peer": true }, "node_modules/source-map": { - "version": "0.6.1", - "dev": true, + "version": "0.5.7", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -23678,6 +23870,14 @@ "source-map": "^0.6.0" } }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/spdx-correct": { "version": "3.2.0", "dev": true, @@ -23702,7 +23902,7 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.18", + "version": "3.0.20", "dev": true, "license": "CC0-1.0" }, @@ -24252,6 +24452,19 @@ "node": ">=8" } }, + "node_modules/standard-version/node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/standard-version/node_modules/split2": { "version": "3.2.2", "dev": true, @@ -24361,30 +24574,12 @@ } }, "node_modules/string_decoder": { - "version": "1.3.0", + "version": "1.1.1", "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "safe-buffer": "~5.1.0" } }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/string-length": { "version": "4.0.2", "dev": true, @@ -24741,6 +24936,19 @@ "node": ">=6" } }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/tar/node_modules/fs-minipass": { "version": "2.1.0", "dev": true, @@ -24863,42 +25071,16 @@ "xtend": "~4.0.1" } }, - "node_modules/through2/node_modules/isarray": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/through2/node_modules/readable-stream": { - "version": "2.3.8", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/through2/node_modules/string_decoder": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/tilebelt": { "version": "1.0.1", "license": "MIT" }, "node_modules/timezone-groups": { - "version": "0.8.0", + "version": "0.9.1", + "license": "MIT", "peer": true, - "bin": { - "timezone-groups": "dist/cli.cjs" + "engines": { + "node": ">=18.12.0" } }, "node_modules/tiny-typed-emitter": { @@ -24986,19 +25168,19 @@ } }, "node_modules/ts-jest": { - "version": "29.2.3", + "version": "29.2.5", "dev": true, "license": "MIT", "dependencies": { - "bs-logger": "0.x", + "bs-logger": "^0.2.6", "ejs": "^3.1.10", - "fast-json-stable-stringify": "2.x", + "fast-json-stable-stringify": "^2.1.0", "jest-util": "^29.0.0", "json5": "^2.2.3", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "^7.5.3", - "yargs-parser": "^21.0.1" + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.6.3", + "yargs-parser": "^21.1.1" }, "bin": { "ts-jest": "cli.js" @@ -25105,7 +25287,7 @@ } }, "node_modules/tslib": { - "version": "2.6.3", + "version": "2.7.0", "dev": true, "license": "0BSD" }, @@ -25304,7 +25486,7 @@ "license": "MIT" }, "node_modules/uglify-js": { - "version": "3.19.1", + "version": "3.19.3", "dev": true, "license": "BSD-2-Clause", "optional": true, @@ -25330,7 +25512,7 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", + "version": "6.19.8", "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -25508,7 +25690,7 @@ } }, "node_modules/uuid": { - "version": "10.0.0", + "version": "9.0.1", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" @@ -25536,6 +25718,11 @@ "node": ">=10.12.0" } }, + "node_modules/v8-to-istanbul/node_modules/convert-source-map": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "dev": true, @@ -25561,13 +25748,13 @@ } }, "node_modules/vite": { - "version": "5.3.5", + "version": "5.4.2", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.21.3", - "postcss": "^8.4.39", - "rollup": "^4.13.0" + "postcss": "^8.4.41", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" @@ -25586,6 +25773,7 @@ "less": "*", "lightningcss": "^1.21.0", "sass": "*", + "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" @@ -25603,6 +25791,9 @@ "sass": { "optional": true }, + "sass-embedded": { + "optional": true + }, "stylus": { "optional": true }, @@ -25724,7 +25915,7 @@ "license": "MIT" }, "node_modules/wgsl_reflect": { - "version": "1.0.8", + "version": "1.0.10", "license": "MIT" }, "node_modules/whatwg-url": { @@ -25765,12 +25956,12 @@ } }, "node_modules/which-builtin-type": { - "version": "1.1.3", + "version": "1.1.4", "dev": true, "license": "MIT", "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.0.5", "is-finalizationregistry": "^1.0.2", @@ -25779,8 +25970,8 @@ "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" @@ -26138,7 +26329,7 @@ "dependencies": { "@godaddy/terminus": "^4.12.1", "@map-colonies/cleanup-registry": "^1.1.0", - "@map-colonies/detiler-common": "^1.0.0", + "@map-colonies/detiler-common": "^1.1.0-rc1", "@map-colonies/error-express-handler": "^2.1.0", "@map-colonies/express-access-log-middleware": "^2.0.1", "@map-colonies/js-logger": "^1.0.1", @@ -26197,9 +26388,8 @@ }, "packages/backend/node_modules/@commitlint/cli": { "version": "18.6.1", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-18.6.1.tgz", - "integrity": "sha512-5IDE0a+lWGdkOvKH892HHAZgbAjcj1mT5QrfA/SVbLJV/BbBMGyKN0W5mhgjekPJJwEQdVNvhl9PwUacY58Usw==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/format": "^18.6.1", "@commitlint/lint": "^18.6.1", @@ -26221,9 +26411,8 @@ }, "packages/backend/node_modules/@commitlint/config-conventional": { "version": "18.6.3", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-18.6.3.tgz", - "integrity": "sha512-8ZrRHqF6je+TRaFoJVwszwnOXb/VeYrPmTwPhf0WxpzpGTcYy1p0SPyZ2eRn/sRi/obnWAcobtDAq6+gJQQNhQ==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/types": "^18.6.1", "conventional-changelog-conventionalcommits": "^7.0.2" @@ -26234,9 +26423,8 @@ }, "packages/backend/node_modules/@commitlint/config-validator": { "version": "18.6.1", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-18.6.1.tgz", - "integrity": "sha512-05uiToBVfPhepcQWE1ZQBR/Io3+tb3gEotZjnI4tTzzPk16NffN6YABgwFQCLmzZefbDcmwWqJWc2XT47q7Znw==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/types": "^18.6.1", "ajv": "^8.11.0" @@ -26247,9 +26435,8 @@ }, "packages/backend/node_modules/@commitlint/ensure": { "version": "18.6.1", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-18.6.1.tgz", - "integrity": "sha512-BPm6+SspyxQ7ZTsZwXc7TRQL5kh5YWt3euKmEIBZnocMFkJevqs3fbLRb8+8I/cfbVcAo4mxRlpTPfz8zX7SnQ==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/types": "^18.6.1", "lodash.camelcase": "^4.3.0", @@ -26264,18 +26451,16 @@ }, "packages/backend/node_modules/@commitlint/execute-rule": { "version": "18.6.1", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-18.6.1.tgz", - "integrity": "sha512-7s37a+iWyJiGUeMFF6qBlyZciUkF8odSAnHijbD36YDctLhGKoYltdvuJ/AFfRm6cBLRtRk9cCVPdsEFtt/2rg==", "dev": true, + "license": "MIT", "engines": { "node": ">=v18" } }, "packages/backend/node_modules/@commitlint/format": { "version": "18.6.1", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-18.6.1.tgz", - "integrity": "sha512-K8mNcfU/JEFCharj2xVjxGSF+My+FbUHoqR+4GqPGrHNqXOGNio47ziiR4HQUPKtiNs05o8/WyLBoIpMVOP7wg==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/types": "^18.6.1", "chalk": "^4.1.0" @@ -26286,9 +26471,8 @@ }, "packages/backend/node_modules/@commitlint/is-ignored": { "version": "18.6.1", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-18.6.1.tgz", - "integrity": "sha512-MOfJjkEJj/wOaPBw5jFjTtfnx72RGwqYIROABudOtJKW7isVjFe9j0t8xhceA02QebtYf4P/zea4HIwnXg8rvA==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/types": "^18.6.1", "semver": "7.6.0" @@ -26299,9 +26483,8 @@ }, "packages/backend/node_modules/@commitlint/lint": { "version": "18.6.1", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-18.6.1.tgz", - "integrity": "sha512-8WwIFo3jAuU+h1PkYe5SfnIOzp+TtBHpFr4S8oJWhu44IWKuVx6GOPux3+9H1iHOan/rGBaiacicZkMZuluhfQ==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/is-ignored": "^18.6.1", "@commitlint/parse": "^18.6.1", @@ -26314,9 +26497,8 @@ }, "packages/backend/node_modules/@commitlint/load": { "version": "18.6.1", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-18.6.1.tgz", - "integrity": "sha512-p26x8734tSXUHoAw0ERIiHyW4RaI4Bj99D8YgUlVV9SedLf8hlWAfyIFhHRIhfPngLlCe0QYOdRKYFt8gy56TA==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/config-validator": "^18.6.1", "@commitlint/execute-rule": "^18.6.1", @@ -26336,18 +26518,16 @@ }, "packages/backend/node_modules/@commitlint/message": { "version": "18.6.1", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-18.6.1.tgz", - "integrity": "sha512-VKC10UTMLcpVjMIaHHsY1KwhuTQtdIKPkIdVEwWV+YuzKkzhlI3aNy6oo1eAN6b/D2LTtZkJe2enHmX0corYRw==", "dev": true, + "license": "MIT", "engines": { "node": ">=v18" } }, "packages/backend/node_modules/@commitlint/parse": { "version": "18.6.1", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-18.6.1.tgz", - "integrity": "sha512-eS/3GREtvVJqGZrwAGRwR9Gdno3YcZ6Xvuaa+vUF8j++wsmxrA2En3n0ccfVO2qVOLJC41ni7jSZhQiJpMPGOQ==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/types": "^18.6.1", "conventional-changelog-angular": "^7.0.0", @@ -26359,9 +26539,8 @@ }, "packages/backend/node_modules/@commitlint/read": { "version": "18.6.1", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-18.6.1.tgz", - "integrity": "sha512-ia6ODaQFzXrVul07ffSgbZGFajpe8xhnDeLIprLeyfz3ivQU1dIoHp7yz0QIorZ6yuf4nlzg4ZUkluDrGN/J/w==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/top-level": "^18.6.1", "@commitlint/types": "^18.6.1", @@ -26374,9 +26553,8 @@ }, "packages/backend/node_modules/@commitlint/resolve-extends": { "version": "18.6.1", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-18.6.1.tgz", - "integrity": "sha512-ifRAQtHwK+Gj3Bxj/5chhc4L2LIc3s30lpsyW67yyjsETR6ctHAHRu1FSpt0KqahK5xESqoJ92v6XxoDRtjwEQ==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/config-validator": "^18.6.1", "@commitlint/types": "^18.6.1", @@ -26391,9 +26569,8 @@ }, "packages/backend/node_modules/@commitlint/rules": { "version": "18.6.1", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-18.6.1.tgz", - "integrity": "sha512-kguM6HxZDtz60v/zQYOe0voAtTdGybWXefA1iidjWYmyUUspO1zBPQEmJZ05/plIAqCVyNUTAiRPWIBKLCrGew==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/ensure": "^18.6.1", "@commitlint/message": "^18.6.1", @@ -26407,18 +26584,16 @@ }, "packages/backend/node_modules/@commitlint/to-lines": { "version": "18.6.1", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-18.6.1.tgz", - "integrity": "sha512-Gl+orGBxYSNphx1+83GYeNy5N0dQsHBQ9PJMriaLQDB51UQHCVLBT/HBdOx5VaYksivSf5Os55TLePbRLlW50Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=v18" } }, "packages/backend/node_modules/@commitlint/top-level": { "version": "18.6.1", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-18.6.1.tgz", - "integrity": "sha512-HyiHQZUTf0+r0goTCDs/bbVv/LiiQ7AVtz6KIar+8ZrseB9+YJAIo8HQ2IC2QT1y3N1lbW6OqVEsTHjbT6hGSw==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^5.0.0" }, @@ -26428,9 +26603,8 @@ }, "packages/backend/node_modules/@commitlint/types": { "version": "18.6.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-18.6.1.tgz", - "integrity": "sha512-gwRLBLra/Dozj2OywopeuHj2ac26gjGkz2cZ+86cTJOdtWfiRRr4+e77ZDAGc6MDWxaWheI+mAV5TLWWRwqrFg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0" }, @@ -26440,15 +26614,13 @@ }, "packages/backend/node_modules/@types/node": { "version": "20.5.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz", - "integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==", - "dev": true + "dev": true, + "license": "MIT" }, "packages/backend/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -26461,9 +26633,8 @@ }, "packages/backend/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -26477,9 +26648,8 @@ }, "packages/backend/node_modules/commitlint": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/commitlint/-/commitlint-17.8.1.tgz", - "integrity": "sha512-X+VPJwZsQDeGj/DG1NsxhZEl+oMHKNC+1myZ/zauNDoo+7OuLHfTOUU1C1a4CjKW4b6T7NuoFcYfK0kRCjCtbA==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/cli": "^17.8.1", "@commitlint/types": "^17.8.1" @@ -26493,9 +26663,8 @@ }, "packages/backend/node_modules/commitlint/node_modules/@commitlint/cli": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-17.8.1.tgz", - "integrity": "sha512-ay+WbzQesE0Rv4EQKfNbSMiJJ12KdKTDzIt0tcK4k11FdsWmtwP0Kp1NWMOUswfIWo6Eb7p7Ln721Nx9FLNBjg==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/format": "^17.8.1", "@commitlint/lint": "^17.8.1", @@ -26517,9 +26686,8 @@ }, "packages/backend/node_modules/commitlint/node_modules/@commitlint/config-validator": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-17.8.1.tgz", - "integrity": "sha512-UUgUC+sNiiMwkyiuIFR7JG2cfd9t/7MV8VB4TZ+q02ZFkHoduUS4tJGsCBWvBOGD9Btev6IecPMvlWUfJorkEA==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/types": "^17.8.1", "ajv": "^8.11.0" @@ -26530,9 +26698,8 @@ }, "packages/backend/node_modules/commitlint/node_modules/@commitlint/ensure": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-17.8.1.tgz", - "integrity": "sha512-xjafwKxid8s1K23NFpL8JNo6JnY/ysetKo8kegVM7c8vs+kWLP8VrQq+NbhgVlmCojhEDbzQKp4eRXSjVOGsow==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/types": "^17.8.1", "lodash.camelcase": "^4.3.0", @@ -26547,18 +26714,16 @@ }, "packages/backend/node_modules/commitlint/node_modules/@commitlint/execute-rule": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-17.8.1.tgz", - "integrity": "sha512-JHVupQeSdNI6xzA9SqMF+p/JjrHTcrJdI02PwesQIDCIGUrv04hicJgCcws5nzaoZbROapPs0s6zeVHoxpMwFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=v14" } }, "packages/backend/node_modules/commitlint/node_modules/@commitlint/format": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-17.8.1.tgz", - "integrity": "sha512-f3oMTyZ84M9ht7fb93wbCKmWxO5/kKSbwuYvS867duVomoOsgrgljkGGIztmT/srZnaiGbaK8+Wf8Ik2tSr5eg==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/types": "^17.8.1", "chalk": "^4.1.0" @@ -26569,9 +26734,8 @@ }, "packages/backend/node_modules/commitlint/node_modules/@commitlint/is-ignored": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-17.8.1.tgz", - "integrity": "sha512-UshMi4Ltb4ZlNn4F7WtSEugFDZmctzFpmbqvpyxD3la510J+PLcnyhf9chs7EryaRFJMdAKwsEKfNK0jL/QM4g==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/types": "^17.8.1", "semver": "7.5.4" @@ -26582,9 +26746,8 @@ }, "packages/backend/node_modules/commitlint/node_modules/@commitlint/lint": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-17.8.1.tgz", - "integrity": "sha512-aQUlwIR1/VMv2D4GXSk7PfL5hIaFSfy6hSHV94O8Y27T5q+DlDEgd/cZ4KmVI+MWKzFfCTiTuWqjfRSfdRllCA==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/is-ignored": "^17.8.1", "@commitlint/parse": "^17.8.1", @@ -26597,9 +26760,8 @@ }, "packages/backend/node_modules/commitlint/node_modules/@commitlint/load": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-17.8.1.tgz", - "integrity": "sha512-iF4CL7KDFstP1kpVUkT8K2Wl17h2yx9VaR1ztTc8vzByWWcbO/WaKwxsnCOqow9tVAlzPfo1ywk9m2oJ9ucMqA==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/config-validator": "^17.8.1", "@commitlint/execute-rule": "^17.8.1", @@ -26622,18 +26784,16 @@ }, "packages/backend/node_modules/commitlint/node_modules/@commitlint/message": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-17.8.1.tgz", - "integrity": "sha512-6bYL1GUQsD6bLhTH3QQty8pVFoETfFQlMn2Nzmz3AOLqRVfNNtXBaSY0dhZ0dM6A2MEq4+2d7L/2LP8TjqGRkA==", "dev": true, + "license": "MIT", "engines": { "node": ">=v14" } }, "packages/backend/node_modules/commitlint/node_modules/@commitlint/parse": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-17.8.1.tgz", - "integrity": "sha512-/wLUickTo0rNpQgWwLPavTm7WbwkZoBy3X8PpkUmlSmQJyWQTj0m6bDjiykMaDt41qcUbfeFfaCvXfiR4EGnfw==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/types": "^17.8.1", "conventional-changelog-angular": "^6.0.0", @@ -26645,9 +26805,8 @@ }, "packages/backend/node_modules/commitlint/node_modules/@commitlint/read": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-17.8.1.tgz", - "integrity": "sha512-Fd55Oaz9irzBESPCdMd8vWWgxsW3OWR99wOntBDHgf9h7Y6OOHjWEdS9Xzen1GFndqgyoaFplQS5y7KZe0kO2w==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/top-level": "^17.8.1", "@commitlint/types": "^17.8.1", @@ -26661,9 +26820,8 @@ }, "packages/backend/node_modules/commitlint/node_modules/@commitlint/resolve-extends": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-17.8.1.tgz", - "integrity": "sha512-W/ryRoQ0TSVXqJrx5SGkaYuAaE/BUontL1j1HsKckvM6e5ZaG0M9126zcwL6peKSuIetJi7E87PRQF8O86EW0Q==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/config-validator": "^17.8.1", "@commitlint/types": "^17.8.1", @@ -26678,9 +26836,8 @@ }, "packages/backend/node_modules/commitlint/node_modules/@commitlint/rules": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-17.8.1.tgz", - "integrity": "sha512-2b7OdVbN7MTAt9U0vKOYKCDsOvESVXxQmrvuVUZ0rGFMCrCPJWWP1GJ7f0lAypbDAhaGb8zqtdOr47192LBrIA==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/ensure": "^17.8.1", "@commitlint/message": "^17.8.1", @@ -26694,18 +26851,16 @@ }, "packages/backend/node_modules/commitlint/node_modules/@commitlint/to-lines": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-17.8.1.tgz", - "integrity": "sha512-LE0jb8CuR/mj6xJyrIk8VLz03OEzXFgLdivBytoooKO5xLt5yalc8Ma5guTWobw998sbR3ogDd+2jed03CFmJA==", "dev": true, + "license": "MIT", "engines": { "node": ">=v14" } }, "packages/backend/node_modules/commitlint/node_modules/@commitlint/top-level": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-17.8.1.tgz", - "integrity": "sha512-l6+Z6rrNf5p333SHfEte6r+WkOxGlWK4bLuZKbtf/2TXRN+qhrvn1XE63VhD8Oe9oIHQ7F7W1nG2k/TJFhx2yA==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^5.0.0" }, @@ -26715,9 +26870,8 @@ }, "packages/backend/node_modules/commitlint/node_modules/@commitlint/types": { "version": "17.8.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-17.8.1.tgz", - "integrity": "sha512-PXDQXkAmiMEG162Bqdh9ChML/GJZo6vU+7F03ALKDK8zYc6SuAr47LjG7hGYRqUOz+WK0dU7bQ0xzuqFMdxzeQ==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0" }, @@ -26727,9 +26881,8 @@ }, "packages/backend/node_modules/commitlint/node_modules/conventional-changelog-angular": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-6.0.0.tgz", - "integrity": "sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg==", "dev": true, + "license": "ISC", "dependencies": { "compare-func": "^2.0.0" }, @@ -26739,9 +26892,8 @@ }, "packages/backend/node_modules/commitlint/node_modules/conventional-commits-parser": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz", - "integrity": "sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==", "dev": true, + "license": "MIT", "dependencies": { "is-text-path": "^1.0.1", "JSONStream": "^1.3.5", @@ -26757,9 +26909,8 @@ }, "packages/backend/node_modules/commitlint/node_modules/cosmiconfig-typescript-loader": { "version": "4.4.0", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.4.0.tgz", - "integrity": "sha512-BabizFdC3wBHhbI4kJh0VkQP9GkBfoHPydD0COMce1nJ1kJAB3F2TmJ/I7diULBKtmEWSwEbuN/KDtgnmUUVmw==", "dev": true, + "license": "MIT", "engines": { "node": ">=v14.21.3" }, @@ -26772,9 +26923,8 @@ }, "packages/backend/node_modules/commitlint/node_modules/semver": { "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -26787,9 +26937,8 @@ }, "packages/backend/node_modules/cosmiconfig": { "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dev": true, + "license": "MIT", "dependencies": { "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", @@ -26813,18 +26962,16 @@ }, "packages/backend/node_modules/dargs": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", - "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "packages/backend/node_modules/execa": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -26845,9 +26992,8 @@ }, "packages/backend/node_modules/find-up": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -26861,9 +27007,8 @@ }, "packages/backend/node_modules/fs-extra": { "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -26875,9 +27020,8 @@ }, "packages/backend/node_modules/get-stream": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -26887,9 +27031,8 @@ }, "packages/backend/node_modules/git-raw-commits": { "version": "2.0.11", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", - "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", "dev": true, + "license": "MIT", "dependencies": { "dargs": "^7.0.0", "lodash": "^4.17.15", @@ -26906,9 +27049,8 @@ }, "packages/backend/node_modules/hosted-git-info": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -26918,18 +27060,16 @@ }, "packages/backend/node_modules/human-signals": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } }, "packages/backend/node_modules/is-stream": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -26939,9 +27079,8 @@ }, "packages/backend/node_modules/is-text-path": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", "dev": true, + "license": "MIT", "dependencies": { "text-extensions": "^1.0.0" }, @@ -26951,9 +27090,8 @@ }, "packages/backend/node_modules/locate-path": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -26966,9 +27104,8 @@ }, "packages/backend/node_modules/lru-cache": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -26978,9 +27115,8 @@ }, "packages/backend/node_modules/meow": { "version": "8.1.2", - "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", - "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/minimist": "^1.2.0", "camelcase-keys": "^6.2.2", @@ -27003,18 +27139,16 @@ }, "packages/backend/node_modules/mimic-fn": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "packages/backend/node_modules/normalize-package-data": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^4.0.1", "is-core-module": "^2.5.0", @@ -27027,9 +27161,8 @@ }, "packages/backend/node_modules/npm-run-path": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -27039,9 +27172,8 @@ }, "packages/backend/node_modules/onetime": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -27054,9 +27186,8 @@ }, "packages/backend/node_modules/p-locate": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -27069,18 +27200,16 @@ }, "packages/backend/node_modules/path-exists": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "packages/backend/node_modules/read-pkg": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "dev": true, + "license": "MIT", "dependencies": { "@types/normalize-package-data": "^2.4.0", "normalize-package-data": "^2.5.0", @@ -27093,9 +27222,8 @@ }, "packages/backend/node_modules/read-pkg-up": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^4.1.0", "read-pkg": "^5.2.0", @@ -27110,9 +27238,8 @@ }, "packages/backend/node_modules/read-pkg-up/node_modules/find-up": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -27123,9 +27250,8 @@ }, "packages/backend/node_modules/read-pkg-up/node_modules/locate-path": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -27135,9 +27261,8 @@ }, "packages/backend/node_modules/read-pkg-up/node_modules/p-limit": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -27150,9 +27275,8 @@ }, "packages/backend/node_modules/read-pkg-up/node_modules/p-locate": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -27162,24 +27286,21 @@ }, "packages/backend/node_modules/read-pkg-up/node_modules/type-fest": { "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" } }, "packages/backend/node_modules/read-pkg/node_modules/hosted-git-info": { "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "dev": true, + "license": "ISC" }, "packages/backend/node_modules/read-pkg/node_modules/normalize-package-data": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -27189,27 +27310,37 @@ }, "packages/backend/node_modules/read-pkg/node_modules/semver": { "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } }, "packages/backend/node_modules/read-pkg/node_modules/type-fest": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" } }, + "packages/backend/node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "packages/backend/node_modules/semver": { "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -27222,51 +27353,45 @@ }, "packages/backend/node_modules/signal-exit": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "dev": true, + "license": "ISC" }, "packages/backend/node_modules/split2": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", "dev": true, + "license": "ISC", "dependencies": { "readable-stream": "^3.0.0" } }, "packages/backend/node_modules/strip-final-newline": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "packages/backend/node_modules/text-extensions": { "version": "1.9.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", - "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10" } }, "packages/backend/node_modules/through2": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", "dev": true, + "license": "MIT", "dependencies": { "readable-stream": "3" } }, "packages/backend/node_modules/type-fest": { "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -27276,25 +27401,23 @@ }, "packages/backend/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "packages/backend/node_modules/yargs-parser": { "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "packages/client": { "name": "@map-colonies/detiler-client", - "version": "1.0.0", + "version": "1.2.0-rc1", "license": "ISC", "dependencies": { - "@map-colonies/detiler-common": "^1.0.0", + "@map-colonies/detiler-common": "^1.1.0-rc1", "axios": "^1.6.5", "axios-retry": "^3.9.1", "http-status-codes": "^2.2.0", @@ -27321,8 +27444,7 @@ }, "packages/client/node_modules/qs": { "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.6" }, @@ -27335,7 +27457,7 @@ }, "packages/common": { "name": "@map-colonies/detiler-common", - "version": "1.0.0", + "version": "1.1.0-rc1", "license": "ISC", "devDependencies": { "@map-colonies/eslint-config": "^4.0.0", @@ -27360,8 +27482,8 @@ "dependencies": { "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", - "@map-colonies/detiler-client": "^1.0.0", - "@map-colonies/detiler-common": "^1.0.0", + "@map-colonies/detiler-client": "^1.2.0-rc1", + "@map-colonies/detiler-common": "^1.1.0-rc1", "@map-colonies/js-logger": "^1.0.1", "@map-colonies/tile-calc": "^0.1.5", "@mui/icons-material": "^5.15.19", @@ -27374,6 +27496,7 @@ "lodash": "^4.17.21", "maplibre-gl": "^2.4.0", "notistack": "^3.0.1", + "p-timeout": "^6.1.2", "pino": "^8.20.0", "react": "^18.2.0", "react-copy-to-clipboard": "^5.1.0", @@ -27402,9 +27525,8 @@ } }, "packages/frontend/node_modules/husky": { - "version": "9.1.4", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.4.tgz", - "integrity": "sha512-bho94YyReb4JV7LYWRWxZ/xr6TtOTt8cMfmQ39MQYJ7f/YE268s3GdghGwi+y4zAeqewE5zYLvuhV0M0ijsDEA==", + "version": "9.1.5", + "license": "MIT", "bin": { "husky": "bin.js" }, diff --git a/packages/backend/openapi3.yaml b/packages/backend/openapi3.yaml index d34653c..f4dc6f7 100644 --- a/packages/backend/openapi3.yaml +++ b/packages/backend/openapi3.yaml @@ -93,6 +93,11 @@ paths: minItems: 4 maxItems: 4 required: true + - in: query + name: shouldMatchCurrentState + description: should the state match the current tile's state + schema: + type: boolean - in: query name: minState description: min tile's state @@ -104,10 +109,10 @@ paths: schema: $ref: '#/components/schemas/state' - in: query - name: from - description: pagination query from + name: cursor + description: pagination cursor schema: - $ref: '#/components/schemas/from' + $ref: '#/components/schemas/cursor' - in: query name: size description: pagination query size limitation @@ -119,9 +124,7 @@ paths: content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/tileDetails' + $ref: '#/components/schemas/getTileDetailsResponse' 400: $ref: '#/components/responses/BadRequest' 5XX: @@ -307,15 +310,13 @@ components: type: number minimum: -85.05112877980659 maximum: 85.05112877980659 - from: - type: number - minimum: 0 - default: 0 size: type: number minimum: 0 maximum: 1000 default: 100 + cursor: + type: number z: type: integer minimum: 0 @@ -365,6 +366,18 @@ components: additionalProperties: true allOf: - $ref: '#/components/schemas/kit' + getTileDetailsResponse: + type: object + additionalProperties: false + required: + - tiles + properties: + tiles: + type: array + items: + $ref: '#/components/schemas/tileDetails' + cursor: + $ref: '#/components/schemas/cursor' tileDetails: type: object properties: @@ -378,6 +391,9 @@ components: $ref: '#/components/schemas/kitName' state: $ref: '#/components/schemas/state' + states: + items: + $ref: '#/components/schemas/state' createdAt: $ref: '#/components/schemas/unixTimestamp' updatedAt: @@ -398,6 +414,7 @@ components: - y - kit - state + - states - createdAt - updatedAt - renderedAt diff --git a/packages/backend/package.json b/packages/backend/package.json index f3baca3..2833ba9 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -33,7 +33,7 @@ "dependencies": { "@godaddy/terminus": "^4.12.1", "@map-colonies/cleanup-registry": "^1.1.0", - "@map-colonies/detiler-common": "^1.0.0", + "@map-colonies/detiler-common": "^1.1.0", "@map-colonies/error-express-handler": "^2.1.0", "@map-colonies/express-access-log-middleware": "^2.0.1", "@map-colonies/js-logger": "^1.0.1", diff --git a/packages/backend/src/redis/index.ts b/packages/backend/src/redis/index.ts index 7d9272f..4696255 100644 --- a/packages/backend/src/redis/index.ts +++ b/packages/backend/src/redis/index.ts @@ -8,7 +8,6 @@ import { RedisConfig, IConfig } from '../common/interfaces'; import { promiseTimeout } from '../common/util'; const DEFAULT_LIMIT_FROM = 0; -const DEFAULT_LIMIT_SIZE = 1000; const createConnectionOptions = (redisConfig: RedisConfig): Partial => { const { host, port, enableSslAuth, sslPaths, ...clientOptions } = redisConfig; @@ -28,10 +27,18 @@ const createConnectionOptions = (redisConfig: RedisConfig): Partial; +export interface AggregateReply { + total: number; + results: Record[]; + cursor?: number; +} + export const redisClientFactory: FactoryFunction = (container: DependencyContainer): RedisClient => { const logger = container.resolve(SERVICES.LOGGER); const config = container.resolve(SERVICES.CONFIG); diff --git a/packages/backend/src/tileDetails/controllers/tileDetailsController.ts b/packages/backend/src/tileDetails/controllers/tileDetailsController.ts index d9dfb11..019177d 100644 --- a/packages/backend/src/tileDetails/controllers/tileDetailsController.ts +++ b/packages/backend/src/tileDetails/controllers/tileDetailsController.ts @@ -1,4 +1,4 @@ -import { TileDetails, TileDetailsPayload, TileQueryParams } from '@map-colonies/detiler-common'; +import { TileDetails, TileDetailsPayload, TileQueryParams, TileQueryResponse } from '@map-colonies/detiler-common'; import { Logger } from '@map-colonies/js-logger'; import { BoundingBox, TILEGRID_WEB_MERCATOR, validateTileGridBoundingBox } from '@map-colonies/tile-calc'; import { RequestHandler } from 'express'; @@ -10,7 +10,7 @@ import { numerifyTileRequestParams, UpsertStatus } from '../../common/util'; import { KitNotFoundError, TileDetailsNotFoundError } from '../models/errors'; import { TileDetailsManager } from '../models/tileDetailsManager'; -type GetTilesDetailsHandler = RequestHandler>; +type GetTilesDetailsHandler = RequestHandler>; type GetMultiKitsTilesDetailsHandler = RequestHandler; type GetTileDetailsByKitHandler = RequestHandler; type PutTileDetailsByKitHandler = RequestHandler; @@ -34,18 +34,19 @@ export class TileDetailController { bbox: [west, south, east, north], minZoom, maxZoom, - from, + cursor, size, ...queryParams } = req.query; + const bbox: BoundingBox = { west: +west, south: +south, east: +east, north: +north }; validateTileGridBoundingBox(bbox, TILEGRID_WEB_MERCATOR); const tilesDetails = await this.manager.queryTilesDetails({ bbox, minZoom: +minZoom, - maxZoom: +minZoom, - from: +from, + maxZoom: +maxZoom, + cursor: cursor ? +cursor : cursor, size: +size, ...queryParams, }); diff --git a/packages/backend/src/tileDetails/models/tileDetailsManager.ts b/packages/backend/src/tileDetails/models/tileDetailsManager.ts index f846b76..7deb167 100644 --- a/packages/backend/src/tileDetails/models/tileDetailsManager.ts +++ b/packages/backend/src/tileDetails/models/tileDetailsManager.ts @@ -1,63 +1,77 @@ import { Logger } from '@map-colonies/js-logger'; import { inject, injectable } from 'tsyringe'; -import { TileDetails, TileDetailsPayload, TileParams, TileParamsWithKit, TileQueryParams, UNSPECIFIED_STATE } from '@map-colonies/detiler-common'; +import { + TileDetails, + TileDetailsPayload, + TileParams, + TileParamsWithKit, + TileQueryParams, + TileQueryResponse, + UNSPECIFIED_STATE, +} from '@map-colonies/detiler-common'; import { WatchError } from 'redis'; import { BoundingBox, TILEGRID_WORLD_CRS84, tileToBoundingBox } from '@map-colonies/tile-calc'; -import { DEFAULT_LIMIT, RedisClient } from '../../redis'; +import { AggregateReply, DEFAULT_LIMIT, DEFAULT_PAGE_SIZE, RedisClient } from '../../redis'; import { keyfy, stringifyCoordinates, bboxToWktPolygon, UpsertStatus, bboxToLonLat } from '../../common/util'; import { REDIS_KITS_HASH_PREFIX, METATILE_SIZE, SERVICES, REDIS_INDEX_NAME, SEARCHED_GEOSHAPE_NAME } from '../../common/constants'; import { KitNotFoundError, TileDetailsNotFoundError } from './errors'; +import { LOAD_FIELDS, transformDocument } from './util'; export interface TilesDetailsQueryParams extends Omit { bbox: BoundingBox; - from: number; - size: number; } @injectable() export class TileDetailsManager { public constructor(@inject(SERVICES.LOGGER) private readonly logger: Logger, @inject(SERVICES.REDIS) private readonly redis: RedisClient) {} - public async queryTilesDetails(params: TilesDetailsQueryParams): Promise { + public async queryTilesDetails(params: TilesDetailsQueryParams): Promise { + let response: AggregateReply; + this.logger.info({ msg: 'quering tile details', ...params }); - const { minZoom, maxZoom, minState, maxState, kits, bbox, from, size } = params; + const { cursor, minZoom, maxZoom, minState, maxState, shouldMatchCurrentState, kits, bbox, size } = params; - const geoshape = bboxToWktPolygon(bbox); + const stateProperty = shouldMatchCurrentState === true ? 'state' : 'states'; + const stateFilter = minState !== undefined || maxState !== undefined ? ` @${stateProperty}:[${minState ?? '-inf'} ${maxState ?? '+inf'}] ` : ' '; - const stateFilter = minState !== undefined || maxState !== undefined ? ` @state:[${minState ?? '-inf'} ${maxState ?? '+inf'}] ` : ' '; + const query = `@z:[${minZoom} ${maxZoom}]${stateFilter}@kit:(${kits.join('|')}) @geoshape:[WITHIN $${SEARCHED_GEOSHAPE_NAME}]`; + const geoshape = bboxToWktPolygon(bbox); /* eslint-disable @typescript-eslint/naming-convention */ // node-redis does not follow eslint naming convention - const result = await this.redis.ft.search( - REDIS_INDEX_NAME, - `@z:[${minZoom} ${maxZoom}]${stateFilter}@kit:(${kits.join('|')}) @geoshape:[WITHIN $${SEARCHED_GEOSHAPE_NAME}]`, - { - PARAMS: { [SEARCHED_GEOSHAPE_NAME]: geoshape }, - DIALECT: 3, - LIMIT: { from, size }, - } - ); + const options = { + DIALECT: 3, + PARAMS: { [SEARCHED_GEOSHAPE_NAME]: geoshape }, + LOAD: LOAD_FIELDS, + TIMEOUT: 0, + COUNT: size ?? DEFAULT_PAGE_SIZE, + }; + + if (cursor === undefined) { + response = await this.redis.ft.aggregateWithCursor(REDIS_INDEX_NAME, query, options); + } else { + response = await this.redis.ft.cursorRead(REDIS_INDEX_NAME, cursor, { COUNT: size ?? DEFAULT_PAGE_SIZE }); + } + /* eslint-enable @typescript-eslint/naming-convention */ this.logger.debug({ - search: { - minZoom, - maxZoom, - kits, - PARAMS: { [SEARCHED_GEOSHAPE_NAME]: geoshape }, - DIALECT: 3, - LIMIT: { from, size }, + cursor, + query, + options, + response: { + total: response.total, + resultsCount: response.results.length, + cursor: response.cursor, }, - result, }); - /* eslint-enable @typescript-eslint/naming-convention */ - if (result.total === 0) { - return []; + if (response.results.length === 0) { + return { tiles: [], cursor: response.cursor }; } - const tilesDetails = result.documents.map((document) => document.value[0]); + const tilesDetails = response.results.map((document) => transformDocument(document)); - return tilesDetails as unknown as TileDetails[]; + return { tiles: tilesDetails as unknown as TileDetails[], cursor: response.cursor }; } public async getTileDetailsByKit(params: TileParamsWithKit): Promise { @@ -135,11 +149,14 @@ export class TileDetailsManager { const transaction = isolatedClient.multi(); if (keyExistCounter === 1) { + const state = payload.state ?? UNSPECIFIED_STATE; + + transaction.json.arrAppend(key, '$.states', state); transaction.json.numIncrBy(key, '$.updateCount', 1); const jsonMSetItems: Parameters = [ [ - { key, path: '$.state', value: payload.state ?? UNSPECIFIED_STATE }, + { key, path: '$.state', value: state }, { key, path: '$.updatedAt', value: payload.timestamp }, ], ]; @@ -163,13 +180,14 @@ export class TileDetailsManager { const wkt = bboxToWktPolygon(bbox); const tileCoordinates = bboxToLonLat(bbox); - + const state = payload.state ?? UNSPECIFIED_STATE; const initialTileDetails: TileDetails = { z: params.z, x: params.x, y: params.y, kit: params.kit, - state: payload.state ?? UNSPECIFIED_STATE, + state: state, + states: [state], updatedAt: payload.timestamp, createdAt: payload.timestamp, renderedAt: payload.timestamp, diff --git a/packages/backend/src/tileDetails/models/util.ts b/packages/backend/src/tileDetails/models/util.ts new file mode 100644 index 0000000..932b9f8 --- /dev/null +++ b/packages/backend/src/tileDetails/models/util.ts @@ -0,0 +1,45 @@ +/* eslint-disable @typescript-eslint/naming-convention */ // node-redis does not follow eslint naming convention +type PropertyName = `${'@' | '$.'}${string}`; + +interface LoadField { + identifier: PropertyName; + AS?: string; +} + +export const LOAD_FIELDS: LoadField[] = [ + { identifier: '@z', AS: 'z' }, + { identifier: '@x', AS: 'x' }, + { identifier: '@y', AS: 'y' }, + { identifier: '$.kit', AS: 'kit' }, + { identifier: '$.state', AS: 'state' }, + { identifier: '$.states', AS: 'states' }, + { identifier: '$.createdAt', AS: 'createdAt' }, + { identifier: '$.updatedAt', AS: 'updatedAt' }, + { identifier: '$.renderedAt', AS: 'renderedAt' }, + { identifier: '$.updateCount', AS: 'updateCount' }, + { identifier: '$.renderCount', AS: 'renderCount' }, + { identifier: '$.skipCount', AS: 'skipCount' }, + { identifier: '$.geoshape', AS: 'geoshape' }, + { identifier: '$.coordinates', AS: 'coordinates' }, +]; +/* eslint-enable @typescript-eslint/naming-convention */ + +export const transformDocument = (input: Record): Record => { + const result: Record = {}; + + Object.entries(input).forEach(([key, value]) => { + // remove square brackets, extra slashes, and quotes + const cleanedValue = value + .replace(/^\[|\]$/g, '') + .replace(/\\/g, '') + .replace(/^"|"$/g, ''); + + // attempt to convert to a number + const numberValue = Number(cleanedValue); + + // if it's a valid number, use it; otherwise, keep it as a string + result[key] = isNaN(numberValue) ? cleanedValue : numberValue; + }); + + return result; +}; diff --git a/packages/backend/tests/unit/tileDetails/tileDetails.spec.ts b/packages/backend/tests/unit/tileDetails/tileDetails.spec.ts index 9b5750c..0b2b4eb 100644 --- a/packages/backend/tests/unit/tileDetails/tileDetails.spec.ts +++ b/packages/backend/tests/unit/tileDetails/tileDetails.spec.ts @@ -4,9 +4,10 @@ import jsLogger from '@map-colonies/js-logger'; import { createClient, WatchError } from 'redis'; import { REDIS_INDEX_NAME, REDIS_KITS_HASH_PREFIX, SEARCHED_GEOSHAPE_NAME, TILE_DETAILS_KEY_PREFIX } from '../../../src/common/constants'; import { bboxToWktPolygon, UpsertStatus } from '../../../src/common/util'; -import { DEFAULT_LIMIT } from '../../../src/redis'; +import { DEFAULT_LIMIT, DEFAULT_PAGE_SIZE } from '../../../src/redis'; import { KitNotFoundError, TileDetailsNotFoundError } from '../../../src/tileDetails/models/errors'; import { TileDetailsManager, TilesDetailsQueryParams } from '../../../src/tileDetails/models/tileDetailsManager'; +import { LOAD_FIELDS } from '../../../src/tileDetails/models/util'; const mGetMock = jest.fn(); const searchMock = jest.fn(); @@ -14,12 +15,15 @@ const hGetMock = jest.fn(); const mSetMock = jest.fn(); const setMock = jest.fn(); const numIncrByMock = jest.fn(); +const arrAppendMock = jest.fn(); const executeIsolatedMock = jest.fn(); const watchMock = jest.fn(); const existsMock = jest.fn(); const multiMock = jest.fn(); const execMock = jest.fn(); +const aggregateWithCursorMock = jest.fn(); +const cursorReadMock = jest.fn(); // eslint-disable-next-line @typescript-eslint/no-unsafe-return jest.mock('redis', () => ({ @@ -38,10 +42,13 @@ jest.mock('redis', () => ({ set: setMock, mSet: mSetMock, numIncrBy: numIncrByMock, + arrAppend: arrAppendMock, }, ft: { search: searchMock, SEARCH: searchMock, + aggregateWithCursor: aggregateWithCursorMock, + cursorRead: cursorReadMock, }, })), })); @@ -62,158 +69,203 @@ describe('TileDetailsManager', () => { }); describe('#queryTilesDetails', () => { - it('should search accoring to given params and handle empty result', async () => { + it('should aggregate search accoring to given params and handle empty result', async () => { const params: TilesDetailsQueryParams = { minZoom: 0, maxZoom: 10, - from: 0, size: 10, kits: ['kit1'], bbox: { east: 1, north: 2, south: 3, west: 4 }, }; - searchMock.mockResolvedValue({ total: 0 }); + aggregateWithCursorMock.mockResolvedValue({ results: [], cursor: undefined }); const index = REDIS_INDEX_NAME; const query = `@z:[${params.minZoom} ${params.maxZoom}] @kit:(kit1) @geoshape:[WITHIN $${SEARCHED_GEOSHAPE_NAME}]`; - const searchParams = { - PARAMS: { [SEARCHED_GEOSHAPE_NAME]: bboxToWktPolygon(params.bbox) }, + const options = { DIALECT: 3, - LIMIT: { from: params.from, size: params.size }, + PARAMS: { [SEARCHED_GEOSHAPE_NAME]: bboxToWktPolygon(params.bbox) }, + LOAD: LOAD_FIELDS, + TIMEOUT: 0, + COUNT: params.size, }; const response = await manager.queryTilesDetails(params); - expect(response).toMatchObject([]); - expect(searchMock).toHaveBeenCalledTimes(1); - expect(searchMock).toHaveBeenCalledWith(index, query, searchParams); + expect(response).toMatchObject({ tiles: [], cursor: undefined }); + expect(aggregateWithCursorMock).toHaveBeenCalledTimes(1); + expect(aggregateWithCursorMock).toHaveBeenCalledWith(index, query, options); }); - it('should search accoring to given params and handle single result', async () => { + it('should aggregate search accoring to given params and handle single result', async () => { const params: TilesDetailsQueryParams = { minZoom: 0, maxZoom: 10, - from: 0, size: 10, kits: ['kit1'], bbox: { east: 1, north: 2, south: 3, west: 4 }, }; - searchMock.mockResolvedValue({ total: 1, documents: [{ value: [{ a: 1 }] }] }); + aggregateWithCursorMock.mockResolvedValue({ results: [{ a: '1' }], cursor: undefined }); const index = REDIS_INDEX_NAME; const query = `@z:[${params.minZoom} ${params.maxZoom}] @kit:(kit1) @geoshape:[WITHIN $${SEARCHED_GEOSHAPE_NAME}]`; - const searchParams = { - PARAMS: { [SEARCHED_GEOSHAPE_NAME]: bboxToWktPolygon(params.bbox) }, + const options = { DIALECT: 3, - LIMIT: { from: params.from, size: params.size }, + PARAMS: { [SEARCHED_GEOSHAPE_NAME]: bboxToWktPolygon(params.bbox) }, + LOAD: LOAD_FIELDS, + TIMEOUT: 0, + COUNT: params.size, }; const response = await manager.queryTilesDetails(params); - expect(response).toMatchObject([{ a: 1 }]); - expect(searchMock).toHaveBeenCalledTimes(1); - expect(searchMock).toHaveBeenCalledWith(index, query, searchParams); + expect(response).toMatchObject({ tiles: [{ a: 1 }], cursor: undefined }); + expect(aggregateWithCursorMock).toHaveBeenCalledTimes(1); + expect(aggregateWithCursorMock).toHaveBeenCalledWith(index, query, options); }); - it('should search accoring to given params and handle multiple results', async () => { + it('should aggregate search accoring to given params and handle multiple results', async () => { const params: TilesDetailsQueryParams = { minZoom: 0, maxZoom: 10, - from: 0, size: 10, kits: ['kit1', 'kit2'], bbox: { east: 1, north: 2, south: 3, west: 4 }, }; - searchMock.mockResolvedValue({ total: 2, documents: [{ value: [{ a: 1 }] }, { value: [{ a: 2 }] }] }); + aggregateWithCursorMock.mockResolvedValue({ total: 2, results: [{ a: '1' }, { a: '2' }], cursor: undefined }); const index = REDIS_INDEX_NAME; const query = `@z:[${params.minZoom} ${params.maxZoom}] @kit:(kit1|kit2) @geoshape:[WITHIN $${SEARCHED_GEOSHAPE_NAME}]`; const searchParams = { - PARAMS: { [SEARCHED_GEOSHAPE_NAME]: bboxToWktPolygon(params.bbox) }, DIALECT: 3, - LIMIT: { from: params.from, size: params.size }, + PARAMS: { [SEARCHED_GEOSHAPE_NAME]: bboxToWktPolygon(params.bbox) }, + LOAD: LOAD_FIELDS, + TIMEOUT: 0, + COUNT: params.size, }; const response = await manager.queryTilesDetails(params); - expect(response).toMatchObject([{ a: 1 }, { a: 2 }]); - expect(searchMock).toHaveBeenCalledTimes(1); - expect(searchMock).toHaveBeenCalledWith(index, query, searchParams); + expect(response).toMatchObject({ tiles: [{ a: 1 }, { a: 2 }], cursor: undefined }); + expect(aggregateWithCursorMock).toHaveBeenCalledTimes(1); + expect(aggregateWithCursorMock).toHaveBeenCalledWith(index, query, searchParams); }); - it('should search accoring to given params including minState', async () => { + it('should aggregate search accoring to given params including minState', async () => { const params: TilesDetailsQueryParams = { minZoom: 0, maxZoom: 10, minState: 100, - from: 0, + shouldMatchCurrentState: true, size: 10, kits: ['kit1', 'kit2'], bbox: { east: 1, north: 2, south: 3, west: 4 }, }; - searchMock.mockResolvedValue({ total: 2, documents: [{ value: [{ a: 1 }] }, { value: [{ a: 2 }] }] }); + aggregateWithCursorMock.mockResolvedValue({ results: [{ a: '1' }, { a: 'abc' }] }); const index = REDIS_INDEX_NAME; const query = `@z:[${params.minZoom} ${params.maxZoom}] @state:[${params.minState} +inf] @kit:(kit1|kit2) @geoshape:[WITHIN $${SEARCHED_GEOSHAPE_NAME}]`; const searchParams = { - PARAMS: { [SEARCHED_GEOSHAPE_NAME]: bboxToWktPolygon(params.bbox) }, DIALECT: 3, - LIMIT: { from: params.from, size: params.size }, + PARAMS: { [SEARCHED_GEOSHAPE_NAME]: bboxToWktPolygon(params.bbox) }, + LOAD: LOAD_FIELDS, + TIMEOUT: 0, + COUNT: params.size, }; const response = await manager.queryTilesDetails(params); - expect(response).toMatchObject([{ a: 1 }, { a: 2 }]); - expect(searchMock).toHaveBeenCalledTimes(1); - expect(searchMock).toHaveBeenCalledWith(index, query, searchParams); + expect(response).toMatchObject({ tiles: [{ a: 1 }, { a: 'abc' }], cursor: undefined }); + expect(aggregateWithCursorMock).toHaveBeenCalledTimes(1); + expect(aggregateWithCursorMock).toHaveBeenCalledWith(index, query, searchParams); }); - it('should search accoring to given params including maxState', async () => { + it('should aggregate search accoring to given params including maxState', async () => { const params: TilesDetailsQueryParams = { minZoom: 0, maxZoom: 10, maxState: 100, - from: 0, size: 10, kits: ['kit1', 'kit2'], bbox: { east: 1, north: 2, south: 3, west: 4 }, }; - searchMock.mockResolvedValue({ total: 2, documents: [{ value: [{ a: 1 }] }, { value: [{ a: 2 }] }] }); + aggregateWithCursorMock.mockResolvedValue({ results: [{ a: '1' }, { a: '2' }], cursor: undefined }); const index = REDIS_INDEX_NAME; - const query = `@z:[${params.minZoom} ${params.maxZoom}] @state:[-inf ${params.maxState}] @kit:(kit1|kit2) @geoshape:[WITHIN $${SEARCHED_GEOSHAPE_NAME}]`; + const query = `@z:[${params.minZoom} ${params.maxZoom}] @states:[-inf ${params.maxState}] @kit:(kit1|kit2) @geoshape:[WITHIN $${SEARCHED_GEOSHAPE_NAME}]`; const searchParams = { - PARAMS: { [SEARCHED_GEOSHAPE_NAME]: bboxToWktPolygon(params.bbox) }, DIALECT: 3, - LIMIT: { from: params.from, size: params.size }, + PARAMS: { [SEARCHED_GEOSHAPE_NAME]: bboxToWktPolygon(params.bbox) }, + LOAD: LOAD_FIELDS, + TIMEOUT: 0, + COUNT: params.size, }; const response = await manager.queryTilesDetails(params); - expect(response).toMatchObject([{ a: 1 }, { a: 2 }]); - expect(searchMock).toHaveBeenCalledTimes(1); - expect(searchMock).toHaveBeenCalledWith(index, query, searchParams); + expect(response).toMatchObject({ tiles: [{ a: 1 }, { a: 2 }], cursor: undefined }); + expect(aggregateWithCursorMock).toHaveBeenCalledTimes(1); + expect(aggregateWithCursorMock).toHaveBeenCalledWith(index, query, searchParams); }); - it('should search accoring to given params including minState and maxState', async () => { + it('should aggregate search accoring to given params including minState and maxState', async () => { const params: TilesDetailsQueryParams = { minZoom: 0, maxZoom: 10, + shouldMatchCurrentState: true, minState: -1, maxState: 100, - from: 0, size: 10, kits: ['kit1', 'kit2'], bbox: { east: 1, north: 2, south: 3, west: 4 }, }; - searchMock.mockResolvedValue({ total: 2, documents: [{ value: [{ a: 1 }] }, { value: [{ a: 2 }] }] }); + aggregateWithCursorMock.mockResolvedValue({ results: [{ a: '1' }, { a: '2' }], cursor: undefined }); const index = REDIS_INDEX_NAME; const query = `@z:[${params.minZoom} ${params.maxZoom}] @state:[${params.minState} ${params.maxState}] @kit:(kit1|kit2) @geoshape:[WITHIN $${SEARCHED_GEOSHAPE_NAME}]`; const searchParams = { - PARAMS: { [SEARCHED_GEOSHAPE_NAME]: bboxToWktPolygon(params.bbox) }, DIALECT: 3, - LIMIT: { from: params.from, size: params.size }, + PARAMS: { [SEARCHED_GEOSHAPE_NAME]: bboxToWktPolygon(params.bbox) }, + LOAD: LOAD_FIELDS, + TIMEOUT: 0, + COUNT: params.size, }; const response = await manager.queryTilesDetails(params); - expect(response).toMatchObject([{ a: 1 }, { a: 2 }]); - expect(searchMock).toHaveBeenCalledTimes(1); - expect(searchMock).toHaveBeenCalledWith(index, query, searchParams); + expect(response).toMatchObject({ tiles: [{ a: 1 }, { a: 2 }], cursor: undefined }); + expect(aggregateWithCursorMock).toHaveBeenCalledTimes(1); + expect(aggregateWithCursorMock).toHaveBeenCalledWith(index, query, searchParams); + }); + + it('should continue aggregate search accoring to given params which include the cursor id', async () => { + const params: TilesDetailsQueryParams = { + minZoom: 0, + maxZoom: 10, + size: 10, + kits: ['kit1', 'kit2'], + bbox: { east: 1, north: 2, south: 3, west: 4 }, + cursor: 666, + }; + cursorReadMock.mockResolvedValue({ results: [{ a: '1' }, { a: '2' }], cursor: 667 }); + const index = REDIS_INDEX_NAME; + + const response = await manager.queryTilesDetails(params); + + expect(response).toMatchObject({ tiles: [{ a: 1 }, { a: 2 }], cursor: 667 }); + expect(cursorReadMock).toHaveBeenCalledTimes(1); + expect(cursorReadMock).toHaveBeenCalledWith(index, params.cursor, { COUNT: params.size }); + }); + + it('should continue aggregate search accoring to given params which include the cursor id and no size', async () => { + const params: TilesDetailsQueryParams = { + minZoom: 0, + maxZoom: 10, + kits: ['kit1', 'kit2'], + bbox: { east: 1, north: 2, south: 3, west: 4 }, + cursor: 666, + }; + cursorReadMock.mockResolvedValue({ results: [{ a: '1' }, { a: '2' }], cursor: 667 }); + const index = REDIS_INDEX_NAME; + + const response = await manager.queryTilesDetails(params); + + expect(response).toMatchObject({ tiles: [{ a: 1 }, { a: 2 }], cursor: 667 }); + expect(cursorReadMock).toHaveBeenCalledTimes(1); + expect(cursorReadMock).toHaveBeenCalledWith(index, params.cursor, { COUNT: DEFAULT_PAGE_SIZE }); }); }); @@ -436,6 +488,8 @@ describe('TileDetailsManager', () => { expect(numIncrByMock).toHaveBeenCalledTimes(2); expect(numIncrByMock).toHaveBeenNthCalledWith(1, `${TILE_DETAILS_KEY_PREFIX}:kit1:1/0/0`, '$.updateCount', 1); expect(numIncrByMock).toHaveBeenNthCalledWith(2, `${TILE_DETAILS_KEY_PREFIX}:kit1:1/0/0`, '$.renderCount', 1); + expect(arrAppendMock).toHaveBeenCalledTimes(1); + expect(arrAppendMock).toHaveBeenCalledWith(`${TILE_DETAILS_KEY_PREFIX}:kit1:1/0/0`, '$.states', UNSPECIFIED_STATE); expect(setMock).not.toHaveBeenCalled(); expect(execMock).toHaveBeenCalledTimes(1); }); @@ -473,6 +527,8 @@ describe('TileDetailsManager', () => { expect(numIncrByMock).toHaveBeenCalledTimes(2); expect(numIncrByMock).toHaveBeenNthCalledWith(1, `${TILE_DETAILS_KEY_PREFIX}:kit1:1/0/0`, '$.updateCount', 1); expect(numIncrByMock).toHaveBeenNthCalledWith(2, `${TILE_DETAILS_KEY_PREFIX}:kit1:1/0/0`, '$.renderCount', 1); + expect(arrAppendMock).toHaveBeenCalledTimes(1); + expect(arrAppendMock).toHaveBeenCalledWith(`${TILE_DETAILS_KEY_PREFIX}:kit1:1/0/0`, '$.states', payload.state); expect(setMock).not.toHaveBeenCalled(); expect(execMock).toHaveBeenCalledTimes(1); }); @@ -509,6 +565,8 @@ describe('TileDetailsManager', () => { expect(numIncrByMock).toHaveBeenCalledTimes(2); expect(numIncrByMock).toHaveBeenNthCalledWith(1, `${TILE_DETAILS_KEY_PREFIX}:kit1:1/0/0`, '$.updateCount', 1); expect(numIncrByMock).toHaveBeenNthCalledWith(2, `${TILE_DETAILS_KEY_PREFIX}:kit1:1/0/0`, '$.skipCount', 1); + expect(arrAppendMock).toHaveBeenCalledTimes(1); + expect(arrAppendMock).toHaveBeenCalledWith(`${TILE_DETAILS_KEY_PREFIX}:kit1:1/0/0`, '$.states', payload.state); expect(setMock).not.toHaveBeenCalled(); expect(execMock).toHaveBeenCalledTimes(1); }); diff --git a/packages/client/package.json b/packages/client/package.json index ef18196..b71b101 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@map-colonies/detiler-client", - "version": "1.0.0", + "version": "1.2.0", "description": "detiler client", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -28,7 +28,7 @@ "dist" ], "dependencies": { - "@map-colonies/detiler-common": "^1.0.0", + "@map-colonies/detiler-common": "^1.1.0", "axios": "^1.6.5", "axios-retry": "^3.9.1", "http-status-codes": "^2.2.0", diff --git a/packages/client/src/client/index.ts b/packages/client/src/client/index.ts index 775d037..82c52d7 100644 --- a/packages/client/src/client/index.ts +++ b/packages/client/src/client/index.ts @@ -1,8 +1,17 @@ -import axios, { AxiosError, AxiosInstance } from 'axios'; +import axios, { AxiosError, AxiosInstance, AxiosResponse } from 'axios'; import axiosRetry, { exponentialDelay, IAxiosRetryConfig } from 'axios-retry'; import { StatusCodes } from 'http-status-codes'; import { stringify } from 'qs'; -import { ILogger, KitMetadata, TileDetails, TileDetailsPayload, TileParams, TileParamsWithKit, TileQueryParams } from '@map-colonies/detiler-common'; +import { + ILogger, + KitMetadata, + TileDetails, + TileDetailsPayload, + TileParams, + TileParamsWithKit, + TileQueryParams, + TileQueryResponse, +} from '@map-colonies/detiler-common'; import { DEFAULT_PAGE_SIZE, DEFAULT_RETRY_STRATEGY_DELAY, DetilerClientConfig, DetilerOptions, RetryStrategy } from './config'; export interface IDetilerClient { @@ -71,35 +80,38 @@ export class DetilerClient implements IDetilerClient { } } - public async *queryTilesDetailsAsyncGenerator(params: TileQueryParams): AsyncGenerator { - let currentPage = params.from ?? 0; + public async *queryTilesDetailsAsyncGenerator(params: TileQueryParams, controller?: AbortController): AsyncGenerator { + let cursor: number | undefined = undefined; + const pageSize = params.size ?? DEFAULT_PAGE_SIZE; - this.logger?.debug({ msg: `getting tile details`, url: this.config.url, pageSize, ...params }); + this.logger?.debug({ msg: `getting tile details`, url: this.config.url, ...params, size: pageSize }); /* eslint-disable-next-line @typescript-eslint/no-unnecessary-condition */ // get the next page unconditionally until done while (true) { - const pageParams: TileQueryParams = { ...params, from: currentPage * pageSize, size: pageSize }; + const pageParams: TileQueryParams = { ...params, cursor, size: pageSize }; try { - const res = await this.axios.get(`${this.config.url}/detail`, { + const res: AxiosResponse = await this.axios.get(`${this.config.url}/detail`, { params: pageParams, paramsSerializer: (params) => stringify(params), + signal: controller?.signal, }); - if (res.data.length < pageSize) { - if (res.data.length !== 0) { - yield res.data; + // check if the cursor has reached is limit + if (res.data.cursor === undefined || res.data.cursor === 0) { + if (res.data.tiles.length !== 0) { + yield res.data.tiles; } break; } - yield res.data; - currentPage++; + yield res.data.tiles; + cursor = res.data.cursor; } catch (error) { const axiosError = error as AxiosError; this.logger?.error({ - msg: `failed to get tiles details for page ${currentPage}`, + msg: `failed to get tiles details for cursor ${cursor}`, err: axiosError, url: this.config.url, params: pageParams, diff --git a/packages/client/tests/unit/client.spec.ts b/packages/client/tests/unit/client.spec.ts index c37aade..92e2bb8 100644 --- a/packages/client/tests/unit/client.spec.ts +++ b/packages/client/tests/unit/client.spec.ts @@ -3,6 +3,7 @@ import { AxiosError } from 'axios'; import httpStatusCodes from 'http-status-codes'; import { TileDetails, TileDetailsPayload, TileParams, TileParamsWithKit, TileQueryParams } from '@map-colonies/detiler-common'; import { DetilerClient } from '../../src'; +import { DEFAULT_PAGE_SIZE } from '../../src/client/config'; const MOCK_DETILER_URL = 'http://detiler.com'; @@ -72,34 +73,37 @@ describe('Client', () => { describe('#queryTilesDetailsAsyncGenerator', () => { it('should query generate details according to params including extra empty res call', async function () { - const details1 = { a: 1 }; - const details2 = { a: 2 }; - const details3 = { a: 3 }; + const details1 = { tiles: [{ a: 1 }], cursor: 2 }; + const details2 = { tiles: [{ a: 2 }], cursor: 3 }; + const details3 = { tiles: [{ a: 3 }], cursor: 4 }; + const details4 = { tiles: [], cursor: undefined }; + let data: TileDetails[] = []; - const params1: TileQueryParams = { size: 1, from: 0, kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; - const params2: TileQueryParams = { size: 1, from: 1, kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; - const params3: TileQueryParams = { size: 1, from: 2, kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; - const lastParams: TileQueryParams = { size: 1, from: 3, kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; + + const params1: TileQueryParams = { size: 1, kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; + const params2: TileQueryParams = { size: 1, cursor: 2, kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; + const params3: TileQueryParams = { size: 1, cursor: 3, kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; + const lastParams: TileQueryParams = { size: 1, cursor: 4, kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; nock(MOCK_DETILER_URL) .get(`/detail`) .query({ ...params1 }) .once() - .reply(httpStatusCodes.OK, [details1]); + .reply(httpStatusCodes.OK, details1); nock(MOCK_DETILER_URL) .get(`/detail`) .query({ ...params2 }) .twice() - .reply(httpStatusCodes.OK, [details2]); + .reply(httpStatusCodes.OK, details2); nock(MOCK_DETILER_URL) .get(`/detail`) .query({ ...params3 }) .thrice() - .reply(httpStatusCodes.OK, [details3]); + .reply(httpStatusCodes.OK, details3); nock(MOCK_DETILER_URL) .get(`/detail`) .query({ ...lastParams }) - .reply(httpStatusCodes.OK, []); + .reply(httpStatusCodes.OK, details4); const getSpy = jest.spyOn(detiler['axios'], 'get'); const queryGenerator = detiler.queryTilesDetailsAsyncGenerator(params1); @@ -108,18 +112,20 @@ describe('Client', () => { data = [...data, ...pageData]; } - expect(data).toMatchObject([details1, details2, details3]); + expect(data).toMatchObject([details1.tiles[0], details2.tiles[0], details3.tiles[0]]); expect(getSpy).toHaveBeenCalledTimes(4); }); it('should query generate details according to params until done', async function () { - const details1 = [{ a: 1 }, { a: 2 }]; - const details2 = [{ a: 3 }, { a: 4 }]; - const details3 = [{ a: 5 }]; + const details1 = { tiles: [{ a: 1 }, { a: 2 }], cursor: 2 }; + const details2 = { tiles: [{ a: 3 }, { a: 4 }], cursor: 3 }; + const details3 = { tiles: [{ a: 5 }], cursor: 0 }; + let data: TileDetails[] = []; - const params1: TileQueryParams = { size: 2, from: 0, kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; - const params2: TileQueryParams = { size: 2, from: 2, kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; - const params3: TileQueryParams = { size: 2, from: 4, kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; + + const params1: TileQueryParams = { size: 2, kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; + const params2: TileQueryParams = { size: 2, cursor: 2, kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; + const params3: TileQueryParams = { size: 2, cursor: 3, kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; nock(MOCK_DETILER_URL) .get(`/detail`) @@ -144,18 +150,18 @@ describe('Client', () => { data = [...data, ...pageData]; } - expect(data).toMatchObject([...details1, ...details2, ...details3]); + expect(data).toMatchObject([...details1.tiles, ...details2.tiles, ...details3.tiles]); expect(getSpy).toHaveBeenCalledTimes(3); }); - it('should query generate details according to params with default size and from', async function () { - const details = [{ a: 1 }]; + it('should query generate details according to params with default size', async function () { + const details = { tiles: [{ a: 1 }], cursor: undefined }; let data: TileDetails[] = []; const params: TileQueryParams = { kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; nock(MOCK_DETILER_URL) .get(`/detail`) - .query({ ...params, from: 0, size: 100 }) + .query({ ...params, size: DEFAULT_PAGE_SIZE }) .once() .reply(httpStatusCodes.OK, details); const getSpy = jest.spyOn(detiler['axios'], 'get'); @@ -166,12 +172,12 @@ describe('Client', () => { data = [...data, ...pageData]; } - expect(data).toMatchObject(details); + expect(data).toMatchObject(details.tiles); expect(getSpy).toHaveBeenCalledTimes(1); }); it('should throw an error if the http get request has errored', async function () { - const params: TileQueryParams = { from: 0, size: 10, kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; + const params: TileQueryParams = { size: 10, kits: ['a'], minZoom: 1, maxZoom: 2, bbox: [1, 2, 3, 4] }; nock(MOCK_DETILER_URL) .get(`/detail`) .query({ ...params }) diff --git a/packages/common/package.json b/packages/common/package.json index 2f04a0c..2b1be53 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -1,6 +1,6 @@ { "name": "@map-colonies/detiler-common", - "version": "1.0.0", + "version": "1.1.0", "description": "detiler common types", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/common/src/types/index.ts b/packages/common/src/types/index.ts index 1c8df4e..38727d9 100644 --- a/packages/common/src/types/index.ts +++ b/packages/common/src/types/index.ts @@ -24,6 +24,7 @@ export interface TileParamsWithKit extends TileParams { export interface TileDetails extends TileParamsWithKit { state: number; + states: number[]; createdAt: number; updatedAt: number; renderedAt: number; @@ -34,6 +35,11 @@ export interface TileDetails extends TileParamsWithKit { geoshape: string; } +export interface TileQueryResponse { + tiles: TileDetails[]; + cursor?: number; +} + export interface TileDetailsPayload { timestamp: number; state?: number; @@ -41,7 +47,7 @@ export interface TileDetailsPayload { } export interface BaseQueryParams { - from?: number; + cursor?: number; size?: number; } @@ -50,6 +56,7 @@ export interface TileQueryParams extends BaseQueryParams { maxZoom: number; minState?: number; maxState?: number; + shouldMatchCurrentState?: boolean; kits: string[]; bbox: number[]; } diff --git a/packages/frontend/config/.env.production b/packages/frontend/config/.env.production index 0ef7269..2a3a6c5 100644 --- a/packages/frontend/config/.env.production +++ b/packages/frontend/config/.env.production @@ -7,7 +7,12 @@ CONFIG_APP_BASEMAP_XAPIKEY=CONFIG_APP_BASEMAP_XAPIKEY_PLACEHOLDER CONFIG_APP_BASEMAP_TILE_SIZE=CONFIG_APP_BASEMAP_TILE_SIZE_PLACEHOLDER CONFIG_APP_BASEMAP_ZOOM_OFFSET=CONFIG_APP_BASEMAP_ZOOM_OFFSET_PLACEHOLDER CONFIG_APP_BASEMAP_DESATURATE=CONFIG_APP_BASEMAP_DESATURATE_PLACEHOLDER +CONFIG_APP_UI_TILES_PER_PAGE=CONFIG_APP_UI_TILES_PER_PAGE_PLACEHOLDER CONFIG_APP_DATA_ALPHA_CHANNEL=CONFIG_APP_DATA_ALPHA_CHANNEL_PLACEHOLDER +CONFIG_APP_KITS_FETCH_INTERVAL=CONFIG_APP_KITS_FETCH_INTERVAL_PLACEHOLDER +CONFIG_APP_TILES_BATCH_SIZE=CONFIG_APP_TILES_BATCH_SIZE_PLACEHOLDER +CONFIG_APP_TILES_FETCH_TIMEOUT=CONFIG_APP_TILES_FETCH_TIMEOUT_PLACEHOLDER +CONFIG_APP_TILES_FETCH_INTERVAL=CONFIG_APP_TILES_FETCH_INTERVAL_PLACEHOLDER CONFIG_DETILER_CLIENT_URL=CONFIG_DETILER_CLIENT_URL_PLACEHOLDER #CONFIG_DETILER_CLIENT_TIMEOUT diff --git a/packages/frontend/helm/templates/configmap.yaml b/packages/frontend/helm/templates/configmap.yaml index b5670bc..61780d4 100644 --- a/packages/frontend/helm/templates/configmap.yaml +++ b/packages/frontend/helm/templates/configmap.yaml @@ -19,7 +19,15 @@ data: {{- else }} CONFIG_APP_BASEMAP_ENABLED_PLACEHOLDER: "false" {{- end }} + CONFIG_APP_UI_TILES_PER_PAGE_PLACEHOLDER: {{ .app.tilesPerPage | quote }} + CONFIG_APP_DATA_ALPHA_CHANNEL_PLACEHOLDER: {{ .app.dataAlphaChannel | quote }} + + CONFIG_APP_KITS_FETCH_INTERVAL_PLACEHOLDER: {{ .app.kits.fetchInterval | quote }} + CONFIG_APP_TILES_BATCH_SIZE_PLACEHOLDER: {{ .app.tiles.batchSize | quote }} + CONFIG_APP_TILES_FETCH_TIMEOUT_PLACEHOLDER: {{ .app.tiles.fetchTimeout | quote }} + CONFIG_APP_TILES_FETCH_INTERVAL_PLACEHOLDER: {{ .app.tiles.fetchInterval | quote }} + CONFIG_DETILER_CLIENT_URL_PLACEHOLDER: {{ .detilerClient.url | quote }} CONFIG_DETILER_CLIENT_TIMEOUT_PLACEHOLDER: {{ .detilerClient.timeout | quote }} CONFIG_DETILER_CLIENT_ENABLE_RETRY_STRATEGY_PLACEHOLDER: {{ .detilerClient.retryStrategy.enabled | quote }} diff --git a/packages/frontend/helm/values.yaml b/packages/frontend/helm/values.yaml index ffb8b58..e2918db 100644 --- a/packages/frontend/helm/values.yaml +++ b/packages/frontend/helm/values.yaml @@ -68,7 +68,14 @@ env: basemapTileSize: 256 basemapTileOffset: 0 basemapDesaturate: 0 + tilesPerPage: 5 dataAlphaChannel: 75 + kits: + fetchInterval: 60000 + tiles: + batchSize: 1000 + fetchTimeout: 5000 + fetchInterval: 5000 detilerClient: url: http://detiler.com timeout: 60000 diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 5e68d26..765a0f2 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -16,8 +16,8 @@ "dependencies": { "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", - "@map-colonies/detiler-client": "^1.0.0", - "@map-colonies/detiler-common": "^1.0.0", + "@map-colonies/detiler-client": "^1.2.0", + "@map-colonies/detiler-common": "^1.1.0", "@map-colonies/js-logger": "^1.0.1", "@map-colonies/tile-calc": "^0.1.5", "@mui/icons-material": "^5.15.19", @@ -30,6 +30,7 @@ "lodash": "^4.17.21", "maplibre-gl": "^2.4.0", "notistack": "^3.0.1", + "p-timeout": "^6.1.2", "pino": "^8.20.0", "react": "^18.2.0", "react-copy-to-clipboard": "^5.1.0", diff --git a/packages/frontend/src/app.tsx b/packages/frontend/src/app.tsx index eafc93b..720e643 100644 --- a/packages/frontend/src/app.tsx +++ b/packages/frontend/src/app.tsx @@ -10,24 +10,46 @@ import { Feature, Geometry } from 'geojson'; import { KitMetadata, TileDetails, TileParams, TileQueryParams } from '@map-colonies/detiler-common'; import { setIntervalAsync, clearIntervalAsync } from 'set-interval-async'; import { useSnackbar } from 'notistack'; +import pTimeout from 'p-timeout'; +import { uniqBy } from 'lodash'; +import { AxiosError } from 'axios'; import { appHelper, compareQueries, parseDataToFeatures, timerify, querifyBounds } from './utils/helpers'; -import { ZOOM_OFFEST, FETCH_KITS_INTERVAL, INITIAL_VIEW_STATE, DEFAULT_MIN_STATE, DEFAULT_MAX_STATE, MAX_KIT_STATE_KEY } from './utils/constants'; +import { + ZOOM_OFFEST, + INITIAL_VIEW_STATE, + DEFAULT_MIN_STATE, + DEFAULT_MAX_STATE, + MAX_KIT_STATE_KEY, + CLIENT_ABORTED_ERROR_CODE, + DEFAULT_KITS_FETCH_INTERVAL, + DEFAULT_TILES_FETCH_INTERVAL, + DEFAULT_TILES_FETCH_TIMEOUT, + DEFAULT_TILES_BATCH_SIZE, + MIN_ZOOM_LEVEL, + MAX_ZOOM_LEVEL, +} from './utils/constants'; import { colorFactory, ColorScale, colorScaleParser, ColorScaleFunc, DEFAULT_TILE_COLOR } from './utils/style'; -import { METRICS, findMinMax, updateMinMax, INITIAL_MIN_MAX, Metric } from './utils/metric'; +import { METRICS, INITIAL_MIN_MAX, Metric } from './utils/metric'; import { INIT_STATS, calcHttpStat, Stats } from './utils/stats'; import { Preferences, Sidebar, Tooltip, CornerTabs } from './components'; import { comparatorFuncWrapper, filterRangeFuncWrapper, transformFuncWrapper } from './deck-gl'; import { CONSTANT_GEOJSON_LAYER_PROPERTIES, GEOJSON_LAYER_ID, BASEMAP_LAYER_ID } from './deck-gl/constants'; import { basemapLayerFactory } from './deck-gl/basemap'; import { logger } from './logger'; +import { config } from './config'; import { client } from './client'; import { MapLibreGL, TargetetEvent } from './deck-gl/types'; +import { AppConfig } from './utils/interfaces'; + +const appConfig = config.get('app'); export const App: React.FC = () => { const [viewState, setViewState] = useState(INITIAL_VIEW_STATE); + const [loadedData, setLoadedData] = useState([]); const [hoverInfo, setHoverInfo] = useState(); const [selectedKit, setSelectedKit] = useState(); const [stateRange, setStateRange] = useState([DEFAULT_MIN_STATE, DEFAULT_MAX_STATE]); + const [queryZoom, setQueryZoom] = useState(INITIAL_VIEW_STATE.zoom + ZOOM_OFFEST); const [selectedMetric, setSelectedMetric] = useState(); const [selectedColorScale, setSelectedColorScale] = useState<{ key: ColorScale; value: ColorScaleFunc }>({ key: 'heat', @@ -36,10 +58,15 @@ export const App: React.FC = () => { const [statsTable, setStatsTable] = useState(INIT_STATS); const [sidebarData, setSidebarData] = useState([]); const [isSidebarOpen, setIsSidebarOpen] = useState(false); + const [isPaused, setIsPaused] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [shouldFollowZoom, setShouldFollowZoom] = useState(true); + const [shouldQueryCurrentState, setShouldQueryCurrentState] = useState(true); const { enqueueSnackbar } = useSnackbar(); const handleKitChange = (event: TargetetEvent): void => { const kitMetadata = appHelper.kits.find((kit) => kit.name === event.target.value); + appHelper.shouldOverrideComarator = true; setSelectedKit(kitMetadata); if (statsTable.metric) { setStatsTable((prevStatsTable) => { @@ -47,7 +74,6 @@ export const App: React.FC = () => { return { ...prevStatsTable, metric: nextMetric }; }); } - appHelper.shouldOverrideComarator = true; setStateRange([DEFAULT_MIN_STATE, kitMetadata ? +kitMetadata[MAX_KIT_STATE_KEY] : DEFAULT_MAX_STATE]); }; @@ -55,17 +81,40 @@ export const App: React.FC = () => { setStateRange(range as number[]); }; + const handleQueryZoomChange = (event: Event, zoom: number | number[]): void => { + if (!shouldFollowZoom) { + setQueryZoom(zoom as number); + } + }; + + const handleShouldFollowZoomChange = (event: React.ChangeEvent, shouldFollow: boolean): void => { + if (shouldFollow) { + setQueryZoom(appHelper.currentZoomLevel + ZOOM_OFFEST); + } + setShouldFollowZoom(shouldFollow); + }; + + const handleQueryZoomChangeByViewport = (zoom: number): void => { + if (shouldFollowZoom) { + setQueryZoom(zoom + ZOOM_OFFEST); + } + }; + + const handleShouldQueryCurrentStateChange = (event: React.ChangeEvent, shouldQueryCurrentState: boolean): void => { + setShouldQueryCurrentState(shouldQueryCurrentState); + }; + const handleMetricChange = (event: TargetetEvent): void => { const index = METRICS.findIndex((metric) => metric.name === event.target.value); const metric = METRICS[index]; - setSelectedMetric(metric); appHelper.shouldOverrideComarator = true; + setSelectedMetric(metric); }; const handleColorScaleChange = (event: TargetetEvent): void => { const colorScale = event.target.value as ColorScale; - setSelectedColorScale({ key: colorScale, value: colorScaleParser(colorScale) }); appHelper.shouldOverrideComarator = true; + setSelectedColorScale({ key: colorScale, value: colorScaleParser(colorScale) }); }; const goToCoordinates = useCallback((longitude: number, latitude: number, zoom?: number) => { @@ -80,26 +129,18 @@ export const App: React.FC = () => { }, []); const handleViewportChange = (nextViewState: ViewStateChangeParameters<{ zoom: number }>): void => { + appHelper.shouldFetch = true; + setViewState({ ...viewState, ...nextViewState.viewState }); + // for higher zoom levels lower the viewport's zoom level by 1 to have a buffer around the query bounds const viewportZoom = nextViewState.viewState.zoom <= ZOOM_OFFEST + 1 ? nextViewState.viewState.zoom : nextViewState.viewState.zoom - 1; appHelper.bounds.query = new WebMercatorViewport({ ...nextViewState.viewState, zoom: viewportZoom }).getBounds(); appHelper.bounds.actual = new WebMercatorViewport(nextViewState.viewState).getBounds(); - appHelper.shouldOverrideComarator = true; const nextZoom = Math.floor(nextViewState.viewState.zoom); - if (appHelper.currentZoomLevel === nextZoom) { - return; - } - appHelper.currentZoomLevel = nextZoom; - // reset min-max values between zoom changes - if (statsTable.metric) { - setStatsTable((prevStatsTable) => { - const nextMetric = prevStatsTable.metric ? { ...prevStatsTable.metric, range: { ...INITIAL_MIN_MAX } } : undefined; - return { ...prevStatsTable, metric: nextMetric }; - }); - } + handleQueryZoomChangeByViewport(nextZoom); }; const handleOpenSidebar = (data: TileDetails[]): void => { @@ -112,6 +153,10 @@ export const App: React.FC = () => { setIsSidebarOpen(false); }; + const handleActionClicked = (): void => { + setIsPaused(!isPaused); + }; + useEffect(() => { if (selectedKit === undefined) { return; @@ -127,15 +172,18 @@ export const App: React.FC = () => { }, [appHelper.kits]); useEffect(() => { + appHelper.lastDetilerQueryParams = undefined; + appHelper.shouldOverrideComarator = true; + if (selectedMetric === undefined) { return; } + setStatsTable((prevStatsTable) => { const nextMetric = { ...selectedMetric, range: { ...INITIAL_MIN_MAX } }; return { ...prevStatsTable, metric: nextMetric }; }); - appHelper.shouldOverrideComarator = true; - }, [selectedMetric]); + }, [selectedMetric, queryZoom, shouldQueryCurrentState]); useEffect(() => { async function kitsFetch(): Promise { @@ -154,60 +202,111 @@ export const App: React.FC = () => { void kitsFetch(); - const timer = setIntervalAsync(kitsFetch, FETCH_KITS_INTERVAL); + const timer = setIntervalAsync(kitsFetch, appConfig.kits.fetchInterval ?? DEFAULT_KITS_FETCH_INTERVAL); return () => { - void clearIntervalAsync(timer).then(() => logger.info(`fetch timer cleared`)); + void clearIntervalAsync(timer).then(() => logger.info(`kits-fetch-timer cleared`)); }; }, []); - const fetchData = async (): Promise => { + useEffect(() => { + const abortController = new AbortController(); + const timeoutMs = appConfig.tiles.fetchTimeout ?? DEFAULT_TILES_FETCH_TIMEOUT; + + if (isPaused) { + return; + } + + // flush data + setLoadedData([]); + + // fetch data immediately + pTimeout(fetchData(abortController), { milliseconds: timeoutMs, signal: abortController.signal }).catch(() => { + appHelper.lastDetilerQueryParams = undefined; + appHelper.shouldFetch = true; + }); + + // fetch data in interval only if should + async function fetchDataFn(): Promise { + if (!appHelper.shouldFetch) { + return; + } + + appHelper.shouldFetch = false; + + try { + await pTimeout(fetchData(abortController), { milliseconds: timeoutMs, signal: abortController.signal }); + } catch (err) { + appHelper.lastDetilerQueryParams = undefined; + appHelper.shouldFetch = true; + } + } + + // init timer + const dataFetchTimer = setIntervalAsync(fetchDataFn, appConfig.tiles.fetchInterval ?? DEFAULT_TILES_FETCH_INTERVAL); + + return () => { + // aborts any previous intervals with previous dependencies + logger.info({ msg: 'aborting previous data fetches' }); + abortController.abort(); + void clearIntervalAsync(dataFetchTimer).then(() => logger.info(`data-fetch-timer cleared`)); + }; + }, [isPaused, selectedKit?.name, statsTable.metric?.name, queryZoom, shouldQueryCurrentState, ...stateRange]); + + const fetchData = async (abortController?: AbortController): Promise => { try { if (appHelper.bounds.query === undefined || selectedKit === undefined) { return; } const nextDetilerQueryParams: TileQueryParams = { - minZoom: appHelper.currentZoomLevel + ZOOM_OFFEST, - maxZoom: appHelper.currentZoomLevel + ZOOM_OFFEST, + minZoom: queryZoom, + maxZoom: queryZoom, + shouldMatchCurrentState: shouldQueryCurrentState, minState: stateRange[0], maxState: stateRange[1], kits: [selectedKit.name], bbox: querifyBounds(appHelper.bounds.query), + size: appConfig.tiles.batchSize ?? DEFAULT_TILES_BATCH_SIZE, }; const areQueriesEqual = compareQueries(appHelper.lastDetilerQueryParams, nextDetilerQueryParams); + if (areQueriesEqual) { return; } + setIsLoading(true); + appHelper.lastDetilerQueryParams = nextDetilerQueryParams; - let data: TileDetails[] = []; - const queryGenerator = client.queryTilesDetailsAsyncGenerator(nextDetilerQueryParams); + const queryGenerator = client.queryTilesDetailsAsyncGenerator(nextDetilerQueryParams, abortController); const [, duration] = await timerify(async () => { for await (const pageData of queryGenerator) { - data = [...data, ...pageData]; + const features = parseDataToFeatures(pageData); + setLoadedData((prev) => { + const next = [...prev, ...features]; + return uniqBy(next, 'properties.id'); + }); } }); - const features = parseDataToFeatures(data); - setStatsTable((prevStatsTable) => { const nextHttpStat = calcHttpStat(prevStatsTable.httpInvokes.query, duration); return { ...prevStatsTable, httpInvokes: { ...prevStatsTable.httpInvokes, query: nextHttpStat } }; }); - - if (statsTable.metric !== undefined) { - const currentMinMax = findMinMax(data, statsTable.metric.property); - if (currentMinMax !== null) { - updateMinMax(currentMinMax, statsTable.metric); + } catch (err) { + if (err instanceof AxiosError) { + if (err.code === CLIENT_ABORTED_ERROR_CODE) { + logger.error({ msg: 'aborted data fetch', err }); + setIsLoading(false); + throw err; } + } else { + logger.error({ msg: 'error fetching data', err }); + enqueueSnackbar(JSON.stringify(err), { variant: 'error' }); } - - return features; - } catch (err) { - logger.error({ msg: 'error fetching data', err }); - enqueueSnackbar(JSON.stringify(err), { variant: 'error' }); + } finally { + setIsLoading(false); } }; @@ -234,11 +333,11 @@ export const App: React.FC = () => { const layer = new GeoJsonLayer({ id: GEOJSON_LAYER_ID, ...CONSTANT_GEOJSON_LAYER_PROPERTIES, - data: fetchData(), + data: loadedData, dataTransform: transformFuncWrapper(statsTable.metric), - dataComparator: comparatorFuncWrapper(appHelper, setStatsTable), - filterRange: filterRangeFuncWrapper(appHelper.currentZoomLevel), - getFillColor: (tile: Feature): [number, number, number, number] => { + dataComparator: comparatorFuncWrapper(setStatsTable), + filterRange: isPaused ? [MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL] : filterRangeFuncWrapper(queryZoom), + getFillColor: (tile: Feature): [number, number, number, number] => { if (!statsTable.metric) { return DEFAULT_TILE_COLOR; } @@ -271,13 +370,22 @@ export const App: React.FC = () => { zoomLevel={appHelper.currentZoomLevel} selectedKit={selectedKit} stateRange={stateRange} + queryZoom={queryZoom} selectedMetric={selectedMetric} selectedColorScale={selectedColorScale} + shouldFollowZoom={shouldFollowZoom} + shouldQueryCurrentState={shouldQueryCurrentState} + isPaused={isPaused} + isLoading={isLoading} onKitChange={handleKitChange} onStateRangeChange={handleKitStateChange} + onQueryZoomChange={handleQueryZoomChange} onMetricChange={handleMetricChange} onColorScaleChange={handleColorScaleChange} onGoToClicked={goToCoordinates} + onShouldFollowZoomChange={handleShouldFollowZoomChange} + onShouldQueryCurrentStateChange={handleShouldQueryCurrentStateChange} + onActionClicked={handleActionClicked} /> diff --git a/packages/frontend/src/components/overviewMap.tsx b/packages/frontend/src/components/overviewMap.tsx index 810f54d..1f03f06 100644 --- a/packages/frontend/src/components/overviewMap.tsx +++ b/packages/frontend/src/components/overviewMap.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useMemo } from 'react'; import { GeoJsonLayer } from '@deck.gl/layers'; import DeckGL from '@deck.gl/react'; import { Map } from 'react-map-gl'; @@ -9,7 +9,7 @@ import { Feature } from 'geojson'; import { differenceWith } from 'lodash'; import { INITIAL_VIEW_STATE, ZOOM_OFFEST } from '../utils/constants'; import { Bounds, MapLibreGL } from '../deck-gl/types'; -import { CONSTANT_GEOJSON_LAYER_PROPERTIES, OVERVIEW_BASEMAP_LAYER_ID } from '../deck-gl/constants'; +import { CONSTANT_GEOJSON_LAYER_PROPERTIES, OVERVIEW_BASEMAP_LAYER_ID, OVERVIEW_GEOJSON_LAYER_ID } from '../deck-gl/constants'; import { bboxToFeature, bboxToLonLat } from '../utils/helpers'; import { basemapLayerFactory } from '../deck-gl/basemap'; import { DEFAULT_COLORED_ALPHA } from '../utils/style'; @@ -33,25 +33,31 @@ export const OverviewMap: React.FC = ({ bounds, zoom }) => { const [viewState] = useState({ ...INITIAL_VIEW_STATE, longitude: lon, latitude: lat, zoom: zoom - ZOOM_OFFEST }); - const overviewGeojsonLayer = new GeoJsonLayer({ - ...CONSTANT_GEOJSON_LAYER_PROPERTIES, - getFillColor: theme.palette.mode === 'dark' ? [...DARK_MODE_MAIN_RGB, DEFAULT_COLORED_ALPHA] : [...LIGHT_MODE_MAIN_RGB, DEFAULT_COLORED_ALPHA], - pickable: true, - getLineWidth: 2, - getLineColor: BACKGROUND_RGBA, - data: [{ ...bboxToFeature(bbox), id: `${zoom},${bbox.west},${bbox.south},${bbox.east},${bbox.north}` }] as Feature[], - dataComparator: (nextData: unknown, prevData: unknown): boolean => { - const comparator = (geojson1: Feature, geojson2: Feature): boolean => geojson1.id === geojson2.id; - const difference = differenceWith(nextData as Feature[], prevData as Feature[], comparator); - const shouldSkipRedering = difference.length === 0; - return shouldSkipRedering; - }, - }); - - const overviewBaseLayer = basemapLayerFactory(OVERVIEW_BASEMAP_LAYER_ID); + const overviewData = useMemo((): Feature[] => { + return [{ ...bboxToFeature(bbox), id: `${zoom},${bbox.west},${bbox.south},${bbox.east},${bbox.north}` }]; + }, [zoom, bbox.east, bbox.north, bbox.south, bbox.west]); + + const layers = [ + basemapLayerFactory(OVERVIEW_BASEMAP_LAYER_ID), + new GeoJsonLayer({ + id: OVERVIEW_GEOJSON_LAYER_ID, + ...CONSTANT_GEOJSON_LAYER_PROPERTIES, + getFillColor: theme.palette.mode === 'dark' ? [...DARK_MODE_MAIN_RGB, DEFAULT_COLORED_ALPHA] : [...LIGHT_MODE_MAIN_RGB, DEFAULT_COLORED_ALPHA], + pickable: true, + getLineWidth: 2, + getLineColor: BACKGROUND_RGBA, + data: overviewData, + dataComparator: (nextData: unknown, prevData: unknown): boolean => { + const comparator = (geojson1: Feature, geojson2: Feature): boolean => geojson1.id === geojson2.id; + const difference = differenceWith(nextData as Feature[], prevData as Feature[], comparator); + const shouldSkipRedering = difference.length === 0; + return shouldSkipRedering; + }, + }), + ]; return ( - + ); diff --git a/packages/frontend/src/components/preferences.tsx b/packages/frontend/src/components/preferences.tsx index b25bf6d..c7df3e1 100644 --- a/packages/frontend/src/components/preferences.tsx +++ b/packages/frontend/src/components/preferences.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useState } from 'react'; +import { useContext, useState } from 'react'; import { Card, CardContent, @@ -16,12 +16,21 @@ import { Typography, Slider, Input, + Switch, + LinearProgress, + Accordion, + AccordionSummary, + AccordionActions, + Box, } from '@mui/material'; import { styled } from '@mui/material/styles'; import InfoIcon from '@mui/icons-material/Info'; import { KitMetadata } from '@map-colonies/detiler-common'; import LocationOnIcon from '@mui/icons-material/LocationOn'; -import { DEFAULT_MAX_STATE, DEFAULT_MIN_STATE, MAX_KIT_STATE_KEY, ZOOM_OFFEST } from '../utils/constants'; +import PlayCircleFilledWhiteIcon from '@mui/icons-material/PlayCircleFilledWhite'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import PauseCircleIcon from '@mui/icons-material/PauseCircle'; +import { DEFAULT_MAX_STATE, DEFAULT_MIN_STATE, MAX_KIT_STATE_KEY, MAX_ZOOM_LEVEL, MIN_ZOOM_LEVEL, ZOOM_OFFEST } from '../utils/constants'; import './css/styles.css'; import { TargetetEvent } from '../deck-gl/types'; import { Metric, METRICS } from '../utils/metric'; @@ -33,36 +42,65 @@ import { GoToModal } from './goToModal'; const StyledCardContent = styled(CardContent)(` padding: 30px; &:last-child { - padding-bottom: 24px; + padding-bottom: 0px; } `); +const ZOOM_MARKS = [ + { + value: MIN_ZOOM_LEVEL, + label: MIN_ZOOM_LEVEL, + }, + { + value: MAX_ZOOM_LEVEL, + label: MAX_ZOOM_LEVEL, + }, +]; + interface PreferencesProps { kits: KitMetadata[]; - zoomLevel: number; selectedKit?: KitMetadata; + zoomLevel: number; + queryZoom: number; + shouldFollowZoom: boolean; + shouldQueryCurrentState: boolean; stateRange?: number[]; selectedMetric?: Metric; selectedColorScale: { key: ColorScale; value: ColorScaleFunc }; + isPaused: boolean; + isLoading: boolean; onKitChange: (event: TargetetEvent) => void; onStateRangeChange: (event: Event, range: number | number[]) => void; + onQueryZoomChange: (event: Event, range: number | number[]) => void; onMetricChange: (event: TargetetEvent) => void; onColorScaleChange: (event: TargetetEvent) => void; onGoToClicked: (longitude: number, latitude: number, zoom?: number) => void; + onShouldFollowZoomChange: (event: React.ChangeEvent, shouldFollow: boolean) => void; + onShouldQueryCurrentStateChange: (event: React.ChangeEvent, shouldQueryCurrentState: boolean) => void; + onActionClicked: () => void; } export const Preferences: React.FC = ({ kits, zoomLevel: currentZoomLevel, + queryZoom, selectedKit, stateRange, selectedMetric, selectedColorScale, + shouldFollowZoom, + shouldQueryCurrentState, + isPaused, + isLoading, onKitChange, onStateRangeChange, + onQueryZoomChange, onMetricChange, onColorScaleChange, onGoToClicked, + onShouldFollowZoomChange, + onShouldQueryCurrentStateChange, + onActionClicked, }) => { const colorMode = useContext(colorModeContext); const [isModalOpen, setIsModalOpen] = useState(false); @@ -104,6 +142,9 @@ export const Preferences: React.FC = ({ + + {isPaused ? : } + Zoom: {currentZoomLevel + ZOOM_OFFEST} @@ -112,25 +153,60 @@ export const Preferences: React.FC = ({ -
- - - Kit - {kits .sort((a, b) => a.name.localeCompare(b.name)) .map((kit, index) => ( - + {kit.name} ))} - - Metric - {METRICS.map((metric, index) => ( - + {metric.name} @@ -141,8 +217,7 @@ export const Preferences: React.FC = ({ ))} - - Color Scale + = ({ - State Range - 'State range'} - marks={marks} - min={minStateValue} - max={maxStateValue} - value={stateRange} - onChange={onStateRangeChange} - valueLabelDisplay="auto" - /> - - Min: - - Max: - - + + } aria-controls="panel3-content" id="panel3-header"> + State Range + + + + + all + + current + + 'State range'} + marks={marks} + min={minStateValue} + max={maxStateValue} + value={stateRange} + onChange={onStateRangeChange} + valueLabelDisplay="auto" + size="small" + /> + + Min: + + Max: + + + + + +
+ {isLoading ? : null}
diff --git a/packages/frontend/src/components/sidebar.tsx b/packages/frontend/src/components/sidebar.tsx index 12fbdce..7a3f678 100644 --- a/packages/frontend/src/components/sidebar.tsx +++ b/packages/frontend/src/components/sidebar.tsx @@ -16,12 +16,16 @@ import RefreshIcon from '@mui/icons-material/Refresh'; import { presentifyValue } from '../utils/metric'; import { LOAD_TIMEOUT_MS, METATILE_SIZE, ZOOM_OFFEST } from '../utils/constants'; import { bboxToLonLat, promiseWithTimeout } from '../utils/helpers'; +import { config } from '../config'; +import { AppConfig } from '../utils/interfaces'; -const TILES_PER_PAGE = 4; +const DEFAULT_TILES_PER_PAGE = 4; const FIRST_PAGE = 1; const DRAWER_WIDTH = 345; const SUCCESS_COPY_MESSAGE = 'Copied to Clipboard'; +const tilesPerPage = config.get('app').style.tilesPerPage ?? DEFAULT_TILES_PER_PAGE; + const StyledCardContent = styled(CardContent)(` padding: 10px; &:last-child { @@ -52,8 +56,8 @@ export const Sidebar: React.FC = ({ isOpen, data, onClose, onGoToC return null; } - const startIndex = (currentPage - 1) * TILES_PER_PAGE; - const endIndex = startIndex + TILES_PER_PAGE; + const startIndex = (currentPage - 1) * tilesPerPage; + const endIndex = startIndex + tilesPerPage; const currentData = data.slice(startIndex, endIndex); const handlePageChange = (_: React.ChangeEvent, page: number): void => { @@ -137,17 +141,55 @@ export const Sidebar: React.FC = ({ isOpen, data, onClose, onGoToC
State: {tile.state}
+ States: {presentifyValue(tile.states)} +
Created At: {presentifyValue(tile.createdAt, 'date')}
Updated At: {presentifyValue(tile.updatedAt, 'date')}
Rendered At: {presentifyValue(tile.renderedAt, 'date')}
- Update Count: {tile.updateCount} -
- Render Count: {tile.renderCount} -
- Skip Count: {tile.skipCount} + Counts:{' '} + + {tile.updateCount} + + + {tile.renderCount} + + + {tile.skipCount} + @@ -161,8 +203,8 @@ export const Sidebar: React.FC = ({ isOpen, data, onClose, onGoToC )} - {data.length > TILES_PER_PAGE && ( - + {data.length > tilesPerPage && ( + )} diff --git a/packages/frontend/src/config/index.ts b/packages/frontend/src/config/index.ts index f1eb9a9..63fed6f 100644 --- a/packages/frontend/src/config/index.ts +++ b/packages/frontend/src/config/index.ts @@ -46,6 +46,15 @@ export const config: IConfig = (function (): IConfig { }, style: { dataAlphaChannel: viteConfig.CONFIG_APP_DATA_ALPHA_CHANNEL !== undefined ? parseInt(viteConfig.CONFIG_APP_DATA_ALPHA_CHANNEL) : undefined, + tilesPerPage: viteConfig.CONFIG_APP_UI_TILES_PER_PAGE !== undefined ? parseInt(viteConfig.CONFIG_APP_UI_TILES_PER_PAGE) : undefined, + }, + kits: { + fetchInterval: viteConfig.CONFIG_APP_KITS_FETCH_INTERVAL !== undefined ? parseInt(viteConfig.CONFIG_APP_KITS_FETCH_INTERVAL) : undefined, + }, + tiles: { + batchSize: viteConfig.CONFIG_APP_TILES_BATCH_SIZE !== undefined ? parseInt(viteConfig.CONFIG_APP_TILES_BATCH_SIZE) : undefined, + fetchInterval: viteConfig.CONFIG_APP_TILES_FETCH_INTERVAL !== undefined ? parseInt(viteConfig.CONFIG_APP_TILES_FETCH_INTERVAL) : undefined, + fetchTimeout: viteConfig.CONFIG_APP_TILES_FETCH_TIMEOUT !== undefined ? parseInt(viteConfig.CONFIG_APP_TILES_FETCH_TIMEOUT) : undefined, }, }; diff --git a/packages/frontend/src/deck-gl/constants.ts b/packages/frontend/src/deck-gl/constants.ts index 5e0cdf2..349e377 100644 --- a/packages/frontend/src/deck-gl/constants.ts +++ b/packages/frontend/src/deck-gl/constants.ts @@ -7,7 +7,7 @@ import { MAX_ZOOM_LEVEL, MIN_ZOOM_LEVEL } from '../utils/constants'; export const BASEMAP_LAYER_ID = 'main-basemap-layer'; export const GEOJSON_LAYER_ID = 'main-geojson-layer'; -export const OVERVIEW_BASEMAP_LAYER_ID = 'overview-geojson-layer'; +export const OVERVIEW_BASEMAP_LAYER_ID = 'overview-basemap-layer'; export const OVERVIEW_GEOJSON_LAYER_ID = 'overview-geojson-layer'; export const CONSTANT_GEOJSON_LAYER_PROPERTIES: Partial = { diff --git a/packages/frontend/src/deck-gl/index.ts b/packages/frontend/src/deck-gl/index.ts index b1012f0..10143b4 100644 --- a/packages/frontend/src/deck-gl/index.ts +++ b/packages/frontend/src/deck-gl/index.ts @@ -2,25 +2,40 @@ import { Feature } from 'geojson'; import { differenceWith } from 'lodash'; import { insertDummyFeature, removeDummyFeature } from '../utils/helpers'; import { Stats } from '../utils/stats'; -import { Metric } from '../utils/metric'; +import { findNumericMinMax, Metric, updateMinMax } from '../utils/metric'; import { normalizeValue } from '../utils/style'; -import { MAX_ZOOM_LEVEL, ZOOM_OFFEST } from '../utils/constants'; -import { AppHelper } from '../utils/interfaces'; - -type TransformFunc = (data: T) => T; +import { MAX_ZOOM_LEVEL } from '../utils/constants'; +import { appHelper } from '../utils/helpers'; type ComparatorFunc = (nextData: T, prevData: T) => boolean; +export type TransformFunc = (data: T) => T; + export const transformFuncWrapper = (metric: Metric | undefined): TransformFunc => { const transformFunc = (data: Feature[]): Feature[] => { if (metric !== undefined) { - data.forEach((feature) => { - if (feature.properties !== null) { - const value = feature.properties[metric.property] as number; - const normalizedValue = normalizeValue(value, metric.range); - feature.properties['score'] = normalizedValue; + const metricPropertyArr = data + .map((feature) => { + if (feature.properties?.[metric.property] !== undefined) { + return feature.properties[metric.property] as number; + } + }) + .filter((property) => property !== undefined); + + if (metricPropertyArr.length !== 0) { + const currentMinMax = findNumericMinMax(metricPropertyArr as unknown[] as number[]); + if (currentMinMax !== null) { + updateMinMax(currentMinMax, metric); } - }); + + data.forEach((feature) => { + if (feature.properties !== null) { + const value = feature.properties[metric.property] as number; + const normalizedValue = normalizeValue(value, metric.range); + feature.properties['score'] = normalizedValue; + } + }); + } } // to accomplish rendering empty data @@ -34,12 +49,13 @@ export const transformFuncWrapper = (metric: Metric | undefined): TransformFunc< return transformFunc; }; -export const comparatorFuncWrapper = (helper: AppHelper, setStatsTable: (value: React.SetStateAction) => void): ComparatorFunc => { +export const comparatorFuncWrapper = (setStatsTable: (value: React.SetStateAction) => void): ComparatorFunc => { const comparatorFunc = (nextData: Feature[], prevData: Feature[]): boolean => { let shouldSkipRedering = false; + // render if override flag is enabled or next data is greater than prev - if (helper.shouldOverrideComarator || prevData.length < nextData.length) { - helper.shouldOverrideComarator = false; + if (appHelper.shouldOverrideComarator || prevData.length < nextData.length) { + appHelper.shouldOverrideComarator = false; } else { // render if new data is not contained in prev data const comparator = (tile1: Feature, tile2: Feature): boolean => tile1.properties?.id === tile2.properties?.id; @@ -74,5 +90,5 @@ export const comparatorFuncWrapper = (helper: AppHelper, setStatsTable: (value: }; export const filterRangeFuncWrapper = (zoom: number): [number, number] => { - return [Math.min(zoom + ZOOM_OFFEST, MAX_ZOOM_LEVEL), Math.min(zoom + ZOOM_OFFEST, MAX_ZOOM_LEVEL)]; + return [Math.min(zoom, MAX_ZOOM_LEVEL), Math.min(zoom, MAX_ZOOM_LEVEL)]; }; diff --git a/packages/frontend/src/env.d.ts b/packages/frontend/src/env.d.ts index 6c8d95b..5472dd3 100644 --- a/packages/frontend/src/env.d.ts +++ b/packages/frontend/src/env.d.ts @@ -17,7 +17,12 @@ interface AppConfig { readonly CONFIG_APP_BASEMAP_TILE_SIZE?: string; readonly CONFIG_APP_BASEMAP_ZOOM_OFFSET?: string; readonly CONFIG_APP_BASEMAP_DESATURATE?: string; + readonly CONFIG_APP_UI_TILES_PER_PAGE?: string; readonly CONFIG_APP_DATA_ALPHA_CHANNEL?: string; + readonly CONFIG_APP_KITS_FETCH_INTERVAL?: string; + readonly CONFIG_APP_TILES_FETCH_INTERVAL?: string; + readonly CONFIG_APP_TILES_BATCH_SIZE?: string; + readonly CONFIG_APP_TILES_FETCH_TIMEOUT?: string; } interface ImportMetaEnv extends AppConfig, DetilerClientConfig { diff --git a/packages/frontend/src/utils/constants.ts b/packages/frontend/src/utils/constants.ts index bc4ecef..f83733a 100644 --- a/packages/frontend/src/utils/constants.ts +++ b/packages/frontend/src/utils/constants.ts @@ -1,7 +1,6 @@ export const ZOOM_OFFEST = 3; export const MIN_ZOOM_LEVEL = 0; export const MAX_ZOOM_LEVEL = 21; -export const FETCH_KITS_INTERVAL = 60000; export const MILLISECONDS_IN_SECOND = 1000; export const MIN_LONGITUDE = -179.99999; @@ -32,3 +31,10 @@ export const DEFAULT_MIN_STATE = -1; export const DEFAULT_MAX_STATE = 1; export const MAX_KIT_STATE_KEY = 'maxState'; +export const CLIENT_ABORTED_ERROR_CODE = 'ECONNABORTED'; + +export const DEFAULT_KITS_FETCH_INTERVAL = 60000; + +export const DEFAULT_TILES_FETCH_INTERVAL = 2000; +export const DEFAULT_TILES_BATCH_SIZE = 1000; +export const DEFAULT_TILES_FETCH_TIMEOUT = 1500; diff --git a/packages/frontend/src/utils/helpers.ts b/packages/frontend/src/utils/helpers.ts index 9d6165b..6f1a229 100644 --- a/packages/frontend/src/utils/helpers.ts +++ b/packages/frontend/src/utils/helpers.ts @@ -40,6 +40,8 @@ export const compareQueries = (prev: TileQueryParams | undefined, next: TileQuer prev.kits[0] !== next.kits[0] || prev.minZoom !== next.minZoom || prev.maxZoom !== next.maxZoom || + prev.minState !== next.minState || + prev.maxState !== next.maxState || prev.bbox[0] !== next.bbox[0] || prev.bbox[1] !== next.bbox[1] || prev.bbox[2] !== next.bbox[2] || @@ -105,13 +107,13 @@ export const parseDataToFeatures = (data: TileDetails[]): Feature[] => { export const insertDummyFeature = (features: Feature[]): Feature[] => { if (features.length === 0) { - features.push({ type: 'Feature', id: FEATURE_ID_DUMMY, properties: {}, geometry: { type: 'Point', coordinates: [] } }); + features.push({ type: 'Feature', properties: { id: FEATURE_ID_DUMMY }, geometry: { type: 'Point', coordinates: [] } }); } return features; }; export const removeDummyFeature = (features?: Feature[]): Feature[] | undefined => { - if (features?.length === 1 && features[0].id === FEATURE_ID_DUMMY) { + if (features?.length === 1 && features[0].properties?.id === FEATURE_ID_DUMMY) { features.splice(0, 1); } return features; @@ -157,4 +159,7 @@ export const appHelper: AppHelper = { bounds: {}, lastDetilerQueryParams: undefined, shouldOverrideComarator: false, + shouldFetch: false, + selectedKit: undefined, + queryZoom: ZOOM_OFFEST, }; diff --git a/packages/frontend/src/utils/interfaces.ts b/packages/frontend/src/utils/interfaces.ts index 9d97a32..9537d26 100644 --- a/packages/frontend/src/utils/interfaces.ts +++ b/packages/frontend/src/utils/interfaces.ts @@ -11,8 +11,17 @@ export interface AppConfig { desaturate?: number; }; style: { + tilesPerPage?: number; dataAlphaChannel?: number; }; + kits: { + fetchInterval?: number; + }; + tiles: { + batchSize?: number; + fetchInterval?: number; + fetchTimeout?: number; + }; } export interface AppHelper { @@ -21,4 +30,7 @@ export interface AppHelper { bounds: { actual?: Bounds; query?: Bounds }; lastDetilerQueryParams?: TileQueryParams; shouldOverrideComarator: boolean; + shouldFetch: boolean; + selectedKit?: string; + queryZoom: number; } diff --git a/packages/frontend/src/utils/metric.ts b/packages/frontend/src/utils/metric.ts index e2af04b..5d8d673 100644 --- a/packages/frontend/src/utils/metric.ts +++ b/packages/frontend/src/utils/metric.ts @@ -1,6 +1,8 @@ import { TileDetails } from '@map-colonies/detiler-common'; import { MILLISECONDS_IN_SECOND } from './constants'; +const SECOND_TO_LAST = 2; +const THIRD_TO_LAST = 3; const DIGITS_AFTER_DECIMAL = 6; type PresentationType = 'date' | 'string'; @@ -70,6 +72,27 @@ export const findMinMax = (arr: T[], property: keyof T): MinMax | null => { return { min: minValue, max: maxValue }; }; +export const findNumericMinMax = (arr: number[]): MinMax | null => { + if (arr.length === 0) { + return null; + } + + let minValue = arr[0]; + let maxValue = arr[0]; + + for (const value of arr) { + if (value < minValue) { + minValue = value; + } + + if (value > maxValue) { + maxValue = value; + } + } + + return { min: minValue, max: maxValue }; +}; + export const updateMinMax = (current: MinMax, metric: Omit & { range: MinMax }): void => { if (metric.minFn === undefined) { if (current.min < metric.range.min) { @@ -92,13 +115,13 @@ export const updateMinMax = (current: MinMax, metric: Omit & { } }; -export const presentifyValue = (value: number | undefined, type: PresentationType = 'string'): string => { +export const presentifyValue = (value: number | number[] | undefined, type: PresentationType = 'string'): string => { if (value === undefined || value === Number.MAX_SAFE_INTEGER || value === Number.MIN_SAFE_INTEGER) { return 'N/A'; } if (type === 'date') { - return `${new Date(value * MILLISECONDS_IN_SECOND).toISOString().split('.')[0]}`; + return `${new Date((value as number) * MILLISECONDS_IN_SECOND).toISOString().split('.')[0]}`; } if (typeof value === 'number') { @@ -108,5 +131,13 @@ export const presentifyValue = (value: number | undefined, type: PresentationTyp return value.toFixed(DIGITS_AFTER_DECIMAL).toString(); } + if (typeof value === 'object') { + const length = value.length; + if (length <= THIRD_TO_LAST) { + return `[${value.toString()}]`; + } + return `[...,${value[length - THIRD_TO_LAST]},${value[length - SECOND_TO_LAST]},${value[length - 1]}]`; + } + return value; };