diff --git a/.github/workflows/build-and-publish.yml b/.github/workflows/build-and-publish.yml index 65f344b..642135d 100644 --- a/.github/workflows/build-and-publish.yml +++ b/.github/workflows/build-and-publish.yml @@ -53,7 +53,7 @@ jobs: - name: Build run: | - pnpm build:css + pnpm prebuild pnpm build - uses: actions/upload-artifact@v3 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 2be0945..d008614 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -52,7 +52,7 @@ jobs: - name: Build run: | - pnpm build:css + pnpm prebuild pnpm build - name: Test diff --git a/.gitmodules b/.gitmodules index 519f86b..20457ce 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,7 @@ [submodule "litegraph"] path = litegraph url = https://github.com/space-nuko/litegraph.ts +[submodule "klecks"] + path = klecks + url = https://github.com/space-nuko/klecks + branch = comfybox diff --git a/klecks b/klecks new file mode 160000 index 0000000..a36de32 --- /dev/null +++ b/klecks @@ -0,0 +1 @@ +Subproject commit a36de3203fb970fac80f72be75a8ceee0cb01819 diff --git a/package.json b/package.json index ee0e8d0..e3a4729 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "web2", + "name": "ComfyBox", "version": "0.0.1", "private": true, "scripts": { @@ -13,6 +13,7 @@ "lint": "prettier --plugin-search-dir . --check . && eslint .", "format": "prettier --plugin-search-dir . --write .", "svelte-check": "svelte-check", + "prebuild": "pnpm run build:css && pnpm --filter=klecks lang:build", "build:css": "pollen -c gradio/js/theme/src/pollen.config.cjs && mv src/pollen.css node_modules/@gradio/theme/src" }, "devDependencies": { @@ -28,6 +29,7 @@ "svelte-dnd-action": "^0.9.22", "typescript": "^5.0.3", "vite": "^4.3.1", + "vite-plugin-glsl": "^1.1.2", "vite-plugin-static-copy": "^0.14.0", "vite-plugin-svelte-console-remover": "^1.0.10", "vite-tsconfig-paths": "^4.0.8", @@ -62,6 +64,7 @@ "framework7": "^8.0.3", "framework7-svelte": "^8.0.3", "img-comparison-slider": "^8.0.0", + "klecks": "workspace:*", "pollen-css": "^4.6.2", "radix-icons-svelte": "^1.2.1", "svelte-feather-icons": "^4.0.0", @@ -71,6 +74,7 @@ "svelte-tiny-virtual-list": "^2.0.5", "tailwindcss": "^3.3.1", "typed-emitter": "github:andywer/typed-emitter", + "uuid": "^9.0.0", "vite-plugin-full-reload": "^1.0.5" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cf6e721..0ecaee1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -85,6 +85,9 @@ importers: img-comparison-slider: specifier: ^8.0.0 version: 8.0.0 + klecks: + specifier: workspace:* + version: link:klecks pollen-css: specifier: ^4.6.2 version: 4.6.2 @@ -112,6 +115,9 @@ importers: typed-emitter: specifier: github:andywer/typed-emitter version: github.com/andywer/typed-emitter/9a139b6fa0ec6b0db6141b5b756b784e4f7ef4e4 + uuid: + specifier: ^9.0.0 + version: 9.0.0 vite-plugin-full-reload: specifier: ^1.0.5 version: 1.0.5(vite@4.3.1) @@ -152,6 +158,9 @@ importers: vite: specifier: ^4.3.1 version: 4.3.1(sass@1.61.0) + vite-plugin-glsl: + specifier: ^1.1.2 + version: 1.1.2(vite@4.3.1) vite-plugin-static-copy: specifier: ^0.14.0 version: 0.14.0(vite@4.3.1) @@ -767,6 +776,36 @@ importers: specifier: ~4.5.4 version: 4.5.4 + klecks: + dependencies: + '@parcel/transformer-glsl': + specifier: ^2.8.2 + version: 2.8.3 + '@parcel/transformer-image': + specifier: ^2.8.2 + version: 2.8.3 + '@parcel/transformer-sass': + specifier: ^2.8.2 + version: 2.8.3 + ag-psd: + specifier: ^15.0.1 + version: 15.2.0 + buffer: + specifier: ^5.5.0 + version: 5.7.1 + js-beautify: + specifier: ^1.14.7 + version: 1.14.7 + json5: + specifier: ^2.2.2 + version: 2.2.3 + mdn-polyfills: + specifier: ^5.20.0 + version: 5.20.0 + parcel: + specifier: ^2.8.2 + version: 2.8.3 + litegraph/packages/core: dependencies: '@litegraph-ts/tsconfig': @@ -923,7 +962,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.18.6 - dev: true /@babel/compat-data@7.21.7: resolution: {integrity: sha512-KYMqFYTaenzMK4yUtf4EW9wc4N9ef80FsbMtkwool5zpwl4YrT1SdWYSTRcT94KO4hannogdS+LxY7L+arP3gA==} @@ -1070,7 +1108,6 @@ packages: '@babel/helper-validator-identifier': 7.19.1 chalk: 2.4.2 js-tokens: 4.0.0 - dev: true /@babel/parser@7.21.4: resolution: {integrity: sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==} @@ -1273,6 +1310,13 @@ packages: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true + /@choojs/findup@0.2.1: + resolution: {integrity: sha512-YstAqNb0MCN8PjdLCDfRsBcGVRN41f3vgLvaI0IrIcBp4AqILRSS0DeWNGkicC+f/zRIPJLc+9RURVSepwvfBw==} + hasBin: true + dependencies: + commander: 2.20.3 + dev: false + /@codemirror/autocomplete@6.6.1(@codemirror/language@6.6.0)(@codemirror/state@6.2.0)(@codemirror/view@6.11.0)(@lezer/common@1.0.2): resolution: {integrity: sha512-RpsvnYOopnyNbZg487qoRD5bKg63KMMUVP5d8MQ4Luc7Mb6JBWTORovLi6cTvWaKlbmLW8Zd2dAJkIdrhBsXug==} peerDependencies: @@ -1906,6 +1950,13 @@ packages: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} + /@jridgewell/source-map@0.3.3: + resolution: {integrity: sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==} + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.18 + dev: false + /@jridgewell/sourcemap-codec@1.4.14: resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} @@ -1918,6 +1969,10 @@ packages: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.4.14 + /@lezer/common@0.15.12: + resolution: {integrity: sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==} + dev: false + /@lezer/common@1.0.2: resolution: {integrity: sha512-SVgiGtMnMnW3ActR8SXgsDhw7a0w0ChHSYAyAUxxrOiJ1OqYWEKk/xJd84tTSPo1mo6DXLObAJALNnd0Hrv7Ng==} dev: false @@ -1957,6 +2012,12 @@ packages: '@lezer/lr': 1.3.4 dev: false + /@lezer/lr@0.15.8: + resolution: {integrity: sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==} + dependencies: + '@lezer/common': 0.15.12 + dev: false + /@lezer/lr@1.3.4: resolution: {integrity: sha512-7o+e4og/QoC/6btozDPJqnzBhUaD1fMfmvnEKQO1wRRiTse1WxaJ3OMEXZJnkgT6HCcTVOctSoXK9jGJw2oe9g==} dependencies: @@ -1977,6 +2038,54 @@ packages: '@lezer/lr': 1.3.4 dev: false + /@lmdb/lmdb-darwin-arm64@2.5.2: + resolution: {integrity: sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@lmdb/lmdb-darwin-x64@2.5.2: + resolution: {integrity: sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@lmdb/lmdb-linux-arm64@2.5.2: + resolution: {integrity: sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@lmdb/lmdb-linux-arm@2.5.2: + resolution: {integrity: sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@lmdb/lmdb-linux-x64@2.5.2: + resolution: {integrity: sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@lmdb/lmdb-win32-x64@2.5.2: + resolution: {integrity: sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@microsoft/api-extractor-model@7.26.4: resolution: {integrity: sha512-PDCgCzXDo+SLY5bsfl4bS7hxaeEtnXj7XtuzEE+BtALp7B5mK/NrS2kHWU69pohgsRmEALycQdaQPXoyT2i5MQ==} dependencies: @@ -2020,6 +2129,63 @@ packages: resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} dev: false + /@mischnic/json-sourcemap@0.1.0: + resolution: {integrity: sha512-dQb3QnfNqmQNYA4nFSN/uLaByIic58gOXq4Y4XqLOWmOrw73KmJPt/HLyG0wvn1bnR6mBKs/Uwvkh+Hns1T0XA==} + engines: {node: '>=12.0.0'} + dependencies: + '@lezer/common': 0.15.12 + '@lezer/lr': 0.15.8 + json5: 2.2.3 + dev: false + + /@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2: + resolution: {integrity: sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.2: + resolution: {integrity: sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.2: + resolution: {integrity: sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@msgpackr-extract/msgpackr-extract-linux-arm@3.0.2: + resolution: {integrity: sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@msgpackr-extract/msgpackr-extract-linux-x64@3.0.2: + resolution: {integrity: sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@msgpackr-extract/msgpackr-extract-win32-x64@3.0.2: + resolution: {integrity: sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -2038,6 +2204,698 @@ packages: '@nodelib/fs.scandir': 2.1.5 fastq: 1.15.0 + /@parcel/bundler-default@2.8.3: + resolution: {integrity: sha512-yJvRsNWWu5fVydsWk3O2L4yIy3UZiKWO2cPDukGOIWMgp/Vbpp+2Ct5IygVRtE22bnseW/E/oe0PV3d2IkEJGg==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/graph': 2.8.3 + '@parcel/hash': 2.8.3 + '@parcel/plugin': 2.8.3 + '@parcel/utils': 2.8.3 + nullthrows: 1.1.1 + dev: false + + /@parcel/cache@2.8.3: + resolution: {integrity: sha512-k7xv5vSQrJLdXuglo+Hv3yF4BCSs1tQ/8Vbd6CHTkOhf7LcGg6CPtLw053R/KdMpd/4GPn0QrAsOLdATm1ELtQ==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@parcel/core': ^2.8.3 + dependencies: + '@parcel/fs': 2.8.3 + '@parcel/logger': 2.8.3 + '@parcel/utils': 2.8.3 + lmdb: 2.5.2 + dev: false + + /@parcel/cache@2.8.3(@parcel/core@2.8.3): + resolution: {integrity: sha512-k7xv5vSQrJLdXuglo+Hv3yF4BCSs1tQ/8Vbd6CHTkOhf7LcGg6CPtLw053R/KdMpd/4GPn0QrAsOLdATm1ELtQ==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@parcel/core': ^2.8.3 + dependencies: + '@parcel/core': 2.8.3 + '@parcel/fs': 2.8.3(@parcel/core@2.8.3) + '@parcel/logger': 2.8.3 + '@parcel/utils': 2.8.3 + lmdb: 2.5.2 + dev: false + + /@parcel/codeframe@2.8.3: + resolution: {integrity: sha512-FE7sY53D6n/+2Pgg6M9iuEC6F5fvmyBkRE4d9VdnOoxhTXtkEqpqYgX7RJ12FAQwNlxKq4suBJQMgQHMF2Kjeg==} + engines: {node: '>= 12.0.0'} + dependencies: + chalk: 4.1.2 + dev: false + + /@parcel/compressor-raw@2.8.3: + resolution: {integrity: sha512-bVDsqleBUxRdKMakWSlWC9ZjOcqDKE60BE+Gh3JSN6WJrycJ02P5wxjTVF4CStNP/G7X17U+nkENxSlMG77ySg==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + dev: false + + /@parcel/config-default@2.8.3(@parcel/core@2.8.3): + resolution: {integrity: sha512-o/A/mbrO6X/BfGS65Sib8d6SSG45NYrNooNBkH/o7zbOBSRQxwyTlysleK1/3Wa35YpvFyLOwgfakqCtbGy4fw==} + peerDependencies: + '@parcel/core': ^2.8.3 + dependencies: + '@parcel/bundler-default': 2.8.3 + '@parcel/compressor-raw': 2.8.3 + '@parcel/core': 2.8.3 + '@parcel/namer-default': 2.8.3 + '@parcel/optimizer-css': 2.8.3 + '@parcel/optimizer-htmlnano': 2.8.3 + '@parcel/optimizer-image': 2.8.3(@parcel/core@2.8.3) + '@parcel/optimizer-svgo': 2.8.3 + '@parcel/optimizer-terser': 2.8.3 + '@parcel/packager-css': 2.8.3 + '@parcel/packager-html': 2.8.3 + '@parcel/packager-js': 2.8.3 + '@parcel/packager-raw': 2.8.3 + '@parcel/packager-svg': 2.8.3 + '@parcel/reporter-dev-server': 2.8.3 + '@parcel/resolver-default': 2.8.3 + '@parcel/runtime-browser-hmr': 2.8.3 + '@parcel/runtime-js': 2.8.3 + '@parcel/runtime-react-refresh': 2.8.3 + '@parcel/runtime-service-worker': 2.8.3 + '@parcel/transformer-babel': 2.8.3 + '@parcel/transformer-css': 2.8.3 + '@parcel/transformer-html': 2.8.3 + '@parcel/transformer-image': 2.8.3(@parcel/core@2.8.3) + '@parcel/transformer-js': 2.8.3(@parcel/core@2.8.3) + '@parcel/transformer-json': 2.8.3 + '@parcel/transformer-postcss': 2.8.3 + '@parcel/transformer-posthtml': 2.8.3 + '@parcel/transformer-raw': 2.8.3 + '@parcel/transformer-react-refresh-wrap': 2.8.3 + '@parcel/transformer-svg': 2.8.3 + transitivePeerDependencies: + - cssnano + - postcss + - purgecss + - relateurl + - srcset + - terser + - uncss + dev: false + + /@parcel/core@2.8.3: + resolution: {integrity: sha512-Euf/un4ZAiClnlUXqPB9phQlKbveU+2CotZv7m7i+qkgvFn5nAGnrV4h1OzQU42j9dpgOxWi7AttUDMrvkbhCQ==} + engines: {node: '>= 12.0.0'} + dependencies: + '@mischnic/json-sourcemap': 0.1.0 + '@parcel/cache': 2.8.3(@parcel/core@2.8.3) + '@parcel/diagnostic': 2.8.3 + '@parcel/events': 2.8.3 + '@parcel/fs': 2.8.3(@parcel/core@2.8.3) + '@parcel/graph': 2.8.3 + '@parcel/hash': 2.8.3 + '@parcel/logger': 2.8.3 + '@parcel/package-manager': 2.8.3(@parcel/core@2.8.3) + '@parcel/plugin': 2.8.3 + '@parcel/source-map': 2.1.1 + '@parcel/types': 2.8.3 + '@parcel/utils': 2.8.3 + '@parcel/workers': 2.8.3(@parcel/core@2.8.3) + abortcontroller-polyfill: 1.7.5 + base-x: 3.0.9 + browserslist: 4.21.5 + clone: 2.1.2 + dotenv: 7.0.0 + dotenv-expand: 5.1.0 + json5: 2.2.3 + msgpackr: 1.9.1 + nullthrows: 1.1.1 + semver: 5.7.1 + dev: false + + /@parcel/diagnostic@2.8.3: + resolution: {integrity: sha512-u7wSzuMhLGWZjVNYJZq/SOViS3uFG0xwIcqXw12w54Uozd6BH8JlhVtVyAsq9kqnn7YFkw6pXHqAo5Tzh4FqsQ==} + engines: {node: '>= 12.0.0'} + dependencies: + '@mischnic/json-sourcemap': 0.1.0 + nullthrows: 1.1.1 + dev: false + + /@parcel/events@2.8.3: + resolution: {integrity: sha512-hoIS4tAxWp8FJk3628bsgKxEvR7bq2scCVYHSqZ4fTi/s0+VymEATrRCUqf+12e5H47uw1/ZjoqrGtBI02pz4w==} + engines: {node: '>= 12.0.0'} + dev: false + + /@parcel/fs-search@2.8.3: + resolution: {integrity: sha512-DJBT2N8knfN7Na6PP2mett3spQLTqxFrvl0gv+TJRp61T8Ljc4VuUTb0hqBj+belaASIp3Q+e8+SgaFQu7wLiQ==} + engines: {node: '>= 12.0.0'} + dependencies: + detect-libc: 1.0.3 + dev: false + + /@parcel/fs@2.8.3: + resolution: {integrity: sha512-y+i+oXbT7lP0e0pJZi/YSm1vg0LDsbycFuHZIL80pNwdEppUAtibfJZCp606B7HOjMAlNZOBo48e3hPG3d8jgQ==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@parcel/core': ^2.8.3 + dependencies: + '@parcel/fs-search': 2.8.3 + '@parcel/types': 2.8.3 + '@parcel/utils': 2.8.3 + '@parcel/watcher': 2.1.0 + '@parcel/workers': 2.8.3 + dev: false + + /@parcel/fs@2.8.3(@parcel/core@2.8.3): + resolution: {integrity: sha512-y+i+oXbT7lP0e0pJZi/YSm1vg0LDsbycFuHZIL80pNwdEppUAtibfJZCp606B7HOjMAlNZOBo48e3hPG3d8jgQ==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@parcel/core': ^2.8.3 + dependencies: + '@parcel/core': 2.8.3 + '@parcel/fs-search': 2.8.3 + '@parcel/types': 2.8.3 + '@parcel/utils': 2.8.3 + '@parcel/watcher': 2.1.0 + '@parcel/workers': 2.8.3(@parcel/core@2.8.3) + dev: false + + /@parcel/graph@2.8.3: + resolution: {integrity: sha512-26GL8fYZPdsRhSXCZ0ZWliloK6DHlMJPWh6Z+3VVZ5mnDSbYg/rRKWmrkhnr99ZWmL9rJsv4G74ZwvDEXTMPBg==} + engines: {node: '>= 12.0.0'} + dependencies: + nullthrows: 1.1.1 + dev: false + + /@parcel/hash@2.8.3: + resolution: {integrity: sha512-FVItqzjWmnyP4ZsVgX+G00+6U2IzOvqDtdwQIWisCcVoXJFCqZJDy6oa2qDDFz96xCCCynjRjPdQx2jYBCpfYw==} + engines: {node: '>= 12.0.0'} + dependencies: + detect-libc: 1.0.3 + xxhash-wasm: 0.4.2 + dev: false + + /@parcel/logger@2.8.3: + resolution: {integrity: sha512-Kpxd3O/Vs7nYJIzkdmB6Bvp3l/85ydIxaZaPfGSGTYOfaffSOTkhcW9l6WemsxUrlts4za6CaEWcc4DOvaMOPA==} + engines: {node: '>= 12.0.0'} + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/events': 2.8.3 + dev: false + + /@parcel/markdown-ansi@2.8.3: + resolution: {integrity: sha512-4v+pjyoh9f5zuU/gJlNvNFGEAb6J90sOBwpKJYJhdWXLZMNFCVzSigxrYO+vCsi8G4rl6/B2c0LcwIMjGPHmFQ==} + engines: {node: '>= 12.0.0'} + dependencies: + chalk: 4.1.2 + dev: false + + /@parcel/namer-default@2.8.3: + resolution: {integrity: sha512-tJ7JehZviS5QwnxbARd8Uh63rkikZdZs1QOyivUhEvhN+DddSAVEdQLHGPzkl3YRk0tjFhbqo+Jci7TpezuAMw==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/plugin': 2.8.3 + nullthrows: 1.1.1 + dev: false + + /@parcel/node-resolver-core@2.8.3: + resolution: {integrity: sha512-12YryWcA5Iw2WNoEVr/t2HDjYR1iEzbjEcxfh1vaVDdZ020PiGw67g5hyIE/tsnG7SRJ0xdRx1fQ2hDgED+0Ww==} + engines: {node: '>= 12.0.0'} + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/utils': 2.8.3 + nullthrows: 1.1.1 + semver: 5.7.1 + dev: false + + /@parcel/optimizer-css@2.8.3: + resolution: {integrity: sha512-JotGAWo8JhuXsQDK0UkzeQB0UR5hDAKvAviXrjqB4KM9wZNLhLleeEAW4Hk8R9smCeQFP6Xg/N/NkLDpqMwT3g==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/plugin': 2.8.3 + '@parcel/source-map': 2.1.1 + '@parcel/utils': 2.8.3 + browserslist: 4.21.5 + lightningcss: 1.20.0 + nullthrows: 1.1.1 + dev: false + + /@parcel/optimizer-htmlnano@2.8.3: + resolution: {integrity: sha512-L8/fHbEy8Id2a2E0fwR5eKGlv9VYDjrH9PwdJE9Za9v1O/vEsfl/0T/79/x129l5O0yB6EFQkFa20MiK3b+vOg==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + htmlnano: 2.0.4(svgo@2.8.0) + nullthrows: 1.1.1 + posthtml: 0.16.6 + svgo: 2.8.0 + transitivePeerDependencies: + - cssnano + - postcss + - purgecss + - relateurl + - srcset + - terser + - uncss + dev: false + + /@parcel/optimizer-image@2.8.3(@parcel/core@2.8.3): + resolution: {integrity: sha512-SD71sSH27SkCDNUNx9A3jizqB/WIJr3dsfp+JZGZC42tpD/Siim6Rqy9M4To/BpMMQIIiEXa5ofwS+DgTEiEHQ==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/plugin': 2.8.3 + '@parcel/utils': 2.8.3 + '@parcel/workers': 2.8.3(@parcel/core@2.8.3) + detect-libc: 1.0.3 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/optimizer-svgo@2.8.3: + resolution: {integrity: sha512-9KQed99NZnQw3/W4qBYVQ7212rzA9EqrQG019TIWJzkA9tjGBMIm2c/nXpK1tc3hQ3e7KkXkFCQ3C+ibVUnHNA==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/plugin': 2.8.3 + '@parcel/utils': 2.8.3 + svgo: 2.8.0 + dev: false + + /@parcel/optimizer-terser@2.8.3: + resolution: {integrity: sha512-9EeQlN6zIeUWwzrzu6Q2pQSaYsYGah8MtiQ/hog9KEPlYTP60hBv/+utDyYEHSQhL7y5ym08tPX5GzBvwAD/dA==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/plugin': 2.8.3 + '@parcel/source-map': 2.1.1 + '@parcel/utils': 2.8.3 + nullthrows: 1.1.1 + terser: 5.17.3 + dev: false + + /@parcel/package-manager@2.8.3: + resolution: {integrity: sha512-tIpY5pD2lH53p9hpi++GsODy6V3khSTX4pLEGuMpeSYbHthnOViobqIlFLsjni+QA1pfc8NNNIQwSNdGjYflVA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@parcel/core': ^2.8.3 + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/fs': 2.8.3 + '@parcel/logger': 2.8.3 + '@parcel/types': 2.8.3 + '@parcel/utils': 2.8.3 + '@parcel/workers': 2.8.3 + semver: 5.7.1 + dev: false + + /@parcel/package-manager@2.8.3(@parcel/core@2.8.3): + resolution: {integrity: sha512-tIpY5pD2lH53p9hpi++GsODy6V3khSTX4pLEGuMpeSYbHthnOViobqIlFLsjni+QA1pfc8NNNIQwSNdGjYflVA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@parcel/core': ^2.8.3 + dependencies: + '@parcel/core': 2.8.3 + '@parcel/diagnostic': 2.8.3 + '@parcel/fs': 2.8.3(@parcel/core@2.8.3) + '@parcel/logger': 2.8.3 + '@parcel/types': 2.8.3 + '@parcel/utils': 2.8.3 + '@parcel/workers': 2.8.3(@parcel/core@2.8.3) + semver: 5.7.1 + dev: false + + /@parcel/packager-css@2.8.3: + resolution: {integrity: sha512-WyvkMmsurlHG8d8oUVm7S+D+cC/T3qGeqogb7sTI52gB6uiywU7lRCizLNqGFyFGIxcVTVHWnSHqItBcLN76lA==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + '@parcel/source-map': 2.1.1 + '@parcel/utils': 2.8.3 + nullthrows: 1.1.1 + dev: false + + /@parcel/packager-html@2.8.3: + resolution: {integrity: sha512-OhPu1Hx1RRKJodpiu86ZqL8el2Aa4uhBHF6RAL1Pcrh2EhRRlPf70Sk0tC22zUpYL7es+iNKZ/n0Rl+OWSHWEw==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + '@parcel/types': 2.8.3 + '@parcel/utils': 2.8.3 + nullthrows: 1.1.1 + posthtml: 0.16.6 + dev: false + + /@parcel/packager-js@2.8.3: + resolution: {integrity: sha512-0pGKC3Ax5vFuxuZCRB+nBucRfFRz4ioie19BbDxYnvBxrd4M3FIu45njf6zbBYsI9eXqaDnL1b3DcZJfYqtIzw==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/hash': 2.8.3 + '@parcel/plugin': 2.8.3 + '@parcel/source-map': 2.1.1 + '@parcel/utils': 2.8.3 + globals: 13.20.0 + nullthrows: 1.1.1 + dev: false + + /@parcel/packager-raw@2.8.3: + resolution: {integrity: sha512-BA6enNQo1RCnco9MhkxGrjOk59O71IZ9DPKu3lCtqqYEVd823tXff2clDKHK25i6cChmeHu6oB1Rb73hlPqhUA==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + dev: false + + /@parcel/packager-svg@2.8.3: + resolution: {integrity: sha512-mvIoHpmv5yzl36OjrklTDFShLUfPFTwrmp1eIwiszGdEBuQaX7JVI3Oo2jbVQgcN4W7J6SENzGQ3Q5hPTW3pMw==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + '@parcel/types': 2.8.3 + '@parcel/utils': 2.8.3 + posthtml: 0.16.6 + dev: false + + /@parcel/plugin@2.8.3: + resolution: {integrity: sha512-jZ6mnsS4D9X9GaNnvrixDQwlUQJCohDX2hGyM0U0bY2NWU8Km97SjtoCpWjq+XBCx/gpC4g58+fk9VQeZq2vlw==} + engines: {node: '>= 12.0.0'} + dependencies: + '@parcel/types': 2.8.3 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/reporter-cli@2.8.3: + resolution: {integrity: sha512-3sJkS6tFFzgIOz3u3IpD/RsmRxvOKKiQHOTkiiqRt1l44mMDGKS7zANRnJYsQzdCsgwc9SOP30XFgJwtoVlMbw==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + '@parcel/types': 2.8.3 + '@parcel/utils': 2.8.3 + chalk: 4.1.2 + term-size: 2.2.1 + dev: false + + /@parcel/reporter-dev-server@2.8.3: + resolution: {integrity: sha512-Y8C8hzgzTd13IoWTj+COYXEyCkXfmVJs3//GDBsH22pbtSFMuzAZd+8J9qsCo0EWpiDow7V9f1LischvEh3FbQ==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + '@parcel/utils': 2.8.3 + dev: false + + /@parcel/resolver-default@2.8.3: + resolution: {integrity: sha512-k0B5M/PJ+3rFbNj4xZSBr6d6HVIe6DH/P3dClLcgBYSXAvElNDfXgtIimbjCyItFkW9/BfcgOVKEEIZOeySH/A==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/node-resolver-core': 2.8.3 + '@parcel/plugin': 2.8.3 + dev: false + + /@parcel/runtime-browser-hmr@2.8.3: + resolution: {integrity: sha512-2O1PYi2j/Q0lTyGNV3JdBYwg4rKo6TEVFlYGdd5wCYU9ZIN9RRuoCnWWH2qCPj3pjIVtBeppYxzfVjPEHINWVg==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + '@parcel/utils': 2.8.3 + dev: false + + /@parcel/runtime-js@2.8.3: + resolution: {integrity: sha512-IRja0vNKwvMtPgIqkBQh0QtRn0XcxNC8HU1jrgWGRckzu10qJWO+5ULgtOeR4pv9krffmMPqywGXw6l/gvJKYQ==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + '@parcel/utils': 2.8.3 + nullthrows: 1.1.1 + dev: false + + /@parcel/runtime-react-refresh@2.8.3: + resolution: {integrity: sha512-2v/qFKp00MfG0234OdOgQNAo6TLENpFYZMbVbAsPMY9ITiqG73MrEsrGXVoGbYiGTMB/Toer/lSWlJxtacOCuA==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + '@parcel/utils': 2.8.3 + react-error-overlay: 6.0.9 + react-refresh: 0.9.0 + dev: false + + /@parcel/runtime-service-worker@2.8.3: + resolution: {integrity: sha512-/Skkw+EeRiwzOJso5fQtK8c9b452uWLNhQH1ISTodbmlcyB4YalAiSsyHCtMYD0c3/t5Sx4ZS7vxBAtQd0RvOw==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + '@parcel/utils': 2.8.3 + nullthrows: 1.1.1 + dev: false + + /@parcel/source-map@2.1.1: + resolution: {integrity: sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==} + engines: {node: ^12.18.3 || >=14} + dependencies: + detect-libc: 1.0.3 + dev: false + + /@parcel/transformer-babel@2.8.3: + resolution: {integrity: sha512-L6lExfpvvC7T/g3pxf3CIJRouQl+sgrSzuWQ0fD4PemUDHvHchSP4SNUVnd6gOytF3Y1KpnEZIunQGi5xVqQCQ==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/plugin': 2.8.3 + '@parcel/source-map': 2.1.1 + '@parcel/utils': 2.8.3 + browserslist: 4.21.5 + json5: 2.2.3 + nullthrows: 1.1.1 + semver: 5.7.1 + dev: false + + /@parcel/transformer-css@2.8.3: + resolution: {integrity: sha512-xTqFwlSXtnaYen9ivAgz+xPW7yRl/u4QxtnDyDpz5dr8gSeOpQYRcjkd4RsYzKsWzZcGtB5EofEk8ayUbWKEUg==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/plugin': 2.8.3 + '@parcel/source-map': 2.1.1 + '@parcel/utils': 2.8.3 + browserslist: 4.21.5 + lightningcss: 1.20.0 + nullthrows: 1.1.1 + dev: false + + /@parcel/transformer-glsl@2.8.3: + resolution: {integrity: sha512-epX9X0tnaAqwhEKr07pbYbTMXYYNJ9JSK/lJmgRbyncPgnRsOS9GfG8KRvlDRjyht21JURt+HWqlbAusApQfMw==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + glslify-bundle: 5.1.1 + glslify-deps: 1.3.2 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/transformer-html@2.8.3: + resolution: {integrity: sha512-kIZO3qsMYTbSnSpl9cnZog+SwL517ffWH54JeB410OSAYF1ouf4n5v9qBnALZbuCCmPwJRGs4jUtE452hxwN4g==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/hash': 2.8.3 + '@parcel/plugin': 2.8.3 + nullthrows: 1.1.1 + posthtml: 0.16.6 + posthtml-parser: 0.10.2 + posthtml-render: 3.0.0 + semver: 5.7.1 + srcset: 4.0.0 + dev: false + + /@parcel/transformer-image@2.8.3: + resolution: {integrity: sha512-cO4uptcCGTi5H6bvTrAWEFUsTNhA4kCo8BSvRSCHA2sf/4C5tGQPHt3JhdO0GQLPwZRCh/R41EkJs5HZ8A8DAg==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + peerDependencies: + '@parcel/core': ^2.8.3 + dependencies: + '@parcel/plugin': 2.8.3 + '@parcel/utils': 2.8.3 + '@parcel/workers': 2.8.3 + nullthrows: 1.1.1 + dev: false + + /@parcel/transformer-image@2.8.3(@parcel/core@2.8.3): + resolution: {integrity: sha512-cO4uptcCGTi5H6bvTrAWEFUsTNhA4kCo8BSvRSCHA2sf/4C5tGQPHt3JhdO0GQLPwZRCh/R41EkJs5HZ8A8DAg==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + peerDependencies: + '@parcel/core': ^2.8.3 + dependencies: + '@parcel/core': 2.8.3 + '@parcel/plugin': 2.8.3 + '@parcel/utils': 2.8.3 + '@parcel/workers': 2.8.3(@parcel/core@2.8.3) + nullthrows: 1.1.1 + dev: false + + /@parcel/transformer-js@2.8.3(@parcel/core@2.8.3): + resolution: {integrity: sha512-9Qd6bib+sWRcpovvzvxwy/PdFrLUXGfmSW9XcVVG8pvgXsZPFaNjnNT8stzGQj1pQiougCoxMY4aTM5p1lGHEQ==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + peerDependencies: + '@parcel/core': ^2.8.3 + dependencies: + '@parcel/core': 2.8.3 + '@parcel/diagnostic': 2.8.3 + '@parcel/plugin': 2.8.3 + '@parcel/source-map': 2.1.1 + '@parcel/utils': 2.8.3 + '@parcel/workers': 2.8.3(@parcel/core@2.8.3) + '@swc/helpers': 0.4.14 + browserslist: 4.21.5 + detect-libc: 1.0.3 + nullthrows: 1.1.1 + regenerator-runtime: 0.13.11 + semver: 5.7.1 + dev: false + + /@parcel/transformer-json@2.8.3: + resolution: {integrity: sha512-B7LmVq5Q7bZO4ERb6NHtRuUKWGysEeaj9H4zelnyBv+wLgpo4f5FCxSE1/rTNmP9u1qHvQ3scGdK6EdSSokGPg==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + json5: 2.2.3 + dev: false + + /@parcel/transformer-postcss@2.8.3: + resolution: {integrity: sha512-e8luB/poIlz6jBsD1Izms+6ElbyzuoFVa4lFVLZnTAChI3UxPdt9p/uTsIO46HyBps/Bk8ocvt3J4YF84jzmvg==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/hash': 2.8.3 + '@parcel/plugin': 2.8.3 + '@parcel/utils': 2.8.3 + clone: 2.1.2 + nullthrows: 1.1.1 + postcss-value-parser: 4.2.0 + semver: 5.7.1 + dev: false + + /@parcel/transformer-posthtml@2.8.3: + resolution: {integrity: sha512-pkzf9Smyeaw4uaRLsT41RGrPLT5Aip8ZPcntawAfIo+KivBQUV0erY1IvHYjyfFzq1ld/Fo2Ith9He6mxpPifA==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + '@parcel/utils': 2.8.3 + nullthrows: 1.1.1 + posthtml: 0.16.6 + posthtml-parser: 0.10.2 + posthtml-render: 3.0.0 + semver: 5.7.1 + dev: false + + /@parcel/transformer-raw@2.8.3: + resolution: {integrity: sha512-G+5cXnd2/1O3nV/pgRxVKZY/HcGSseuhAe71gQdSQftb8uJEURyUHoQ9Eh0JUD3MgWh9V+nIKoyFEZdf9T0sUQ==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + dev: false + + /@parcel/transformer-react-refresh-wrap@2.8.3: + resolution: {integrity: sha512-q8AAoEvBnCf/nPvgOwFwKZfEl/thwq7c2duxXkhl+tTLDRN2vGmyz4355IxCkavSX+pLWSQ5MexklSEeMkgthg==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + '@parcel/utils': 2.8.3 + react-refresh: 0.9.0 + dev: false + + /@parcel/transformer-sass@2.8.3: + resolution: {integrity: sha512-ak196rjvXdsBOGi5aTkBEKv6i4LKQgOkHuaKEjeT8g2a3CU6Z36J+j2GbZzsznfws/hH+CRTf8bAsbkxtKlkjQ==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3 + '@parcel/source-map': 2.1.1 + sass: 1.61.0 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/transformer-svg@2.8.3: + resolution: {integrity: sha512-3Zr/gBzxi1ZH1fftH/+KsZU7w5GqkmxlB0ZM8ovS5E/Pl1lq1t0xvGJue9m2VuQqP8Mxfpl5qLFmsKlhaZdMIQ==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/hash': 2.8.3 + '@parcel/plugin': 2.8.3 + nullthrows: 1.1.1 + posthtml: 0.16.6 + posthtml-parser: 0.10.2 + posthtml-render: 3.0.0 + semver: 5.7.1 + dev: false + + /@parcel/types@2.8.3: + resolution: {integrity: sha512-FECA1FB7+0UpITKU0D6TgGBpGxYpVSMNEENZbSJxFSajNy3wrko+zwBKQmFOLOiPcEtnGikxNs+jkFWbPlUAtw==} + dependencies: + '@parcel/cache': 2.8.3 + '@parcel/diagnostic': 2.8.3 + '@parcel/fs': 2.8.3 + '@parcel/package-manager': 2.8.3 + '@parcel/source-map': 2.1.1 + '@parcel/workers': 2.8.3 + utility-types: 3.10.0 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/utils@2.8.3: + resolution: {integrity: sha512-IhVrmNiJ+LOKHcCivG5dnuLGjhPYxQ/IzbnF2DKNQXWBTsYlHkJZpmz7THoeLtLliGmSOZ3ZCsbR8/tJJKmxjA==} + engines: {node: '>= 12.0.0'} + dependencies: + '@parcel/codeframe': 2.8.3 + '@parcel/diagnostic': 2.8.3 + '@parcel/hash': 2.8.3 + '@parcel/logger': 2.8.3 + '@parcel/markdown-ansi': 2.8.3 + '@parcel/source-map': 2.1.1 + chalk: 4.1.2 + dev: false + + /@parcel/watcher@2.1.0: + resolution: {integrity: sha512-8s8yYjd19pDSsBpbkOHnT6Z2+UJSuLQx61pCFM0s5wSRvKCEMDjd/cHY3/GI1szHIWbpXpsJdg3V6ISGGx9xDw==} + engines: {node: '>= 10.0.0'} + requiresBuild: true + dependencies: + is-glob: 4.0.3 + micromatch: 4.0.5 + node-addon-api: 3.2.1 + node-gyp-build: 4.6.0 + dev: false + + /@parcel/workers@2.8.3: + resolution: {integrity: sha512-+AxBnKgjqVpUHBcHLWIHcjYgKIvHIpZjN33mG5LG9XXvrZiqdWvouEzqEXlVLq5VzzVbKIQQcmsvRy138YErkg==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@parcel/core': ^2.8.3 + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/logger': 2.8.3 + '@parcel/types': 2.8.3 + '@parcel/utils': 2.8.3 + chrome-trace-event: 1.0.3 + nullthrows: 1.1.1 + dev: false + + /@parcel/workers@2.8.3(@parcel/core@2.8.3): + resolution: {integrity: sha512-+AxBnKgjqVpUHBcHLWIHcjYgKIvHIpZjN33mG5LG9XXvrZiqdWvouEzqEXlVLq5VzzVbKIQQcmsvRy138YErkg==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@parcel/core': ^2.8.3 + dependencies: + '@parcel/core': 2.8.3 + '@parcel/diagnostic': 2.8.3 + '@parcel/logger': 2.8.3 + '@parcel/types': 2.8.3 + '@parcel/utils': 2.8.3 + chrome-trace-event: 1.0.3 + nullthrows: 1.1.1 + dev: false + /@polka/url@1.0.0-next.21: resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} dev: true @@ -2066,7 +2924,6 @@ packages: '@types/estree': 1.0.1 estree-walker: 2.0.2 picomatch: 2.3.1 - dev: false /@rushstack/node-core-library@3.55.2: resolution: {integrity: sha512-SaLe/x/Q/uBVdNFK5V1xXvsVps0y7h1sN7aSJllQyFbugyOaxhNRF25bwEDnicARNEjJw0pk0lYnJQ9Kr6ev0A==} @@ -2190,6 +3047,17 @@ packages: - supports-color dev: false + /@swc/helpers@0.4.14: + resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} + dependencies: + tslib: 2.5.0 + dev: false + + /@trysound/sax@0.2.0: + resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} + engines: {node: '>=10.13.0'} + dev: false + /@ts-morph/common@0.18.1: resolution: {integrity: sha512-RVE+zSRICWRsfrkAw5qCAK+4ZH9kwEFv5h0+/YeHTLieWP7F4wWq4JsKFuNWG+fYh/KF+8rAtgdj5zb2mm+DVA==} dependencies: @@ -2236,6 +3104,10 @@ packages: '@babel/types': 7.21.5 dev: true + /@types/base64-js@1.3.0: + resolution: {integrity: sha512-ZmI0sZGAUNXUfMWboWwi4LcfpoVUYldyN6Oe0oJ5cCsHDU/LlRq8nQKPXhYLOx36QYSW9bNIb1vvRrD6K7Llgw==} + dev: false + /@types/chai-subset@1.3.3: resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} dependencies: @@ -2279,7 +3151,6 @@ packages: /@types/estree@1.0.1: resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} - dev: false /@types/form-data@0.0.33: resolution: {integrity: sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==} @@ -2331,6 +3202,10 @@ packages: resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==} dev: false + /@types/pako@2.0.0: + resolution: {integrity: sha512-10+iaz93qR5WYxTo+PMifD5TSxiOtdRaxBf7INGGXMQgTCu8Z/7GYWYFUOS3q/G0nE5boj1r4FEB+WSy7s5gbA==} + dev: false + /@types/prettier@2.7.2: resolution: {integrity: sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==} dev: true @@ -2486,6 +3361,14 @@ packages: svelte: 3.58.0 dev: true + /abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + dev: false + + /abortcontroller-polyfill@1.7.5: + resolution: {integrity: sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==} + dev: false + /acorn-jsx@5.3.2(acorn@8.8.2): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -2503,6 +3386,15 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + /ag-psd@15.2.0: + resolution: {integrity: sha512-Sbe2AzDA48r6/o6HCKpJPsCa8odymTklDl/qoarCTfHkKobFVZ7eo7sYKAtqZSdhgSeQbab9CwU9QY3W8O0Zcg==} + dependencies: + '@types/base64-js': 1.3.0 + '@types/pako': 2.0.0 + base64-js: 1.5.1 + pako: 2.1.0 + dev: false + /ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: @@ -2527,14 +3419,12 @@ packages: engines: {node: '>=4'} dependencies: color-convert: 1.9.3 - dev: true /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} dependencies: color-convert: 2.0.1 - dev: true /ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} @@ -2560,7 +3450,6 @@ packages: /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} @@ -2715,6 +3604,16 @@ packages: /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + /base-x@3.0.9: + resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: false + /bcrypt-pbkdf@1.0.2: resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} dependencies: @@ -2729,6 +3628,10 @@ packages: resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} dev: false + /boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: false + /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -2765,7 +3668,6 @@ packages: electron-to-chromium: 1.4.371 node-releases: 2.0.10 update-browserslist-db: 1.0.11(browserslist@4.21.5) - dev: true /bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} @@ -2779,6 +3681,13 @@ packages: /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + /buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + /busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} @@ -2801,7 +3710,6 @@ packages: /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - dev: true /camelcase-css@2.0.1: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} @@ -2819,7 +3727,6 @@ packages: /caniuse-lite@1.0.30001481: resolution: {integrity: sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==} - dev: true /case@1.6.3: resolution: {integrity: sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==} @@ -2849,7 +3756,6 @@ packages: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 - dev: true /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -2857,7 +3763,6 @@ packages: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - dev: true /char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} @@ -2881,6 +3786,11 @@ packages: optionalDependencies: fsevents: 2.3.2 + /chrome-trace-event@1.0.3: + resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==} + engines: {node: '>=6.0'} + dev: false + /ci-info@3.8.0: resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} engines: {node: '>=8'} @@ -2899,6 +3809,11 @@ packages: wrap-ansi: 7.0.0 dev: true + /clone@2.1.2: + resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} + engines: {node: '>=0.8'} + dev: false + /cm6-theme-basic-dark@0.2.0(@codemirror/language@6.6.0)(@codemirror/state@6.2.0)(@codemirror/view@6.11.0)(@lezer/highlight@1.1.4): resolution: {integrity: sha512-+mNNJecRtxS/KkloMDCQF0oTrT6aFGRZTjnBcdT5UG1pcDO4Brq8l1+0KR/8dZ7hub2gOGOzoi3rGFD8GzlH7Q==} peerDependencies: @@ -2958,18 +3873,15 @@ packages: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: color-name: 1.1.3 - dev: true /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 - dev: true /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -3056,6 +3968,13 @@ packages: well-known-symbols: 2.0.0 dev: false + /config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + dev: false + /convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} dev: true @@ -3077,6 +3996,16 @@ packages: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} dev: false + /cosmiconfig@8.1.3: + resolution: {integrity: sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==} + engines: {node: '>=14'} + dependencies: + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + dev: false + /crelt@1.0.5: resolution: {integrity: sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==} dev: false @@ -3094,6 +4023,24 @@ packages: which: 2.0.2 dev: true + /css-select@4.3.0: + resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 4.3.1 + domutils: 2.8.0 + nth-check: 2.1.1 + dev: false + + /css-tree@1.1.3: + resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} + engines: {node: '>=8.0.0'} + dependencies: + mdn-data: 2.0.14 + source-map: 0.6.1 + dev: false + /css-vars-ponyfill@2.4.8: resolution: {integrity: sha512-4/j4AX4htytYHWyHVZ2BFQ+NoCGZEcOH2h4/2mmgE4SkrFg4Xq6tGYR77DtvvUIDsaXuJN+sj41bbgauA0Gfmg==} dependencies: @@ -3101,11 +4048,23 @@ packages: get-css-data: 2.1.0 dev: false + /css-what@6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + dev: false + /cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} hasBin: true + /csso@4.2.0: + resolution: {integrity: sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==} + engines: {node: '>=8.0.0'} + dependencies: + css-tree: 1.1.3 + dev: false + /d3-array@3.2.2: resolution: {integrity: sha512-yEEyEAbDrF8C6Ob2myOBLjwBLck1Z89jMGFee0oPsn95GqjerpaOA4ch+vc2l0FNFFwMD5N7OCSEN5eAlsUbgQ==} engines: {node: '>=12'} @@ -3336,6 +4295,12 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} + /detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + dev: false + /detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} @@ -3370,12 +4335,48 @@ packages: esutils: 2.0.3 dev: true + /dom-serializer@1.4.1: + resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + entities: 2.2.0 + dev: false + /dom7@4.0.6: resolution: {integrity: sha512-emjdpPLhpNubapLFdjNL9tP06Sr+GZkrIHEXLWvOGsytACUrkbeIdjO5g77m00BrHTznnlcNqgmn7pCN192TBA==} dependencies: ssr-window: 4.0.2 dev: false + /domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: false + + /domhandler@4.3.1: + resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: false + + /domutils@2.8.0: + resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + dependencies: + dom-serializer: 1.4.1 + domelementtype: 2.3.0 + domhandler: 4.3.1 + dev: false + + /dotenv-expand@5.1.0: + resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==} + dev: false + + /dotenv@7.0.0: + resolution: {integrity: sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==} + engines: {node: '>=6'} + dev: false + /ecc-jsbn@0.1.2: resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} dependencies: @@ -3383,9 +4384,18 @@ packages: safer-buffer: 2.1.2 dev: false + /editorconfig@0.15.3: + resolution: {integrity: sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==} + hasBin: true + dependencies: + commander: 2.20.3 + lru-cache: 4.1.5 + semver: 5.7.1 + sigmund: 1.0.1 + dev: false + /electron-to-chromium@1.4.371: resolution: {integrity: sha512-jlBzY4tFcJaiUjzhRTCWAqRvTO/fWzjA3Bls0mykzGZ7zvcMP7h05W6UcgzfT9Ca1SW2xyKDOFRyI0pQeRNZGw==} - dev: true /emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} @@ -3396,11 +4406,19 @@ packages: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true + /entities@2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + dev: false + + /entities@3.0.1: + resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==} + engines: {node: '>=0.12'} + dev: false + /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: is-arrayish: 0.2.1 - dev: true /es6-promise@3.3.1: resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} @@ -3646,12 +4664,10 @@ packages: /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} - dev: true /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} - dev: true /escape-string-regexp@2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} @@ -3823,7 +4839,6 @@ packages: /estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - dev: false /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} @@ -4124,6 +5139,11 @@ packages: engines: {node: '>=4'} dev: false + /get-port@4.2.0: + resolution: {integrity: sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==} + engines: {node: '>=6'} + dev: false + /get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -4167,6 +5187,17 @@ packages: once: 1.4.0 path-is-absolute: 1.0.1 + /glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + dev: false + /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -4177,7 +5208,6 @@ packages: engines: {node: '>=8'} dependencies: type-fest: 0.20.2 - dev: true /globalyzer@0.1.0: resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} @@ -4199,6 +5229,98 @@ packages: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} dev: true + /glsl-inject-defines@1.0.3: + resolution: {integrity: sha512-W49jIhuDtF6w+7wCMcClk27a2hq8znvHtlGnrYkSWEr8tHe9eA2dcnohlcAmxLYBSpSSdzOkRdyPTrx9fw49+A==} + dependencies: + glsl-token-inject-block: 1.1.0 + glsl-token-string: 1.0.1 + glsl-tokenizer: 2.1.5 + dev: false + + /glsl-resolve@0.0.1: + resolution: {integrity: sha512-xxFNsfnhZTK9NBhzJjSBGX6IOqYpvBHxxmo+4vapiljyGNCY0Bekzn0firQkQrazK59c1hYxMDxYS8MDlhw4gA==} + dependencies: + resolve: 0.6.3 + xtend: 2.2.0 + dev: false + + /glsl-token-assignments@2.0.2: + resolution: {integrity: sha512-OwXrxixCyHzzA0U2g4btSNAyB2Dx8XrztY5aVUCjRSh4/D0WoJn8Qdps7Xub3sz6zE73W3szLrmWtQ7QMpeHEQ==} + dev: false + + /glsl-token-defines@1.0.0: + resolution: {integrity: sha512-Vb5QMVeLjmOwvvOJuPNg3vnRlffscq2/qvIuTpMzuO/7s5kT+63iL6Dfo2FYLWbzuiycWpbC0/KV0biqFwHxaQ==} + dependencies: + glsl-tokenizer: 2.1.5 + dev: false + + /glsl-token-depth@1.1.2: + resolution: {integrity: sha512-eQnIBLc7vFf8axF9aoi/xW37LSWd2hCQr/3sZui8aBJnksq9C7zMeUYHVJWMhFzXrBU7fgIqni4EhXVW4/krpg==} + dev: false + + /glsl-token-descope@1.0.2: + resolution: {integrity: sha512-kS2PTWkvi/YOeicVjXGgX5j7+8N7e56srNDEHDTVZ1dcESmbmpmgrnpjPcjxJjMxh56mSXYoFdZqb90gXkGjQw==} + dependencies: + glsl-token-assignments: 2.0.2 + glsl-token-depth: 1.1.2 + glsl-token-properties: 1.0.1 + glsl-token-scope: 1.1.2 + dev: false + + /glsl-token-inject-block@1.1.0: + resolution: {integrity: sha512-q/m+ukdUBuHCOtLhSr0uFb/qYQr4/oKrPSdIK2C4TD+qLaJvqM9wfXIF/OOBjuSA3pUoYHurVRNao6LTVVUPWA==} + dev: false + + /glsl-token-properties@1.0.1: + resolution: {integrity: sha512-dSeW1cOIzbuUoYH0y+nxzwK9S9O3wsjttkq5ij9ZGw0OS41BirKJzzH48VLm8qLg+au6b0sINxGC0IrGwtQUcA==} + dev: false + + /glsl-token-scope@1.1.2: + resolution: {integrity: sha512-YKyOMk1B/tz9BwYUdfDoHvMIYTGtVv2vbDSLh94PT4+f87z21FVdou1KNKgF+nECBTo0fJ20dpm0B1vZB1Q03A==} + dev: false + + /glsl-token-string@1.0.1: + resolution: {integrity: sha512-1mtQ47Uxd47wrovl+T6RshKGkRRCYWhnELmkEcUAPALWGTFe2XZpH3r45XAwL2B6v+l0KNsCnoaZCSnhzKEksg==} + dev: false + + /glsl-token-whitespace-trim@1.0.0: + resolution: {integrity: sha512-ZJtsPut/aDaUdLUNtmBYhaCmhIjpKNg7IgZSfX5wFReMc2vnj8zok+gB/3Quqs0TsBSX/fGnqUUYZDqyuc2xLQ==} + dev: false + + /glsl-tokenizer@2.1.5: + resolution: {integrity: sha512-XSZEJ/i4dmz3Pmbnpsy3cKh7cotvFlBiZnDOwnj/05EwNp2XrhQ4XKJxT7/pDt4kp4YcpRSKz8eTV7S+mwV6MA==} + dependencies: + through2: 0.6.5 + dev: false + + /glslify-bundle@5.1.1: + resolution: {integrity: sha512-plaAOQPv62M1r3OsWf2UbjN0hUYAB7Aph5bfH58VxJZJhloRNbxOL9tl/7H71K7OLJoSJ2ZqWOKk3ttQ6wy24A==} + dependencies: + glsl-inject-defines: 1.0.3 + glsl-token-defines: 1.0.0 + glsl-token-depth: 1.1.2 + glsl-token-descope: 1.0.2 + glsl-token-scope: 1.1.2 + glsl-token-string: 1.0.1 + glsl-token-whitespace-trim: 1.0.0 + glsl-tokenizer: 2.1.5 + murmurhash-js: 1.0.0 + shallow-copy: 0.0.1 + dev: false + + /glslify-deps@1.3.2: + resolution: {integrity: sha512-7S7IkHWygJRjcawveXQjRXLO2FTjijPDYC7QfZyAQanY+yGLCFHYnPtsGT9bdyHiwPTw/5a1m1M9hamT2aBpag==} + dependencies: + '@choojs/findup': 0.2.1 + events: 3.3.0 + glsl-resolve: 0.0.1 + glsl-tokenizer: 2.1.5 + graceful-fs: 4.2.11 + inherits: 2.0.4 + map-limit: 0.0.1 + resolve: 1.22.2 + dev: false + /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -4223,12 +5345,10 @@ packages: /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} - dev: true /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - dev: true /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} @@ -4249,6 +5369,50 @@ packages: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} dev: true + /htmlnano@2.0.4(svgo@2.8.0): + resolution: {integrity: sha512-WGCkyGFwjKW1GeCBsPYacMvaMnZtFJ0zIRnC2NCddkA+IOEhTqskXrS7lep+3yYZw/nQ3dW1UAX4yA/GJyR8BA==} + peerDependencies: + cssnano: ^6.0.0 + postcss: ^8.3.11 + purgecss: ^5.0.0 + relateurl: ^0.2.7 + srcset: 4.0.0 + svgo: ^3.0.2 + terser: ^5.10.0 + uncss: ^0.17.3 + peerDependenciesMeta: + cssnano: + optional: true + postcss: + optional: true + purgecss: + optional: true + relateurl: + optional: true + srcset: + optional: true + svgo: + optional: true + terser: + optional: true + uncss: + optional: true + dependencies: + cosmiconfig: 8.1.3 + posthtml: 0.16.6 + svgo: 2.8.0 + timsort: 0.3.0 + dev: false + + /htmlparser2@7.2.0: + resolution: {integrity: sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==} + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + domutils: 2.8.0 + entities: 3.0.1 + dev: false + /http-basic@8.1.3: resolution: {integrity: sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==} engines: {node: '>=6.0.0'} @@ -4286,6 +5450,10 @@ packages: safer-buffer: 2.1.2 dev: false + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: false + /ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} @@ -4304,7 +5472,6 @@ packages: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - dev: true /import-lazy@4.0.0: resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} @@ -4342,6 +5509,10 @@ packages: /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + /ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: false + /internmap@2.0.3: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} @@ -4349,7 +5520,6 @@ packages: /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - dev: true /is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} @@ -4382,6 +5552,10 @@ packages: dependencies: is-extglob: 2.1.1 + /is-json@2.0.1: + resolution: {integrity: sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==} + dev: false + /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -4400,6 +5574,10 @@ packages: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} dev: false + /isarray@0.0.1: + resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} + dev: false + /isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} dev: false @@ -4917,6 +6095,17 @@ packages: resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} dev: false + /js-beautify@1.14.7: + resolution: {integrity: sha512-5SOX1KXPFKx+5f6ZrPsIPEY7NwKeQz47n3jm2i+XeHx9MoRsfQenlOP13FQhWvg8JRS0+XLO6XYUQ2GX+q+T9A==} + engines: {node: '>=10'} + hasBin: true + dependencies: + config-chain: 1.1.13 + editorconfig: 0.15.3 + glob: 8.1.0 + nopt: 6.0.0 + dev: false + /js-sdsl@4.4.0: resolution: {integrity: sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==} dev: true @@ -4928,7 +6117,6 @@ packages: /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true /js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} @@ -4943,7 +6131,6 @@ packages: hasBin: true dependencies: argparse: 2.0.1 - dev: true /jsbn@0.1.1: resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} @@ -4957,7 +6144,6 @@ packages: /json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - dev: true /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -4982,7 +6168,6 @@ packages: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true - dev: true /jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} @@ -5041,6 +6226,94 @@ packages: type-check: 0.4.0 dev: true + /lightningcss-darwin-arm64@1.20.0: + resolution: {integrity: sha512-aYEohJTlzwB8URJaNiS57tMbjyLub0mYvxlxKQk8SZv+irXx6MoBWpDNQKKTS9gg1pGf/eAwjpa3BLAoCBsh1A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /lightningcss-darwin-x64@1.20.0: + resolution: {integrity: sha512-cmMgY8FFWVaGgtift7eKKkHMqlz9O09/yTdlCXEDOeDP9yeo6vHOBTRP7ojb368kjw8Ew3l0L2uT1Gtx56eNkg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /lightningcss-linux-arm-gnueabihf@1.20.0: + resolution: {integrity: sha512-/m+NDO1O6JCv7R9F0XWlXcintQHx4MPNU+kt8jZJO07LLdGwCfvjN31GVcwVPlStnnx/cU8uTTmax6g/Qu/whg==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /lightningcss-linux-arm64-gnu@1.20.0: + resolution: {integrity: sha512-gtXoa6v0HvMRLbev6Hsef0+Q5He7NslB+Rs7G49Y5LUSdJeGIATEN+j8JzHC0DnxCsOGbEgGRmvtJzzYDkkluw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /lightningcss-linux-arm64-musl@1.20.0: + resolution: {integrity: sha512-Po7XpucM1kZnkiyd2BNwTExSDcZ8jm8uB9u+Sq44qjpkf5f75jreQwn3DQm9I1t5C6tB9HGt30HExMju9umJBQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /lightningcss-linux-x64-gnu@1.20.0: + resolution: {integrity: sha512-8yR/fGNn/P0I+Lc3PK+VWPET/zdSpBfHFIG0DJ38TywMbItVKvnFvoTBwnIm4LqBz7g2G2dDexnNP95za2Ll8g==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /lightningcss-linux-x64-musl@1.20.0: + resolution: {integrity: sha512-EmpJ+VkPZ8RACiB4m+l8TmapmE1W2UvJKDHE+ML/3Ihr9tRKUs3CibfnQTFZC8aSsrxgXagDAN+PgCDDhIyriA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /lightningcss-win32-x64-msvc@1.20.0: + resolution: {integrity: sha512-BRdPvbq7Cc1qxAzp2emqWJHrqsEkf4ggxS29VOnxT7jhkdHKU+a26OVMjvm/OL0NH0ToNOZNAPvHMSexiEgBeA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /lightningcss@1.20.0: + resolution: {integrity: sha512-4bj8aP+Vi+or8Gwq/hknmicr4PmA8D9uL/3qY0N0daX5vYBMYERGI6Y93nzoeRgQMULq+gtrN/FvJYtH0xNN8g==} + engines: {node: '>= 12.0.0'} + dependencies: + detect-libc: 1.0.3 + optionalDependencies: + lightningcss-darwin-arm64: 1.20.0 + lightningcss-darwin-x64: 1.20.0 + lightningcss-linux-arm-gnueabihf: 1.20.0 + lightningcss-linux-arm64-gnu: 1.20.0 + lightningcss-linux-arm64-musl: 1.20.0 + lightningcss-linux-x64-gnu: 1.20.0 + lightningcss-linux-x64-musl: 1.20.0 + lightningcss-win32-x64-msvc: 1.20.0 + dev: false + /lilconfig@2.1.0: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} engines: {node: '>=10'} @@ -5048,6 +6321,24 @@ packages: /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + /lmdb@2.5.2: + resolution: {integrity: sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA==} + requiresBuild: true + dependencies: + msgpackr: 1.9.1 + node-addon-api: 4.3.0 + node-gyp-build-optional-packages: 5.0.3 + ordered-binary: 1.4.0 + weak-lru-cache: 1.2.2 + optionalDependencies: + '@lmdb/lmdb-darwin-arm64': 2.5.2 + '@lmdb/lmdb-darwin-x64': 2.5.2 + '@lmdb/lmdb-linux-arm': 2.5.2 + '@lmdb/lmdb-linux-arm64': 2.5.2 + '@lmdb/lmdb-linux-x64': 2.5.2 + '@lmdb/lmdb-win32-x64': 2.5.2 + dev: false + /local-pkg@0.4.3: resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} engines: {node: '>=14'} @@ -5095,6 +6386,13 @@ packages: dependencies: get-func-name: 2.0.0 + /lru-cache@4.1.5: + resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} + dependencies: + pseudomap: 1.0.2 + yallist: 2.1.2 + dev: false + /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: @@ -5145,6 +6443,12 @@ packages: tmpl: 1.0.5 dev: true + /map-limit@0.0.1: + resolution: {integrity: sha512-pJpcfLPnIF/Sk3taPW21G/RQsEEirGaFpCW3oXRwH9dnFHPHNGjNyvh++rdmC2fNqEaTw2MhYJraoJWAHx8kEg==} + dependencies: + once: 1.3.3 + dev: false + /map-obj@5.0.2: resolution: {integrity: sha512-K6K2NgKnTXimT3779/4KxSvobxOtMmx1LBZ3NwRxT/MDIR3Br/fQ4Q+WCX5QxjyUR8zg5+RV9Tbf2c5pAWTD2A==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -5157,6 +6461,14 @@ packages: blueimp-md5: 2.19.0 dev: false + /mdn-data@2.0.14: + resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} + dev: false + + /mdn-polyfills@5.20.0: + resolution: {integrity: sha512-AbTv1ytcoOUAkxw6u5oo2QPf27kEZgxBAQr49jFb4i2VnTnFGfJbcIQ9UDBOdfNECeXsgkYFwB2BkdeTfOzztw==} + dev: false + /media-encoder-host-broker@7.0.79: resolution: {integrity: sha512-uAKboXNaXflOGvHMrj8eOjx3cPJkYDcCOI3mUpAoHBquDzqhgIDovF4yiedCT2YMUPtqPmHOlHUPofH5/3cDmA==} dependencies: @@ -5276,6 +6588,28 @@ packages: /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + /msgpackr-extract@3.0.2: + resolution: {integrity: sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==} + hasBin: true + requiresBuild: true + dependencies: + node-gyp-build-optional-packages: 5.0.7 + optionalDependencies: + '@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.2 + '@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.2 + '@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.2 + '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.2 + '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.2 + '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.2 + dev: false + optional: true + + /msgpackr@1.9.1: + resolution: {integrity: sha512-jJdrNH8tzfCtT0rjPFryBXjRDQE7rqfLkah4/8B4gYa7NNZYFBcGxqWBtfQpGC+oYyBwlkj3fARk4aooKNPHxg==} + optionalDependencies: + msgpackr-extract: 3.0.2 + dev: false + /multi-buffer-data-view@3.0.24: resolution: {integrity: sha512-jm7Ycplx37ExXyQmqhwl7zfQmAj81y5LLzVx0XyWea4omP9W/xJhLEHs/5b+WojGyYSRt8BHiXZVcYzu68Ma0Q==} engines: {node: '>=12.20.1'} @@ -5284,6 +6618,10 @@ packages: tslib: 2.5.0 dev: false + /murmurhash-js@1.0.0: + resolution: {integrity: sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==} + dev: false + /mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} dependencies: @@ -5300,6 +6638,14 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /node-addon-api@3.2.1: + resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==} + dev: false + + /node-addon-api@4.3.0: + resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} + dev: false + /node-fetch@2.6.9: resolution: {integrity: sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==} engines: {node: 4.x || >=6.0.0} @@ -5312,13 +6658,36 @@ packages: whatwg-url: 5.0.0 dev: false + /node-gyp-build-optional-packages@5.0.3: + resolution: {integrity: sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==} + hasBin: true + dev: false + + /node-gyp-build-optional-packages@5.0.7: + resolution: {integrity: sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==} + hasBin: true + dev: false + optional: true + + /node-gyp-build@4.6.0: + resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==} + hasBin: true + dev: false + /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} dev: true /node-releases@2.0.10: resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==} - dev: true + + /nopt@6.0.0: + resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + hasBin: true + dependencies: + abbrev: 1.1.1 + dev: false /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} @@ -5336,6 +6705,16 @@ packages: path-key: 3.1.1 dev: true + /nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + dependencies: + boolbase: 1.0.0 + dev: false + + /nullthrows@1.1.1: + resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} + dev: false + /oauth-sign@0.9.0: resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} dev: false @@ -5352,6 +6731,12 @@ packages: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} dev: false + /once@1.3.3: + resolution: {integrity: sha512-6vaNInhu+CHxtONf3zw3vq4SP2DOQhjBvIa3rNcG0+P7eKWlYH6Peu7rHizSloRU2EwMz6GraLieis9Ac9+p1w==} + dependencies: + wrappy: 1.0.2 + dev: false + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: @@ -5376,6 +6761,10 @@ packages: word-wrap: 1.2.3 dev: true + /ordered-binary@1.4.0: + resolution: {integrity: sha512-EHQ/jk4/a9hLupIKxTfUsQRej1Yd/0QLQs3vGvIqg5ZtCYSzNhkzHoZc7Zf4e4kUlDaC3Uw8Q/1opOLNN2OKRQ==} + dev: false + /p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -5416,12 +6805,47 @@ packages: engines: {node: '>=6'} dev: true + /pako@2.1.0: + resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + dev: false + + /parcel@2.8.3: + resolution: {integrity: sha512-5rMBpbNE72g6jZvkdR5gS2nyhwIXaJy8i65osOqs/+5b7zgf3eMKgjSsDrv6bhz3gzifsba6MBJiZdBckl+vnA==} + engines: {node: '>= 12.0.0'} + hasBin: true + peerDependenciesMeta: + '@parcel/core': + optional: true + dependencies: + '@parcel/config-default': 2.8.3(@parcel/core@2.8.3) + '@parcel/core': 2.8.3 + '@parcel/diagnostic': 2.8.3 + '@parcel/events': 2.8.3 + '@parcel/fs': 2.8.3(@parcel/core@2.8.3) + '@parcel/logger': 2.8.3 + '@parcel/package-manager': 2.8.3(@parcel/core@2.8.3) + '@parcel/reporter-cli': 2.8.3 + '@parcel/reporter-dev-server': 2.8.3 + '@parcel/utils': 2.8.3 + chalk: 4.1.2 + commander: 7.2.0 + get-port: 4.2.0 + v8-compile-cache: 2.3.0 + transitivePeerDependencies: + - cssnano + - postcss + - purgecss + - relateurl + - srcset + - terser + - uncss + dev: false + /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} dependencies: callsites: 3.1.0 - dev: true /parse-cache-control@1.0.1: resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==} @@ -5435,7 +6859,6 @@ packages: error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - dev: true /path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} @@ -5465,7 +6888,6 @@ packages: /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - dev: true /pathe@1.1.0: resolution: {integrity: sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==} @@ -5597,6 +7019,35 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 + /posthtml-parser@0.10.2: + resolution: {integrity: sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==} + engines: {node: '>=12'} + dependencies: + htmlparser2: 7.2.0 + dev: false + + /posthtml-parser@0.11.0: + resolution: {integrity: sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==} + engines: {node: '>=12'} + dependencies: + htmlparser2: 7.2.0 + dev: false + + /posthtml-render@3.0.0: + resolution: {integrity: sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==} + engines: {node: '>=12'} + dependencies: + is-json: 2.0.1 + dev: false + + /posthtml@0.16.6: + resolution: {integrity: sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==} + engines: {node: '>=12.0.0'} + dependencies: + posthtml-parser: 0.11.0 + posthtml-render: 3.0.0 + dev: false + /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -5653,6 +7104,14 @@ packages: sisteransi: 1.0.5 dev: true + /proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + dev: false + + /pseudomap@1.0.2: + resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} + dev: false + /psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} dev: false @@ -5688,6 +7147,10 @@ packages: resolution: {integrity: sha512-svmiMd0ocpdTm9cvAz0klcZpnh639lVctj6psQiawd4pYalVzOG4cX+JizAgRckyTAsRVdzObP7D2EBrSfdghA==} dev: false + /react-error-overlay@6.0.9: + resolution: {integrity: sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==} + dev: false + /react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} dev: false @@ -5696,11 +7159,25 @@ packages: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} dev: true + /react-refresh@0.9.0: + resolution: {integrity: sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==} + engines: {node: '>=0.10.0'} + dev: false + /read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} dependencies: pify: 2.3.0 + /readable-stream@1.0.34: + resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 0.0.1 + string_decoder: 0.10.31 + dev: false + /readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} dependencies: @@ -5789,7 +7266,6 @@ packages: /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} - dev: true /resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} @@ -5801,6 +7277,10 @@ packages: engines: {node: '>=10'} dev: true + /resolve@0.6.3: + resolution: {integrity: sha512-UHBY3viPlJKf85YijDUcikKX6tmF4SokIDp518ZDVT92JNDcG5uKIthaT/owt3Sar0lwtOafsQuwrg22/v2Dwg==} + dev: false + /resolve@1.19.0: resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} dependencies: @@ -5909,6 +7389,11 @@ packages: immutable: 4.3.0 source-map-js: 1.0.2 + /semver@5.7.1: + resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + hasBin: true + dev: false + /semver@6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true @@ -5941,6 +7426,10 @@ packages: resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} dev: true + /shallow-copy@0.0.1: + resolution: {integrity: sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==} + dev: false + /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -5965,6 +7454,10 @@ packages: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} dev: false + /sigmund@1.0.1: + resolution: {integrity: sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==} + dev: false + /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true @@ -6021,6 +7514,13 @@ packages: source-map: 0.6.1 dev: true + /source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: false + /source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -6038,6 +7538,11 @@ packages: /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + /srcset@4.0.0: + resolution: {integrity: sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==} + engines: {node: '>=12'} + dev: false + /sshpk@1.17.0: resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==} engines: {node: '>=0.10.0'} @@ -6058,6 +7563,11 @@ packages: resolution: {integrity: sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ==} dev: false + /stable@0.1.8: + resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==} + deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility' + dev: false + /stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -6108,6 +7618,10 @@ packages: strip-ansi: 6.0.1 dev: true + /string_decoder@0.10.31: + resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} + dev: false + /string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} dependencies: @@ -6176,14 +7690,12 @@ packages: engines: {node: '>=4'} dependencies: has-flag: 3.0.0 - dev: true /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} dependencies: has-flag: 4.0.0 - dev: true /supports-color@8.1.1: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} @@ -6474,6 +7986,20 @@ packages: resolution: {integrity: sha512-brIBNNB76mXFmU/Kerm4wFnkskBbluBDCjx/8TcpYRb298Yh2dztS2kQ6bhtjMcvUhd5ynClfwpz5h2gnzdQ1A==} engines: {node: '>= 8'} + /svgo@2.8.0: + resolution: {integrity: sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==} + engines: {node: '>=10.13.0'} + hasBin: true + dependencies: + '@trysound/sax': 0.2.0 + commander: 7.2.0 + css-select: 4.3.0 + css-tree: 1.1.3 + csso: 4.2.0 + picocolors: 1.0.0 + stable: 0.1.8 + dev: false + /swiper@9.2.4: resolution: {integrity: sha512-L7y3K/iiMXNYQ94FbfcJn7jex4QPnS4+voXGupTdC+UHW4XrR40QDdm4c9hXJ+Br0Il7PP0vP1W3goM9/Ly6Sg==} engines: {node: '>= 4.7.0'} @@ -6528,6 +8054,22 @@ packages: transitivePeerDependencies: - ts-node + /term-size@2.2.1: + resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} + engines: {node: '>=8'} + dev: false + + /terser@5.17.3: + resolution: {integrity: sha512-AudpAZKmZHkG9jueayypz4duuCFJMMNGRMwaPvQKWfxKedh8Z2x3OCoDqIIi1xx5+iwx1u6Au8XQcc9Lke65Yg==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.3 + acorn: 8.8.2 + commander: 2.20.3 + source-map-support: 0.5.21 + dev: false + /test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} @@ -6569,11 +8111,22 @@ packages: dependencies: any-promise: 1.3.0 + /through2@0.6.5: + resolution: {integrity: sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==} + dependencies: + readable-stream: 1.0.34 + xtend: 4.0.2 + dev: false + /time-zone@1.0.0: resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==} engines: {node: '>=4'} dev: false + /timsort@0.3.0: + resolution: {integrity: sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==} + dev: false + /tiny-glob@0.2.9: resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} dependencies: @@ -6710,7 +8263,6 @@ packages: /type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} - dev: true /type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} @@ -6767,7 +8319,6 @@ packages: browserslist: 4.21.5 escalade: 3.1.1 picocolors: 1.0.0 - dev: true /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -6777,6 +8328,11 @@ packages: /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + /utility-types@3.10.0: + resolution: {integrity: sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==} + engines: {node: '>= 4'} + dev: false + /uuid@3.4.0: resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. @@ -6788,6 +8344,10 @@ packages: hasBin: true dev: false + /v8-compile-cache@2.3.0: + resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} + dev: false + /v8-to-istanbul@9.1.0: resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==} engines: {node: '>=10.12.0'} @@ -7307,6 +8867,18 @@ packages: vite: 4.3.1(sass@1.61.0) dev: false + /vite-plugin-glsl@1.1.2(vite@4.3.1): + resolution: {integrity: sha512-zmXsfc1vn2MlYve9t3FAoWuhLyoCkNS1TuQL+TkXZL7tGmBjRErp10eNYxcse5tK9oUC5MyJpNc4ElpQnx8DoA==} + engines: {node: '>= 16.15.1', npm: '>= 8.11.0'} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 + dependencies: + '@rollup/pluginutils': 5.0.2 + vite: 4.3.1(sass@1.61.0) + transitivePeerDependencies: + - rollup + dev: true + /vite-plugin-static-copy@0.14.0(vite@4.3.1): resolution: {integrity: sha512-RMFmb4czomcrsbQBiUZs9HcDGN3kxGvF+OrtkfTVocp12CuoUCuJQhcY26RK35A6KS4WasGzEwcYZqHMjkAvVw==} engines: {node: ^14.18.0 || >=16.0.0} @@ -7742,6 +9314,10 @@ packages: makeerror: 1.0.12 dev: true + /weak-lru-cache@1.2.2: + resolution: {integrity: sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==} + dev: false + /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} dev: false @@ -7831,11 +9407,29 @@ packages: optional: true dev: false + /xtend@2.2.0: + resolution: {integrity: sha512-SLt5uylT+4aoXxXuwtQp5ZnMMzhDb1Xkg4pEqc00WUJCQifPfV9Ub1VrNhp9kXkrjZD2I2Hl8WnjP37jzZLPZw==} + engines: {node: '>=0.4'} + dev: false + + /xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + dev: false + + /xxhash-wasm@0.4.2: + resolution: {integrity: sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA==} + dev: false + /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} dev: true + /yallist@2.1.2: + resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} + dev: false + /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} dev: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 0cf1b02..dcc77ea 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,3 +2,4 @@ packages: - 'gradio/js/*' - 'gradio/client/js' - 'litegraph/packages/*' + - 'klecks' diff --git a/src/lib/ComfyGraphCanvas.ts b/src/lib/ComfyGraphCanvas.ts index 72ec18f..3da6311 100644 --- a/src/lib/ComfyGraphCanvas.ts +++ b/src/lib/ComfyGraphCanvas.ts @@ -1,4 +1,4 @@ -import { BuiltInSlotShape, LGraph, LGraphCanvas, LGraphNode, LiteGraph, NodeMode, type MouseEventExt, type Vector2, type Vector4, TitleMode, type ContextMenuItem, type IContextMenuItem, Subgraph } from "@litegraph-ts/core"; +import { BuiltInSlotShape, LGraph, LGraphCanvas, LGraphNode, LiteGraph, NodeMode, type MouseEventExt, type Vector2, type Vector4, TitleMode, type ContextMenuItem, type IContextMenuItem, Subgraph, LLink } from "@litegraph-ts/core"; import type ComfyApp from "./components/ComfyApp"; import queueState from "./stores/queueState"; import { get } from "svelte/store"; @@ -259,66 +259,59 @@ export default class ComfyGraphCanvas extends LGraphCanvas { const newNode = LiteGraph.createNode(node.type); - for (let index = 0; index < newNode.inputs.length; index++) { - const newInput = newNode.inputs[index]; - const oldInput = node.inputs[index] - - if (oldInput && newInput.type === oldInput.type) { - continue; - } - - let link: LLink | null = null; - - if (oldInput) { - link = node.getInputLink(index); - node.disconnectInput(index) - oldInput.type = newInput.type - oldInput.name = newInput.name - } - else { - node.addInput(newInput.name, newInput.type, newInput) - } - + const createInputReroute = (slotIndex: number, link: LLink | null): ComfyReroute => { const reroute = LiteGraph.createNode(ComfyReroute); reroute.properties.ignoreTypes = true; node.graph.add(reroute) - const inputPos = node.getConnectionPos(true, index); + const inputPos = node.getConnectionPos(true, slotIndex); reroute.pos = [inputPos[0] - 140, inputPos[1] + LiteGraph.NODE_SLOT_HEIGHT / 2]; - reroute.connect(0, node, index); - if (link != null) - node.graph.getNodeById(link.target_id).connect(link.target_slot, reroute, 0) + node.graph.getNodeById(link.origin_id).connect(link.origin_slot, reroute, 0) + return reroute } - for (let index = 0; index < newNode.outputs.length; index++) { - const newOutput = newNode.outputs[index]; - const oldOutput = node.outputs[index] + for (let index = node.inputs.length - 1; index >= 0; index--) { + let link: LLink | null = null; - if (oldOutput && newOutput.type === oldOutput.type) { - continue; - } + link = node.getInputLink(index); + node.disconnectInput(index) - let links = [] + if (link) + createInputReroute(index, link); - if (oldOutput) { - links = node.getOutputLinks(index) - node.disconnectOutput(index) - oldOutput.type = newOutput.type - oldOutput.name = newOutput.name - } - else { - node.addOutput(newOutput.name, newOutput.type, newOutput) - } + node.removeInput(index); + } + for (let index = 0; index < newNode.inputs.length; index++) { + const newInput = newNode.inputs[index] + const input = node.addInput(newInput.name, newInput.type); + } + + const createOutputReroute = (index: number, links: LLink[], connect: boolean = true): ComfyReroute => { const reroute = LiteGraph.createNode(ComfyReroute); reroute.properties.ignoreTypes = true; node.graph.add(reroute) const rerouteSize = reroute.computeSize(); const outputPos = node.getConnectionPos(false, index); reroute.pos = [outputPos[0] + rerouteSize[0] + 20, outputPos[1] + LiteGraph.NODE_SLOT_HEIGHT / 2]; - node.connect(index, reroute, 0); for (const link of links) { - reroute.connect(0, link.target_id, link.target_slot) + reroute.connect(0, node.graph.getNodeById(link.target_id), link.target_slot) } + return reroute + } + + for (let index = node.outputs.length - 1; index >= 0; index--) { + let links = node.getOutputLinks(index) + node.disconnectOutput(index) + + if (links.length > 0) + createOutputReroute(index, links); + + node.removeOutput(index); + } + + for (let index = 0; index < newNode.outputs.length; index++) { + const newOutput = newNode.outputs[index] + const output = node.addOutput(newOutput.name, newOutput.type); } } diff --git a/src/lib/api.ts b/src/lib/api.ts index d60b39c..2ac50e7 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -1,7 +1,7 @@ import type { Progress, SerializedPrompt, SerializedPromptInputs, SerializedPromptInputsAll, SerializedPromptOutput, SerializedPromptOutputs } from "./components/ComfyApp"; import type TypedEmitter from "typed-emitter"; import EventEmitter from "events"; -import type { GalleryOutput, GalleryOutputEntry } from "./nodes/ComfyWidgetNodes"; +import type { ComfyExecutionResult, ComfyImageLocation } from "./nodes/ComfyWidgetNodes"; import type { SerializedLGraph, UUID } from "@litegraph-ts/core"; import type { SerializedLayoutState } from "./stores/layoutState"; @@ -63,7 +63,7 @@ export type ComfyPromptPNGInfo = { } export type ComfyBoxPromptExtraData = ComfyUIPromptExtraData & { - thumbnails?: GalleryOutputEntry[], + thumbnails?: ComfyImageLocation[], } export type ComfyUIPromptExtraData = { @@ -258,9 +258,13 @@ export default class ComfyAPI { }, body: postBody }) - .then(res => res.json()) + .then(async (res) => { + if (res.status != 200) { + throw await res.text() + } + return res.json() + }) .then(raw => { return { promptID: raw.prompt_id } }) - .catch(res => { throw res.text() }) .catch(error => { return { error } }) } diff --git a/src/lib/components/ComfyApp.ts b/src/lib/components/ComfyApp.ts index 0b9d393..acb560f 100644 --- a/src/lib/components/ComfyApp.ts +++ b/src/lib/components/ComfyApp.ts @@ -32,7 +32,7 @@ import { download, jsonToJsObject, promptToGraphVis, range, workflowToGraphVis } import notify from "$lib/notify"; import configState from "$lib/stores/configState"; import { blankGraph } from "$lib/defaultGraph"; -import type { GalleryOutput } from "$lib/nodes/ComfyWidgetNodes"; +import type { ComfyExecutionResult } from "$lib/nodes/ComfyWidgetNodes"; export const COMFYBOX_SERIAL_VERSION = 1; @@ -71,7 +71,7 @@ export type SerializedPrompt = { output: SerializedPromptInputsAll } -export type SerializedPromptOutputs = Record +export type SerializedPromptOutputs = Record export type Progress = { value: number, @@ -245,7 +245,7 @@ export default class ComfyApp { const node: LGraphNodeConstructor = { class: ctor, - title: nodeData.name, + title: nodeData.display_name || nodeData.name, type: nodeId, desc: `ComfyNode: ${nodeId}` } @@ -347,7 +347,7 @@ export default class ComfyApp { this.lGraph.setDirtyCanvas(true, false); }); - this.api.addEventListener("executed", (promptID: PromptID, nodeID: NodeID, output: GalleryOutput) => { + this.api.addEventListener("executed", (promptID: PromptID, nodeID: NodeID, output: ComfyExecutionResult) => { this.nodeOutputs[nodeID] = output; const node = this.lGraph.getNodeById(nodeID) as ComfyGraphNode; if (node?.onExecuted) { @@ -408,7 +408,8 @@ export default class ComfyApp { setColor(type, "orange") } - setColor("IMAGE", "rebeccapurple") + setColor("COMFYBOX_IMAGES", "rebeccapurple") + setColor("COMFYBOX_IMAGE", "fuchsia") setColor(BuiltInSlotType.EVENT, "lightseagreen") setColor(BuiltInSlotType.ACTION, "lightseagreen") } @@ -785,15 +786,15 @@ export default class ComfyApp { queueState.afterQueued(promptID, num, p.output, extraData) error = response.error; - } catch (error) { - error = error.toString(); + } catch (err) { + error = err } if (error != null) { const mes = error.response || error.toString() notify(`Error queuing prompt:\n${mes}`, { type: "error" }) console.error(promptToGraphVis(p)) - console.error("Error queuing prompt", mes, num, p) + console.error("Error queuing prompt", error, num, p) break; } diff --git a/src/lib/components/ComfyQueue.svelte b/src/lib/components/ComfyQueue.svelte index ba6b8ae..2d2abf4 100644 --- a/src/lib/components/ComfyQueue.svelte +++ b/src/lib/components/ComfyQueue.svelte @@ -339,6 +339,7 @@ border-bottom: 1px solid var(--block-border-color); border-top: 1px solid var(--table-border-color); background: var(--panel-background-fill); + max-height: 14rem; &:hover:not(:has(img:hover)) { cursor: pointer; @@ -387,6 +388,7 @@ column-gap: 1px; row-gap: 1px; vertical-align: top; + flex: 1 1 40%; img { aspect-ratio: 1 / 1; diff --git a/src/lib/components/ImageUpload.svelte b/src/lib/components/ImageUpload.svelte new file mode 100644 index 0000000..1eb2c7f --- /dev/null +++ b/src/lib/components/ImageUpload.svelte @@ -0,0 +1,254 @@ + + +
+ {#if value} + + + {#if value && value.length > 0 && !pending_upload} + {@const firstImage = value[0]} + + {firstImage.filename} + {:else} + + + + {/if} + + {/if} +
+ + diff --git a/src/lib/components/Modal.svelte b/src/lib/components/Modal.svelte index 856882e..83200e0 100644 --- a/src/lib/components/Modal.svelte +++ b/src/lib/components/Modal.svelte @@ -1,23 +1,52 @@ - (showModal = false)} - on:click|self={() => dialog.close()} + bind:this={dialog} + on:close={close} + on:cancel={doClose} + on:click|self={close} > -
- - - - -
+
+ + +
+ + + + +
+
diff --git a/src/lib/components/NumberInput.svelte b/src/lib/components/NumberInput.svelte new file mode 100644 index 0000000..0a574c4 --- /dev/null +++ b/src/lib/components/NumberInput.svelte @@ -0,0 +1,110 @@ + + + +
+
+ + +
+
+ + diff --git a/src/lib/components/gradio/app/Column.svelte b/src/lib/components/gradio/app/Column.svelte new file mode 100644 index 0000000..77da7a1 --- /dev/null +++ b/src/lib/components/gradio/app/Column.svelte @@ -0,0 +1,58 @@ + + +
+ +
+ + diff --git a/src/lib/components/gradio/app/Row.svelte b/src/lib/components/gradio/app/Row.svelte new file mode 100644 index 0000000..84a61fa --- /dev/null +++ b/src/lib/components/gradio/app/Row.svelte @@ -0,0 +1,60 @@ + + +
+ +
+ + diff --git a/src/lib/nodes/ComfyActionNodes.ts b/src/lib/nodes/ComfyActionNodes.ts index c7e5cb2..a34fa81 100644 --- a/src/lib/nodes/ComfyActionNodes.ts +++ b/src/lib/nodes/ComfyActionNodes.ts @@ -5,10 +5,10 @@ import queueState from "$lib/stores/queueState"; import { BuiltInSlotType, LiteGraph, NodeMode, type ITextWidget, type IToggleWidget, type SerializedLGraphNode, type SlotLayout, type PropertyLayout } from "@litegraph-ts/core"; import { get } from "svelte/store"; import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode"; -import type { ComfyWidgetNode, GalleryOutput, GalleryOutputEntry } from "./ComfyWidgetNodes"; +import type { ComfyWidgetNode, ComfyExecutionResult, ComfyImageLocation } from "./ComfyWidgetNodes"; import type { NotifyOptions } from "$lib/notify"; import type { FileData as GradioFileData } from "@gradio/upload"; -import { convertComfyOutputToGradio, uploadImageToComfyUI, type ComfyUploadImageAPIResponse } from "$lib/utils"; +import { convertComfyOutputToGradio, type ComfyUploadImageAPIResponse } from "$lib/utils"; export class ComfyQueueEvents extends ComfyGraphNode { static slotLayout: SlotLayout = { @@ -63,7 +63,7 @@ LiteGraph.registerNodeType({ }) export interface ComfyStoreImagesActionProperties extends ComfyGraphNodeProperties { - images: GalleryOutput | null + images: ComfyExecutionResult | null } export class ComfyStoreImagesAction extends ComfyGraphNode { @@ -90,7 +90,7 @@ export class ComfyStoreImagesAction extends ComfyGraphNode { if (action !== "store" || !param || !("images" in param)) return; - this.setProperty("images", param as GalleryOutput) + this.setProperty("images", param as ComfyExecutionResult) this.setOutputData(0, this.properties.images) } } @@ -223,7 +223,7 @@ export class ComfyNotifyAction extends ComfyGraphNode { // native notifications. if (param != null && typeof param === "object") { if ("images" in param) { - const output = param as GalleryOutput; + const output = param as ComfyExecutionResult; const converted = convertComfyOutputToGradio(output); if (converted.length > 0) options.imageUrl = converted[0].data; @@ -581,86 +581,6 @@ LiteGraph.registerNodeType({ type: "events/no_change" }) -export interface ComfyUploadImageActionProperties extends ComfyGraphNodeProperties { - folderType: "output" | "temp" - lastUploadedImageFile: string | null -} - -export class ComfyUploadImageAction extends ComfyGraphNode { - override properties: ComfyUploadImageActionProperties = { - tags: [], - folderType: "output", - lastUploadedImageFile: null - } - - static slotLayout: SlotLayout = { - inputs: [ - { name: "filename", type: "string" }, - { name: "trigger", type: BuiltInSlotType.ACTION } - ], - outputs: [ - { name: "input_filename", type: "string" }, - { name: "uploaded", type: BuiltInSlotType.EVENT } - ], - } - - private _promise = null; - - displayWidget: ITextWidget; - - constructor(title?: string) { - super(title); - this.displayWidget = this.addWidget( - "text", - "File", - this.properties.lastUploadedImageFile, - "lastUploadedImageFile" - ); - this.displayWidget.disabled = true; - } - - override onExecute() { - this.setOutputData(0, this.properties.lastUploadedImageFile) - } - - override onAction(action: any, param: any) { - if (action !== "trigger" || this._promise != null) - return; - - const filename = this.getInputData(0) - if (typeof filename !== "string" || !filename) { - return; - } - - const data: GalleryOutputEntry = { - filename, - subfolder: "", - type: this.properties.folderType || "output" - } - - this._promise = uploadImageToComfyUI(data) - .then((json: ComfyUploadImageAPIResponse) => { - console.debug("[UploadImageAction] Succeeded", json) - this.properties.lastUploadedImageFile = json.name; - this.triggerSlot(1, this.properties.lastUploadedImageFile); - this._promise = null; - }) - .catch((e) => { - console.error("Error uploading:", e) - notify(`Error uploading image to ComfyUi: ${e}`, { type: "error", timeout: 10000 }) - this.properties.lastUploadedImageFile = null; - this._promise = null; - }) - } -} - -LiteGraph.registerNodeType({ - class: ComfyUploadImageAction, - title: "Comfy.UploadImageAction", - desc: "Uploads an image from the specified ComfyUI folder into its input folder", - type: "actions/store_images" -}) - export interface ComfySetPromptThumbnailsActionProperties extends ComfyGraphNodeProperties { defaultFolderType: string | null } @@ -679,12 +599,12 @@ export class ComfySetPromptThumbnailsAction extends ComfyGraphNode { _value: any = null; - override getPromptThumbnails(): GalleryOutputEntry[] | null { + override getPromptThumbnails(): ComfyImageLocation[] | null { const data = this.getInputData(0) const folderType = this.properties.folderType || "input"; - const convertString = (s: string): GalleryOutputEntry => { + const convertString = (s: string): ComfyImageLocation => { return { filename: data, subfolder: "", type: folderType } } @@ -693,13 +613,13 @@ export class ComfySetPromptThumbnailsAction extends ComfyGraphNode { } else if (data != null && typeof data === "object") { if ("filename" in data && "type" in data) - return [data as GalleryOutputEntry]; + return [data as ComfyImageLocation]; } else if (Array.isArray(data) && data.length > 0) { if (typeof data[0] === "string") return data.map(convertString) else if (typeof data[0] === "object" && "filename" in data[0] && "type" in data[0]) - return data as GalleryOutputEntry[] + return data as ComfyImageLocation[] } return null; } diff --git a/src/lib/nodes/ComfyBackendNode.ts b/src/lib/nodes/ComfyBackendNode.ts index c6039e6..a75c968 100644 --- a/src/lib/nodes/ComfyBackendNode.ts +++ b/src/lib/nodes/ComfyBackendNode.ts @@ -1,8 +1,8 @@ import LGraphCanvas from "@litegraph-ts/core/src/LGraphCanvas"; import ComfyGraphNode from "./ComfyGraphNode"; import ComfyWidgets from "$lib/widgets" -import type { ComfyWidgetNode, GalleryOutput } from "./ComfyWidgetNodes"; -import { BuiltInSlotType, type SerializedLGraphNode } from "@litegraph-ts/core"; +import type { ComfyWidgetNode, ComfyExecutionResult } from "./ComfyWidgetNodes"; +import { BuiltInSlotShape, BuiltInSlotType, type SerializedLGraphNode } from "@litegraph-ts/core"; import type IComfyInputSlot from "$lib/IComfyInputSlot"; import type { ComfyInputConfig } from "$lib/IComfyInputSlot"; @@ -11,10 +11,12 @@ import type { ComfyInputConfig } from "$lib/IComfyInputSlot"; */ export class ComfyBackendNode extends ComfyGraphNode { comfyClass: string; + displayName: string | null; constructor(title: string, comfyClass: string, nodeData: any) { super(title) this.type = comfyClass; // XXX: workaround dependency in LGraphNode.addInput() + this.displayName = nodeData.display_name; this.comfyClass = comfyClass; this.isBackendNode = true; @@ -32,6 +34,7 @@ export class ComfyBackendNode extends ComfyGraphNode { } } + // comfy class -> input name -> input config private static defaultInputConfigs: Record> = {} private setup(nodeData: any) { @@ -43,7 +46,7 @@ export class ComfyBackendNode extends ComfyGraphNode { ComfyBackendNode.defaultInputConfigs[this.type] = {} for (const inputName in inputs) { - const config = { minWidth: 1, minHeight: 1 }; + const config: Partial = {}; const inputData = inputs[inputName]; const type = inputData[0]; @@ -67,13 +70,14 @@ export class ComfyBackendNode extends ComfyGraphNode { } if ("widgetNodeType" in config) - ComfyBackendNode.defaultInputConfigs[this.type][config.name] = config.config + ComfyBackendNode.defaultInputConfigs[this.type][inputName] = (config as IComfyInputSlot).config } for (const o in nodeData["output"]) { const output = nodeData["output"][o]; const outputName = nodeData["output_name"][o] || output; - this.addOutput(outputName, output); + const outputShape = nodeData["output_is_list"][o] ? BuiltInSlotShape.GRID_SHAPE : BuiltInSlotShape.CIRCLE_SHAPE; + this.addOutput(outputName, output, { shape: outputShape }); } this.serialize_widgets = false; @@ -110,7 +114,7 @@ export class ComfyBackendNode extends ComfyGraphNode { } } - override onExecuted(outputData: GalleryOutput) { + override onExecuted(outputData: ComfyExecutionResult) { console.warn("onExecuted outputs", outputData) this.triggerSlot(0, outputData) } diff --git a/src/lib/nodes/ComfyGraphNode.ts b/src/lib/nodes/ComfyGraphNode.ts index b91c0ac..367ae19 100644 --- a/src/lib/nodes/ComfyGraphNode.ts +++ b/src/lib/nodes/ComfyGraphNode.ts @@ -3,7 +3,7 @@ import type { SerializedPrompt } from "$lib/components/ComfyApp"; import type ComfyWidget from "$lib/components/widgets/ComfyWidget"; import { LGraph, LGraphNode, LLink, LiteGraph, NodeMode, type INodeInputSlot, type SerializedLGraphNode, type Vector2, type INodeOutputSlot, LConnectionKind, type SlotType, LGraphCanvas, getStaticPropertyOnInstance, type PropertyLayout, type SlotLayout } from "@litegraph-ts/core"; import type { SvelteComponentDev } from "svelte/internal"; -import type { ComfyWidgetNode, GalleryOutput, GalleryOutputEntry } from "./ComfyWidgetNodes"; +import type { ComfyWidgetNode, ComfyExecutionResult, ComfyImageLocation } from "./ComfyWidgetNodes"; import type IComfyInputSlot from "$lib/IComfyInputSlot"; import uiState from "$lib/stores/uiState"; import { get } from "svelte/store"; @@ -48,14 +48,14 @@ export default class ComfyGraphNode extends LGraphNode { * Triggered when the backend sends a finished output back with this node's ID. * Valid for output nodes like SaveImage and PreviewImage. */ - onExecuted?(output: GalleryOutput): void; + onExecuted?(output: ComfyExecutionResult): void; /* * When a prompt is queued, this will be called on the node if it can * provide any thumbnails for use with the prompt queue. Useful for HR Fix * or img2img workloads. */ - getPromptThumbnails?(): GalleryOutputEntry[] | null + getPromptThumbnails?(): ComfyImageLocation[] | null /* * Allows you to manually specify an auto-config for certain input slot diff --git a/src/lib/nodes/ComfyImageCacheNode.ts b/src/lib/nodes/ComfyImageCacheNode.ts deleted file mode 100644 index 65910af..0000000 --- a/src/lib/nodes/ComfyImageCacheNode.ts +++ /dev/null @@ -1,241 +0,0 @@ -import { BuiltInSlotType, LiteGraph, type ITextWidget, type SlotLayout, clamp, type PropertyLayout, type IComboWidget, type SerializedLGraphNode } from "@litegraph-ts/core"; -import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode"; -import type { GalleryOutput } from "./ComfyWidgetNodes"; -import { uploadImageToComfyUI, type ComfyUploadImageAPIResponse } from "$lib/utils"; - -export interface ComfyImageCacheNodeProperties extends ComfyGraphNodeProperties { - images: GalleryOutput | null, - index: number, - filenames: Record, - genNumber: number, - updateMode: "replace" | "append" -} - -type ImageCacheState = "none" | "uploading" | "failed" | "cached" - -/* - * A node that can act as both an input and output image node by uploading - * the output file into ComfyUI's input folder. - */ -export default class ComfyImageCacheNode extends ComfyGraphNode { - override properties: ComfyImageCacheNodeProperties = { - tags: [], - images: null, - index: 0, - filenames: {}, - genNumber: 0, - updateMode: "replace" - } - - static slotLayout: SlotLayout = { - inputs: [ - { name: "images", type: "OUTPUT" }, - { name: "index", type: "number" }, - { name: "store", type: BuiltInSlotType.ACTION, options: { color_off: "rebeccapurple", color_on: "rebeccapurple" } }, - { name: "clear", type: BuiltInSlotType.ACTION } - ], - outputs: [ - { name: "filename", type: "string" }, - { name: "state", type: "string" }, - ] - } - - static propertyLayout: PropertyLayout = [ - { name: "updateMode", defaultValue: "replace", type: "enum", options: { values: ["replace", "append"] } } - ] - - override saveUserState = false; - - private _uploadPromise: Promise | null = null; - - stateWidget: ITextWidget; - filenameWidget: ITextWidget; - modeWidget: IComboWidget; - - constructor(name?: string) { - super(name) - this.stateWidget = this.addWidget( - "text", - "State", - "none" - ); - this.stateWidget.disabled = true; - - this.filenameWidget = this.addWidget( - "text", - "File", - "" - ); - this.filenameWidget.disabled = true; - - this.modeWidget = this.addWidget( - "combo", - "Mode", - this.properties.updateMode, - null, - { property: "updateMode", values: ["replace", "append"] } - ); - } - - override onPropertyChanged(property: string, value: any, prevValue?: any) { - if (property === "images") { - if (value != null) - this.properties.index = clamp(this.properties.index, 0, value.length) - else - this.properties.index = 0 - } - else if (property === "updateMode") { - this.modeWidget.value = value; - } - - this.updateWidgets() - } - - private updateWidgets() { - if (this.properties.filenames && this.properties.images) { - const fileCount = this.properties.images.images.length; - const cachedCount = Object.keys(this.properties.filenames).length - console.warn(cachedCount, this.properties.filenames) - this.filenameWidget.value = `${fileCount} files, ${cachedCount} cached` - } - else { - this.filenameWidget.value = `No files cached` - } - } - - override onExecute() { - const index = this.getInputData(1) - if (typeof index === "number") - this.setIndex(index) - - const existing = this.properties.filenames[this.properties.index] - let state = "none" - if (existing) - state = existing.status - - this.stateWidget.value = state - - let filename = null - if (this.properties.index in this.properties.filenames) - filename = this.properties.filenames[this.properties.index].filename - - this.setOutputData(0, filename) - this.setOutputData(1, state) - } - - override stripUserState(o: SerializedLGraphNode) { - super.stripUserState(o); - o.properties.images = null - o.properties.index = 0 - o.properties.filenames = {} - o.properties.genNumber = 0 - } - - private setIndex(newIndex: number, force: boolean = false) { - if (newIndex === this.properties.index && !force) - return; - - if (!this.properties.images || newIndex < 0 || newIndex >= this.properties.images.images.length) { - return - } - - this.setProperty("index", newIndex) - - const data = this.properties.images.images[newIndex] - - if (data == null) { - return; - } - - this.properties.filenames ||= {} - const existing = this.properties.filenames[newIndex] - - if (existing != null && existing.status === "cached") { - return - } - - const lastGenNumber = this.properties.genNumber - - // ComfyUI's LoadImage node only operates on files in its input - // folder. Usually we're dealing with an image in either the output - // folder (SaveImage) or the temp folder (PreviewImage). So we have - // to copy the image into ComfyUI's input folder first by using - // their upload API. - - if (data.subfolder === "input") { - // Already in the correct folder for use by LoadImage - this.properties.filenames[newIndex] = { filename: data.filename, status: "cached" } - this.onPropertyChanged("filenames", this.properties.filenames) - } - else { - this.properties.filenames[newIndex] = { filename: null, status: "uploading" } - this.onPropertyChanged("filenames", this.properties.filenames) - - const promise = uploadImageToComfyUI(data) - .then((json: ComfyUploadImageAPIResponse) => { - console.debug("Gottem", json) - if (lastGenNumber === this.properties.genNumber) { - this.properties.filenames[newIndex] = { filename: json.name, status: "cached" } - this.onPropertyChanged("filenames", this.properties.filenames) - } - else { - console.warn("[ComfyImageCacheNode] New generation since index switched!") - } - this._uploadPromise = null; - }) - .catch((e) => { - console.error("Error uploading:", e) - if (lastGenNumber === this.properties.genNumber) { - this.properties.filenames[newIndex] = { filename: null, status: "failed" } - this.onPropertyChanged("filenames", this.properties.filenames) - } - else { - console.warn("[ComfyImageCacheNode] New generation since index switched!") - } - }) - - if (this._uploadPromise) - this._uploadPromise.then(() => promise) - else - this._uploadPromise = promise - } - } - - override onAction(action: any, param: any) { - if (action === "clear") { - this.setProperty("images", null) - this.setProperty("filenames", {}) - this.setProperty("index", 0) - this.updateWidgets(); - return - } - - if (param && "images" in param) { - this.setProperty("genNumber", this.properties.genNumber + 1) - - const output = param as GalleryOutput; - - if (this.properties.updateMode === "append" && this.properties.images != null) { - const newImages = this.properties.images.images.concat(output.images) - this.properties.images.images = newImages - this.setProperty("images", this.properties.images) - } - else { - this.setProperty("images", param as GalleryOutput) - this.setProperty("filenames", {}) - } - - console.debug("[ComfyImageCacheNode] Received output!", output, this.properties.updateMode, this.properties.images) - this.setIndex(0, true) - } - - this.updateWidgets(); - } -} - -LiteGraph.registerNodeType({ - class: ComfyImageCacheNode, - title: "Comfy.ImageCache", - desc: "Allows reusing a previously output image by uploading it into ComfyUI's input folder.", - type: "image/cache" -}) diff --git a/src/lib/nodes/ComfyImageToFilepathNode.ts b/src/lib/nodes/ComfyImageToFilepathNode.ts new file mode 100644 index 0000000..5118d31 --- /dev/null +++ b/src/lib/nodes/ComfyImageToFilepathNode.ts @@ -0,0 +1,33 @@ +import { LiteGraph, type SlotLayout } from "@litegraph-ts/core"; +import ComfyGraphNode from "./ComfyGraphNode"; +import { comfyFileToAnnotatedFilepath, isComfyBoxImageMetadata, parseWhateverIntoImageMetadata } from "$lib/utils"; + +export default class ComfyImageToFilepathNode extends ComfyGraphNode { + static slotLayout: SlotLayout = { + inputs: [ + { name: "image", type: "COMFYBOX_IMAGES,COMFYBOX_IMAGE" }, + ], + outputs: [ + { name: "filepath", type: "string" }, + ] + } + + override onExecute() { + const data = this.getInputData(0) + const meta = parseWhateverIntoImageMetadata(data); + if (meta == null || meta.length === 0) { + this.setOutputData(0, null) + return; + } + + const path = comfyFileToAnnotatedFilepath(meta[0].comfyUIFile); + this.setOutputData(0, path); + } +} + +LiteGraph.registerNodeType({ + class: ComfyImageToFilepathNode, + title: "Comfy.ImageToFilepath", + desc: "Converts ComfyBox image metadata to an annotated filepath like \"image.png[output]\" for use with ComfyUI.", + type: "image/file_to_filepath" +}) diff --git a/src/lib/nodes/ComfyPickImageNode.ts b/src/lib/nodes/ComfyPickImageNode.ts new file mode 100644 index 0000000..46dfb2c --- /dev/null +++ b/src/lib/nodes/ComfyPickImageNode.ts @@ -0,0 +1,35 @@ +import { LiteGraph, type SlotLayout } from "@litegraph-ts/core"; +import ComfyGraphNode from "./ComfyGraphNode"; +import { isComfyBoxImageMetadataArray } from "$lib/utils"; + +/* + * TODO: This is just a temporary workaround until litegraph can handle typed + * array arguments. + */ +export default class ComfyPickImageNode extends ComfyGraphNode { + static slotLayout: SlotLayout = { + inputs: [ + { name: "images", type: "COMFYBOX_IMAGES" }, + ], + outputs: [ + { name: "image", type: "COMFYBOX_IMAGE" }, + ] + } + + override onExecute() { + const data = this.getInputData(0) + if (data == null || !isComfyBoxImageMetadataArray(data)) { + this.setOutputData(0, null) + return; + } + + this.setOutputData(0, data[0]); + } +} + +LiteGraph.registerNodeType({ + class: ComfyPickImageNode, + title: "Comfy.PickImage", + desc: "Picks out the first image from an array of ComfyBox images.", + type: "image/pick_image" +}) diff --git a/src/lib/nodes/ComfyWidgetNodes.ts b/src/lib/nodes/ComfyWidgetNodes.ts index e3e9667..0185bdc 100644 --- a/src/lib/nodes/ComfyWidgetNodes.ts +++ b/src/lib/nodes/ComfyWidgetNodes.ts @@ -1,10 +1,10 @@ -import { LiteGraph, type ContextMenuItem, type LGraphNode, type Vector2, LConnectionKind, LLink, LGraphCanvas, type SlotType, TitleMode, type SlotLayout, LGraph, type INodeInputSlot, type ITextWidget, type INodeOutputSlot, type SerializedLGraphNode, BuiltInSlotType, type PropertyLayout, type IComboWidget, NodeMode, type INumberWidget } from "@litegraph-ts/core"; +import { LiteGraph, type ContextMenuItem, type LGraphNode, type Vector2, LConnectionKind, LLink, LGraphCanvas, type SlotType, TitleMode, type SlotLayout, LGraph, type INodeInputSlot, type ITextWidget, type INodeOutputSlot, type SerializedLGraphNode, BuiltInSlotType, type PropertyLayout, type IComboWidget, NodeMode, type INumberWidget, type UUID } from "@litegraph-ts/core"; import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode"; import type { SvelteComponentDev } from "svelte/internal"; import { Watch } from "@litegraph-ts/nodes-basic"; import type IComfyInputSlot from "$lib/IComfyInputSlot"; import { writable, type Unsubscriber, type Writable, get } from "svelte/store"; -import { clamp, convertComfyOutputToGradio, range } from "$lib/utils" +import { clamp, convertComfyOutputToGradio, range, type ComfyUploadImageType, isComfyBoxImageMetadata, filenameToComfyBoxMetadata, type ComfyBoxImageMetadata, isComfyExecutionResult, executionResultToImageMetadata, parseWhateverIntoImageMetadata } from "$lib/utils" import layoutState from "$lib/stores/layoutState"; import type { FileData as GradioFileData } from "@gradio/upload"; import queueState from "$lib/stores/queueState"; @@ -17,7 +17,8 @@ import ButtonWidget from "$lib/widgets/ButtonWidget.svelte"; import CheckboxWidget from "$lib/widgets/CheckboxWidget.svelte"; import RadioWidget from "$lib/widgets/RadioWidget.svelte"; import ImageUploadWidget from "$lib/widgets/ImageUploadWidget.svelte"; -import ImageCompareWidget from "$lib/widgets/ImageCompareWidget.svelte"; +import ImageEditorWidget from "$lib/widgets/ImageEditorWidget.svelte"; +import type { NodeID } from "$lib/api"; export type AutoConfigOptions = { includeProperties?: Set | null, @@ -33,7 +34,7 @@ export type AutoConfigOptions = { * - Go to layoutState, look for `ALL_ATTRIBUTES,` insert or find a "variant" * attribute and set `validNodeTypes` to the type of the litegraph node * - Add a new entry in the `values` array, like "knob" or "dial" for ComfySliderWidget - * - Add an {#if widget.attrs.variant === <...>} statement in the corresponding Svelte component + * - Add an {#if widget.attrs.variant === <...>} statement in the existing Svelte component * * Also, BEWARE of calling setOutputData() and triggerSlot() on the same frame! * You will have to either implement an internal delay on the event triggering @@ -91,7 +92,7 @@ export abstract class ComfyWidgetNode extends ComfyGraphNode { // TODO these are bad, create override methods instead // input slots - inputIndex: number = 0; + inputIndex: number | null = null; storeActionName: string | null = "store"; // output slots @@ -169,6 +170,10 @@ export abstract class ComfyWidgetNode extends ComfyGraphNode { parseValue(value: any): T { return value as T }; + getValue(): T { + return get(this.value); + } + setValue(value: any, noChangedEvent: boolean = false) { if (noChangedEvent) this._noChangedEvent = true; @@ -193,7 +198,7 @@ export abstract class ComfyWidgetNode extends ComfyGraphNode { * Logic to run if this widget can be treated as output (slider, combo, text) */ override onExecute(param: any, options: object) { - if (this.copyFromInputLink) { + if (this.inputIndex != null) { if (this.inputs.length >= this.inputIndex) { const data = this.getInputData(this.inputIndex) if (data != null) { // TODO can "null" be a legitimate value here? @@ -201,8 +206,10 @@ export abstract class ComfyWidgetNode extends ComfyGraphNode { } } } - if (this.outputs.length >= this.outputIndex) { - this.setOutputData(this.outputIndex, get(this.value)) + if (this.outputIndex != null) { + if (this.outputs.length >= this.outputIndex) { + this.setOutputData(this.outputIndex, get(this.value)) + } } for (const propName in this.shownOutputProperties) { const data = this.shownOutputProperties[propName] @@ -265,7 +272,7 @@ export abstract class ComfyWidgetNode extends ComfyGraphNode { } if (options.setWidgetTitle) { - const widget = layoutState.findLayoutForNode(this.id) + const widget = layoutState.findLayoutForNode(this.id as NodeID) if (widget && input.name !== "") { widget.attrs.title = input.name; } @@ -284,7 +291,7 @@ export abstract class ComfyWidgetNode extends ComfyGraphNode { } notifyPropsChanged() { - const layoutEntry = layoutState.findLayoutEntryForNode(this.id) + const layoutEntry = layoutState.findLayoutEntryForNode(this.id as NodeID) if (layoutEntry && layoutEntry.parent) { layoutEntry.parent.attrsChanged.set(get(layoutEntry.parent.attrsChanged) + 1) } @@ -596,15 +603,21 @@ LiteGraph.registerNodeType({ }) /** Raw output as received from ComfyUI's backend */ -export type GalleryOutput = { - images: GalleryOutputEntry[] +export interface ComfyExecutionResult { + // Technically this response can contain arbitrary data, but "images" is the + // most frequently used as it's output by LoadImage and PreviewImage, the + // only two output nodes in base ComfyUI. + images: ComfyImageLocation[] | null, } /** Raw output entry as received from ComfyUI's backend */ -export type GalleryOutputEntry = { +export type ComfyImageLocation = { + /* Filename with extension in the subfolder. */ filename: string, + /* Subfolder in the containing folder. */ subfolder: string, - type: string + /* Base ComfyUI folder where the image is located. */ + type: ComfyUploadImageType } export interface ComfyGalleryProperties extends ComfyWidgetProperties { @@ -612,7 +625,7 @@ export interface ComfyGalleryProperties extends ComfyWidgetProperties { updateMode: "replace" | "append", } -export class ComfyGalleryNode extends ComfyWidgetNode { +export class ComfyGalleryNode extends ComfyWidgetNode { override properties: ComfyGalleryProperties = { tags: [], defaultValue: [], @@ -623,14 +636,11 @@ export class ComfyGalleryNode extends ComfyWidgetNode { static slotLayout: SlotLayout = { inputs: [ { name: "images", type: "OUTPUT" }, - { name: "store", type: BuiltInSlotType.ACTION, options: { color_off: "rebeccapurple", color_on: "rebeccapurple" } }, - { name: "clear", type: BuiltInSlotType.ACTION } + { name: "store", type: BuiltInSlotType.ACTION, options: { color_off: "rebeccapurple", color_on: "rebeccapurple" } } ], outputs: [ + { name: "images", type: "COMFYBOX_IMAGES" }, { name: "selected_index", type: "number" }, - { name: "width", type: "number" }, - { name: "height", type: "number" }, - { name: "filename", type: "string" }, ] } @@ -640,7 +650,7 @@ export class ComfyGalleryNode extends ComfyWidgetNode { override svelteComponentType = GalleryWidget override defaultValue = [] - override copyFromInputLink = false; + override inputIndex = null; override saveUserState = false; override outputIndex = null; override changedIndex = null; @@ -663,53 +673,30 @@ export class ComfyGalleryNode extends ComfyWidgetNode { } } - imageSize: Vector2 = [1, 1] - override onExecute() { - const index = this.properties.index; - - this.setOutputData(0, index) - this.setOutputData(1, this.imageSize[0]) - this.setOutputData(2, this.imageSize[1]) - - let filename: string | null = null; - if (index != null) { - const entry = get(this.value)[index]; - if (entry) - filename = entry.name - } - - this.setOutputData(3, filename) + this.setOutputData(0, get(this.value)) + this.setOutputData(1, this.properties.index) } override onAction(action: any, param: any, options: { action_call?: string }) { super.onAction(action, param, options) - - if (action === "clear") { - this.setValue([]) - } } - override formatValue(value: GradioFileData[] | null): string { + override formatValue(value: ComfyBoxImageMetadata[] | null): string { return `Images: ${value?.length || 0}` } - override parseValue(param: any): GradioFileData[] { - if (!(typeof param === "object" && "images" in param)) { - return [] - } + override parseValue(param: any): ComfyBoxImageMetadata[] { + const meta = parseWhateverIntoImageMetadata(param) || []; - const data = param as GalleryOutput - console.debug("[ComfyGalleryNode] Received output!", data) - - const galleryItems: GradioFileData[] = convertComfyOutputToGradio(data) + console.debug("[ComfyGalleryNode] Received output!", param) if (this.properties.updateMode === "append") { const currentValue = get(this.value) - return currentValue.concat(galleryItems) + return currentValue.concat(meta) } else { - return galleryItems; + return meta; } } @@ -886,15 +873,13 @@ LiteGraph.registerNodeType({ type: "ui/radio" }) -export interface ComfyImageUploadProperties extends ComfyWidgetProperties { - fileCount: "single" | "multiple" // gradio File component format +export interface ComfyImageEditorNodeProperties extends ComfyWidgetProperties { } -export class ComfyImageUploadNode extends ComfyWidgetNode> { - override properties: ComfyImageUploadProperties = { +export class ComfyImageEditorNode extends ComfyWidgetNode { + override properties: ComfyImageEditorNodeProperties = { defaultValue: [], tags: [], - fileCount: "single", } static slotLayout: SlotLayout = { @@ -902,55 +887,25 @@ export class ComfyImageUploadNode extends ComfyWidgetNode> { name: "store", type: BuiltInSlotType.ACTION } ], outputs: [ - { name: "filename", type: "string" }, // TODO support batches - { name: "width", type: "number" }, - { name: "height", type: "number" }, - { name: "image_count", type: "number" }, + { name: "images", type: "COMFYBOX_IMAGES" }, // TODO support batches { name: "changed", type: BuiltInSlotType.EVENT }, ] } - override svelteComponentType = ImageUploadWidget; + override svelteComponentType = ImageEditorWidget; override defaultValue = []; - override outputIndex = null; - override changedIndex = 3; + override outputIndex = 0; + override inputIndex = null; + override changedIndex = 1; override storeActionName = "store"; override saveUserState = false; - imageSize: Vector2 = [1, 1]; - constructor(name?: string) { super(name, []) } - override parseValue(value: any): GradioFileData[] { - if (value == null) - return [] - - if (typeof value === "string" && value !== "") { // Single filename - return [{ name: value, data: value, orig_name: value, is_file: true }] - } - else { - return [] - } - } - - override onExecute(param: any, options: object) { - super.onExecute(param, options); - - const value = get(this.value) - if (value.length > 0 && value[0].name) { - this.setOutputData(0, value[0].name) // TODO when ComfyUI LoadImage supports loading an image batch - this.setOutputData(1, this.imageSize[0]) - this.setOutputData(2, this.imageSize[1]) - this.setOutputData(3, value.length) - } - else { - this.setOutputData(0, "") - this.setOutputData(1, 1) - this.setOutputData(2, 1) - this.setOutputData(3, 0) - } + override parseValue(value: any): ComfyBoxImageMetadata[] { + return parseWhateverIntoImageMetadata(value) || []; } override formatValue(value: GradioFileData[]): string { @@ -959,97 +914,8 @@ export class ComfyImageUploadNode extends ComfyWidgetNode> } LiteGraph.registerNodeType({ - class: ComfyImageUploadNode, - title: "UI.ImageUpload", - desc: "Widget that lets you upload images into ComfyUI's input folder", - type: "ui/image_upload" -}) - -export interface ComfyImageCompareNodeProperties extends ComfyWidgetProperties { -} - -export type FileNameOrGalleryData = string | GalleryOutputEntry; -export type ImageCompareData = [FileNameOrGalleryData, FileNameOrGalleryData] - -export class ComfyImageCompareNode extends ComfyWidgetNode { - override properties: ComfyImageCompareNodeProperties = { - defaultValue: [], - tags: [], - } - - static slotLayout: SlotLayout = { - inputs: [ - { name: "store", type: BuiltInSlotType.ACTION }, - { name: "left_image", type: "string" }, - { name: "right_image", type: "string" }, - ], - outputs: [ - ] - } - - override svelteComponentType = ImageCompareWidget; - override defaultValue: ImageCompareData = ["", ""]; - override outputIndex = null; - override changedIndex = 3; - override storeActionName = "store"; - override saveUserState = false; - - constructor(name?: string) { - super(name, ["", ""]) - } - - override onExecute() { - const valueA = this.getInputData(1) - const valueB = this.getInputData(2) - let current = get(this.value) - let changed = false; - if (valueA != null && current[0] != valueA) { - current[0] = valueA - changed = true; - } - if (valueB != null && current[1] != valueB) { - current[1] = valueB - changed = true; - } - if (changed) - this.value.set(current) - } - - override parseValue(value: any): ImageCompareData { - if (value == null) { - return ["", ""] - } - else if (typeof value === "string" && value !== "") { // Single filename - const prevValue = get(this.value) - prevValue.push(value) - if (prevValue.length > 2) - prevValue.splice(0, 1) - return prevValue as ImageCompareData - } - else if (typeof value === "object" && "images" in value && value.images.length > 0) { - const output = value as GalleryOutput - const prevValue = get(this.value) - prevValue.push(output.images[0].filename) - if (prevValue.length > 2) - prevValue.splice(0, 1) - return prevValue as ImageCompareData - } - else if (Array.isArray(value) && typeof value[0] === "string" && typeof value[1] === "string") { - return value as ImageCompareData - } - else { - return ["", ""] - } - } - - override formatValue(value: GradioFileData[]): string { - return `Images: ${value?.length || 0}` - } -} - -LiteGraph.registerNodeType({ - class: ComfyImageCompareNode, - title: "UI.ImageCompare", - desc: "Widget that lets you compare two images", - type: "ui/image_compare" + class: ComfyImageEditorNode, + title: "UI.ImageEditor", + desc: "Widget that lets you upload and edit a multi-layered image. Can also act like a standalone image uploader.", + type: "ui/image_editor" }) diff --git a/src/lib/nodes/index.ts b/src/lib/nodes/index.ts index 1ccbfd0..19b35cd 100644 --- a/src/lib/nodes/index.ts +++ b/src/lib/nodes/index.ts @@ -14,6 +14,7 @@ export { export { default as ComfyPickFirstNode } from "./ComfyPickFirstNode" export { default as ComfyValueControl } from "./ComfyValueControl" export { default as ComfySelector } from "./ComfySelector" -export { default as ComfyImageCacheNode } from "./ComfyImageCacheNode" export { default as ComfyTriggerNewEventNode } from "./ComfyTriggerNewEventNode" export { default as ComfyConfigureQueuePromptButton } from "./ComfyConfigureQueuePromptButton" +export { default as ComfyPickImageNode } from "./ComfyPickImageNode" +export { default as ComfyImageToFilepathNode } from "./ComfyImageToFilepathNode" diff --git a/src/lib/stores/layoutState.ts b/src/lib/stores/layoutState.ts index af3643b..b65d848 100644 --- a/src/lib/stores/layoutState.ts +++ b/src/lib/stores/layoutState.ts @@ -5,6 +5,7 @@ import { type LGraphNode, type IWidget, type LGraph, NodeMode, type LGraphRemove import { SHADOW_PLACEHOLDER_ITEM_ID } from 'svelte-dnd-action'; import type { ComfyWidgetNode } from '$lib/nodes'; import type { NodeID } from '$lib/api'; +import { v4 as uuidv4 } from "uuid"; type DragItemEntry = { /* @@ -61,11 +62,6 @@ export type LayoutState = { */ allItemsByNode: Record, - /* - * Next ID to use for instantiating a new drag item - */ - currentId: UUID, - /* * Selected drag items. */ @@ -411,6 +407,18 @@ const ALL_ATTRIBUTES: AttributesSpecList = [ defaultValue: "" }, + // Editor + { + name: "variant", + type: "enum", + location: "widget", + editable: true, + validNodeTypes: ["ui/image_editor"], + values: ["inlineEditor", "fileUpload"], + defaultValue: "inlineEditor", + refreshPanelOnChange: true + }, + // Gallery { name: "variant", @@ -668,7 +676,6 @@ const store: Writable = writable({ root: null, allItems: {}, allItemsByNode: {}, - currentId: 0, currentSelection: [], currentSelectionNodes: [], isMenuOpen: false, @@ -703,7 +710,7 @@ function addContainer(parent: ContainerLayout | null, attrs: Partial const state = get(store); const dragItem: ContainerLayout = { type: "container", - id: `${state.currentId++}`, + id: uuidv4(), attrsChanged: writable(0), attrs: { ...defaultWidgetAttributes, @@ -726,7 +733,7 @@ function addWidget(parent: ContainerLayout, node: ComfyWidgetNode, attrs: Partia const widgetName = "Widget" const dragItem: WidgetLayout = { type: "widget", - id: `${state.currentId++}`, + id: uuidv4(), node: node, attrsChanged: writable(0), attrs: { @@ -939,7 +946,6 @@ function initDefaultLayout() { root: null, allItems: {}, allItemsByNode: {}, - currentId: 0, currentSelection: [], currentSelectionNodes: [], isMenuOpen: false, @@ -964,7 +970,6 @@ function initDefaultLayout() { export type SerializedLayoutState = { root: DragItemID | null, allItems: Record, - currentId: UUID, attrs: LayoutAttributes } @@ -1002,7 +1007,6 @@ function serialize(): SerializedLayoutState { return { root: state.root?.id, allItems, - currentId: state.currentId, attrs: state.attrs } } @@ -1055,7 +1059,6 @@ function deserialize(data: SerializedLayoutState, graph: LGraph) { root, allItems, allItemsByNode, - currentId: data.currentId, currentSelection: [], currentSelectionNodes: [], isMenuOpen: false, diff --git a/src/lib/stores/queueState.ts b/src/lib/stores/queueState.ts index 13807f6..32a9f4d 100644 --- a/src/lib/stores/queueState.ts +++ b/src/lib/stores/queueState.ts @@ -1,6 +1,6 @@ import type { ComfyAPIHistoryEntry, ComfyAPIHistoryItem, ComfyAPIHistoryResponse, ComfyAPIQueueResponse, ComfyAPIStatusResponse, ComfyBoxPromptExtraData, NodeID, PromptID } from "$lib/api"; import type { Progress, SerializedPromptInputsAll, SerializedPromptOutputs } from "$lib/components/ComfyApp"; -import type { GalleryOutput } from "$lib/nodes/ComfyWidgetNodes"; +import type { ComfyExecutionResult } from "$lib/nodes/ComfyWidgetNodes"; import notify from "$lib/notify"; import { get, writable, type Writable } from "svelte/store"; @@ -19,7 +19,7 @@ type QueueStateOps = { executionError: (promptID: PromptID, message: string) => void, progressUpdated: (progress: Progress) => void afterQueued: (promptID: PromptID, number: number, prompt: SerializedPromptInputsAll, extraData: any) => void - onExecuted: (promptID: PromptID, nodeID: NodeID, output: GalleryOutput) => void + onExecuted: (promptID: PromptID, nodeID: NodeID, output: ComfyExecutionResult) => void } export type QueueEntry = { @@ -257,7 +257,7 @@ function afterQueued(promptID: PromptID, number: number, prompt: SerializedPromp }) } -function onExecuted(promptID: PromptID, nodeID: NodeID, output: GalleryOutput) { +function onExecuted(promptID: PromptID, nodeID: NodeID, output: ComfyExecutionResult) { console.debug("[queueState] onExecuted", promptID, nodeID, output) store.update(s => { const [index, entry, queue] = findEntryInPending(promptID) diff --git a/src/lib/utils.ts b/src/lib/utils.ts index b2fbb82..9c0cdc1 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -6,7 +6,7 @@ import { get } from "svelte/store" import layoutState from "$lib/stores/layoutState" import type { SvelteComponentDev } from "svelte/internal"; import type { SerializedLGraph } from "@litegraph-ts/core"; -import type { GalleryOutput, GalleryOutputEntry } from "./nodes/ComfyWidgetNodes"; +import type { FileNameOrGalleryData, ComfyExecutionResult, ComfyImageLocation } from "./nodes/ComfyWidgetNodes"; import type { FileData as GradioFileData } from "@gradio/upload"; export function clamp(n: number, min: number, max: number): number { @@ -125,26 +125,48 @@ export const debounce = (callback: Function, wait = 250) => { }; }; -export function convertComfyOutputToGradio(output: GalleryOutput): GradioFileData[] { - return output.images.map(r => { - const url = `http://${location.hostname}:8188` // TODO make configurable - const params = new URLSearchParams(r) - const fileData: GradioFileData = { - name: r.filename, - orig_name: r.filename, - is_file: false, - data: url + "/view?" + params - } - return fileData - }); +export function convertComfyOutputToGradio(output: ComfyExecutionResult): GradioFileData[] { + return output.images.map(convertComfyOutputEntryToGradio); } -export function convertComfyOutputToComfyURL(output: GalleryOutputEntry): string { +export function convertComfyOutputEntryToGradio(r: ComfyImageLocation): GradioFileData { + const url = `http://${location.hostname}:8188` // TODO make configurable + const params = new URLSearchParams(r) + const fileData: GradioFileData = { + name: r.filename, + orig_name: r.filename, + is_file: false, + data: url + "/view?" + params + } + return fileData +} + +export function convertComfyOutputToComfyURL(output: FileNameOrGalleryData): string { + if (typeof output === "string") + return output; + const params = new URLSearchParams(output) const url = `http://${location.hostname}:8188` // TODO make configurable return url + "/view?" + params } +export function convertGradioFileDataToComfyURL(image: GradioFileData, type: ComfyUploadImageType = "input"): string { + const baseUrl = `http://${location.hostname}:8188` // TODO make configurable + const params = new URLSearchParams({ filename: image.name, subfolder: "", type }) + return `${baseUrl}/view?${params}` +} + +export function convertGradioFileDataToComfyOutput(fileData: GradioFileData, type: ComfyUploadImageType = "input"): ComfyImageLocation { + if (!fileData.is_file) + throw "Can't convert blob data to comfy output!" + + return { + filename: fileData.name, + subfolder: "", + type + } +} + export function convertFilenameToComfyURL(filename: string, subfolder: string = "", type: "input" | "output" | "temp" = "output"): string { @@ -171,26 +193,137 @@ export function jsonToJsObject(json: string): string { }); } +export type ComfyUploadImageType = "output" | "input" | "temp" + export interface ComfyUploadImageAPIResponse { - name: string + name: string, // Yes this is different from the "executed" event args + subfolder: string, + type: ComfyUploadImageType } -export async function uploadImageToComfyUI(data: GalleryOutputEntry): Promise { +/* + * Uploads an image into ComfyUI's `input` folder. + */ +export async function uploadImageToComfyUI(blob: Blob, filename: string, type: ComfyUploadImageType, subfolder: string = "", overwrite: boolean = false): Promise { + console.debug("[utils] Uploading image to ComfyUI", filename, blob.size) + const url = `http://${location.hostname}:8188` // TODO make configurable - const params = new URLSearchParams(data) - return fetch(url + "/view?" + params) - .then((r) => r.blob()) - .then((blob) => { - console.debug("Fetchin", url, params) - const formData = new FormData(); - formData.append("image", blob, data.filename); - return fetch( - new Request(url + "/upload/image", { - body: formData, - method: 'POST' - }) - ) - }) + const formData = new FormData(); + formData.append("image", blob, filename); + formData.set("type", type) + formData.set("subfolder", subfolder) + formData.set("overwrite", String(overwrite)) + + const req = new Request(url + "/upload/image", { + body: formData, + method: 'POST' + }); + + return fetch(req) .then((r) => r.json()) + .then((resp) => { + return { + filename: resp.name, + subfolder: resp.subfolder, + type: resp.type + } + }); +} + +/* + * Convenient type for passing around image filepaths and their metadata with + * wires. Needs to be converted to a filename for use with LoadImage. + * + * Litegraph type is COMFYBOX_IMAGE. The array type is COMFYBOX_IMAGES. + */ +export type ComfyBoxImageMetadata = { + /* For easy structural type detection */ + isComfyBoxImageMetadata: true, + /* Pointer to where this image resides in ComfyUI. */ + comfyUIFile: ComfyImageLocation, + /* Readable name of the image. */ + name: string + /* Tags applicable to this image, like ["mask"]. */ + tags: string[], + /* Image width. */ + width?: number, + /* Image height. */ + height?: number, +} + +export function isComfyBoxImageMetadata(value: any): value is ComfyBoxImageMetadata { + return value && typeof value === "object" && (value as any).isComfyBoxImageMetadata; +} + +export function isComfyBoxImageMetadataArray(value: any): value is ComfyBoxImageMetadata[] { + return Array.isArray(value) && value.every(isComfyBoxImageMetadata); +} + +export function isComfyExecutionResult(value: any): value is ComfyExecutionResult { + return value && typeof value === "object" && Array.isArray(value.images) +} + +export function filenameToComfyBoxMetadata(filename: string, type: ComfyUploadImageType, subfolder: string = ""): ComfyBoxImageMetadata { + return { + isComfyBoxImageMetadata: true, + comfyUIFile: { + filename, + subfolder, + type + }, + name: "Filename", + tags: [], + } +} + +export function comfyFileToComfyBoxMetadata(comfyUIFile: ComfyImageLocation): ComfyBoxImageMetadata { + return { + isComfyBoxImageMetadata: true, + comfyUIFile, + name: "File", + tags: [], + } +} + +/* + * Converts a ComfyUI file into an annotated filepath. Backend nodes like + * LoadImage support syntax like "subfolder/image.png [output]" to specify which + * image folder to load from. + */ +export function comfyFileToAnnotatedFilepath(comfyUIFile: ComfyImageLocation): string { + let path = "" + if (comfyUIFile.subfolder != "") + path = comfyUIFile.subfolder + "/"; + + path += `${comfyUIFile.filename} [${comfyUIFile.type}]` + return path; +} + +export function executionResultToImageMetadata(result: ComfyExecutionResult): ComfyBoxImageMetadata[] { + return result.images.map(comfyFileToComfyBoxMetadata) +} + +export function parseWhateverIntoImageMetadata(param: any): ComfyBoxImageMetadata[] | null { + let meta: ComfyBoxImageMetadata[] | null = null + + if (isComfyBoxImageMetadata(param)) { + meta = [param]; + } + else if (Array.isArray(param) && param.every(isComfyBoxImageMetadata)) { + meta = param + } + else if (isComfyExecutionResult(param)) { + meta = executionResultToImageMetadata(param) + } + + return meta; +} + +export function comfyBoxImageToComfyFile(image: ComfyBoxImageMetadata): ComfyImageLocation { + return image.comfyUIFile +} + +export function comfyBoxImageToComfyURL(image: ComfyBoxImageMetadata): string { + return convertComfyOutputToComfyURL(image.comfyUIFile) } diff --git a/src/lib/widgets/GalleryWidget.svelte b/src/lib/widgets/GalleryWidget.svelte index 0ffdd3a..acb9f9d 100644 --- a/src/lib/widgets/GalleryWidget.svelte +++ b/src/lib/widgets/GalleryWidget.svelte @@ -10,13 +10,13 @@ import type { ComfyGalleryNode } from "$lib/nodes/ComfyWidgetNodes"; import type { FileData as GradioFileData } from "@gradio/upload"; import type { SelectData as GradioSelectData } from "@gradio/utils"; - import { clamp } from "$lib/utils"; + import { clamp, comfyBoxImageToComfyURL, type ComfyBoxImageMetadata } from "$lib/utils"; import { f7 } from "framework7-svelte"; export let widget: WidgetLayout | null = null; export let isMobile: boolean = false; let node: ComfyGalleryNode | null = null; - let nodeValue: Writable | null = null; + let nodeValue: Writable | null = null; let propsChanged: Writable | null = null; let option: number | null = null; let imageWidth: number = 1; @@ -154,8 +154,10 @@
{#if $nodeValue && $nodeValue.length > 0} + {@const value = $nodeValue[$nodeValue.length-1]} + {@const url = comfyBoxImageToComfyURL(value)}
{:else} + {@const images = $nodeValue.map(comfyBoxImageToComfyURL)}