From 9a15d190eda8272226e045cc144807016958b0d4 Mon Sep 17 00:00:00 2001 From: TheoryOfNekomata Date: Tue, 4 Jul 2023 17:42:23 +0800 Subject: [PATCH] Update image utils Provide logic for server. --- packages/image-utils/package.json | 5 +- packages/image-utils/src/client.ts | 38 +++ packages/image-utils/src/common.ts | 13 + packages/image-utils/src/index.ts | 48 +--- packages/image-utils/src/server.ts | 19 ++ .../web-kitchensink-reactnext/next.config.js | 6 + .../src/utils/blob.ts | 4 +- pnpm-lock.yaml | 234 +++++++++++++++++- 8 files changed, 325 insertions(+), 42 deletions(-) create mode 100644 packages/image-utils/src/client.ts create mode 100644 packages/image-utils/src/common.ts create mode 100644 packages/image-utils/src/server.ts diff --git a/packages/image-utils/package.json b/packages/image-utils/package.json index ca2769f..2bc261c 100644 --- a/packages/image-utils/package.json +++ b/packages/image-utils/package.json @@ -13,6 +13,7 @@ "pridepack" ], "devDependencies": { + "@types/get-image-colors": "^4.0.2", "@types/node": "^18.14.1", "eslint": "^8.35.0", "eslint-config-lxsmnsyc": "^0.5.0", @@ -47,7 +48,9 @@ "access": "public" }, "dependencies": { - "colorthief": "^2.4.0" + "colorthief": "^2.4.0", + "get-image-colors": "^4.0.1", + "image-size": "^1.0.2" }, "types": "./dist/types/index.d.ts", "main": "./dist/cjs/production/index.js", diff --git a/packages/image-utils/src/client.ts b/packages/image-utils/src/client.ts new file mode 100644 index 0000000..5f4769e --- /dev/null +++ b/packages/image-utils/src/client.ts @@ -0,0 +1,38 @@ +import ColorThief from 'colorthief'; +import {DEFAULT_PALETTE_COLOR_COUNT, GetImageMetadataOptions, ImageMetadata} from './common'; + +const doGetImageMetadata = async (thisImage: HTMLImageElement, options = {} as GetImageMetadataOptions) => { + const { paletteColorCount = DEFAULT_PALETTE_COLOR_COUNT } = options; + const colorThief = new ColorThief(); + const palette = await colorThief.getPalette(thisImage, paletteColorCount); + return { + width: thisImage.naturalWidth, + height: thisImage.naturalHeight, + palette, + }; +}; + +export const getMetadataFromElement = (thisImage: HTMLImageElement, options?: GetImageMetadataOptions): Promise => doGetImageMetadata(thisImage, options); + +export const getMetadataFromUrl = (imageUrl: string, options = {} as GetImageMetadataOptions): Promise => new Promise((resolve, reject) => { + const image = new Image(); + + image.addEventListener('load', async (imageLoadEvent) => { + const thisImage = imageLoadEvent.currentTarget as HTMLImageElement; + const metadata = await doGetImageMetadata(thisImage, options); + image.remove(); + resolve(metadata); + }); + + image.addEventListener('error', () => { + reject(new Error('Could not load file as image')); + image.remove(); + }); + + if (imageUrl === undefined) { + resolve({}); + return; + } + + image.src = imageUrl; +}); diff --git a/packages/image-utils/src/common.ts b/packages/image-utils/src/common.ts new file mode 100644 index 0000000..f3a6c75 --- /dev/null +++ b/packages/image-utils/src/common.ts @@ -0,0 +1,13 @@ +export type RgbTuple = [number, number, number]; + +export interface ImageMetadata { + width?: number; + height?: number; + palette?: RgbTuple[]; +} + +export const DEFAULT_PALETTE_COLOR_COUNT = 8 as const; + +export interface GetImageMetadataOptions { + paletteColorCount?: number; +} diff --git a/packages/image-utils/src/index.ts b/packages/image-utils/src/index.ts index a14eb7a..7214b05 100644 --- a/packages/image-utils/src/index.ts +++ b/packages/image-utils/src/index.ts @@ -1,39 +1,15 @@ -import ColorThief from 'colorthief'; - -type RgbTuple = [number, number, number]; - -export interface ImageMetadata { - width?: number; - height?: number; - palette?: RgbTuple[]; -} - -export const getImageMetadata = (imageUrl?: string) => new Promise((resolve, reject) => { - // TODO server side - const image = new Image(); - - image.addEventListener('load', async (imageLoadEvent) => { - const thisImage = imageLoadEvent.currentTarget as HTMLImageElement; - const colorThief = new ColorThief(); - const palette = await colorThief.getPalette(thisImage, 8); - const metadata = { - width: thisImage.naturalWidth, - height: thisImage.naturalHeight, - palette, - }; - image.remove(); - resolve(metadata); - }); - - image.addEventListener('error', () => { - reject(new Error('Could not load file as image')); - image.remove(); - }); - +export const getMetadataFromUrl = async (imageUrl?: string) => { if (imageUrl === undefined) { - resolve({}); - return; + return {}; + } + + if (typeof window !== 'undefined') { + const { getMetadataFromUrl: client } = await import('./client'); + return client(imageUrl); } - image.src = imageUrl; -}); + const { getMetadataFromUrl: server } = await import('./server'); + return server(imageUrl); +}; + +export * from './common'; diff --git a/packages/image-utils/src/server.ts b/packages/image-utils/src/server.ts new file mode 100644 index 0000000..96d54ad --- /dev/null +++ b/packages/image-utils/src/server.ts @@ -0,0 +1,19 @@ +import {DEFAULT_PALETTE_COLOR_COUNT, GetImageMetadataOptions, ImageMetadata} from './common'; + +const doGetImageMetadata = async (input: string | Buffer, options = {} as GetImageMetadataOptions) => { + const { paletteColorCount = DEFAULT_PALETTE_COLOR_COUNT } = options; + const { imageSize, disableFS } = await import('image-size'); + disableFS(true); + const { default: getColors } = await import('get-image-colors'); + const dimensions = imageSize(input); + const palette = await getColors(input, { count: paletteColorCount }); + return { + width: dimensions.width, + height: dimensions.height, + palette: palette.map((color) => color.rgb()), + }; +}; + +export const getMetadataFromUrl = (imageUrl: string, options?: GetImageMetadataOptions): Promise => doGetImageMetadata(imageUrl, options); + +export const getMetadataFromBuffer = (buffer: Buffer, options?: GetImageMetadataOptions): Promise => doGetImageMetadata(buffer, options); diff --git a/packages/web-kitchensink-reactnext/next.config.js b/packages/web-kitchensink-reactnext/next.config.js index a843cbe..b255dd9 100644 --- a/packages/web-kitchensink-reactnext/next.config.js +++ b/packages/web-kitchensink-reactnext/next.config.js @@ -1,6 +1,12 @@ /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, + webpack: (config, { isServer }) => { + if (!isServer) { + config.resolve.fallback.fs = false; + } + return config; + } } module.exports = nextConfig diff --git a/packages/web-kitchensink-reactnext/src/utils/blob.ts b/packages/web-kitchensink-reactnext/src/utils/blob.ts index b8e0af3..42cbc4b 100644 --- a/packages/web-kitchensink-reactnext/src/utils/blob.ts +++ b/packages/web-kitchensink-reactnext/src/utils/blob.ts @@ -1,6 +1,6 @@ import * as mimeTypes from 'mime-types'; import {getTextMetadata, TextMetadata} from '@modal-soft/text-utils'; -import {getImageMetadata, ImageMetadata} from '@modal-soft/image-utils'; +import {getMetadataFromUrl, ImageMetadata} from '@modal-soft/image-utils'; import {getAudioMetadata, AudioMetadata} from '@modal-soft/audio-utils'; import {getVideoMetadata, VideoFileMetadata} from '@modal-soft/video-utils'; @@ -164,7 +164,7 @@ export interface ImageFile extends FileWithResolvedContentType { export const augmentImageFile = async >(file: T): Promise => { const fileMutable = file as unknown as Record; - fileMutable.metadata = await getImageMetadata(file.url); + fileMutable.metadata = await getMetadataFromUrl(file.url); return fileMutable as unknown as ImageFile; }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5061973..99d1d7e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,7 +39,16 @@ importers: colorthief: specifier: ^2.4.0 version: 2.4.0 + get-image-colors: + specifier: ^4.0.1 + version: 4.0.1 + image-size: + specifier: ^1.0.2 + version: 1.0.2 devDependencies: + '@types/get-image-colors': + specifier: ^4.0.2 + version: 4.0.2 '@types/node': specifier: ^18.14.1 version: 18.14.1 @@ -916,6 +925,17 @@ packages: resolution: {integrity: sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==} dev: true + /@types/chroma-js@2.4.0: + resolution: {integrity: sha512-JklMxityrwjBTjGY2anH8JaTx3yjRU3/sEHSblLH1ba5lqcSh1LnImXJZO5peJfXyqKYWjHTGy4s5Wz++hARrw==} + dev: true + + /@types/get-image-colors@4.0.2: + resolution: {integrity: sha512-8E/xA3Dyl70sboWbjjt+UEHTC2Nvv6EIDxPx5nCSTN+QfBWbx60gGyBH0pQ9ABrRNqQ2gKtGboK3MoZodxMWtw==} + dependencies: + '@types/chroma-js': 2.4.0 + '@types/node': 18.14.1 + dev: true + /@types/hast@2.3.4: resolution: {integrity: sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==} dependencies: @@ -1411,7 +1431,6 @@ packages: /boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - dev: true /bplist-parser@0.2.0: resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==} @@ -1547,6 +1566,28 @@ packages: resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} dev: true + /cheerio@0.22.0: + resolution: {integrity: sha512-8/MzidM6G/TgRelkzDG13y3Y9LxBjCb+8yOEZ9+wwq5gVF2w2pV0wmHvjfT0RvuxGyR7UEuK36r+yYMbT4uKgA==} + engines: {node: '>= 0.6'} + dependencies: + css-select: 1.2.0 + dom-serializer: 0.1.1 + entities: 1.1.2 + htmlparser2: 3.10.1 + lodash.assignin: 4.2.0 + lodash.bind: 4.2.1 + lodash.defaults: 4.2.0 + lodash.filter: 4.6.0 + lodash.flatten: 4.4.0 + lodash.foreach: 4.5.0 + lodash.map: 4.6.0 + lodash.merge: 4.6.2 + lodash.pick: 4.4.0 + lodash.reduce: 4.6.0 + lodash.reject: 4.6.0 + lodash.some: 4.6.0 + dev: false + /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -1562,6 +1603,10 @@ packages: fsevents: 2.3.2 dev: false + /chroma-js@2.4.2: + resolution: {integrity: sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A==} + dev: false + /cli-cursor@4.0.0: resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1695,6 +1740,19 @@ packages: engines: {node: '>=8'} dev: true + /css-select@1.2.0: + resolution: {integrity: sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA==} + dependencies: + boolbase: 1.0.0 + css-what: 2.1.3 + domutils: 1.5.1 + nth-check: 1.0.2 + dev: false + + /css-what@2.1.3: + resolution: {integrity: sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==} + dev: false + /cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -1844,6 +1902,37 @@ packages: dependencies: esutils: 2.0.3 + /dom-serializer@0.1.1: + resolution: {integrity: sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==} + dependencies: + domelementtype: 1.3.1 + entities: 1.1.2 + dev: false + + /domelementtype@1.3.1: + resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==} + dev: false + + /domhandler@2.4.2: + resolution: {integrity: sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==} + dependencies: + domelementtype: 1.3.1 + dev: false + + /domutils@1.5.1: + resolution: {integrity: sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==} + dependencies: + dom-serializer: 0.1.1 + domelementtype: 1.3.1 + dev: false + + /domutils@1.7.0: + resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==} + dependencies: + dom-serializer: 0.1.1 + domelementtype: 1.3.1 + dev: false + /dot-prop@5.3.0: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} engines: {node: '>=8'} @@ -1884,6 +1973,10 @@ packages: graceful-fs: 4.2.11 tapable: 2.2.1 + /entities@1.1.2: + resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==} + dev: false + /es-abstract@1.21.2: resolution: {integrity: sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==} engines: {node: '>= 0.4'} @@ -2492,6 +2585,13 @@ packages: /fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + /fast-xml-parser@4.2.5: + resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==} + hasBin: true + dependencies: + strnum: 1.0.5 + dev: false + /fastq@1.15.0: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} dependencies: @@ -2599,6 +2699,16 @@ packages: resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} dev: true + /get-image-colors@4.0.1: + resolution: {integrity: sha512-UVw9LdFemitTVCpwZY33JUkedmY1kNt0UGoneVMzbD12GkBja67/jX2AJFsJOCDefea0oCFFf9z9pa5fjKhAQw==} + dependencies: + chroma-js: 2.4.2 + get-pixels: 3.3.3 + get-rgba-palette: 2.0.1 + get-svg-colors: 2.0.0 + pify: 5.0.0 + dev: false + /get-intrinsic@1.2.1: resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} dependencies: @@ -2623,10 +2733,26 @@ packages: through: 2.3.8 dev: false + /get-rgba-palette@2.0.1: + resolution: {integrity: sha512-rYbQg/u2tGnRYWuYHNMcF/nDg0WakAbQRiYLM86AE96d2MA0oYPaphsuywSoYajG0PImMZEEjKbtY4UuL/620A==} + dependencies: + quantize: 1.0.2 + dev: false + /get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} + /get-svg-colors@2.0.0: + resolution: {integrity: sha512-okpaFZob1vGeJJm7s1704Ny/3DgmLhwn2S7NYjeLSrwTBm+xylNXZn+N2xBi8AQkNGTIWu3V1fkqgrMo4X6+Gg==} + dependencies: + cheerio: 0.22.0 + chroma-js: 2.4.2 + is-svg: 4.4.0 + lodash.compact: 3.0.1 + lodash.uniq: 4.5.0 + dev: false + /get-symbol-description@1.0.0: resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} engines: {node: '>= 0.4'} @@ -2815,6 +2941,17 @@ packages: space-separated-tokens: 1.1.5 dev: false + /htmlparser2@3.10.1: + resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==} + dependencies: + domelementtype: 1.3.1 + domhandler: 2.4.2 + domutils: 1.7.0 + entities: 1.1.2 + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: false + /http-signature@1.2.0: resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} engines: {node: '>=0.8', npm: '>=1.3.7'} @@ -2840,6 +2977,14 @@ packages: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} + /image-size@1.0.2: + resolution: {integrity: sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + queue: 6.0.2 + dev: false + /import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -3031,6 +3176,13 @@ packages: dependencies: has-tostringtag: 1.0.0 + /is-svg@4.4.0: + resolution: {integrity: sha512-v+AgVwiK5DsGtT9ng+m4mClp6zDAmwrW8nZi6Gg15qzvBnRWWdfWA1TGaXyCDnWq5g5asofIgMVl3PjKxvk1ug==} + engines: {node: '>=6'} + dependencies: + fast-xml-parser: 4.2.5 + dev: false + /is-symbol@1.0.4: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} @@ -3217,6 +3369,38 @@ packages: dependencies: p-locate: 5.0.0 + /lodash.assignin@4.2.0: + resolution: {integrity: sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg==} + dev: false + + /lodash.bind@4.2.1: + resolution: {integrity: sha512-lxdsn7xxlCymgLYo1gGvVrfHmkjDiyqVv62FAeF2i5ta72BipE1SLxw8hPEPLhD4/247Ijw07UQH7Hq/chT5LA==} + dev: false + + /lodash.compact@3.0.1: + resolution: {integrity: sha512-2ozeiPi+5eBXW1CLtzjk8XQFhQOEMwwfxblqeq6EGyTxZJ1bPATqilY0e6g2SLQpP4KuMeuioBhEnWz5Pr7ICQ==} + dev: false + + /lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + dev: false + + /lodash.filter@4.6.0: + resolution: {integrity: sha512-pXYUy7PR8BCLwX5mgJ/aNtyOvuJTdZAo9EQFUvMIYugqmJxnrYaANvTbgndOzHSCSR0wnlBBfRXJL5SbWxo3FQ==} + dev: false + + /lodash.flatten@4.4.0: + resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + dev: false + + /lodash.foreach@4.5.0: + resolution: {integrity: sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==} + dev: false + + /lodash.map@4.6.0: + resolution: {integrity: sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==} + dev: false + /lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} dev: true @@ -3224,6 +3408,26 @@ packages: /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + /lodash.pick@4.4.0: + resolution: {integrity: sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==} + dev: false + + /lodash.reduce@4.6.0: + resolution: {integrity: sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw==} + dev: false + + /lodash.reject@4.6.0: + resolution: {integrity: sha512-qkTuvgEzYdyhiJBx42YPzPo71R1aEr0z79kAv7Ixg8wPFEjgRgJdUsGMG3Hf3OYSF/kHI79XhNlt+5Ar6OzwxQ==} + dev: false + + /lodash.some@4.6.0: + resolution: {integrity: sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ==} + dev: false + + /lodash.uniq@4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + dev: false + /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true @@ -3431,6 +3635,12 @@ packages: dependencies: path-key: 4.0.0 + /nth-check@1.0.2: + resolution: {integrity: sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==} + dependencies: + boolbase: 1.0.0 + dev: false + /nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} dependencies: @@ -3672,6 +3882,11 @@ packages: engines: {node: '>=0.10.0'} dev: false + /pify@5.0.0: + resolution: {integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==} + engines: {node: '>=10'} + dev: false + /pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} @@ -3854,9 +4069,20 @@ packages: engines: {node: '>=0.6'} dev: false + /quantize@1.0.2: + resolution: {integrity: sha512-25P7wI2UoDbIQsQp50ARkt+5pwPsOq7G/BqvT5xAbapnRoNWMN8/p55H9TXd5MuENiJnm5XICB2H2aDZGwts7w==} + engines: {node: '>=0.10.21'} + dev: false + /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + /queue@6.0.2: + resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + dependencies: + inherits: 2.0.4 + dev: false + /react-dom@18.2.0(react@18.2.0): resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: @@ -3916,7 +4142,6 @@ packages: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 - dev: true /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} @@ -4239,7 +4464,6 @@ packages: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} dependencies: safe-buffer: 5.2.1 - dev: true /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} @@ -4276,6 +4500,10 @@ packages: acorn: 8.9.0 dev: true + /strnum@1.0.5: + resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + dev: false + /styled-jsx@5.1.1(react@18.2.0): resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} engines: {node: '>= 12.0.0'}