diff --git a/LICENCE.txt b/LICENSE.md similarity index 100% rename from LICENCE.txt rename to LICENSE.md diff --git a/README.md b/README.md index 0b42020b63e742b9782dba2b1b843d81a6158f18..9e7703d0902b5bc406e49ab172c6df35436025fe 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ I have setup Prettier and ESLint, they use some basic rules (you can propose new To run all the tests (unit and e2e) please run: -`npm test` +`npm run test` This is not instantaneous: playwright may seems to do nothing for a while at first. diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..a704420547a8c3b28c5266a6f4d9e7ea3fcb6554 Binary files /dev/null and b/bun.lockb differ diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index ff73b9cc036dcdffd43ecce7775b7d7f736cc288..0000000000000000000000000000000000000000 --- a/package-lock.json +++ /dev/null @@ -1,21714 +0,0 @@ -{ - "name": "clapper", - "version": "0.0.8", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "clapper", - "version": "0.0.8", - "license": "GPL-3.0-only", - "dependencies": { - "@aitube/broadway": "0.2.3", - "@aitube/clap": "0.2.3", - "@aitube/clapper-services": "0.2.3-2", - "@aitube/client": "0.2.3", - "@aitube/engine": "0.2.3", - "@aitube/timeline": "0.2.3", - "@fal-ai/serverless-client": "^0.13.0", - "@ffmpeg/ffmpeg": "^0.12.10", - "@ffmpeg/util": "^0.12.1", - "@gradio/client": "^1.5.0", - "@huggingface/hub": "^0.15.1", - "@huggingface/inference": "^2.8.0", - "@langchain/anthropic": "^0.2.14", - "@langchain/cohere": "^0.2.2", - "@langchain/core": "^0.2.23", - "@langchain/google-vertexai": "^0.0.25", - "@langchain/groq": "^0.0.16", - "@langchain/mistralai": "^0.0.28", - "@langchain/openai": "^0.2.6", - "@monaco-editor/react": "^4.6.0", - "@radix-ui/react-accordion": "^1.1.2", - "@radix-ui/react-avatar": "^1.0.4", - "@radix-ui/react-checkbox": "^1.0.4", - "@radix-ui/react-collapsible": "^1.0.3", - "@radix-ui/react-dialog": "^1.1.1", - "@radix-ui/react-dropdown-menu": "^2.0.6", - "@radix-ui/react-icons": "^1.3.0", - "@radix-ui/react-label": "^2.0.2", - "@radix-ui/react-menubar": "^1.0.4", - "@radix-ui/react-popover": "^1.0.7", - "@radix-ui/react-progress": "^1.0.3", - "@radix-ui/react-scroll-area": "^1.0.5", - "@radix-ui/react-select": "^2.0.0", - "@radix-ui/react-separator": "^1.0.3", - "@radix-ui/react-slider": "^1.1.2", - "@radix-ui/react-slot": "^1.0.2", - "@radix-ui/react-switch": "^1.0.3", - "@radix-ui/react-tabs": "^1.0.4", - "@radix-ui/react-toast": "^1.1.5", - "@radix-ui/react-tooltip": "^1.0.7", - "@react-spring/three": "^9.7.3", - "@react-spring/types": "^9.7.3", - "@react-three/drei": "^9.106.0", - "@react-three/fiber": "^8.16.6", - "@react-three/uikit": "^0.3.4", - "@react-three/uikit-lucide": "^0.3.4", - "@saintno/comfyui-sdk": "^0.1.11", - "@tailwindcss/container-queries": "^0.1.1", - "@types/dom-speech-recognition": "^0.0.4", - "@types/pngjs": "^6.0.5", - "@xenova/transformers": "github:xenova/transformers.js#v3", - "@xyflow/react": "^12.0.3", - "autoprefixer": "10.4.19", - "base64-arraybuffer": "^1.0.2", - "class-variance-authority": "^0.7.0", - "clsx": "^2.1.1", - "cmdk": "^0.2.1", - "comfydeploy": "^0.0.21", - "date-fns": "^3.6.0", - "dotenv": "^16.4.5", - "fflate": "^0.8.2", - "fluent-ffmpeg": "^2.1.3", - "framer-motion": "11.1.7", - "fs-extra": "^11.2.0", - "is-hotkey": "^0.2.0", - "lucide-react": "^0.396.0", - "mediainfo.js": "^0.3.2", - "mlt-xml": "^2.0.2", - "monaco-editor": "^0.50.0", - "next": "^14.2.5", - "next-themes": "^0.3.0", - "pngjs": "^7.0.0", - "qs": "^6.12.1", - "query-string": "^9.0.0", - "react": "^18.3.1", - "react-device-frameset": "^1.3.4", - "react-dnd": "^16.0.1", - "react-dnd-html5-backend": "^16.0.1", - "react-dom": "^18.3.1", - "react-drag-drop-files": "^2.3.10", - "react-error-boundary": "^4.0.13", - "react-hook-consent": "^3.5.3", - "react-hotkeys-hook": "^4.5.0", - "react-icons": "^5.2.1", - "react-markdown": "^9.0.1", - "react-reflex": "^4.2.6", - "react-speakup": "^1.0.0", - "remark-gfm": "^4.0.0", - "replicate": "^0.32.0", - "sharp": "0.33.4", - "sonner": "^1.5.0", - "tailwind-merge": "^2.5.2", - "tailwindcss-animate": "^1.0.7", - "three": "^0.164.1", - "ts-node": "^10.9.2", - "use-file-picker": "^2.1.2", - "usehooks-ts": "^2.14.0", - "uuid": "^9.0.1", - "web-audio-beat-detector": "^8.2.12", - "yaml": "^2.4.5", - "zustand": "4.5.2", - "zx": "^8.1.4" - }, - "devDependencies": { - "@electron-forge/cli": "^7.4.0", - "@electron-forge/maker-deb": "^7.4.0", - "@electron-forge/maker-dmg": "^7.4.0", - "@electron-forge/maker-rpm": "^7.4.0", - "@electron-forge/maker-squirrel": "^7.4.0", - "@electron-forge/maker-zip": "^7.4.0", - "@electron-forge/plugin-auto-unpack-natives": "^7.4.0", - "@electron-forge/publisher-github": "^7.4.0", - "@playwright/test": "^1.45.1", - "@testing-library/react": "^16.0.0", - "@types/fluent-ffmpeg": "^2.1.24", - "@types/is-hotkey": "^0.1.10", - "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", - "@types/uuid": "^9.0.8", - "@vitejs/plugin-react": "^4.3.1", - "@webgpu/types": "^0.1.44", - "electron": "^31.2.1", - "eslint": "^8", - "eslint-config-next": "14.2.5", - "eslint-config-prettier": "^9.1.0", - "jsdom": "^24.1.0", - "node-gyp": "^10.2.0", - "postcss": "^8", - "prettier": "^3.3.3", - "prettier-plugin-tailwindcss": "^0.6.5", - "tailwind-scrollbar": "^3.1.0", - "tailwindcss": "^3.4.3", - "typescript": "^5.5.0", - "vitest": "^2.0.2" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.33.4", - "@img/sharp-darwin-x64": "0.33.4", - "@img/sharp-libvips-darwin-arm64": "1.0.2", - "@img/sharp-libvips-darwin-x64": "1.0.2", - "@img/sharp-libvips-linux-arm": "1.0.2", - "@img/sharp-libvips-linux-arm64": "1.0.2", - "@img/sharp-libvips-linux-x64": "1.0.2", - "@img/sharp-libvips-linuxmusl-arm64": "1.0.2", - "@img/sharp-libvips-linuxmusl-x64": "1.0.2", - "@img/sharp-libvips-win32-ia32": "1.0.2", - "@img/sharp-libvips-win32-x64": "1.0.2", - "@img/sharp-linux-arm": "0.33.4", - "@img/sharp-linux-arm64": "0.33.4", - "@img/sharp-linux-x64": "0.33.4", - "@img/sharp-linuxmusl-arm64": "0.33.4", - "@img/sharp-linuxmusl-x64": "0.33.4", - "@img/sharp-win32-ia32": "0.33.4", - "@img/sharp-win32-x64": "0.33.4" - } - }, - "node_modules/@aitube/broadway": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@aitube/broadway/-/broadway-0.2.3.tgz", - "integrity": "sha512-zuJ8zsVbTury3Phw7flMit8TnlnlLaSympkuxdR1Aea5YeZOOZmJh5+S/Y1f+xkcj9wox2ej8J8XGfIJWbd3RA==", - "dependencies": { - "@datagica/parse-entities": "^0.3.0", - "@datagica/parse-names": "^0.0.8", - "indexeddb-fs": "^2.1.5" - }, - "peerDependencies": { - "@aitube/clap": "0.2.3", - "@aitube/colors": "0.2.3" - } - }, - "node_modules/@aitube/clap": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@aitube/clap/-/clap-0.2.3.tgz", - "integrity": "sha512-qT0wI6R5BrkIWDr1Dog/GPMYjKnwy5glwO3MibPcM0BWJVQlbj0cy0qbwH+wZPC1ZmRZnaJPlhCEj5e3/U6UsA==", - "dependencies": { - "pure-uuid": "^1.8.1" - }, - "peerDependencies": { - "yaml": "^2.5.0" - } - }, - "node_modules/@aitube/clapper-services": { - "version": "0.2.3-2", - "resolved": "https://registry.npmjs.org/@aitube/clapper-services/-/clapper-services-0.2.3-2.tgz", - "integrity": "sha512-Qd6Riridk4FVcTjlscxw5wsbUgojwi1wkTIjlgPluhT5J5kLyEJQL/hmT2gBDBRsB4kyieVNZiGflgXnauDENw==", - "peerDependencies": { - "@aitube/clap": "0.2.3", - "@aitube/timeline": "0.2.3", - "@monaco-editor/react": "4.6.0", - "monaco-editor": "0.50.0", - "react": "*", - "react-dom": "*", - "zustand": "4.5.2" - } - }, - "node_modules/@aitube/client": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@aitube/client/-/client-0.2.3.tgz", - "integrity": "sha512-REgFjqvK2I+Qe4tbabHwtU5uNxQwOHMXY2XQAIN34Ff7wrd4Y4vaWB3EZ37l/yKgt7Bd3kldp2ddDt09osedMQ==", - "dependencies": { - "query-string": "^9.0.0" - }, - "peerDependencies": { - "@aitube/clap": "0.2.3" - } - }, - "node_modules/@aitube/colors": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@aitube/colors/-/colors-0.2.3.tgz", - "integrity": "sha512-bqie0eFUG/UA62lhJIibCVPdBNyudqE9YF6HoWMY2JpFtjV3EHJlla3NuXtTgfTgs7XGcmtTyqoXtmPsRSHZtw==", - "peer": true, - "peerDependencies": { - "@aitube/clap": "0.2.3" - } - }, - "node_modules/@aitube/engine": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@aitube/engine/-/engine-0.2.3.tgz", - "integrity": "sha512-y6KktN1BU5L/WFC5rrNwx0CHdQYM9xPJX1fTPZVDYfZC/6NJhn1Rm1SAnV1SkkP+3NCDQBabKvUivjmZY0CFDw==", - "peerDependencies": { - "@aitube/clap": "0.2.3" - } - }, - "node_modules/@aitube/timeline": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@aitube/timeline/-/timeline-0.2.3.tgz", - "integrity": "sha512-zr9G5t/koz/vwXxKHs2qFot5gSau72J+luTfBK0o1tgf/TK/+yP6ACO3QbO8kAmkqa6wtWuBHdVXkVceB8z7Rw==", - "dependencies": { - "date-fns": "^3.6.0", - "react-virtualized-auto-sizer": "^1.0.24" - }, - "peerDependencies": { - "@aitube/clap": "0.2.3", - "@radix-ui/react-slider": "^1.1.2", - "@react-spring/three": "^9.7.3", - "@react-spring/types": "^9.7.3", - "@react-three/drei": "^9.105.4", - "@react-three/fiber": "^8.16.2", - "clsx": "^2.1.1", - "react": "*", - "react-dom": "*", - "tailwind-merge": "^2.4.0", - "tailwindcss": "^3.4.6", - "three": "^0.164.1", - "zustand": "4.5.2" - } - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@anthropic-ai/sdk": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.22.0.tgz", - "integrity": "sha512-dv4BCC6FZJw3w66WNLsHlUFjhu19fS1L/5jMPApwhZLa/Oy1j0A2i3RypmDtHEPp4Wwg3aZkSHksp7VzYWjzmw==", - "dependencies": { - "@types/node": "^18.11.18", - "@types/node-fetch": "^2.6.4", - "abort-controller": "^3.0.0", - "agentkeepalive": "^4.2.1", - "form-data-encoder": "1.7.2", - "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7", - "web-streams-polyfill": "^3.2.1" - } - }, - "node_modules/@anthropic-ai/sdk/node_modules/@types/node": { - "version": "18.19.43", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.43.tgz", - "integrity": "sha512-Mw/YlgXnyJdEwLoFv2dpuJaDFriX+Pc+0qOBJ57jC1H6cDxIj2xc5yUrdtArDVG0m+KV6622a4p2tenEqB3C/g==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@aws-crypto/crc32": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", - "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", - "dependencies": { - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-crypto/crc32/node_modules/@aws-crypto/util": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", - "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-crypto/crc32/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-crypto/sha256-browser": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", - "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", - "dependencies": { - "@aws-crypto/sha256-js": "^5.2.0", - "@aws-crypto/supports-web-crypto": "^5.2.0", - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", - "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", - "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-crypto/supports-web-crypto": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", - "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", - "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.624.0.tgz", - "integrity": "sha512-imw3bNptHdhcogU3lwSVlQJsRpTxnkT4bQbchS/qX6+fF0Pk6ERZ+Q0YjzitPqTjkeyAWecUT4riyqv2djo+5w==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.624.0", - "@aws-sdk/client-sts": "3.624.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/credential-provider-node": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sagemaker": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sagemaker/-/client-sagemaker-3.624.0.tgz", - "integrity": "sha512-J04HAxGhC3dQRn43aPcPL6C+uW0wd0gR/dehFqJJA+XvSNLxa9HEiTjYUHCHUY+iaLQn5QCk7ICKRosynhQkxw==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.624.0", - "@aws-sdk/client-sts": "3.624.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/credential-provider-node": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "@smithy/util-waiter": "^3.1.2", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.624.0.tgz", - "integrity": "sha512-EX6EF+rJzMPC5dcdsu40xSi2To7GSvdGQNIpe97pD9WvZwM9tRNQnNM4T6HA4gjV1L6Jwk8rBlG/CnveXtLEMw==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.624.0.tgz", - "integrity": "sha512-Ki2uKYJKKtfHxxZsiMTOvJoVRP6b2pZ1u3rcUb2m/nVgBPUfLdl8ZkGpqE29I+t5/QaS/sEdbn6cgMUZwl+3Dg==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/credential-provider-node": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.624.0" - } - }, - "node_modules/@aws-sdk/client-sts": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.624.0.tgz", - "integrity": "sha512-k36fLZCb2nfoV/DKK3jbRgO/Yf7/R80pgYfMiotkGjnZwDmRvNN08z4l06L9C+CieazzkgRxNUzyppsYcYsQaw==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.624.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/credential-provider-node": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/core": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.624.0.tgz", - "integrity": "sha512-WyFmPbhRIvtWi7hBp8uSFy+iPpj8ccNV/eX86hwF4irMjfc/FtsGVIAeBXxXM/vGCjkdfEzOnl+tJ2XACD4OXg==", - "dependencies": { - "@smithy/core": "^2.3.2", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "fast-xml-parser": "4.4.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.624.0.tgz", - "integrity": "sha512-gbXaxZP29yzMmEUzsGqUrHpKBnfMBtemvrlufJbaz/MGJNIa5qtJQp7n1LMI5R49DBVUN9s/e9Rf5liyMvlHiw==", - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.624.0", - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.620.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.620.1.tgz", - "integrity": "sha512-ExuILJ2qLW5ZO+rgkNRj0xiAipKT16Rk77buvPP8csR7kkCflT/gXTyzRe/uzIiETTxM7tr8xuO9MP/DQXqkfg==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.622.0.tgz", - "integrity": "sha512-VUHbr24Oll1RK3WR8XLUugLpgK9ZuxEm/NVeVqyFts1Ck9gsKpRg1x4eH7L7tW3SJ4TDEQNMbD7/7J+eoL2svg==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.624.0.tgz", - "integrity": "sha512-mMoNIy7MO2WTBbdqMyLpbt6SZpthE6e0GkRYpsd0yozPt0RZopcBhEh+HG1U9Y1PVODo+jcMk353vAi61CfnhQ==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.624.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.624.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.624.0.tgz", - "integrity": "sha512-vYyGK7oNpd81BdbH5IlmQ6zfaQqU+rPwsKTDDBeLRjshtrGXOEpfoahVpG9PX0ibu32IOWp4ZyXBNyVrnvcMOw==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", - "@aws-sdk/credential-provider-ini": "3.624.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.624.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.620.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.620.1.tgz", - "integrity": "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.624.0.tgz", - "integrity": "sha512-A02bayIjU9APEPKr3HudrFHEx0WfghoSPsPopckDkW7VBqO4wizzcxr75Q9A3vNX+cwg0wCN6UitTNe6pVlRaQ==", - "dependencies": { - "@aws-sdk/client-sso": "3.624.0", - "@aws-sdk/token-providers": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.621.0.tgz", - "integrity": "sha512-w7ASSyfNvcx7+bYGep3VBgC3K6vEdLmlpjT7nSIHxxQf+WSdvy+HynwJosrpZax0sK5q0D1Jpn/5q+r5lwwW6w==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" - } - }, - "node_modules/@aws-sdk/credential-providers": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.624.0.tgz", - "integrity": "sha512-SX+F5x/w8laQkhXLd1oww2lTuBDJSxzXWyxuOi25a9s4bMDs0V/wOj885Vr6h8QEGi3F8jZ8aWLwpsm2yuk9BA==", - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.624.0", - "@aws-sdk/client-sso": "3.624.0", - "@aws-sdk/client-sts": "3.624.0", - "@aws-sdk/credential-provider-cognito-identity": "3.624.0", - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", - "@aws-sdk/credential-provider-ini": "3.624.0", - "@aws-sdk/credential-provider-node": "3.624.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.624.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", - "integrity": "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-logger": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", - "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.620.0.tgz", - "integrity": "sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz", - "integrity": "sha512-bvS6etn+KsuL32ubY5D3xNof1qkenpbJXf/ugGXbg0n98DvDFQ/F+SMLxHgbnER5dsKYchNnhmtI6/FC3HFu/A==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/protocol-http": { - "version": "3.374.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.374.0.tgz", - "integrity": "sha512-9WpRUbINdGroV3HiZZIBoJvL2ndoWk39OfwxWs2otxByppJZNN14bg/lvCx5e8ggHUti7IBk5rb0nqQZ4m05pg==", - "deprecated": "This package has moved to @smithy/protocol-http", - "dependencies": { - "@smithy/protocol-http": "^1.1.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/protocol-http/node_modules/@smithy/protocol-http": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-1.2.0.tgz", - "integrity": "sha512-GfGfruksi3nXdFok5RhgtOnWe5f6BndzYfmEXISD+5gAGdayFGpjWu5pIqIweTudMtse20bGbc+7MFZXT1Tb8Q==", - "dependencies": { - "@smithy/types": "^1.2.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/protocol-http/node_modules/@smithy/types": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-1.2.0.tgz", - "integrity": "sha512-z1r00TvBqF3dh4aHhya7nz1HhvCg4TRmw51fjMrh5do3h+ngSstt/yKlNbHeb9QxJmFbmN8KEVSWgb1bRvfEoA==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", - "integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4": { - "version": "3.374.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.374.0.tgz", - "integrity": "sha512-2xLJvSdzcZZAg0lsDLUAuSQuihzK0dcxIK7WmfuJeF7DGKJFmp9czQmz5f3qiDz6IDQzvgK1M9vtJSVCslJbyQ==", - "deprecated": "This package has moved to @smithy/signature-v4", - "dependencies": { - "@smithy/signature-v4": "^1.0.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4/node_modules/@smithy/is-array-buffer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-1.1.0.tgz", - "integrity": "sha512-twpQ/n+3OWZJ7Z+xu43MJErmhB/WO/mMTnqR6PwWQShvSJ/emx5d1N59LQZk6ZpTAeuRWrc+eHhkzTp9NFjNRQ==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4/node_modules/@smithy/signature-v4": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-1.1.0.tgz", - "integrity": "sha512-fDo3m7YqXBs7neciOePPd/X9LPm5QLlDMdIC4m1H6dgNLnXfLMFNIxEfPyohGA8VW9Wn4X8lygnPSGxDZSmp0Q==", - "dependencies": { - "@smithy/eventstream-codec": "^1.1.0", - "@smithy/is-array-buffer": "^1.1.0", - "@smithy/types": "^1.2.0", - "@smithy/util-hex-encoding": "^1.1.0", - "@smithy/util-middleware": "^1.1.0", - "@smithy/util-uri-escape": "^1.1.0", - "@smithy/util-utf8": "^1.1.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4/node_modules/@smithy/types": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-1.2.0.tgz", - "integrity": "sha512-z1r00TvBqF3dh4aHhya7nz1HhvCg4TRmw51fjMrh5do3h+ngSstt/yKlNbHeb9QxJmFbmN8KEVSWgb1bRvfEoA==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4/node_modules/@smithy/util-buffer-from": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-1.1.0.tgz", - "integrity": "sha512-9m6NXE0ww+ra5HKHCHig20T+FAwxBAm7DIdwc/767uGWbRcY720ybgPacQNB96JMOI7xVr/CDa3oMzKmW4a+kw==", - "dependencies": { - "@smithy/is-array-buffer": "^1.1.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4/node_modules/@smithy/util-hex-encoding": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-1.1.0.tgz", - "integrity": "sha512-7UtIE9eH0u41zpB60Jzr0oNCQ3hMJUabMcKRUVjmyHTXiWDE4vjSqN6qlih7rCNeKGbioS7f/y2Jgym4QZcKFg==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4/node_modules/@smithy/util-middleware": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-1.1.0.tgz", - "integrity": "sha512-6hhckcBqVgjWAqLy2vqlPZ3rfxLDhFWEmM7oLh2POGvsi7j0tHkbN7w4DFhuBExVJAbJ/qqxqZdRY6Fu7/OezQ==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4/node_modules/@smithy/util-uri-escape": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-1.1.0.tgz", - "integrity": "sha512-/jL/V1xdVRt5XppwiaEU8Etp5WHZj609n0xMTuehmCqdoOFbId1M+aEeDWZsQ+8JbEB/BJ6ynY2SlYmOaKtt8w==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4/node_modules/@smithy/util-utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-1.1.0.tgz", - "integrity": "sha512-p/MYV+JmqmPyjdgyN2UxAeYDj9cBqCjp0C/NsTWnnjoZUVqoeZ6IrW915L9CAKWVECgv9lVQGc4u/yz26/bI1A==", - "dependencies": { - "@smithy/util-buffer-from": "^1.1.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", - "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sso-oidc": "^3.614.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", - "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/util-endpoints": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", - "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", - "@smithy/util-endpoints": "^2.0.5", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/util-locate-window": { - "version": "3.568.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.568.0.tgz", - "integrity": "sha512-3nh4TINkXYr+H41QaPelCceEB2FXP3fxp93YZXB/kqJvX0U9j0N0Uk45gvsjmEPzG8XxkPEeLIfT2I1M7A6Lig==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", - "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz", - "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } - } - }, - "node_modules/@aws-sdk/util-utf8-browser": { - "version": "3.259.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", - "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", - "dependencies": { - "tslib": "^2.3.1" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", - "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", - "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/helper-compilation-targets": "^7.25.2", - "@babel/helper-module-transforms": "^7.25.2", - "@babel/helpers": "^7.25.0", - "@babel/parser": "^7.25.0", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.2", - "@babel/types": "^7.25.2", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", - "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", - "dependencies": { - "@babel/types": "^7.25.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", - "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", - "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", - "dependencies": { - "@babel/compat-data": "^7.25.2", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", - "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", - "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "@babel/traverse": "^7.25.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", - "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", - "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", - "dependencies": { - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", - "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", - "dependencies": { - "@babel/types": "^7.25.2" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", - "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.7.tgz", - "integrity": "sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.7.tgz", - "integrity": "sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", - "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", - "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.25.0", - "@babel/types": "^7.25.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", - "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.3", - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.2", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", - "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", - "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bundled-es-modules/cookie": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.0.tgz", - "integrity": "sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==", - "dependencies": { - "cookie": "^0.5.0" - } - }, - "node_modules/@bundled-es-modules/statuses": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz", - "integrity": "sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==", - "dependencies": { - "statuses": "^2.0.1" - } - }, - "node_modules/@bundled-es-modules/tough-cookie": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@bundled-es-modules/tough-cookie/-/tough-cookie-0.1.6.tgz", - "integrity": "sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==", - "dependencies": { - "@types/tough-cookie": "^4.0.5", - "tough-cookie": "^4.1.4" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@datagica/fast-index": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@datagica/fast-index/-/fast-index-0.1.0.tgz", - "integrity": "sha512-e6jK4wWGROc8lgps2agayuKXQIqOjvTL8brgFLEtzUzYwdVbzfc8foOW4SpmA43/desLU1YgoASredFmmFWqcQ==" - }, - "node_modules/@datagica/parse-entities": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@datagica/parse-entities/-/parse-entities-0.3.0.tgz", - "integrity": "sha512-Ai/SZAANZ4sUpcAIeW8C7M5I5tVymKengXaKYiNtmJmWBl79e+VBWUPxcv2DLmIcZ5CQxWnJUgSVyQ9NIfyQUw==", - "dependencies": { - "@datagica/treegram": "^0.3.0" - } - }, - "node_modules/@datagica/parse-names": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/@datagica/parse-names/-/parse-names-0.0.8.tgz", - "integrity": "sha512-wfpGYgJIB35XOPlb4CFC148XrYcbXN+ZP3pt/mSJbxF46tyacgfZ+9+KHfDK0M0H6eKx7Ngm1DhYCbAY3JyXyA==", - "dependencies": { - "@datagica/parse-entities": "^0.2.7" - } - }, - "node_modules/@datagica/parse-names/node_modules/@datagica/fast-index": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/@datagica/fast-index/-/fast-index-0.0.7.tgz", - "integrity": "sha512-S0bBOIh15KRjQkUvmGijhPci8K+/k0yw5oatGwDGPL1AOVoJNkXt8d8Dnt71k7uWr1S2k4akIlytkh9V3TrlQw==" - }, - "node_modules/@datagica/parse-names/node_modules/@datagica/parse-entities": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@datagica/parse-entities/-/parse-entities-0.2.8.tgz", - "integrity": "sha512-RP0ol+uG7jzpWR3kBZMtoQ3/8F71Sjrt/3LtDp6By3/8EA5wxeHCXwy8iqFQUpQiC0L1K9sjg0wRjKqLwECw2g==", - "dependencies": { - "@datagica/treegram": "^0.2.8" - } - }, - "node_modules/@datagica/parse-names/node_modules/@datagica/treegram": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@datagica/treegram/-/treegram-0.2.9.tgz", - "integrity": "sha512-IDhQUFmA8TqkjBnJtXRXFTPOPmorJswFEw7k5YCbxvLj7O2hqojs5pfCaS31rdOe0VXxmde+AFidUZqVtLaR6w==", - "dependencies": { - "@datagica/fast-index": "^0.0.7", - "@datagica/tokenize": "^0.0.2" - } - }, - "node_modules/@datagica/tokenize": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@datagica/tokenize/-/tokenize-0.0.2.tgz", - "integrity": "sha512-MmZwlj5yzp3HzFSFEYOCvzC/IURsaQmRuLKy5rfoOzPk7NPHYnq0Vct9MxeZ+3jjRoTHI/PpUlDKKF93ngVe7Q==" - }, - "node_modules/@datagica/treegram": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@datagica/treegram/-/treegram-0.3.0.tgz", - "integrity": "sha512-iZAqiQI1jsgI+MYwbCRhKUpev+eIVyP0JZoL/E7rJE0k5V5yTbunt7K/KyyLYRpGfRIkzaDga1qfr8wrskeJIQ==", - "dependencies": { - "@datagica/fast-index": "^0.1.0", - "@datagica/tokenize": "^0.0.2" - } - }, - "node_modules/@electron-forge/cli": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/cli/-/cli-7.4.0.tgz", - "integrity": "sha512-a+zZv3ja/IxkJzNyx4sOHSZv6DPV85S0PEVF6pcRjUpbDL5r+DxjRFsNc0Nq4UIWyFm1nw7RWoPdd9uDst4Tvg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/malept" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/subscription/pkg/npm-.electron-forge-cli?utm_medium=referral&utm_source=npm_fund" - } - ], - "dependencies": { - "@electron-forge/core": "7.4.0", - "@electron-forge/shared-types": "7.4.0", - "@electron/get": "^3.0.0", - "chalk": "^4.0.0", - "commander": "^4.1.1", - "debug": "^4.3.1", - "fs-extra": "^10.0.0", - "listr2": "^7.0.2", - "semver": "^7.2.1" - }, - "bin": { - "electron-forge": "dist/electron-forge.js", - "electron-forge-vscode-nix": "script/vscode.sh", - "electron-forge-vscode-win": "script/vscode.cmd" - }, - "engines": { - "node": ">= 16.4.0" - } - }, - "node_modules/@electron-forge/cli/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron-forge/core": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/core/-/core-7.4.0.tgz", - "integrity": "sha512-pYHKpB2CKeQgWsb+gox+FPkEvP+6Q2zGj2eZtgZRtKppoWIXrHIpOtcm6FllJ/gZ5u4AsQzVIYReAHGaBa0osw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/malept" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/subscription/pkg/npm-.electron-forge-core?utm_medium=referral&utm_source=npm_fund" - } - ], - "dependencies": { - "@electron-forge/core-utils": "7.4.0", - "@electron-forge/maker-base": "7.4.0", - "@electron-forge/plugin-base": "7.4.0", - "@electron-forge/publisher-base": "7.4.0", - "@electron-forge/shared-types": "7.4.0", - "@electron-forge/template-base": "7.4.0", - "@electron-forge/template-vite": "7.4.0", - "@electron-forge/template-vite-typescript": "7.4.0", - "@electron-forge/template-webpack": "7.4.0", - "@electron-forge/template-webpack-typescript": "7.4.0", - "@electron-forge/tracer": "7.4.0", - "@electron/get": "^3.0.0", - "@electron/packager": "^18.3.1", - "@electron/rebuild": "^3.2.10", - "@malept/cross-spawn-promise": "^2.0.0", - "chalk": "^4.0.0", - "debug": "^4.3.1", - "fast-glob": "^3.2.7", - "filenamify": "^4.1.0", - "find-up": "^5.0.0", - "fs-extra": "^10.0.0", - "got": "^11.8.5", - "interpret": "^3.1.1", - "listr2": "^7.0.2", - "lodash": "^4.17.20", - "log-symbols": "^4.0.0", - "node-fetch": "^2.6.7", - "progress": "^2.0.3", - "rechoir": "^0.8.0", - "resolve-package": "^1.0.1", - "semver": "^7.2.1", - "source-map-support": "^0.5.13", - "sudo-prompt": "^9.1.1", - "username": "^5.1.0", - "yarn-or-npm": "^3.0.1" - }, - "engines": { - "node": ">= 16.4.0" - } - }, - "node_modules/@electron-forge/core-utils": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/core-utils/-/core-utils-7.4.0.tgz", - "integrity": "sha512-9RLG0F9SX466TpkaTcW+V15KmnGuTpmr7NKMRlngtHXmnkBUJz4Mxp1x33WZLgL90dJrxrRgHSfVBtA4lstDPw==", - "dev": true, - "dependencies": { - "@electron-forge/shared-types": "7.4.0", - "@electron/rebuild": "^3.2.10", - "@malept/cross-spawn-promise": "^2.0.0", - "chalk": "^4.0.0", - "debug": "^4.3.1", - "find-up": "^5.0.0", - "fs-extra": "^10.0.0", - "log-symbols": "^4.0.0", - "semver": "^7.2.1", - "yarn-or-npm": "^3.0.1" - }, - "engines": { - "node": ">= 16.4.0" - } - }, - "node_modules/@electron-forge/core-utils/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron-forge/core/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron-forge/maker-base": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/maker-base/-/maker-base-7.4.0.tgz", - "integrity": "sha512-LwWS4VPdwjISl1KpLhmM1Qr1M3sRTTQ/RsX+GlFd7cQ1W/FsgxMjaTG4Od1d+a5CGVTh3s6X2g99TSUfxjOveg==", - "dev": true, - "dependencies": { - "@electron-forge/shared-types": "7.4.0", - "fs-extra": "^10.0.0", - "which": "^2.0.2" - }, - "engines": { - "node": ">= 16.4.0" - } - }, - "node_modules/@electron-forge/maker-base/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron-forge/maker-deb": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/maker-deb/-/maker-deb-7.4.0.tgz", - "integrity": "sha512-npWea3IpGeu96xNqJpsCOYX6V4E+HY6u/okeTUzUOMX96UteT14MecdUefMam158glRTX84k2ryh7WcBoOa4mg==", - "dev": true, - "dependencies": { - "@electron-forge/maker-base": "7.4.0", - "@electron-forge/shared-types": "7.4.0" - }, - "engines": { - "node": ">= 16.4.0" - }, - "optionalDependencies": { - "electron-installer-debian": "^3.2.0" - } - }, - "node_modules/@electron-forge/maker-dmg": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/maker-dmg/-/maker-dmg-7.4.0.tgz", - "integrity": "sha512-xRCMNtnpvQNwrDYvwbVFegnErnIMpHGZANrjwushlH9+Fsu60DFvf5s3AVkgsYdQTqlY7wYRG1mziYZmRlPAIw==", - "dev": true, - "dependencies": { - "@electron-forge/maker-base": "7.4.0", - "@electron-forge/shared-types": "7.4.0", - "fs-extra": "^10.0.0" - }, - "engines": { - "node": ">= 16.4.0" - }, - "optionalDependencies": { - "electron-installer-dmg": "^4.0.0" - } - }, - "node_modules/@electron-forge/maker-dmg/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron-forge/maker-rpm": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/maker-rpm/-/maker-rpm-7.4.0.tgz", - "integrity": "sha512-N64Yh/K/91GzIk28T1jKsCGgYaquDuhXcEJW+TkVyP5tPZ9aTz9SjXLBxAg8WhcroArAZEsVyPOFKthmFzAUuA==", - "dev": true, - "dependencies": { - "@electron-forge/maker-base": "7.4.0", - "@electron-forge/shared-types": "7.4.0" - }, - "engines": { - "node": ">= 16.4.0" - }, - "optionalDependencies": { - "electron-installer-redhat": "^3.2.0" - } - }, - "node_modules/@electron-forge/maker-squirrel": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/maker-squirrel/-/maker-squirrel-7.4.0.tgz", - "integrity": "sha512-mCQyufnSNfjffiKho59ZqVg4W601zGOl6h01OyfDwjOU/G4iQtpnnDEOXGe26q7OVT5ORb1WDnfyGgBeJ6Ge7g==", - "dev": true, - "dependencies": { - "@electron-forge/maker-base": "7.4.0", - "@electron-forge/shared-types": "7.4.0", - "fs-extra": "^10.0.0" - }, - "engines": { - "node": ">= 16.4.0" - }, - "optionalDependencies": { - "electron-winstaller": "^5.3.0" - } - }, - "node_modules/@electron-forge/maker-squirrel/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron-forge/maker-zip": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/maker-zip/-/maker-zip-7.4.0.tgz", - "integrity": "sha512-UGbMdpuK/P29x1FFRWNOs3bNz+7QNFWVWyTM5hcWqib66cNuUmoaPifQyuwW2POIrIohrxlzLK87/i9Zc8g4dA==", - "dev": true, - "dependencies": { - "@electron-forge/maker-base": "7.4.0", - "@electron-forge/shared-types": "7.4.0", - "cross-zip": "^4.0.0", - "fs-extra": "^10.0.0", - "got": "^11.8.5" - }, - "engines": { - "node": ">= 16.4.0" - } - }, - "node_modules/@electron-forge/maker-zip/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron-forge/plugin-auto-unpack-natives": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/plugin-auto-unpack-natives/-/plugin-auto-unpack-natives-7.4.0.tgz", - "integrity": "sha512-jJ/v2blH32bcvdlJbeeW/yO99K9SduW8yrS7zuFN6y+B1cmzLd+S7L8oCcOghFDMAlYjQaBlnCe/nMJbT9mN4g==", - "dev": true, - "dependencies": { - "@electron-forge/plugin-base": "7.4.0", - "@electron-forge/shared-types": "7.4.0" - }, - "engines": { - "node": ">= 16.4.0" - } - }, - "node_modules/@electron-forge/plugin-base": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/plugin-base/-/plugin-base-7.4.0.tgz", - "integrity": "sha512-LcTNtEc2YaWvhhqWVIfdJ+J0/krSgc2dqYAHhOH2aLUSm9End3dKO/PZ1Y6DPsiPiJKHnSLBJ/XBN/16NY4Sjw==", - "dev": true, - "dependencies": { - "@electron-forge/shared-types": "7.4.0" - }, - "engines": { - "node": ">= 16.4.0" - } - }, - "node_modules/@electron-forge/publisher-base": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/publisher-base/-/publisher-base-7.4.0.tgz", - "integrity": "sha512-PiJk4RfaC55SnVnteLW2ZIQNM9DpGOi6YoUn5t8i9UcVp2rFIdya7bJY/b9u1hwubm4d5+TdypMVEuJjM44CJQ==", - "dev": true, - "dependencies": { - "@electron-forge/shared-types": "7.4.0" - }, - "engines": { - "node": ">= 16.4.0" - } - }, - "node_modules/@electron-forge/publisher-github": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/publisher-github/-/publisher-github-7.4.0.tgz", - "integrity": "sha512-hrxKNssJyU8Yuz0qv384y5RKojMG0nWeG7/kidjp8PX/RnqjGRU/JJ0Worl28g8LGiLt5R5JIfNLngLaFMn8tg==", - "dev": true, - "dependencies": { - "@electron-forge/publisher-base": "7.4.0", - "@electron-forge/shared-types": "7.4.0", - "@octokit/core": "^3.2.4", - "@octokit/plugin-retry": "^3.0.9", - "@octokit/request-error": "^2.0.5", - "@octokit/rest": "^18.0.11", - "@octokit/types": "^6.1.2", - "chalk": "^4.0.0", - "debug": "^4.3.1", - "fs-extra": "^10.0.0", - "log-symbols": "^4.0.0", - "mime-types": "^2.1.25" - }, - "engines": { - "node": ">= 16.4.0" - } - }, - "node_modules/@electron-forge/publisher-github/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron-forge/shared-types": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/shared-types/-/shared-types-7.4.0.tgz", - "integrity": "sha512-5Ehy6enUjBaU08odf9u9TOhmOVXlqobzMvKUixtkdAWgV1XZAUJmn+p21xhj0IkO92MQiXMGv66w9pDNjRT8uQ==", - "dev": true, - "dependencies": { - "@electron-forge/tracer": "7.4.0", - "@electron/packager": "^18.3.1", - "@electron/rebuild": "^3.2.10", - "listr2": "^7.0.2" - }, - "engines": { - "node": ">= 16.4.0" - } - }, - "node_modules/@electron-forge/template-base": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/template-base/-/template-base-7.4.0.tgz", - "integrity": "sha512-3YWdRSGzQfQPQkQxStn2wkJ/SuNGGKo9slwFJGvqMV+Pbx3/M/hYi9sMXOuaqVZgeaBp8Ap27yFPxaIIOC3vcA==", - "dev": true, - "dependencies": { - "@electron-forge/shared-types": "7.4.0", - "@malept/cross-spawn-promise": "^2.0.0", - "debug": "^4.3.1", - "fs-extra": "^10.0.0", - "username": "^5.1.0" - }, - "engines": { - "node": ">= 16.4.0" - } - }, - "node_modules/@electron-forge/template-base/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron-forge/template-vite": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/template-vite/-/template-vite-7.4.0.tgz", - "integrity": "sha512-YPVyCGiBKmZPCxK/Bd2louV3PBcxI2nT2+tRKP+mlEHOWrxbZIfmZSR2lIAFvK/ALKlwUKROdmlwyi7ZcdT7JQ==", - "dev": true, - "dependencies": { - "@electron-forge/shared-types": "7.4.0", - "@electron-forge/template-base": "7.4.0", - "fs-extra": "^10.0.0" - }, - "engines": { - "node": ">= 16.4.0" - } - }, - "node_modules/@electron-forge/template-vite-typescript": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/template-vite-typescript/-/template-vite-typescript-7.4.0.tgz", - "integrity": "sha512-wdByG807VWcUd81E6572b/G/Ki8gb+GrCIWxO7Cl3qBa+yNaU1sHhBwB1RyTbQy1r8ubSBtsWrRD1J/yzHKWoQ==", - "dev": true, - "dependencies": { - "@electron-forge/shared-types": "7.4.0", - "@electron-forge/template-base": "7.4.0", - "fs-extra": "^10.0.0" - }, - "engines": { - "node": ">= 16.4.0" - } - }, - "node_modules/@electron-forge/template-vite-typescript/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron-forge/template-vite/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron-forge/template-webpack": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/template-webpack/-/template-webpack-7.4.0.tgz", - "integrity": "sha512-W558AEGwQrwEtKIbIJPPs0LIsaC/1Vncj5NgqKehEMJjBb0KQq4hwBu/6dauQrfun4jRCOp7LV+OVrf5XPJ7QA==", - "dev": true, - "dependencies": { - "@electron-forge/shared-types": "7.4.0", - "@electron-forge/template-base": "7.4.0", - "fs-extra": "^10.0.0" - }, - "engines": { - "node": ">= 16.4.0" - } - }, - "node_modules/@electron-forge/template-webpack-typescript": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/template-webpack-typescript/-/template-webpack-typescript-7.4.0.tgz", - "integrity": "sha512-O5gwjNSGFNRdJWyiCtevcOBDPAMhgOPvLORh9qR1GcjyTutWwHWmZzycqH+MmkhpQPgrAYDEeipXcOQhSbzNZA==", - "dev": true, - "dependencies": { - "@electron-forge/shared-types": "7.4.0", - "@electron-forge/template-base": "7.4.0", - "fs-extra": "^10.0.0" - }, - "engines": { - "node": ">= 16.4.0" - } - }, - "node_modules/@electron-forge/template-webpack-typescript/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron-forge/template-webpack/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron-forge/tracer": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@electron-forge/tracer/-/tracer-7.4.0.tgz", - "integrity": "sha512-F4jbnDn4yIZjmky1FZ6rgBKTM05AZQQfHkyJW2hdS4pDKJjdKAqWytoZKDi1/S6Cr6tN+DD0TFGD3V0i6HPHYQ==", - "dev": true, - "dependencies": { - "chrome-trace-event": "^1.0.3" - }, - "engines": { - "node": ">= 14.17.5" - } - }, - "node_modules/@electron/asar": { - "version": "3.2.10", - "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.2.10.tgz", - "integrity": "sha512-mvBSwIBUeiRscrCeJE1LwctAriBj65eUDm0Pc11iE5gRwzkmsdbS7FnZ1XUWjpSeQWL1L5g12Fc/SchPM9DUOw==", - "dev": true, - "dependencies": { - "commander": "^5.0.0", - "glob": "^7.1.6", - "minimatch": "^3.0.4" - }, - "bin": { - "asar": "bin/asar.js" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/@electron/asar/node_modules/commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@electron/get": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-3.1.0.tgz", - "integrity": "sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "env-paths": "^2.2.0", - "fs-extra": "^8.1.0", - "got": "^11.8.5", - "progress": "^2.0.3", - "semver": "^6.2.0", - "sumchecker": "^3.0.1" - }, - "engines": { - "node": ">=14" - }, - "optionalDependencies": { - "global-agent": "^3.0.0" - } - }, - "node_modules/@electron/get/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/@electron/get/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@electron/get/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@electron/get/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/@electron/notarize": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.3.2.tgz", - "integrity": "sha512-zfayxCe19euNwRycCty1C7lF7snk9YwfRpB5M8GLr1a4ICH63znxaPNAubrMvj0yDvVozqfgsdYpXVUnpWBDpg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "fs-extra": "^9.0.1", - "promise-retry": "^2.0.1" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@electron/notarize/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@electron/osx-sign": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.3.1.tgz", - "integrity": "sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==", - "dev": true, - "dependencies": { - "compare-version": "^0.1.2", - "debug": "^4.3.4", - "fs-extra": "^10.0.0", - "isbinaryfile": "^4.0.8", - "minimist": "^1.2.6", - "plist": "^3.0.5" - }, - "bin": { - "electron-osx-flat": "bin/electron-osx-flat.js", - "electron-osx-sign": "bin/electron-osx-sign.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/@electron/osx-sign/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron/packager": { - "version": "18.3.3", - "resolved": "https://registry.npmjs.org/@electron/packager/-/packager-18.3.3.tgz", - "integrity": "sha512-hGXzwbUdxv49XvlYwlVPC6W6j6WaXUAzKkYyyTeiwdhxvHFMfQSEJxVHsQpqMFzZZ7wrr7iqiokOFZ/qkgEzUQ==", - "dev": true, - "dependencies": { - "@electron/asar": "^3.2.1", - "@electron/get": "^3.0.0", - "@electron/notarize": "^2.1.0", - "@electron/osx-sign": "^1.0.5", - "@electron/universal": "^2.0.1", - "@electron/windows-sign": "^1.0.0", - "debug": "^4.0.1", - "extract-zip": "^2.0.0", - "filenamify": "^4.1.0", - "fs-extra": "^11.1.0", - "galactus": "^1.0.0", - "get-package-info": "^1.0.0", - "junk": "^3.1.0", - "parse-author": "^2.0.0", - "plist": "^3.0.0", - "resedit": "^2.0.0", - "resolve": "^1.1.6", - "semver": "^7.1.3", - "yargs-parser": "^21.1.1" - }, - "bin": { - "electron-packager": "bin/electron-packager.js" - }, - "engines": { - "node": ">= 16.13.0" - }, - "funding": { - "url": "https://github.com/electron/packager?sponsor=1" - } - }, - "node_modules/@electron/rebuild": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.6.0.tgz", - "integrity": "sha512-zF4x3QupRU3uNGaP5X1wjpmcjfw1H87kyqZ00Tc3HvriV+4gmOGuvQjGNkrJuXdsApssdNyVwLsy+TaeTGGcVw==", - "dev": true, - "dependencies": { - "@malept/cross-spawn-promise": "^2.0.0", - "chalk": "^4.0.0", - "debug": "^4.1.1", - "detect-libc": "^2.0.1", - "fs-extra": "^10.0.0", - "got": "^11.7.0", - "node-abi": "^3.45.0", - "node-api-version": "^0.2.0", - "node-gyp": "^9.0.0", - "ora": "^5.1.0", - "read-binary-file-arch": "^1.0.6", - "semver": "^7.3.5", - "tar": "^6.0.5", - "yargs": "^17.0.1" - }, - "bin": { - "electron-rebuild": "lib/cli.js" - }, - "engines": { - "node": ">=12.13.0" - } - }, - "node_modules/@electron/rebuild/node_modules/@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", - "dev": true, - "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@electron/rebuild/node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "node_modules/@electron/rebuild/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@electron/rebuild/node_modules/cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", - "dev": true, - "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@electron/rebuild/node_modules/cacache/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@electron/rebuild/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron/rebuild/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@electron/rebuild/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@electron/rebuild/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron/rebuild/node_modules/make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", - "dev": true, - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@electron/rebuild/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@electron/rebuild/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@electron/rebuild/node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@electron/rebuild/node_modules/minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", - "dev": true, - "dependencies": { - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/@electron/rebuild/node_modules/node-gyp": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", - "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", - "dev": true, - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^12.13 || ^14.13 || >=16" - } - }, - "node_modules/@electron/rebuild/node_modules/nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", - "dev": true, - "dependencies": { - "abbrev": "^1.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@electron/rebuild/node_modules/socks-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", - "dev": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@electron/rebuild/node_modules/ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", - "dev": true, - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@electron/rebuild/node_modules/unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", - "dev": true, - "dependencies": { - "unique-slug": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@electron/rebuild/node_modules/unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@electron/rebuild/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@electron/universal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-2.0.1.tgz", - "integrity": "sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==", - "dev": true, - "dependencies": { - "@electron/asar": "^3.2.7", - "@malept/cross-spawn-promise": "^2.0.0", - "debug": "^4.3.1", - "dir-compare": "^4.2.0", - "fs-extra": "^11.1.1", - "minimatch": "^9.0.3", - "plist": "^3.1.0" - }, - "engines": { - "node": ">=16.4" - } - }, - "node_modules/@electron/universal/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@electron/universal/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@electron/windows-sign": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@electron/windows-sign/-/windows-sign-1.1.3.tgz", - "integrity": "sha512-OqVSdAe+/88fIjvTDWiy+5Ho1nXsiBhE5RTsIQ6M/zcxcDAEP2TlQCkOyusItnmzXRN+XTFaK9gKhiZ6KGyXQw==", - "dev": true, - "dependencies": { - "cross-dirname": "^0.1.0", - "debug": "^4.3.4", - "fs-extra": "^11.1.1", - "minimist": "^1.2.8", - "postject": "^1.0.0-alpha.6" - }, - "bin": { - "electron-windows-sign": "bin/electron-windows-sign.js" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@emotion/is-prop-valid": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.0.tgz", - "integrity": "sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ==", - "dependencies": { - "@emotion/memoize": "^0.9.0" - } - }, - "node_modules/@emotion/memoize": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", - "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" - }, - "node_modules/@emotion/stylis": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", - "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" - }, - "node_modules/@emotion/unitless": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", - "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", - "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@fal-ai/serverless-client": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@fal-ai/serverless-client/-/serverless-client-0.13.0.tgz", - "integrity": "sha512-Nkb/5YXJIPQHzM79+fRb1LZ1zQLSSvNhDVL2l62sN6/H4XqAWueIOqAAvPF8ds39uSGn8nF1WQV1mt7raVMlWw==", - "dependencies": { - "@msgpack/msgpack": "^3.0.0-beta2", - "eventsource-parser": "^1.1.2", - "robot3": "^0.4.1", - "uuid-random": "^1.3.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@ffmpeg/ffmpeg": { - "version": "0.12.10", - "resolved": "https://registry.npmjs.org/@ffmpeg/ffmpeg/-/ffmpeg-0.12.10.tgz", - "integrity": "sha512-lVtk8PW8e+NUzGZhPTWj2P1J4/NyuCrbDD3O9IGpSeLYtUZKBqZO8CNj1WYGghep/MXoM8e1qVY1GztTkf8YYQ==", - "dependencies": { - "@ffmpeg/types": "^0.12.2" - }, - "engines": { - "node": ">=18.x" - } - }, - "node_modules/@ffmpeg/types": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@ffmpeg/types/-/types-0.12.2.tgz", - "integrity": "sha512-NJtxwPoLb60/z1Klv0ueshguWQ/7mNm106qdHkB4HL49LXszjhjCCiL+ldHJGQ9ai2Igx0s4F24ghigy//ERdA==", - "engines": { - "node": ">=16.x" - } - }, - "node_modules/@ffmpeg/util": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@ffmpeg/util/-/util-0.12.1.tgz", - "integrity": "sha512-10jjfAKWaDyb8+nAkijcsi9wgz/y26LOc1NKJradNMyCIl6usQcBbhkjX5qhALrSBcOy6TOeksunTYa+a03qNQ==", - "engines": { - "node": ">=18.x" - } - }, - "node_modules/@floating-ui/core": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz", - "integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==", - "dependencies": { - "@floating-ui/utils": "^0.2.7" - } - }, - "node_modules/@floating-ui/dom": { - "version": "1.6.10", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz", - "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==", - "dependencies": { - "@floating-ui/core": "^1.6.0", - "@floating-ui/utils": "^0.2.7" - } - }, - "node_modules/@floating-ui/react-dom": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", - "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", - "dependencies": { - "@floating-ui/dom": "^1.0.0" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@floating-ui/utils": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz", - "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==" - }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true - }, - "node_modules/@gradio/client": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@gradio/client/-/client-1.5.0.tgz", - "integrity": "sha512-ZQ1coiujVZjVfas0zyyFgVQOocUL+pnYJagRNfLTzCsJ0m/DXGngELhGTM/QjIVkJGVDuhUyY5VCM7vD1n4LDQ==", - "dependencies": { - "@types/eventsource": "^1.1.15", - "bufferutil": "^4.0.7", - "eventsource": "^2.0.2", - "fetch-event-stream": "^0.1.5", - "msw": "^2.2.1", - "semiver": "^1.1.0", - "textlinestream": "^1.1.1", - "typescript": "^5.0.0", - "ws": "^8.13.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@huggingface/hub": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@huggingface/hub/-/hub-0.15.1.tgz", - "integrity": "sha512-uHb4aFkJDoGfLeRHfFTjkI36Z8IV6Z1c+KzhMDqUSC56opyr7Mn1Nsx7Rri/C7KDwROhQfBp/fOOqqjTzn6Cgg==", - "dependencies": { - "@huggingface/tasks": "^0.10.6", - "hash-wasm": "^4.9.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@huggingface/inference": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@huggingface/inference/-/inference-2.8.0.tgz", - "integrity": "sha512-Ti681P1qckcCAqgzmL53jBnluPuZGelmMIuXNjgAwC5+RIjF4S0SDQu6oy44ZTwekwNp2ETaZ2sXsOk+45aC4w==", - "dependencies": { - "@huggingface/tasks": "^0.11.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@huggingface/inference/node_modules/@huggingface/tasks": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@huggingface/tasks/-/tasks-0.11.8.tgz", - "integrity": "sha512-HOdx2vwhd/rCmy6gpDPiUbsXD+vwVpYSS/h2Tx+yV1uMDfS98MWl/TvoVGV+u5cJWTFbvdiTHMXIuw8B6JbHuQ==" - }, - "node_modules/@huggingface/jinja": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.3.0.tgz", - "integrity": "sha512-GLJzso0M07ZncFkrJMIXVU4os6GFbPocD4g8fMQPMGJubf48FtGOsUORH2rtFdXPIPelz8SLBMn8ZRmOTwXm9Q==", - "engines": { - "node": ">=18" - } - }, - "node_modules/@huggingface/tasks": { - "version": "0.10.22", - "resolved": "https://registry.npmjs.org/@huggingface/tasks/-/tasks-0.10.22.tgz", - "integrity": "sha512-sCtp+A6sq6NXoUU7NXuXWoVNNjKddk1GTQIh3cJ6illF8S4zmFoerCVRvFf19BdgICGvF+RVZiv9sGGK9KRDTg==" - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.4.tgz", - "integrity": "sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "glibc": ">=2.26", - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.0.2" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.4.tgz", - "integrity": "sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "glibc": ">=2.26", - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.0.2" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.2.tgz", - "integrity": "sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "macos": ">=11", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.2.tgz", - "integrity": "sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "macos": ">=10.13", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.2.tgz", - "integrity": "sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "glibc": ">=2.28", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.2.tgz", - "integrity": "sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "glibc": ">=2.26", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.2.tgz", - "integrity": "sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "glibc": ">=2.26", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.2.tgz", - "integrity": "sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "musl": ">=1.2.2", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.2.tgz", - "integrity": "sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "musl": ">=1.2.2", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-win32-ia32": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-win32-ia32/-/sharp-libvips-win32-ia32-1.0.2.tgz", - "integrity": "sha512-NDMPtXP7TTnm7588hpVwzUm48oMH3GOP8UKZLeBpL4yTLY89Jya3QBuKTVkh22GJGs8rV0ben7raSWXWsfMyww==", - "optional": true, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-win32-x64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-win32-x64/-/sharp-libvips-win32-x64-1.0.2.tgz", - "integrity": "sha512-rpNEXU8TJSrwmYh/pOoKNxsYcnA92MfuUmNWEz7Twb2kRffK23zIIIIf2Km3wqLhbLR2hqvGB5g2avN9SMQTvg==", - "optional": true, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.4.tgz", - "integrity": "sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "glibc": ">=2.28", - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.0.2" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.4.tgz", - "integrity": "sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "glibc": ">=2.26", - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.0.2" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.4.tgz", - "integrity": "sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "glibc": ">=2.26", - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.0.2" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.4.tgz", - "integrity": "sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "musl": ">=1.2.2", - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.0.2" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.4.tgz", - "integrity": "sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "musl": ">=1.2.2", - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.2" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.4.tgz", - "integrity": "sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.4.tgz", - "integrity": "sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@inquirer/confirm": { - "version": "3.1.22", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.1.22.tgz", - "integrity": "sha512-gsAKIOWBm2Q87CDfs9fEo7wJT3fwWIJfnDGMn9Qy74gBnNFOACDNfhUzovubbJjWnKLGBln7/NcSmZwj5DuEXg==", - "dependencies": { - "@inquirer/core": "^9.0.10", - "@inquirer/type": "^1.5.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@inquirer/core": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", - "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", - "dependencies": { - "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.2", - "@types/mute-stream": "^0.0.4", - "@types/node": "^22.1.0", - "@types/wrap-ansi": "^3.0.0", - "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@inquirer/core/node_modules/@types/node": { - "version": "22.1.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz", - "integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==", - "dependencies": { - "undici-types": "~6.13.0" - } - }, - "node_modules/@inquirer/core/node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@inquirer/core/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@inquirer/core/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@inquirer/core/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/@inquirer/core/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@inquirer/core/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@inquirer/core/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@inquirer/core/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@inquirer/core/node_modules/undici-types": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", - "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==" - }, - "node_modules/@inquirer/core/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@inquirer/figures": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.5.tgz", - "integrity": "sha512-79hP/VWdZ2UVc9bFGJnoQ/lQMpL74mGgzSYX1xUqCVk7/v73vJCMw1VuyWN1jGkZ9B3z7THAbySqGbCNefcjfA==", - "engines": { - "node": ">=18" - } - }, - "node_modules/@inquirer/type": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.2.tgz", - "integrity": "sha512-w9qFkumYDCNyDZmNQjf/n6qQuvQ4dMC3BJesY4oF+yr0CxR5vxujflAVeIcS6U336uzi9GM0kAfZlLrZ9UTkpA==", - "dependencies": { - "mute-stream": "^1.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", - "optional": true, - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@langchain/anthropic": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/@langchain/anthropic/-/anthropic-0.2.14.tgz", - "integrity": "sha512-qTFlsMej8SE0hz6IrqcQTkza/TGnlc7Tq/9W65TjQGLX51rGCYkprbLfpTi/LL9gahdB9VvB2Q5knUL0/N/xtQ==", - "dependencies": { - "@anthropic-ai/sdk": "^0.22.0", - "@langchain/core": ">=0.2.21 <0.3.0", - "fast-xml-parser": "^4.4.1", - "zod": "^3.22.4", - "zod-to-json-schema": "^3.22.4" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@langchain/cohere": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@langchain/cohere/-/cohere-0.2.2.tgz", - "integrity": "sha512-XbH6vBnPz0dmJaTMKMFriFhh4eYiajYrEg7Jr0bdejj7s7lxhST92znNrJezi76LjSTtDQo3PyLBKDktk8OxKw==", - "dependencies": { - "@langchain/core": ">=0.2.21 <0.3.0", - "cohere-ai": "^7.10.5", - "uuid": "^10.0.0", - "zod": "^3.23.8", - "zod-to-json-schema": "^3.23.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@langchain/cohere/node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@langchain/core": { - "version": "0.2.23", - "resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.2.23.tgz", - "integrity": "sha512-elPg6WpAkxWEIGC9u38F2anbzqfYYEy32lJdsd9dtChcHSFmFLlXqa+SnpO3R772gUuJmcu+Pd+fCvmRFy029w==", - "dependencies": { - "ansi-styles": "^5.0.0", - "camelcase": "6", - "decamelize": "1.2.0", - "js-tiktoken": "^1.0.12", - "langsmith": "~0.1.39", - "mustache": "^4.2.0", - "p-queue": "^6.6.2", - "p-retry": "4", - "uuid": "^10.0.0", - "zod": "^3.22.4", - "zod-to-json-schema": "^3.22.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@langchain/core/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "engines": { - "node": ">=14" - } - }, - "node_modules/@langchain/core/node_modules/langsmith": { - "version": "0.1.41", - "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.1.41.tgz", - "integrity": "sha512-8R7s/225Pxmv0ipMfd6sqmWVsfHLQivYlQZ0vx5K+ReoknummTenQlVK8gapk3kqRMnzkrouuRHMhWjMR6RgUA==", - "dependencies": { - "@types/uuid": "^9.0.1", - "commander": "^10.0.1", - "p-queue": "^6.6.2", - "p-retry": "4", - "semver": "^7.6.3", - "uuid": "^9.0.0" - }, - "peerDependencies": { - "@langchain/core": "*", - "langchain": "*", - "openai": "*" - }, - "peerDependenciesMeta": { - "@langchain/core": { - "optional": true - }, - "langchain": { - "optional": true - }, - "openai": { - "optional": true - } - } - }, - "node_modules/@langchain/core/node_modules/langsmith/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@langchain/core/node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@langchain/google-common": { - "version": "0.0.25", - "resolved": "https://registry.npmjs.org/@langchain/google-common/-/google-common-0.0.25.tgz", - "integrity": "sha512-5k9WrEAVT7po+NBa+36Xr2mkZzbw5JAV9kkdi4hjE3mCK8KS8s1kIqkbKZ4wfYCCP59ZcPs5MZayzbNdq8Dhag==", - "dependencies": { - "@langchain/core": ">=0.2.21 <0.3.0", - "uuid": "^10.0.0", - "zod-to-json-schema": "^3.22.4" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@langchain/google-common/node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@langchain/google-gauth": { - "version": "0.0.25", - "resolved": "https://registry.npmjs.org/@langchain/google-gauth/-/google-gauth-0.0.25.tgz", - "integrity": "sha512-M6kFGZNDGwYNQvr0kNCMQEWvxk8P8yGDk/KQul9UjjWrAmJuJ8qsVEtucvTzFIppj4ee6LR5CGxSJSmIynKMhQ==", - "dependencies": { - "@langchain/core": ">=0.2.21 <0.3.0", - "@langchain/google-common": "~0.0.25", - "google-auth-library": "^8.9.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@langchain/google-vertexai": { - "version": "0.0.25", - "resolved": "https://registry.npmjs.org/@langchain/google-vertexai/-/google-vertexai-0.0.25.tgz", - "integrity": "sha512-hXiTz7gsTXou8CXZVauDmFZWzsjIKUTBUa9hPgpxj/Rh3/EV6esixI9+HWVn20kATjaZ7bY1aD8RI0+krQ52vw==", - "dependencies": { - "@langchain/core": ">=0.2.21 <0.3.0", - "@langchain/google-gauth": "~0.0.25" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@langchain/groq": { - "version": "0.0.16", - "resolved": "https://registry.npmjs.org/@langchain/groq/-/groq-0.0.16.tgz", - "integrity": "sha512-rwD57PzT54clE4WigMzTMmA9rIifXq82uQ9nqFHJ4hfDV38P2lbQ1/N21QE0+L8c9oKvdY+TVm0vlilxV4w22A==", - "dependencies": { - "@langchain/core": ">=0.2.21 <0.3.0", - "@langchain/openai": "~0.2.6", - "groq-sdk": "^0.5.0", - "zod": "^3.22.4", - "zod-to-json-schema": "^3.22.5" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@langchain/mistralai": { - "version": "0.0.28", - "resolved": "https://registry.npmjs.org/@langchain/mistralai/-/mistralai-0.0.28.tgz", - "integrity": "sha512-6+6AUlRtNTw+fZatbrYNBaZn2Qgn8s+EMBhrpmT5pG4n5usQ57zIKT9VKfv4nJOauBF9J3+3+GiA4bwC8tmkNw==", - "dependencies": { - "@langchain/core": ">=0.2.21 <0.3.0", - "@mistralai/mistralai": "^0.4.0", - "uuid": "^10.0.0", - "zod": "^3.22.4", - "zod-to-json-schema": "^3.22.4" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@langchain/mistralai/node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@langchain/openai": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-0.2.6.tgz", - "integrity": "sha512-LZgSzHOZPJGsZr2ZXJICqZo1GN0kUyP9/RN+T45g7HDdMRfS5Df7fJgY9w7EIfznT83Q0Ywhz+At/UvWMR3xhw==", - "dependencies": { - "@langchain/core": ">=0.2.21 <0.3.0", - "js-tiktoken": "^1.0.12", - "openai": "^4.55.0", - "zod": "^3.22.4", - "zod-to-json-schema": "^3.22.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@malept/cross-spawn-promise": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", - "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/malept" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" - } - ], - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/@mediapipe/tasks-vision": { - "version": "0.10.8", - "resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.8.tgz", - "integrity": "sha512-Rp7ll8BHrKB3wXaRFKhrltwZl1CiXGdibPxuWXvqGnKTnv8fqa/nvftYNuSbf+pbJWKYCXdBtYTITdAUTGGh0Q==" - }, - "node_modules/@mistralai/mistralai": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-0.4.0.tgz", - "integrity": "sha512-KmFzNro1RKxIFh19J3osmUQhucefBBauMXN5fa9doG6dT9OHR/moBvvn+riVlR7c0AVfuxO8Dfa03AyLYYzbyg==", - "dependencies": { - "node-fetch": "^2.6.7" - } - }, - "node_modules/@monaco-editor/loader": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.4.0.tgz", - "integrity": "sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==", - "dependencies": { - "state-local": "^1.0.6" - }, - "peerDependencies": { - "monaco-editor": ">= 0.21.0 < 1" - } - }, - "node_modules/@monaco-editor/react": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.6.0.tgz", - "integrity": "sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==", - "dependencies": { - "@monaco-editor/loader": "^1.4.0" - }, - "peerDependencies": { - "monaco-editor": ">= 0.25.0 < 1", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/@monogrid/gainmap-js": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.0.5.tgz", - "integrity": "sha512-53sCTG4FaJBaAq/tcufARtVYDMDGqyBT9i7F453pWGhZ5LqubDHDWtYoHo9VhQqMcHTEexdJqSsR58y+9HVmQA==", - "dependencies": { - "promise-worker-transferable": "^1.0.4" - }, - "peerDependencies": { - "three": ">= 0.159.0" - } - }, - "node_modules/@msgpack/msgpack": { - "version": "3.0.0-beta2", - "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-3.0.0-beta2.tgz", - "integrity": "sha512-y+l1PNV0XDyY8sM3YtuMLK5vE3/hkfId+Do8pLo/OPxfxuFAUwcGz3oiiUuV46/aBpwTzZ+mRWVMtlSKbradhw==", - "engines": { - "node": ">= 14" - } - }, - "node_modules/@mswjs/interceptors": { - "version": "0.29.1", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.29.1.tgz", - "integrity": "sha512-3rDakgJZ77+RiQUuSK69t1F0m8BQKA8Vh5DCS5V0DWvNY67zob2JhhQrhCO0AKLGINTRSFd1tBaHcJTkhefoSw==", - "dependencies": { - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/logger": "^0.3.0", - "@open-draft/until": "^2.0.0", - "is-node-process": "^1.2.0", - "outvariant": "^1.2.1", - "strict-event-emitter": "^0.5.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@next/env": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.5.tgz", - "integrity": "sha512-/zZGkrTOsraVfYjGP8uM0p6r0BDT6xWpkjdVbcz66PJVSpwXX3yNiRycxAuDfBKGWBrZBXRuK/YVlkNgxHGwmA==" - }, - "node_modules/@next/eslint-plugin-next": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.5.tgz", - "integrity": "sha512-LY3btOpPh+OTIpviNojDpUdIbHW9j0JBYBjsIp8IxtDFfYFyORvw3yNq6N231FVqQA7n7lwaf7xHbVJlA1ED7g==", - "dev": true, - "dependencies": { - "glob": "10.3.10" - } - }, - "node_modules/@next/eslint-plugin-next/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@next/eslint-plugin-next/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@next/eslint-plugin-next/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.5.tgz", - "integrity": "sha512-/9zVxJ+K9lrzSGli1///ujyRfon/ZneeZ+v4ptpiPoOU+GKZnm8Wj8ELWU1Pm7GHltYRBklmXMTUqM/DqQ99FQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.5.tgz", - "integrity": "sha512-vXHOPCwfDe9qLDuq7U1OYM2wUY+KQ4Ex6ozwsKxp26BlJ6XXbHleOUldenM67JRyBfVjv371oneEvYd3H2gNSA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.5.tgz", - "integrity": "sha512-vlhB8wI+lj8q1ExFW8lbWutA4M2ZazQNvMWuEDqZcuJJc78iUnLdPPunBPX8rC4IgT6lIx/adB+Cwrl99MzNaA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.5.tgz", - "integrity": "sha512-NpDB9NUR2t0hXzJJwQSGu1IAOYybsfeB+LxpGsXrRIb7QOrYmidJz3shzY8cM6+rO4Aojuef0N/PEaX18pi9OA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.5.tgz", - "integrity": "sha512-8XFikMSxWleYNryWIjiCX+gU201YS+erTUidKdyOVYi5qUQo/gRxv/3N1oZFCgqpesN6FPeqGM72Zve+nReVXQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.5.tgz", - "integrity": "sha512-6QLwi7RaYiQDcRDSU/os40r5o06b5ue7Jsk5JgdRBGGp8l37RZEh9JsLSM8QF0YDsgcosSeHjglgqi25+m04IQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.5.tgz", - "integrity": "sha512-1GpG2VhbspO+aYoMOQPQiqc/tG3LzmsdBH0LhnDS3JrtDx2QmzXe0B6mSZZiN3Bq7IOMXxv1nlsjzoS1+9mzZw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.5.tgz", - "integrity": "sha512-Igh9ZlxwvCDsu6438FXlQTHlRno4gFpJzqPjSIBZooD22tKeI4fE/YMRoHVJHmrQ2P5YL1DoZ0qaOKkbeFWeMg==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.5.tgz", - "integrity": "sha512-tEQ7oinq1/CjSG9uSTerca3v4AZ+dFa+4Yu6ihaG8Ud8ddqLQgFGcnwYls13H5X5CPDPZJdYxyeMui6muOLd4g==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@npmcli/agent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", - "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", - "dev": true, - "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.3" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/agent/node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@npmcli/agent/node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", - "dev": true, - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@npmcli/agent/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true - }, - "node_modules/@npmcli/fs": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", - "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", - "dev": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/move-file": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@octokit/auth-token": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", - "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", - "dev": true, - "dependencies": { - "@octokit/types": "^6.0.3" - } - }, - "node_modules/@octokit/core": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", - "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", - "dev": true, - "dependencies": { - "@octokit/auth-token": "^2.4.4", - "@octokit/graphql": "^4.5.8", - "@octokit/request": "^5.6.3", - "@octokit/request-error": "^2.0.5", - "@octokit/types": "^6.0.3", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/endpoint": { - "version": "6.0.12", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", - "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", - "dev": true, - "dependencies": { - "@octokit/types": "^6.0.3", - "is-plain-object": "^5.0.0", - "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/graphql": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", - "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", - "dev": true, - "dependencies": { - "@octokit/request": "^5.6.0", - "@octokit/types": "^6.0.3", - "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/openapi-types": { - "version": "12.11.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", - "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==", - "dev": true - }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "2.21.3", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz", - "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==", - "dev": true, - "dependencies": { - "@octokit/types": "^6.40.0" - }, - "peerDependencies": { - "@octokit/core": ">=2" - } - }, - "node_modules/@octokit/plugin-request-log": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", - "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", - "dev": true, - "peerDependencies": { - "@octokit/core": ">=3" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "5.16.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz", - "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==", - "dev": true, - "dependencies": { - "@octokit/types": "^6.39.0", - "deprecation": "^2.3.1" - }, - "peerDependencies": { - "@octokit/core": ">=3" - } - }, - "node_modules/@octokit/plugin-retry": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-3.0.9.tgz", - "integrity": "sha512-r+fArdP5+TG6l1Rv/C9hVoty6tldw6cE2pRHNGmFPdyfrc696R6JjrQ3d7HdVqGwuzfyrcaLAKD7K8TX8aehUQ==", - "dev": true, - "dependencies": { - "@octokit/types": "^6.0.3", - "bottleneck": "^2.15.3" - } - }, - "node_modules/@octokit/request": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", - "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", - "dev": true, - "dependencies": { - "@octokit/endpoint": "^6.0.1", - "@octokit/request-error": "^2.1.0", - "@octokit/types": "^6.16.1", - "is-plain-object": "^5.0.0", - "node-fetch": "^2.6.7", - "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/request-error": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", - "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", - "dev": true, - "dependencies": { - "@octokit/types": "^6.0.3", - "deprecation": "^2.0.0", - "once": "^1.4.0" - } - }, - "node_modules/@octokit/rest": { - "version": "18.12.0", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz", - "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==", - "dev": true, - "dependencies": { - "@octokit/core": "^3.5.1", - "@octokit/plugin-paginate-rest": "^2.16.8", - "@octokit/plugin-request-log": "^1.0.4", - "@octokit/plugin-rest-endpoint-methods": "^5.12.0" - } - }, - "node_modules/@octokit/types": { - "version": "6.41.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", - "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", - "dev": true, - "dependencies": { - "@octokit/openapi-types": "^12.11.0" - } - }, - "node_modules/@open-draft/deferred-promise": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", - "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==" - }, - "node_modules/@open-draft/logger": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", - "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", - "dependencies": { - "is-node-process": "^1.2.0", - "outvariant": "^1.4.0" - } - }, - "node_modules/@open-draft/until": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", - "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==" - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@playwright/test": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.46.0.tgz", - "integrity": "sha512-/QYft5VArOrGRP5pgkrfKksqsKA6CEFyGQ/gjNe6q0y4tZ1aaPfq4gIjudr1s3D+pXyrPRdsy4opKDrjBabE5w==", - "devOptional": true, - "dependencies": { - "playwright": "1.46.0" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@pmndrs/uikit": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@pmndrs/uikit/-/uikit-0.3.13.tgz", - "integrity": "sha512-DxKE1kHBnp6C7Bp57KwfPcM4BSwlE+7sbyntwzIyIBHPqH2786nEeZNn5hkYMIw9Gjw1ioEXRLoyIZ16UwYGfQ==", - "dependencies": { - "@preact/signals-core": "^1.5.1", - "inline-style-parser": "^0.2.3", - "node-html-parser": "^6.1.13", - "tw-to-css": "^0.0.12", - "yoga-layout": "^3.0.4" - }, - "peerDependencies": { - "three": ">=0.160" - } - }, - "node_modules/@preact/signals-core": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.8.0.tgz", - "integrity": "sha512-OBvUsRZqNmjzCZXWLxkZfhcgT+Fk8DDcT/8vD6a1xhDemodyy87UJRJfASMuSD8FaAIeGgGm85ydXhm7lr4fyA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/preact" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "node_modules/@radix-ui/number": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz", - "integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==" - }, - "node_modules/@radix-ui/primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", - "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==" - }, - "node_modules/@radix-ui/react-accordion": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.0.tgz", - "integrity": "sha512-HJOzSX8dQqtsp/3jVxCU3CXEONF7/2jlGAB28oX8TTw1Dz8JYbEI1UcL8355PuLBE41/IRRMvCw7VkiK/jcUOQ==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-collapsible": "1.1.0", - "@radix-ui/react-collection": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-direction": "1.1.0", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-controllable-state": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-arrow": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz", - "integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==", - "dependencies": { - "@radix-ui/react-primitive": "2.0.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-avatar": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.0.tgz", - "integrity": "sha512-Q/PbuSMk/vyAd/UoIShVGZ7StHHeRFYU7wXmi5GV+8cLXflZAEpHL/F697H1klrzxKXNtZ97vWiC0q3RKUH8UA==", - "dependencies": { - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-checkbox": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.1.1.tgz", - "integrity": "sha512-0i/EKJ222Afa1FE0C6pNJxDq1itzcl3HChE9DwskA4th4KRse8ojx8a1nVcOjwJdbpDLcz7uol77yYnQNMHdKw==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-presence": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-controllable-state": "1.1.0", - "@radix-ui/react-use-previous": "1.1.0", - "@radix-ui/react-use-size": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collapsible": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.0.tgz", - "integrity": "sha512-zQY7Epa8sTL0mq4ajSJpjgn2YmCgyrG7RsQgLp3C0LQVkG7+Tf6Pv1CeNWZLyqMjhdPkBa5Lx7wYBeSu7uCSTA==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-presence": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-controllable-state": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collection": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz", - "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", - "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-context": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", - "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dialog": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.1.tgz", - "integrity": "sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-dismissable-layer": "1.1.0", - "@radix-ui/react-focus-guards": "1.1.0", - "@radix-ui/react-focus-scope": "1.1.0", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-portal": "1.1.1", - "@radix-ui/react-presence": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0", - "@radix-ui/react-use-controllable-state": "1.1.0", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.7" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-direction": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", - "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz", - "integrity": "sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-escape-keydown": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dropdown-menu": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.1.tgz", - "integrity": "sha512-y8E+x9fBq9qvteD2Zwa4397pUVhYsh9iq44b5RD5qu1GMJWBCBuVg1hMyItbc6+zH00TxGRqd9Iot4wzf3OoBQ==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-menu": "2.1.1", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-controllable-state": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz", - "integrity": "sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz", - "integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-callback-ref": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-icons": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.0.tgz", - "integrity": "sha512-jQxj/0LKgp+j9BiTXz3O3sgs26RNet2iLWmsPyRz2SIcR4q/4SbazXfnYwbAr+vLYKSfc7qxzyGQA1HLlYiuNw==", - "peerDependencies": { - "react": "^16.x || ^17.x || ^18.x" - } - }, - "node_modules/@radix-ui/react-id": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", - "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-label": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.0.tgz", - "integrity": "sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==", - "dependencies": { - "@radix-ui/react-primitive": "2.0.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-menu": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.1.tgz", - "integrity": "sha512-oa3mXRRVjHi6DZu/ghuzdylyjaMXLymx83irM7hTxutQbD+7IhPKdMdRHD26Rm+kHRrWcrUkkRPv5pd47a2xFQ==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-collection": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-direction": "1.1.0", - "@radix-ui/react-dismissable-layer": "1.1.0", - "@radix-ui/react-focus-guards": "1.1.0", - "@radix-ui/react-focus-scope": "1.1.0", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.0", - "@radix-ui/react-portal": "1.1.1", - "@radix-ui/react-presence": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-roving-focus": "1.1.0", - "@radix-ui/react-slot": "1.1.0", - "@radix-ui/react-use-callback-ref": "1.1.0", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.7" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-menubar": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.1.tgz", - "integrity": "sha512-V05Hryq/BE2m+rs8d5eLfrS0jmSWSDHEbG7jEyLA5D5J9jTvWj/o3v3xDN9YsOlH6QIkJgiaNDaP+S4T1rdykw==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-collection": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-direction": "1.1.0", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-menu": "2.1.1", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-roving-focus": "1.1.0", - "@radix-ui/react-use-controllable-state": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popover": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.1.tgz", - "integrity": "sha512-3y1A3isulwnWhvTTwmIreiB8CF4L+qRjZnK1wYLO7pplddzXKby/GnZ2M7OZY3qgnl6p9AodUIHRYGXNah8Y7g==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-dismissable-layer": "1.1.0", - "@radix-ui/react-focus-guards": "1.1.0", - "@radix-ui/react-focus-scope": "1.1.0", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.0", - "@radix-ui/react-portal": "1.1.1", - "@radix-ui/react-presence": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0", - "@radix-ui/react-use-controllable-state": "1.1.0", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.7" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-popper": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz", - "integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==", - "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0", - "@radix-ui/react-use-rect": "1.1.0", - "@radix-ui/react-use-size": "1.1.0", - "@radix-ui/rect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-portal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.1.tgz", - "integrity": "sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==", - "dependencies": { - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-layout-effect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-presence": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.0.tgz", - "integrity": "sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", - "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", - "dependencies": { - "@radix-ui/react-slot": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-progress": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.0.tgz", - "integrity": "sha512-aSzvnYpP725CROcxAOEBVZZSIQVQdHgBr2QQFKySsaD14u8dNT0batuXI+AAGDdAHfXH8rbnHmjYFqVJ21KkRg==", - "dependencies": { - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-primitive": "2.0.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz", - "integrity": "sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-collection": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-direction": "1.1.0", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-controllable-state": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-scroll-area": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.1.0.tgz", - "integrity": "sha512-9ArIZ9HWhsrfqS765h+GZuLoxaRHD/j0ZWOWilsCvYTpYJp8XwCqNG7Dt9Nu/TItKOdgLGkOPCodQvDc+UMwYg==", - "dependencies": { - "@radix-ui/number": "1.1.0", - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-direction": "1.1.0", - "@radix-ui/react-presence": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.1.tgz", - "integrity": "sha512-8iRDfyLtzxlprOo9IicnzvpsO1wNCkuwzzCM+Z5Rb5tNOpCdMvcc2AkzX0Fz+Tz9v6NJ5B/7EEgyZveo4FBRfQ==", - "dependencies": { - "@radix-ui/number": "1.1.0", - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-collection": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-direction": "1.1.0", - "@radix-ui/react-dismissable-layer": "1.1.0", - "@radix-ui/react-focus-guards": "1.1.0", - "@radix-ui/react-focus-scope": "1.1.0", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.0", - "@radix-ui/react-portal": "1.1.1", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-controllable-state": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0", - "@radix-ui/react-use-previous": "1.1.0", - "@radix-ui/react-visually-hidden": "1.1.0", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.7" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.0.tgz", - "integrity": "sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA==", - "dependencies": { - "@radix-ui/react-primitive": "2.0.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-slider": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.2.0.tgz", - "integrity": "sha512-dAHCDA4/ySXROEPaRtaMV5WHL8+JB/DbtyTbJjYkY0RXmKMO2Ln8DFZhywG5/mVQ4WqHDBc8smc14yPXPqZHYA==", - "dependencies": { - "@radix-ui/number": "1.1.0", - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-collection": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-direction": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-controllable-state": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0", - "@radix-ui/react-use-previous": "1.1.0", - "@radix-ui/react-use-size": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", - "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-switch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.1.0.tgz", - "integrity": "sha512-OBzy5WAj641k0AOSpKQtreDMe+isX0MQJ1IVyF03ucdF3DunOnROVrjWs8zsXUxC3zfZ6JL9HFVCUlMghz9dJw==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-controllable-state": "1.1.0", - "@radix-ui/react-use-previous": "1.1.0", - "@radix-ui/react-use-size": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.0.tgz", - "integrity": "sha512-bZgOKB/LtZIij75FSuPzyEti/XBhJH52ExgtdVqjCIh+Nx/FW+LhnbXtbCzIi34ccyMsyOja8T0thCzoHFXNKA==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-direction": "1.1.0", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-presence": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-roving-focus": "1.1.0", - "@radix-ui/react-use-controllable-state": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-toast": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.1.tgz", - "integrity": "sha512-5trl7piMXcZiCq7MW6r8YYmu0bK5qDpTWz+FdEPdKyft2UixkspheYbjbrLXVN5NGKHFbOP7lm8eD0biiSqZqg==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-collection": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-dismissable-layer": "1.1.0", - "@radix-ui/react-portal": "1.1.1", - "@radix-ui/react-presence": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-controllable-state": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0", - "@radix-ui/react-visually-hidden": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.2.tgz", - "integrity": "sha512-9XRsLwe6Yb9B/tlnYCPVUd/TFS4J7HuOZW345DCeC6vKIxQGMZdx21RK4VoZauPD5frgkXTYVS5y90L+3YBn4w==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-dismissable-layer": "1.1.0", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.0", - "@radix-ui/react-portal": "1.1.1", - "@radix-ui/react-presence": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0", - "@radix-ui/react-use-controllable-state": "1.1.0", - "@radix-ui/react-visually-hidden": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", - "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", - "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", - "dependencies": { - "@radix-ui/react-use-callback-ref": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-escape-keydown": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", - "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", - "dependencies": { - "@radix-ui/react-use-callback-ref": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", - "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-previous": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz", - "integrity": "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-rect": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", - "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", - "dependencies": { - "@radix-ui/rect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-size": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", - "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.0.tgz", - "integrity": "sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==", - "dependencies": { - "@radix-ui/react-primitive": "2.0.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/rect": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", - "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==" - }, - "node_modules/@react-dnd/asap": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", - "integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==" - }, - "node_modules/@react-dnd/invariant": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz", - "integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==" - }, - "node_modules/@react-dnd/shallowequal": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz", - "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" - }, - "node_modules/@react-spring/animated": { - "version": "9.7.4", - "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.4.tgz", - "integrity": "sha512-7As+8Pty2QlemJ9O5ecsuPKjmO0NKvmVkRR1n6mEotFgWar8FKuQt2xgxz3RTgxcccghpx1YdS1FCdElQNexmQ==", - "dependencies": { - "@react-spring/shared": "~9.7.4", - "@react-spring/types": "~9.7.4" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/@react-spring/core": { - "version": "9.7.4", - "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.4.tgz", - "integrity": "sha512-GzjA44niEJBFUe9jN3zubRDDDP2E4tBlhNlSIkTChiNf9p4ZQlgXBg50qbXfSXHQPHak/ExYxwhipKVsQ/sUTw==", - "dependencies": { - "@react-spring/animated": "~9.7.4", - "@react-spring/shared": "~9.7.4", - "@react-spring/types": "~9.7.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/react-spring/donate" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/@react-spring/rafz": { - "version": "9.7.4", - "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.4.tgz", - "integrity": "sha512-mqDI6rW0Ca8IdryOMiXRhMtVGiEGLIO89vIOyFQXRIwwIMX30HLya24g9z4olDvFyeDW3+kibiKwtZnA4xhldA==" - }, - "node_modules/@react-spring/shared": { - "version": "9.7.4", - "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.4.tgz", - "integrity": "sha512-bEPI7cQp94dOtCFSEYpxvLxj0+xQfB5r9Ru1h8OMycsIq7zFZon1G0sHrBLaLQIWeMCllc4tVDYRTLIRv70C8w==", - "dependencies": { - "@react-spring/rafz": "~9.7.4", - "@react-spring/types": "~9.7.4" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/@react-spring/three": { - "version": "9.7.4", - "resolved": "https://registry.npmjs.org/@react-spring/three/-/three-9.7.4.tgz", - "integrity": "sha512-HKUhrrvWW7F/MAroObOloqcYyFqsUHp1ANIDvPVxk9cSh7veW7gQbJm2Sc7Ka+L4gVJEwSkS+MRfr8kk+sRZBw==", - "dependencies": { - "@react-spring/animated": "~9.7.4", - "@react-spring/core": "~9.7.4", - "@react-spring/shared": "~9.7.4", - "@react-spring/types": "~9.7.4" - }, - "peerDependencies": { - "@react-three/fiber": ">=6.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "three": ">=0.126" - } - }, - "node_modules/@react-spring/types": { - "version": "9.7.4", - "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.4.tgz", - "integrity": "sha512-iQVztO09ZVfsletMiY+DpT/JRiBntdsdJ4uqk3UJFhrhS8mIC9ZOZbmfGSRs/kdbNPQkVyzucceDicQ/3Mlj9g==" - }, - "node_modules/@react-three/drei": { - "version": "9.109.5", - "resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-9.109.5.tgz", - "integrity": "sha512-Ftw2d01N+83aXTOOMA5y8hF2KBU0w7gBEctyjeHJihUyRuLBdfcgfu5c1OhBjhrdy23ycSYRINaeLkqUBPDFxQ==", - "dependencies": { - "@babel/runtime": "^7.11.2", - "@mediapipe/tasks-vision": "0.10.8", - "@monogrid/gainmap-js": "^3.0.5", - "@react-spring/three": "~9.6.1", - "@use-gesture/react": "^10.2.24", - "camera-controls": "^2.4.2", - "cross-env": "^7.0.3", - "detect-gpu": "^5.0.28", - "glsl-noise": "^0.0.0", - "hls.js": "1.3.5", - "maath": "^0.10.7", - "meshline": "^3.1.6", - "react-composer": "^5.0.3", - "stats-gl": "^2.0.0", - "stats.js": "^0.17.0", - "suspend-react": "^0.1.3", - "three-mesh-bvh": "^0.7.0", - "three-stdlib": "^2.29.9", - "troika-three-text": "^0.49.0", - "tunnel-rat": "^0.1.2", - "utility-types": "^3.10.0", - "uuid": "^9.0.1", - "zustand": "^3.7.1" - }, - "peerDependencies": { - "@react-three/fiber": ">=8.0", - "react": ">=18.0", - "react-dom": ">=18.0", - "three": ">=0.137" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } - } - }, - "node_modules/@react-three/drei/node_modules/@react-spring/animated": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.6.1.tgz", - "integrity": "sha512-ls/rJBrAqiAYozjLo5EPPLLOb1LM0lNVQcXODTC1SMtS6DbuBCPaKco5svFUQFMP2dso3O+qcC4k9FsKc0KxMQ==", - "dependencies": { - "@react-spring/shared": "~9.6.1", - "@react-spring/types": "~9.6.1" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/@react-three/drei/node_modules/@react-spring/core": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.6.1.tgz", - "integrity": "sha512-3HAAinAyCPessyQNNXe5W0OHzRfa8Yo5P748paPcmMowZ/4sMfaZ2ZB6e5x5khQI8NusOHj8nquoutd6FRY5WQ==", - "dependencies": { - "@react-spring/animated": "~9.6.1", - "@react-spring/rafz": "~9.6.1", - "@react-spring/shared": "~9.6.1", - "@react-spring/types": "~9.6.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/react-spring/donate" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/@react-three/drei/node_modules/@react-spring/rafz": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.6.1.tgz", - "integrity": "sha512-v6qbgNRpztJFFfSE3e2W1Uz+g8KnIBs6SmzCzcVVF61GdGfGOuBrbjIcp+nUz301awVmREKi4eMQb2Ab2gGgyQ==" - }, - "node_modules/@react-three/drei/node_modules/@react-spring/shared": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.6.1.tgz", - "integrity": "sha512-PBFBXabxFEuF8enNLkVqMC9h5uLRBo6GQhRMQT/nRTnemVENimgRd+0ZT4yFnAQ0AxWNiJfX3qux+bW2LbG6Bw==", - "dependencies": { - "@react-spring/rafz": "~9.6.1", - "@react-spring/types": "~9.6.1" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/@react-three/drei/node_modules/@react-spring/three": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@react-spring/three/-/three-9.6.1.tgz", - "integrity": "sha512-Tyw2YhZPKJAX3t2FcqvpLRb71CyTe1GvT3V+i+xJzfALgpk10uPGdGaQQ5Xrzmok1340DAeg2pR/MCfaW7b8AA==", - "dependencies": { - "@react-spring/animated": "~9.6.1", - "@react-spring/core": "~9.6.1", - "@react-spring/shared": "~9.6.1", - "@react-spring/types": "~9.6.1" - }, - "peerDependencies": { - "@react-three/fiber": ">=6.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "three": ">=0.126" - } - }, - "node_modules/@react-three/drei/node_modules/@react-spring/types": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.6.1.tgz", - "integrity": "sha512-POu8Mk0hIU3lRXB3bGIGe4VHIwwDsQyoD1F394OK7STTiX9w4dG3cTLljjYswkQN+hDSHRrj4O36kuVa7KPU8Q==" - }, - "node_modules/@react-three/drei/node_modules/zustand": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz", - "integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==", - "engines": { - "node": ">=12.7.0" - }, - "peerDependencies": { - "react": ">=16.8" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - } - } - }, - "node_modules/@react-three/fiber": { - "version": "8.16.8", - "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.16.8.tgz", - "integrity": "sha512-Lc8fjATtvQEfSd8d5iKdbpHtRm/aPMeFj7jQvp6TNHfpo8IQTW3wwcE1ZMrGGoUH+w2mnyS+0MK1NLPLnuzGkQ==", - "dependencies": { - "@babel/runtime": "^7.17.8", - "@types/react-reconciler": "^0.26.7", - "@types/webxr": "*", - "base64-js": "^1.5.1", - "buffer": "^6.0.3", - "its-fine": "^1.0.6", - "react-reconciler": "^0.27.0", - "react-use-measure": "^2.1.1", - "scheduler": "^0.21.0", - "suspend-react": "^0.1.3", - "zustand": "^3.7.1" - }, - "peerDependencies": { - "expo": ">=43.0", - "expo-asset": ">=8.4", - "expo-file-system": ">=11.0", - "expo-gl": ">=11.0", - "react": ">=18.0", - "react-dom": ">=18.0", - "react-native": ">=0.64", - "three": ">=0.133" - }, - "peerDependenciesMeta": { - "expo": { - "optional": true - }, - "expo-asset": { - "optional": true - }, - "expo-file-system": { - "optional": true - }, - "expo-gl": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, - "node_modules/@react-three/fiber/node_modules/zustand": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz", - "integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==", - "engines": { - "node": ">=12.7.0" - }, - "peerDependencies": { - "react": ">=16.8" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - } - } - }, - "node_modules/@react-three/uikit": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@react-three/uikit/-/uikit-0.3.13.tgz", - "integrity": "sha512-tS6JFpKygxJSCr0z3K7KEv+VFkBQckDgcOpQzcqaCHgDNf/jGr1uudieqCCct31hChO6bosIq42SRhIvR//DnA==", - "dependencies": { - "@pmndrs/uikit": "^0.3.13", - "@preact/signals-core": "^1.5.1", - "chalk": "^5.3.0", - "commander": "^12.0.0", - "ora": "^8.0.1", - "prettier": "^3.2.5", - "prompts": "^2.4.2", - "zod": "^3.22.4", - "zustand": "^4.5.2" - }, - "bin": { - "uikit": "dist/cli/index.js" - }, - "peerDependencies": { - "@react-three/fiber": ">=8", - "react": ">=18" - } - }, - "node_modules/@react-three/uikit-lucide": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@react-three/uikit-lucide/-/uikit-lucide-0.3.13.tgz", - "integrity": "sha512-VFdwvR7YTPlia4o8rsiIbrB6k2d31Bkm/gcEqS/1+J6kkXaLOwGCE0jmmPu3/4um7bsUK83Ni1/KiafhsmBnOQ==", - "dependencies": { - "@react-three/uikit": "^0.3.13" - } - }, - "node_modules/@react-three/uikit/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@react-three/uikit/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@react-three/uikit/node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "engines": { - "node": ">=18" - } - }, - "node_modules/@react-three/uikit/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==" - }, - "node_modules/@react-three/uikit/node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@react-three/uikit/node_modules/is-unicode-supported": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.0.0.tgz", - "integrity": "sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@react-three/uikit/node_modules/log-symbols": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", - "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", - "dependencies": { - "chalk": "^5.3.0", - "is-unicode-supported": "^1.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@react-three/uikit/node_modules/log-symbols/node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@react-three/uikit/node_modules/ora": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-8.0.1.tgz", - "integrity": "sha512-ANIvzobt1rls2BDny5fWZ3ZVKyD6nscLvfFRpQgfWsythlcsVUC9kL0zq6j2Z5z9wwp1kd7wpsD/T9qNPVLCaQ==", - "dependencies": { - "chalk": "^5.3.0", - "cli-cursor": "^4.0.0", - "cli-spinners": "^2.9.2", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^2.0.0", - "log-symbols": "^6.0.0", - "stdin-discarder": "^0.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@react-three/uikit/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@react-three/uikit/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", - "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rushstack/eslint-patch": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.4.tgz", - "integrity": "sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==", - "dev": true - }, - "node_modules/@saintno/comfyui-sdk": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/@saintno/comfyui-sdk/-/comfyui-sdk-0.1.11.tgz", - "integrity": "sha512-k8Wui1ejYKOKhEF4WvNiNz3DTCtg+zJSnwKBKP6AHn9xOp+73mNF7F+TXXTTTuq9SCVNQdalEXTkDS6uDnEmxg==", - "dependencies": { - "@types/node": "^22.2.0", - "bun-types": "^1.1.22", - "ws": "^8.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - } - }, - "node_modules/@saintno/comfyui-sdk/node_modules/@types/node": { - "version": "22.2.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.2.0.tgz", - "integrity": "sha512-bm6EG6/pCpkxDf/0gDNDdtDILMOHgaQBVOJGdwsqClnxA3xL6jtMv76rLBc006RVMWbmaf0xbmom4Z/5o2nRkQ==", - "dependencies": { - "undici-types": "~6.13.0" - } - }, - "node_modules/@saintno/comfyui-sdk/node_modules/undici-types": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", - "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==" - }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@smithy/abort-controller": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", - "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/config-resolver": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.5.tgz", - "integrity": "sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA==", - "dependencies": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/core": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.2.tgz", - "integrity": "sha512-in5wwt6chDBcUv1Lw1+QzZxN9fBffi+qOixfb65yK4sDuKG7zAUO9HAFqmVzsZM3N+3tTyvZjtnDXePpvp007Q==", - "dependencies": { - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.0.tgz", - "integrity": "sha512-0SCIzgd8LYZ9EJxUjLXBmEKSZR/P/w6l7Rz/pab9culE/RWuqelAKGJvn5qUOl8BgX8Yj5HWM50A5hiB/RzsgA==", - "dependencies": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/eventstream-codec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-1.1.0.tgz", - "integrity": "sha512-3tEbUb8t8an226jKB6V/Q2XU/J53lCwCzULuBPEaF4JjSh+FlCMp7TmogE/Aij5J9DwlsZ4VAD/IRDuQ/0ZtMw==", - "dependencies": { - "@aws-crypto/crc32": "3.0.0", - "@smithy/types": "^1.2.0", - "@smithy/util-hex-encoding": "^1.1.0", - "tslib": "^2.5.0" - } - }, - "node_modules/@smithy/eventstream-codec/node_modules/@smithy/types": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-1.2.0.tgz", - "integrity": "sha512-z1r00TvBqF3dh4aHhya7nz1HhvCg4TRmw51fjMrh5do3h+ngSstt/yKlNbHeb9QxJmFbmN8KEVSWgb1bRvfEoA==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/eventstream-codec/node_modules/@smithy/util-hex-encoding": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-1.1.0.tgz", - "integrity": "sha512-7UtIE9eH0u41zpB60Jzr0oNCQ3hMJUabMcKRUVjmyHTXiWDE4vjSqN6qlih7rCNeKGbioS7f/y2Jgym4QZcKFg==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", - "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", - "dependencies": { - "@smithy/protocol-http": "^4.1.0", - "@smithy/querystring-builder": "^3.0.3", - "@smithy/types": "^3.3.0", - "@smithy/util-base64": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/hash-node": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.3.tgz", - "integrity": "sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw==", - "dependencies": { - "@smithy/types": "^3.3.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/invalid-dependency": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.3.tgz", - "integrity": "sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-content-length": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.5.tgz", - "integrity": "sha512-ILEzC2eyxx6ncej3zZSwMpB5RJ0zuqH7eMptxC4KN3f+v9bqT8ohssKbhNR78k/2tWW+KS5Spw+tbPF4Ejyqvw==", - "dependencies": { - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-endpoint": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", - "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", - "dependencies": { - "@smithy/middleware-serde": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-retry": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.14.tgz", - "integrity": "sha512-7ZaWZJOjUxa5hgmuMspyt8v/zVsh0GXYuF7OvCmdcbVa/xbnKQoYC+uYKunAqRGTkxjOyuOCw9rmFUFOqqC0eQ==", - "dependencies": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-serde": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", - "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-stack": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", - "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/node-config-provider": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", - "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", - "dependencies": { - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/node-http-handler": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", - "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", - "dependencies": { - "@smithy/abort-controller": "^3.1.1", - "@smithy/protocol-http": "^4.1.0", - "@smithy/querystring-builder": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/property-provider": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", - "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/protocol-http": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", - "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/querystring-builder": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", - "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", - "dependencies": { - "@smithy/types": "^3.3.0", - "@smithy/util-uri-escape": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/querystring-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", - "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/service-error-classification": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz", - "integrity": "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==", - "dependencies": { - "@smithy/types": "^3.3.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/shared-ini-file-loader": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", - "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/signature-v4": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.1.0.tgz", - "integrity": "sha512-aRryp2XNZeRcOtuJoxjydO6QTaVhxx/vjaR+gx7ZjaFgrgPRyZ3HCTbfwqYj6ZWEBHkCSUfcaymKPURaByukag==", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-uri-escape": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", - "dependencies": { - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/types": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", - "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/url-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", - "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", - "dependencies": { - "@smithy/querystring-parser": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/util-base64": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", - "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-body-length-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", - "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/util-body-length-node": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", - "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-config-provider": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", - "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.14.tgz", - "integrity": "sha512-0iwTgKKmAIf+vFLV8fji21Jb2px11ktKVxbX6LIDPAUJyWQqGqBVfwba7xwa1f2FZUoolYQgLvxQEpJycXuQ5w==", - "dependencies": { - "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.14.tgz", - "integrity": "sha512-e9uQarJKfXApkTMMruIdxHprhcXivH1flYCe8JRDTzkkLx8dA3V5J8GZlST9yfDiRWkJpZJlUXGN9Rc9Ade3OQ==", - "dependencies": { - "@smithy/config-resolver": "^3.0.5", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@smithy/util-endpoints": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.5.tgz", - "integrity": "sha512-ReQP0BWihIE68OAblC/WQmDD40Gx+QY1Ez8mTdFMXpmjfxSyz2fVQu3A4zXRfQU9sZXtewk3GmhfOHswvX+eNg==", - "dependencies": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-hex-encoding": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", - "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-middleware": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", - "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-retry": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.3.tgz", - "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==", - "dependencies": { - "@smithy/service-error-classification": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-stream": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", - "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", - "dependencies": { - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-uri-escape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", - "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-waiter": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.1.2.tgz", - "integrity": "sha512-4pP0EV3iTsexDx+8PPGAKCQpd/6hsQBaQhqWzU4hqKPHN5epPsxKbvUTIiYIHTxaKt6/kEaqPBpu/ufvfbrRzw==", - "dependencies": { - "@smithy/abort-controller": "^3.1.1", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@swc/counter": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==" - }, - "node_modules/@swc/helpers": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", - "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", - "dependencies": { - "@swc/counter": "^0.1.3", - "tslib": "^2.4.0" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@tailwindcss/container-queries": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/container-queries/-/container-queries-0.1.1.tgz", - "integrity": "sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==", - "peerDependencies": { - "tailwindcss": ">=3.2.0" - } - }, - "node_modules/@testing-library/dom": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", - "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@testing-library/react": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.0.tgz", - "integrity": "sha512-guuxUKRWQ+FgNX0h0NS0FIq3Q3uLtWVpBzcLOggmfMoUpgBnzBzvLLd4fbm6yS8ydJd94cIfY4yP9qUQjM2KwQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@testing-library/dom": "^10.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" - }, - "node_modules/@tweenjs/tween.js": { - "version": "23.1.3", - "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", - "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==" - }, - "node_modules/@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true, - "peer": true - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dev": true, - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, - "node_modules/@types/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==" - }, - "node_modules/@types/d3-color": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", - "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" - }, - "node_modules/@types/d3-drag": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", - "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-interpolate": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", - "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", - "dependencies": { - "@types/d3-color": "*" - } - }, - "node_modules/@types/d3-selection": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.10.tgz", - "integrity": "sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg==" - }, - "node_modules/@types/d3-transition": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.8.tgz", - "integrity": "sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ==", - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-zoom": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", - "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", - "dependencies": { - "@types/d3-interpolate": "*", - "@types/d3-selection": "*" - } - }, - "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/dom-speech-recognition": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@types/dom-speech-recognition/-/dom-speech-recognition-0.0.4.tgz", - "integrity": "sha512-zf2GwV/G6TdaLwpLDcGTIkHnXf8JEf/viMux+khqKQKDa8/8BAUtXXZS563GnvJ4Fg0PBLGAaFf2GekEVSZ6GQ==" - }, - "node_modules/@types/draco3d": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/@types/draco3d/-/draco3d-1.4.10.tgz", - "integrity": "sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==" - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" - }, - "node_modules/@types/estree-jsx": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", - "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/@types/eventsource": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@types/eventsource/-/eventsource-1.1.15.tgz", - "integrity": "sha512-XQmGcbnxUNa06HR3VBVkc9+A2Vpi9ZyLJcdS5dwaQQ/4ZMWFO+5c90FnMUpbtMZwB/FChoYHwuVg8TvkECacTA==" - }, - "node_modules/@types/fluent-ffmpeg": { - "version": "2.1.25", - "resolved": "https://registry.npmjs.org/@types/fluent-ffmpeg/-/fluent-ffmpeg-2.1.25.tgz", - "integrity": "sha512-a9/Jtv/RVaCG4lUwWIcuClWE5eXJFoFS/oHOecOv/RS8n+lQdJzcJVmDlxA8Xbk4B82YpO88Dijcoljb6sYTcA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/fs-extra": { - "version": "9.0.13", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", - "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", - "dev": true, - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", - "dev": true, - "optional": true, - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", - "dev": true - }, - "node_modules/@types/is-hotkey": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/@types/is-hotkey/-/is-hotkey-0.1.10.tgz", - "integrity": "sha512-RvC8KMw5BCac1NvRRyaHgMMEtBaZ6wh0pyPTBu7izn4Sj/AX9Y4aXU5c7rX8PnM/knsuUpC1IeoBkANtxBypsQ==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/@types/jsonfile": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz", - "integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==", - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true, - "optional": true - }, - "node_modules/@types/ms": { - "version": "0.7.34", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", - "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" - }, - "node_modules/@types/mute-stream": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz", - "integrity": "sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/node": { - "version": "20.14.14", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.14.tgz", - "integrity": "sha512-d64f00982fS9YoOgJkAMolK7MN8Iq3TDdVjchbYHdEmjth/DHowx82GnoA+tVUAN+7vxfYUgAzi+JXbKNd2SDQ==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", - "dependencies": { - "@types/node": "*", - "form-data": "^4.0.0" - } - }, - "node_modules/@types/offscreencanvas": { - "version": "2019.7.3", - "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", - "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==" - }, - "node_modules/@types/pngjs": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/@types/pngjs/-/pngjs-6.0.5.tgz", - "integrity": "sha512-0k5eKfrA83JOZPppLtS2C7OUtyNAl2wKNxfyYl9Q5g9lPkgBl/9hNyAu6HuEH2J4XmIv2znEpkDd0SaZVxW6iQ==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" - }, - "node_modules/@types/react": { - "version": "18.3.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", - "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", - "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", - "devOptional": true, - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/react-reconciler": { - "version": "0.26.7", - "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.7.tgz", - "integrity": "sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/responselike": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", - "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" - }, - "node_modules/@types/stats.js": { - "version": "0.17.3", - "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz", - "integrity": "sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==" - }, - "node_modules/@types/statuses": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.5.tgz", - "integrity": "sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==" - }, - "node_modules/@types/three": { - "version": "0.167.1", - "resolved": "https://registry.npmjs.org/@types/three/-/three-0.167.1.tgz", - "integrity": "sha512-OCd2Uv/8/4TbmSaIRFawrCOnDMLdpaa+QGJdhlUBmdfbHjLY8k6uFc0tde2/UvcaHQ6NtLl28onj/vJfofV+Tg==", - "peer": true, - "dependencies": { - "@tweenjs/tween.js": "~23.1.2", - "@types/stats.js": "*", - "@types/webxr": "*", - "fflate": "~0.8.2", - "meshoptimizer": "~0.18.1" - } - }, - "node_modules/@types/tough-cookie": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==" - }, - "node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/@types/uuid": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", - "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==" - }, - "node_modules/@types/webxr": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.19.tgz", - "integrity": "sha512-4hxA+NwohSgImdTSlPXEqDqqFktNgmTXQ05ff1uWam05tNGroCMp4G+4XVl6qWm1p7GQ/9oD41kAYsSssF6Mzw==" - }, - "node_modules/@types/wrap-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", - "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==" - }, - "node_modules/@types/ws": { - "version": "8.5.12", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", - "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", - "dev": true, - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz", - "integrity": "sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "7.2.0", - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/typescript-estree": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz", - "integrity": "sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz", - "integrity": "sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==", - "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz", - "integrity": "sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz", - "integrity": "sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.2.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" - }, - "node_modules/@use-gesture/core": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz", - "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==" - }, - "node_modules/@use-gesture/react": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz", - "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==", - "dependencies": { - "@use-gesture/core": "10.3.1" - }, - "peerDependencies": { - "react": ">= 16.8.0" - } - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz", - "integrity": "sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.24.5", - "@babel/plugin-transform-react-jsx-self": "^7.24.5", - "@babel/plugin-transform-react-jsx-source": "^7.24.1", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.14.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0" - } - }, - "node_modules/@vitest/expect": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.0.5.tgz", - "integrity": "sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==", - "dev": true, - "dependencies": { - "@vitest/spy": "2.0.5", - "@vitest/utils": "2.0.5", - "chai": "^5.1.1", - "tinyrainbow": "^1.2.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/pretty-format": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.0.5.tgz", - "integrity": "sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==", - "dev": true, - "dependencies": { - "tinyrainbow": "^1.2.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.0.5.tgz", - "integrity": "sha512-TfRfZa6Bkk9ky4tW0z20WKXFEwwvWhRY+84CnSEtq4+3ZvDlJyY32oNTJtM7AW9ihW90tX/1Q78cb6FjoAs+ig==", - "dev": true, - "dependencies": { - "@vitest/utils": "2.0.5", - "pathe": "^1.1.2" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.0.5.tgz", - "integrity": "sha512-SgCPUeDFLaM0mIUHfaArq8fD2WbaXG/zVXjRupthYfYGzc8ztbFbu6dUNOblBG7XLMR1kEhS/DNnfCZ2IhdDew==", - "dev": true, - "dependencies": { - "@vitest/pretty-format": "2.0.5", - "magic-string": "^0.30.10", - "pathe": "^1.1.2" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.0.5.tgz", - "integrity": "sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==", - "dev": true, - "dependencies": { - "tinyspy": "^3.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.0.5.tgz", - "integrity": "sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==", - "dev": true, - "dependencies": { - "@vitest/pretty-format": "2.0.5", - "estree-walker": "^3.0.3", - "loupe": "^3.1.1", - "tinyrainbow": "^1.2.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@webgpu/types": { - "version": "0.1.44", - "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.44.tgz", - "integrity": "sha512-JDpYJN5E/asw84LTYhKyvPpxGnD+bAKPtpW9Ilurf7cZpxaTbxkQcGwOd7jgB9BPBrTYQ+32ufo4HiuomTjHNQ==", - "dev": true - }, - "node_modules/@xenova/transformers": { - "version": "3.0.0-alpha.0", - "resolved": "git+ssh://git@github.com/xenova/transformers.js.git#222b94ed69158798c463d5fb374efbe44da199da", - "dependencies": { - "@huggingface/jinja": "^0.3.0", - "onnxruntime-web": "^1.18.0", - "sharp": "^0.33.2" - }, - "optionalDependencies": { - "onnxruntime-node": "^1.18.0" - } - }, - "node_modules/@xmldom/xmldom": { - "version": "0.8.10", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", - "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@xyflow/react": { - "version": "12.0.4", - "resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.0.4.tgz", - "integrity": "sha512-eeQzw1gIbLKOB55rp2+20uB1PASDUf1q6zy2VsgugnuPEcL/olVMX3WT42XxyG8m3rcbUiHlq2NSmPTFWEjiUQ==", - "dependencies": { - "@xyflow/system": "0.0.37", - "classcat": "^5.0.3", - "zustand": "^4.4.0" - }, - "peerDependencies": { - "react": ">=17", - "react-dom": ">=17" - } - }, - "node_modules/@xyflow/system": { - "version": "0.0.37", - "resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.37.tgz", - "integrity": "sha512-hSIhezhxgftPUpC+xiQVIorcRILZUOWlLjpYPTyGWRu8s4RJvM4GqvrsFmD5OnMKXLgpU7/PqqUibDVO67oWQQ==", - "dependencies": { - "@types/d3-drag": "^3.0.7", - "@types/d3-selection": "^3.0.10", - "@types/d3-transition": "^3.0.8", - "@types/d3-zoom": "^3.0.8", - "d3-drag": "^3.0.0", - "d3-selection": "^3.0.0", - "d3-zoom": "^3.0.0" - } - }, - "node_modules/abbrev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", - "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", - "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/agentkeepalive": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", - "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", - "dev": true, - "dependencies": { - "type-fest": "^1.0.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/appdmg": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/appdmg/-/appdmg-0.6.6.tgz", - "integrity": "sha512-GRmFKlCG+PWbcYF4LUNonTYmy0GjguDy6Jh9WP8mpd0T6j80XIJyXBiWlD0U+MLNhqV9Nhx49Gl9GpVToulpLg==", - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "async": "^1.4.2", - "ds-store": "^0.1.5", - "execa": "^1.0.0", - "fs-temp": "^1.0.0", - "fs-xattr": "^0.3.0", - "image-size": "^0.7.4", - "is-my-json-valid": "^2.20.0", - "minimist": "^1.1.3", - "parse-color": "^1.0.0", - "path-exists": "^4.0.0", - "repeat-string": "^1.5.4" - }, - "bin": { - "appdmg": "bin/appdmg.js" - }, - "engines": { - "node": ">=8.5" - } - }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true - }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/are-we-there-yet/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/aria-hidden": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", - "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", - "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dev": true, - "peer": true, - "dependencies": { - "dequal": "^2.0.3" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.findlast": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", - "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", - "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", - "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", - "engines": { - "node": ">=8" - } - }, - "node_modules/asar": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/asar/-/asar-3.2.0.tgz", - "integrity": "sha512-COdw2ZQvKdFGFxXwX3oYh2/sOsJWJegrdJCGxnN4MZ7IULgRBp9P6665aqj9z1v9VwP4oP1hRBojRDQ//IGgAg==", - "deprecated": "Please use @electron/asar moving forward. There is no API change, just a package name change", - "dev": true, - "optional": true, - "dependencies": { - "chromium-pickle-js": "^0.2.0", - "commander": "^5.0.0", - "glob": "^7.1.6", - "minimatch": "^3.0.4" - }, - "bin": { - "asar": "bin/asar.js" - }, - "engines": { - "node": ">=10.12.0" - }, - "optionalDependencies": { - "@types/glob": "^7.1.1" - } - }, - "node_modules/asar/node_modules/commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dev": true, - "optional": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/ast-types-flow": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", - "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", - "dev": true - }, - "node_modules/async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", - "dev": true, - "optional": true - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/author-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/author-regex/-/author-regex-1.0.0.tgz", - "integrity": "sha512-KbWgR8wOYRAPekEmMXrYYdc7BRyhn2Ftk7KWfMUnQ43hFdojWEFRxhhRUm3/OFEdPa1r0KAvTTg9YQK57xTe0g==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/automation-events": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/automation-events/-/automation-events-7.0.7.tgz", - "integrity": "sha512-eg7aK2P0jrq4QqnZRWXOQJDYs6lxZXK/erfZ/WPTVPP/YQlgt+J0KvIzTo86zYszkru2J/QCW1FFJYgJVd7TgA==", - "dependencies": { - "@babel/runtime": "^7.24.8", - "tslib": "^2.6.3" - }, - "engines": { - "node": ">=18.2.0" - } - }, - "node_modules/autoprefixer": { - "version": "10.4.19", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", - "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "browserslist": "^4.23.0", - "caniuse-lite": "^1.0.30001599", - "fraction.js": "^4.3.7", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axe-core": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.0.tgz", - "integrity": "sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/axobject-query": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", - "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/babel-plugin-styled-components": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.4.tgz", - "integrity": "sha512-Xgp9g+A/cG47sUyRwwYxGM4bR/jDRg5N6it/8+HxCnbT5XNKSKDT9xm4oag/osgqjC2It/vH0yXsomOG6k558g==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", - "@babel/plugin-syntax-jsx": "^7.22.5", - "lodash": "^4.17.21", - "picomatch": "^2.3.1" - }, - "peerDependencies": { - "styled-components": ">= 2" - } - }, - "node_modules/bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base32-encode": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/base32-encode/-/base32-encode-1.2.0.tgz", - "integrity": "sha512-cHFU8XeRyx0GgmoWi5qHMCVRiqU6J3MHWxVgun7jggCBUpVzm1Ir7M9dYr2whjSNc3tFeXfQ/oZjQu/4u55h9A==", - "dev": true, - "optional": true, - "dependencies": { - "to-data-view": "^1.1.0" - } - }, - "node_modules/base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/before-after-hook": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", - "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", - "dev": true - }, - "node_modules/bidi-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", - "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", - "dependencies": { - "require-from-string": "^2.0.2" - } - }, - "node_modules/bignumber.js": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", - "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bl/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, - "node_modules/boolean": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", - "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", - "dev": true, - "optional": true - }, - "node_modules/bottleneck": { - "version": "2.19.5", - "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", - "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", - "dev": true - }, - "node_modules/bowser": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", - "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" - }, - "node_modules/bplist-creator": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.8.tgz", - "integrity": "sha512-Za9JKzD6fjLC16oX2wsXfc+qBEhJBJB1YPInoAQpMLhDuj5aVOv1baGeIQSq1Fr3OCqzvsoQcSBSwGId/Ja2PA==", - "dev": true, - "optional": true, - "dependencies": { - "stream-buffers": "~2.2.0" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.23.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", - "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001646", - "electron-to-chromium": "^1.5.4", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/bufferutil": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", - "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", - "hasInstallScript": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, - "node_modules/bun-types": { - "version": "1.1.22", - "resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.1.22.tgz", - "integrity": "sha512-PBgj4pQd+1WZJ8kWCho7D6i1RMS9/6WkiRikIfqYFzFomfyWZET32Wy83xK2zmF9HiKXd2+bjtVahJ6546oraA==", - "dependencies": { - "@types/node": "~20.12.8", - "@types/ws": "~8.5.10" - } - }, - "node_modules/bun-types/node_modules/@types/node": { - "version": "20.12.14", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.14.tgz", - "integrity": "sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacache": { - "version": "18.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", - "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", - "dev": true, - "dependencies": { - "@npmcli/fs": "^3.1.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^4.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11", - "unique-filename": "^3.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/cacache/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/cacache/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacache/node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true - }, - "node_modules/cacache/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true, - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", - "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", - "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/camelize": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", - "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/camera-controls": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-2.8.5.tgz", - "integrity": "sha512-7VTwRk7Nu1nRKsY7bEt9HVBfKt8DETvzyYhLN4OW26OByBayMDB5fUaNcPI+z++vG23RH5yqn6ZRhZcgLQy2rA==", - "peerDependencies": { - "three": ">=0.126.1" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001651", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", - "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/chai": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz", - "integrity": "sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==", - "dev": true, - "dependencies": { - "assertion-error": "^2.0.1", - "check-error": "^2.1.1", - "deep-eql": "^5.0.1", - "loupe": "^3.1.0", - "pathval": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/chalk/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-html4": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", - "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-reference-invalid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", - "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/check-error": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", - "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", - "dev": true, - "engines": { - "node": ">= 16" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/chromium-pickle-js": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", - "integrity": "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==", - "dev": true, - "optional": true - }, - "node_modules/class-variance-authority": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz", - "integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==", - "dependencies": { - "clsx": "2.0.0" - }, - "funding": { - "url": "https://joebell.co.uk" - } - }, - "node_modules/class-variance-authority/node_modules/clsx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/classcat": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.5.tgz", - "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==" - }, - "node_modules/classnames": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", - "dependencies": { - "restore-cursor": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", - "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", - "dev": true, - "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", - "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", - "engines": { - "node": ">= 12" - } - }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/cliui/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/cmdk": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-0.2.1.tgz", - "integrity": "sha512-U6//9lQ6JvT47+6OF6Gi8BvkxYQ8SCRRSKIJkthIMsFsLZRG0cKvTtuTaefyIKMQb8rvvXy0wGdpTNq/jPtm+g==", - "dependencies": { - "@radix-ui/react-dialog": "1.0.0" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/primitive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz", - "integrity": "sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==", - "dependencies": { - "@babel/runtime": "^7.13.10" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-compose-refs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz", - "integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-context": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.0.tgz", - "integrity": "sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-dialog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.0.tgz", - "integrity": "sha512-Yn9YU+QlHYLWwV1XfKiqnGVpWYWk6MeBVM6x/bcoyPvxgjQGoeT35482viLPctTMWoMw0PoHgqfSox7Ig+957Q==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.0", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-context": "1.0.0", - "@radix-ui/react-dismissable-layer": "1.0.0", - "@radix-ui/react-focus-guards": "1.0.0", - "@radix-ui/react-focus-scope": "1.0.0", - "@radix-ui/react-id": "1.0.0", - "@radix-ui/react-portal": "1.0.0", - "@radix-ui/react-presence": "1.0.0", - "@radix-ui/react-primitive": "1.0.0", - "@radix-ui/react-slot": "1.0.0", - "@radix-ui/react-use-controllable-state": "1.0.0", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.4" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.0.tgz", - "integrity": "sha512-n7kDRfx+LB1zLueRDvZ1Pd0bxdJWDUZNQ/GWoxDn2prnuJKRdxsjulejX/ePkOsLi2tTm6P24mDqlMSgQpsT6g==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.0", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-primitive": "1.0.0", - "@radix-ui/react-use-callback-ref": "1.0.0", - "@radix-ui/react-use-escape-keydown": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-focus-guards": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.0.tgz", - "integrity": "sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ==", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-focus-scope": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.0.tgz", - "integrity": "sha512-C4SWtsULLGf/2L4oGeIHlvWQx7Rf+7cX/vKOAD2dXW0A1b5QXwi3wWeaEgW+wn+SEVrraMUk05vLU9fZZz5HbQ==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-primitive": "1.0.0", - "@radix-ui/react-use-callback-ref": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-id": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz", - "integrity": "sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-use-layout-effect": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-portal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.0.tgz", - "integrity": "sha512-a8qyFO/Xb99d8wQdu4o7qnigNjTPG123uADNecz0eX4usnQEj7o+cG4ZX4zkqq98NYekT7UoEQIjxBNWIFuqTA==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-presence": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.0.tgz", - "integrity": "sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-use-layout-effect": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-primitive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.0.tgz", - "integrity": "sha512-EyXe6mnRlHZ8b6f4ilTDrXmkLShICIuOTTj0GX4w1rp+wSxf3+TD05u1UOITC8VsJ2a9nwHvdXtOXEOl0Cw/zQ==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-slot": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-slot": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.0.tgz", - "integrity": "sha512-3mrKauI/tWXo1Ll+gN5dHcxDPdm/Df1ufcDLCecn+pnCIVcdWE7CujXo8QaXOWRJyZyQWWbpB8eFwHzWXlv5mQ==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz", - "integrity": "sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz", - "integrity": "sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-use-callback-ref": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-use-escape-keydown": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.0.tgz", - "integrity": "sha512-JwfBCUIfhXRxKExgIqGa4CQsiMemo1Xt0W/B4ei3fpzpvPENKpMKQ8mZSB6Acj3ebrAEgi2xiQvcI1PAAodvyg==", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-use-callback-ref": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz", - "integrity": "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/react-remove-scroll": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.4.tgz", - "integrity": "sha512-xGVKJJr0SJGQVirVFAUZ2k1QLyO6m+2fy0l8Qawbp5Jgrv3DeLalrfMNBFSlmz5kriGGzsVBtGVnf4pTKIhhWA==", - "dependencies": { - "react-remove-scroll-bar": "^2.3.3", - "react-style-singleton": "^2.2.1", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.0", - "use-sidecar": "^1.1.2" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/cohere-ai": { - "version": "7.11.2", - "resolved": "https://registry.npmjs.org/cohere-ai/-/cohere-ai-7.11.2.tgz", - "integrity": "sha512-IImDbZLg+kApTH9KswRAEGd0dRuZiChnsqC8gf6RepuklLuSxEkqto4uwSQQSUTj50Ns4uN7yaxzVyS6OmLpIg==", - "dependencies": { - "@aws-sdk/client-sagemaker": "^3.583.0", - "@aws-sdk/credential-providers": "^3.583.0", - "@aws-sdk/protocol-http": "^3.374.0", - "@aws-sdk/signature-v4": "^3.374.0", - "form-data": "^4.0.0", - "form-data-encoder": "^4.0.2", - "formdata-node": "^6.0.3", - "js-base64": "3.7.2", - "node-fetch": "2.7.0", - "qs": "6.11.2", - "readable-stream": "^4.5.2", - "url-join": "4.0.1" - } - }, - "node_modules/cohere-ai/node_modules/form-data-encoder": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-4.0.2.tgz", - "integrity": "sha512-KQVhvhK8ZkWzxKxOr56CPulAhH3dobtuQ4+hNQ+HekH/Wp5gSOafqRAeTphQUJAIk0GBvHZgJ2ZGRWd5kphMuw==", - "engines": { - "node": ">= 18" - } - }, - "node_modules/cohere-ai/node_modules/formdata-node": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-6.0.3.tgz", - "integrity": "sha512-8e1++BCiTzUno9v5IZ2J6bv4RU+3UKDmqWUQD0MIMVCd9AdhWkO1gw57oo1mNEX1dMq2EGI+FbWz4B92pscSQg==", - "engines": { - "node": ">= 18" - } - }, - "node_modules/cohere-ai/node_modules/qs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, - "engines": { - "node": ">=12.5.0" - } - }, - "node_modules/color-convert": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", - "integrity": "sha512-RwBeO/B/vZR3dfKL1ye/vx8MHZ40ugzpyfeVG5GsiuGnrlMWe2o8wxBbLCpw9CsxV+wHuzYlCiWnybrIA0ling==", - "dev": true, - "optional": true - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/color/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/comfydeploy": { - "version": "0.0.21", - "resolved": "https://registry.npmjs.org/comfydeploy/-/comfydeploy-0.0.21.tgz", - "integrity": "sha512-v5i6igitVWN6jmDlg35g8XyJuGsToD1sbhEZIz4nM3F6gSXZf2YjJzL/wzabsHlOtHhKsO/vdQAXuvO7/w8deQ==", - "dependencies": { - "zod": "^3.22.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/comma-separated-tokens": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/compare-version": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", - "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" - }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" - }, - "node_modules/cross-dirname": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz", - "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", - "dev": true - }, - "node_modules/cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "bin": { - "cross-env": "src/bin/cross-env.js", - "cross-env-shell": "src/bin/cross-env-shell.js" - }, - "engines": { - "node": ">=10.14", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cross-zip": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cross-zip/-/cross-zip-4.0.1.tgz", - "integrity": "sha512-n63i0lZ0rvQ6FXiGQ+/JFCKAUyPFhLQYJIqKaa+tSJtfKeULF/IDNDAbdnSIxgS4NTuw2b0+lj8LzfITuq+ZxQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=12.10" - } - }, - "node_modules/css-color-keywords": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", - "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", - "engines": { - "node": ">=4" - } - }, - "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-to-react-native": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", - "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", - "dependencies": { - "camelize": "^1.0.0", - "css-color-keywords": "^1.0.0", - "postcss-value-parser": "^4.0.2" - } - }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cssstyle": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz", - "integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==", - "dev": true, - "dependencies": { - "rrweb-cssom": "^0.6.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cssstyle/node_modules/rrweb-cssom": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", - "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", - "dev": true - }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" - }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dispatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-drag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", - "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-selection": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "dependencies": { - "d3-color": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-transition": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", - "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", - "dependencies": { - "d3-color": "1 - 3", - "d3-dispatch": "1 - 3", - "d3-ease": "1 - 3", - "d3-interpolate": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "d3-selection": "2 - 3" - } - }, - "node_modules/d3-zoom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", - "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "2 - 3", - "d3-transition": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true - }, - "node_modules/data-urls": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", - "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", - "dev": true, - "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/data-view-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/date-fns": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", - "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/kossnocorp" - } - }, - "node_modules/debounce": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", - "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" - }, - "node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "dev": true - }, - "node_modules/decode-named-character-reference": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", - "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", - "dependencies": { - "character-entities": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/decode-uri-component": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.4.1.tgz", - "integrity": "sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==", - "engines": { - "node": ">=14.16" - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-eql": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", - "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-equal": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", - "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.5", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.2", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true - }, - "node_modules/deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", - "dev": true - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/detect-gpu": { - "version": "5.0.42", - "resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-5.0.42.tgz", - "integrity": "sha512-Vdhe87ZNhxIS+OGesy9DOx8P3YBbCBapoomGR9kH26HuDAZ6c0FohsrK47j9efL972kLCaD22EbNUYHVLkqx/w==", - "dependencies": { - "webgl-constants": "^1.1.1" - } - }, - "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true, - "optional": true - }, - "node_modules/detect-node-es": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", - "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" - }, - "node_modules/devlop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", - "dependencies": { - "dequal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-compare": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz", - "integrity": "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==", - "dev": true, - "dependencies": { - "minimatch": "^3.0.5", - "p-limit": "^3.1.0 " - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" - }, - "node_modules/dnd-core": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz", - "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==", - "dependencies": { - "@react-dnd/asap": "^5.0.1", - "@react-dnd/invariant": "^4.0.1", - "redux": "^4.2.0" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true, - "peer": true - }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/draco3d": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz", - "integrity": "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==" - }, - "node_modules/ds-store": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ds-store/-/ds-store-0.1.6.tgz", - "integrity": "sha512-kY21M6Lz+76OS3bnCzjdsJSF7LBpLYGCVfavW8TgQD2XkcqIZ86W0y9qUDZu6fp7SIZzqosMDW2zi7zVFfv4hw==", - "dev": true, - "optional": true, - "dependencies": { - "bplist-creator": "~0.0.3", - "macos-alias": "~0.2.5", - "tn1150": "^0.1.0" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/electron": { - "version": "31.3.1", - "resolved": "https://registry.npmjs.org/electron/-/electron-31.3.1.tgz", - "integrity": "sha512-9fiuWlRhBfygtcT+auRd/WdBK/f8LZZcrpx0RjpXhH2DPTP/PfnkC4JB1PW55qCbGbh4wAgkYbf4ExIag8oGCA==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@electron/get": "^2.0.0", - "@types/node": "^20.9.0", - "extract-zip": "^2.0.1" - }, - "bin": { - "electron": "cli.js" - }, - "engines": { - "node": ">= 12.20.55" - } - }, - "node_modules/electron-installer-common": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/electron-installer-common/-/electron-installer-common-0.10.3.tgz", - "integrity": "sha512-mYbP+6i+nHMIm0WZHXgGdmmXMe+KXncl6jZYQNcCF9C1WsNA9C5SZ2VP4TLQMSIoFO+X4ugkMEA5uld1bmyEvA==", - "dev": true, - "optional": true, - "dependencies": { - "@malept/cross-spawn-promise": "^1.0.0", - "asar": "^3.0.0", - "debug": "^4.1.1", - "fs-extra": "^9.0.0", - "glob": "^7.1.4", - "lodash": "^4.17.15", - "parse-author": "^2.0.0", - "semver": "^7.1.1", - "tmp-promise": "^3.0.2" - }, - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "url": "https://github.com/electron-userland/electron-installer-common?sponsor=1" - }, - "optionalDependencies": { - "@types/fs-extra": "^9.0.1" - } - }, - "node_modules/electron-installer-common/node_modules/@malept/cross-spawn-promise": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", - "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/malept" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" - } - ], - "optional": true, - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/electron-installer-common/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "optional": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/electron-installer-debian": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/electron-installer-debian/-/electron-installer-debian-3.2.0.tgz", - "integrity": "sha512-58ZrlJ1HQY80VucsEIG9tQ//HrTlG6sfofA3nRGr6TmkX661uJyu4cMPPh6kXW+aHdq/7+q25KyQhDrXvRL7jw==", - "dev": true, - "optional": true, - "os": [ - "darwin", - "linux" - ], - "dependencies": { - "@malept/cross-spawn-promise": "^1.0.0", - "debug": "^4.1.1", - "electron-installer-common": "^0.10.2", - "fs-extra": "^9.0.0", - "get-folder-size": "^2.0.1", - "lodash": "^4.17.4", - "word-wrap": "^1.2.3", - "yargs": "^16.0.2" - }, - "bin": { - "electron-installer-debian": "src/cli.js" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/electron-installer-debian/node_modules/@malept/cross-spawn-promise": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", - "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/malept" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" - } - ], - "optional": true, - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/electron-installer-debian/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "optional": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/electron-installer-debian/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "optional": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/electron-installer-debian/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "optional": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/electron-installer-debian/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "optional": true - }, - "node_modules/electron-installer-debian/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "optional": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/electron-installer-debian/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/electron-installer-debian/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "optional": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/electron-installer-debian/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "optional": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/electron-installer-debian/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "optional": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/electron-installer-debian/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "optional": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/electron-installer-dmg": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/electron-installer-dmg/-/electron-installer-dmg-4.0.0.tgz", - "integrity": "sha512-g3W6XnyUa7QGrAF7ViewHdt6bXV2KYU1Pm1CY3pZpp+H6mOjCHHAhf/iZAxtaX1ERCb+SQHz7xSsAHuNH9I8ZQ==", - "dev": true, - "optional": true, - "dependencies": { - "debug": "^4.3.2", - "minimist": "^1.1.1" - }, - "bin": { - "electron-installer-dmg": "bin/electron-installer-dmg.js" - }, - "engines": { - "node": ">= 12.13.0" - }, - "optionalDependencies": { - "appdmg": "^0.6.4" - } - }, - "node_modules/electron-installer-redhat": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/electron-installer-redhat/-/electron-installer-redhat-3.4.0.tgz", - "integrity": "sha512-gEISr3U32Sgtj+fjxUAlSDo3wyGGq6OBx7rF5UdpIgbnpUvMN4W5uYb0ThpnAZ42VEJh/3aODQXHbFS4f5J3Iw==", - "dev": true, - "optional": true, - "os": [ - "darwin", - "linux" - ], - "dependencies": { - "@malept/cross-spawn-promise": "^1.0.0", - "debug": "^4.1.1", - "electron-installer-common": "^0.10.2", - "fs-extra": "^9.0.0", - "lodash": "^4.17.15", - "word-wrap": "^1.2.3", - "yargs": "^16.0.2" - }, - "bin": { - "electron-installer-redhat": "src/cli.js" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/electron-installer-redhat/node_modules/@malept/cross-spawn-promise": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", - "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/malept" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" - } - ], - "optional": true, - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/electron-installer-redhat/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "optional": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/electron-installer-redhat/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "optional": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/electron-installer-redhat/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "optional": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/electron-installer-redhat/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "optional": true - }, - "node_modules/electron-installer-redhat/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "optional": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/electron-installer-redhat/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/electron-installer-redhat/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "optional": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/electron-installer-redhat/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "optional": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/electron-installer-redhat/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "optional": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/electron-installer-redhat/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "optional": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz", - "integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==" - }, - "node_modules/electron-winstaller": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-5.4.0.tgz", - "integrity": "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "dependencies": { - "@electron/asar": "^3.2.1", - "debug": "^4.1.1", - "fs-extra": "^7.0.1", - "lodash": "^4.17.21", - "temp": "^0.9.0" - }, - "engines": { - "node": ">=8.0.0" - }, - "optionalDependencies": { - "@electron/windows-sign": "^1.1.2" - } - }, - "node_modules/electron-winstaller/node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "optional": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/electron-winstaller/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "optional": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/electron-winstaller/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "optional": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/electron/node_modules/@electron/get": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", - "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "env-paths": "^2.2.0", - "fs-extra": "^8.1.0", - "got": "^11.8.5", - "progress": "^2.0.3", - "semver": "^6.2.0", - "sumchecker": "^3.0.1" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "global-agent": "^3.0.0" - } - }, - "node_modules/electron/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/electron/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/electron/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/electron/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" - }, - "node_modules/encode-utf8": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", - "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==", - "dev": true, - "optional": true - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-iterator-helpers": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", - "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true, - "optional": true - }, - "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-next": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.2.5.tgz", - "integrity": "sha512-zogs9zlOiZ7ka+wgUnmcM0KBEDjo4Jis7kxN1jvC0N4wynQ2MIx/KBkg4mVF63J5EK4W0QMCn7xO3vNisjaAoA==", - "dev": true, - "dependencies": { - "@next/eslint-plugin-next": "14.2.5", - "@rushstack/eslint-patch": "^1.3.3", - "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-import-resolver-typescript": "^3.5.2", - "eslint-plugin-import": "^2.28.1", - "eslint-plugin-jsx-a11y": "^6.7.1", - "eslint-plugin-react": "^7.33.2", - "eslint-plugin-react-hooks": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" - }, - "peerDependencies": { - "eslint": "^7.23.0 || ^8.0.0", - "typescript": ">=3.3.1" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-typescript": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", - "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4", - "enhanced-resolve": "^5.12.0", - "eslint-module-utils": "^2.7.4", - "fast-glob": "^3.3.1", - "get-tsconfig": "^4.5.0", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", - "semver": "^6.3.1", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.9.0.tgz", - "integrity": "sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==", - "dev": true, - "dependencies": { - "aria-query": "~5.1.3", - "array-includes": "^3.1.8", - "array.prototype.flatmap": "^1.3.2", - "ast-types-flow": "^0.0.8", - "axe-core": "^4.9.1", - "axobject-query": "~3.1.1", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "es-iterator-helpers": "^1.0.19", - "hasown": "^2.0.2", - "jsx-ast-utils": "^3.3.5", - "language-tags": "^1.0.9", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "safe-regex-test": "^1.0.3", - "string.prototype.includes": "^2.0.0" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.35.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.0.tgz", - "integrity": "sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.8", - "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.2", - "array.prototype.tosorted": "^1.1.4", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.19", - "estraverse": "^5.3.0", - "hasown": "^2.0.2", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.8", - "object.fromentries": "^2.0.8", - "object.values": "^1.2.0", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11", - "string.prototype.repeat": "^1.0.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", - "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-util-is-identifier-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", - "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/eventsource": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", - "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-1.1.2.tgz", - "integrity": "sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==", - "engines": { - "node": ">=14.18" - } - }, - "node_modules/execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/execa/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/execa/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/execa/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/execa/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/exponential-backoff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", - "dev": true - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extract-zip/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fast-text-encoding": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", - "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==" - }, - "node_modules/fast-unique-numbers": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-9.0.7.tgz", - "integrity": "sha512-K6hYNu8ZsVb7mwmd9OKxHmw4aLa+IFiBxt1e/FZVFFta94ZgNAHqIgUtDzd7AJaVoo/CoNTgr6sj1Dbj3PQPKg==", - "dependencies": { - "@babel/runtime": "^7.24.8", - "tslib": "^2.6.3" - }, - "engines": { - "node": ">=18.2.0" - } - }, - "node_modules/fast-xml-parser": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", - "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - }, - { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" - } - ], - "dependencies": { - "strnum": "^1.0.5" - }, - "bin": { - "fxparser": "src/cli/cli.js" - } - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/fetch-event-stream": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/fetch-event-stream/-/fetch-event-stream-0.1.5.tgz", - "integrity": "sha512-V1PWovkspxQfssq/NnxoEyQo1DV+MRK/laPuPblIZmSjMN8P5u46OhlFQznSr9p/t0Sp8Uc6SbM3yCMfr0KU8g==" - }, - "node_modules/fflate": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", - "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==" - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/file-selector": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.2.4.tgz", - "integrity": "sha512-ZDsQNbrv6qRi1YTDOEWzf5J2KjZ9KMI1Q2SGeTkCJmNNW25Jg4TW4UMcmoqcg4WrAyKRcpBXdbWRxkfrOzVRbA==", - "dependencies": { - "tslib": "^2.0.3" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/filename-reserved-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", - "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/filenamify": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", - "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", - "dev": true, - "dependencies": { - "filename-reserved-regex": "^2.0.0", - "strip-outer": "^1.0.1", - "trim-repeated": "^1.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/filter-obj": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-5.1.0.tgz", - "integrity": "sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatbuffers": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-1.12.0.tgz", - "integrity": "sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ==" - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/flora-colossus": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/flora-colossus/-/flora-colossus-2.0.0.tgz", - "integrity": "sha512-dz4HxH6pOvbUzZpZ/yXhafjbR2I8cenK5xL0KtBFb7U2ADsR+OwXifnxZjij/pZWF775uSCMzWVd+jDik2H2IA==", - "dev": true, - "dependencies": { - "debug": "^4.3.4", - "fs-extra": "^10.1.0" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/flora-colossus/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/fluent-ffmpeg": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.3.tgz", - "integrity": "sha512-Be3narBNt2s6bsaqP6Jzq91heDgOEaDCJAXcE3qcma/EJBSy5FB4cvO31XBInuAuKBx8Kptf8dkhjK0IOru39Q==", - "dependencies": { - "async": "^0.2.9", - "which": "^1.1.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fluent-ffmpeg/node_modules/async": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", - "integrity": "sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==" - }, - "node_modules/fluent-ffmpeg/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/fmix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/fmix/-/fmix-0.1.0.tgz", - "integrity": "sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w==", - "dev": true, - "optional": true, - "dependencies": { - "imul": "^1.0.0" - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/form-data-encoder": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", - "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" - }, - "node_modules/formdata-node": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", - "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", - "dependencies": { - "node-domexception": "1.0.0", - "web-streams-polyfill": "4.0.0-beta.3" - }, - "engines": { - "node": ">= 12.20" - } - }, - "node_modules/formdata-node/node_modules/web-streams-polyfill": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", - "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", - "engines": { - "node": ">= 14" - } - }, - "node_modules/fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/framer-motion": { - "version": "11.1.7", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.1.7.tgz", - "integrity": "sha512-cW11Pu53eDAXUEhv5hEiWuIXWhfkbV32PlgVISn7jRdcAiVrJ1S03YQQ0/DzoswGYYwKi4qYmHHjCzAH52eSdQ==", - "dependencies": { - "tslib": "^2.4.0" - }, - "peerDependencies": { - "@emotion/is-prop-valid": "*", - "react": "^18.0.0", - "react-dom": "^18.0.0" - }, - "peerDependenciesMeta": { - "@emotion/is-prop-valid": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/fs-minipass": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/fs-temp": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/fs-temp/-/fs-temp-1.2.1.tgz", - "integrity": "sha512-okTwLB7/Qsq82G6iN5zZJFsOfZtx2/pqrA7Hk/9fvy+c+eJS9CvgGXT2uNxwnI14BDY9L/jQPkaBgSvlKfSW9w==", - "dev": true, - "optional": true, - "dependencies": { - "random-path": "^0.1.0" - } - }, - "node_modules/fs-xattr": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/fs-xattr/-/fs-xattr-0.3.1.tgz", - "integrity": "sha512-UVqkrEW0GfDabw4C3HOrFlxKfx0eeigfRne69FxSBdHIP8Qt5Sq6Pu3RM9KmMlkygtC4pPKkj5CiPO5USnj2GA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "!win32" - ], - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/galactus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/galactus/-/galactus-1.0.0.tgz", - "integrity": "sha512-R1fam6D4CyKQGNlvJne4dkNF+PvUUl7TAJInvTGa9fti9qAv95quQz29GXapA4d8Ec266mJJxFVh82M4GIIGDQ==", - "dev": true, - "dependencies": { - "debug": "^4.3.4", - "flora-colossus": "^2.0.0", - "fs-extra": "^10.1.0" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/galactus/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/gar": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/gar/-/gar-1.0.4.tgz", - "integrity": "sha512-w4n9cPWyP7aHxKxYHFQMegj7WIAsL/YX/C4Bs5Rr8s1H9M1rNtRWRsw+ovYMkXDQ5S4ZbYHsHAPmevPjPgw44w==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dev": true, - "optional": true - }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/gauge/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/gauge/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/gauge/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/gaxios": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", - "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", - "dependencies": { - "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", - "is-stream": "^2.0.0", - "node-fetch": "^2.6.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/gaxios/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gcp-metadata": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", - "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", - "dependencies": { - "gaxios": "^5.0.0", - "json-bigint": "^1.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "dev": true, - "optional": true, - "dependencies": { - "is-property": "^1.0.2" - } - }, - "node_modules/generate-object-property": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==", - "dev": true, - "optional": true, - "dependencies": { - "is-property": "^1.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", - "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-folder-size": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/get-folder-size/-/get-folder-size-2.0.1.tgz", - "integrity": "sha512-+CEb+GDCM7tkOS2wdMKTn9vU7DgnKUTuDlehkNJKNSovdCOVxs14OfKCk4cvSaR3za4gj+OBdl9opPN9xrJ0zA==", - "dev": true, - "optional": true, - "dependencies": { - "gar": "^1.0.4", - "tiny-each-async": "2.0.3" - }, - "bin": { - "get-folder-size": "bin/get-folder-size" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/get-installed-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/get-installed-path/-/get-installed-path-2.1.1.tgz", - "integrity": "sha512-Qkn9eq6tW5/q9BDVdMpB8tOHljX9OSP0jRC5TRNVA4qRc839t4g8KQaR8t0Uv0EFVL0MlyG7m/ofjEgAROtYsA==", - "dev": true, - "dependencies": { - "global-modules": "1.0.0" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-node-dimensions": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-node-dimensions/-/get-node-dimensions-1.2.1.tgz", - "integrity": "sha512-2MSPMu7S1iOTL+BOa6K1S62hB2zUAYNF/lV0gSVlOaacd087lc6nR1H1r0e3B1CerTo+RceOmi1iJW+vp21xcQ==" - }, - "node_modules/get-nonce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", - "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/get-package-info": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-package-info/-/get-package-info-1.0.0.tgz", - "integrity": "sha512-SCbprXGAPdIhKAXiG+Mk6yeoFH61JlYunqdFQFHDtLjJlDjFf6x07dsS8acO+xWt52jpdVo49AlVDnUVK1sDNw==", - "dev": true, - "dependencies": { - "bluebird": "^3.1.1", - "debug": "^2.2.0", - "lodash.get": "^4.0.0", - "read-pkg-up": "^2.0.0" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/get-package-info/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/get-package-info/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-tsconfig": { - "version": "4.7.6", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.6.tgz", - "integrity": "sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==", - "dev": true, - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/global-agent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", - "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", - "dev": true, - "optional": true, - "dependencies": { - "boolean": "^3.0.1", - "es6-error": "^4.1.1", - "matcher": "^3.0.0", - "roarr": "^2.15.3", - "semver": "^7.3.2", - "serialize-error": "^7.0.1" - }, - "engines": { - "node": ">=10.0" - } - }, - "node_modules/global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "dependencies": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/global-prefix/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glsl-noise": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/glsl-noise/-/glsl-noise-0.0.0.tgz", - "integrity": "sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==" - }, - "node_modules/google-auth-library": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.9.0.tgz", - "integrity": "sha512-f7aQCJODJFmYWN6PeNKzgvy9LI2tYmXnzpNDHEjG5sDNPgGb2FXQyTBnXeSH+PAtpKESFD+LmHw3Ox3mN7e1Fg==", - "dependencies": { - "arrify": "^2.0.0", - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "fast-text-encoding": "^1.0.0", - "gaxios": "^5.0.0", - "gcp-metadata": "^5.3.0", - "gtoken": "^6.1.0", - "jws": "^4.0.0", - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/google-auth-library/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/google-auth-library/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/google-p12-pem": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz", - "integrity": "sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==", - "deprecated": "Package is no longer maintained", - "dependencies": { - "node-forge": "^1.3.1" - }, - "bin": { - "gp12-pem": "build/src/bin/gp12-pem.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/got": { - "version": "11.8.6", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", - "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "dev": true, - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/graphql": { - "version": "16.9.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", - "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", - "engines": { - "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" - } - }, - "node_modules/groq-sdk": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/groq-sdk/-/groq-sdk-0.5.0.tgz", - "integrity": "sha512-RVmhW7qZ+XZoy5fIuSdx/LGQJONpL8MHgZEW7dFwTdgkzStub2XQx6OKv28CHogijdwH41J+Npj/z2jBPu3vmw==", - "dependencies": { - "@types/node": "^18.11.18", - "@types/node-fetch": "^2.6.4", - "abort-controller": "^3.0.0", - "agentkeepalive": "^4.2.1", - "form-data-encoder": "1.7.2", - "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7", - "web-streams-polyfill": "^3.2.1" - } - }, - "node_modules/groq-sdk/node_modules/@types/node": { - "version": "18.19.44", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.44.tgz", - "integrity": "sha512-ZsbGerYg72WMXUIE9fYxtvfzLEuq6q8mKERdWFnqTmOvudMxnz+CBNRoOwJ2kNpFOncrKjT1hZwxjlFgQ9qvQA==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/gtoken": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz", - "integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==", - "dependencies": { - "gaxios": "^5.0.1", - "google-p12-pem": "^4.0.0", - "jws": "^4.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/guid-typescript": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz", - "integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==" - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true - }, - "node_modules/hash-wasm": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/hash-wasm/-/hash-wasm-4.11.0.tgz", - "integrity": "sha512-HVusNXlVqHe0fzIzdQOGolnFN6mX/fqcrSAOcTBXdvzrXVHwTz11vXeKRmkR5gTuwVpvHZEIyKoePDvuAR+XwQ==" - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hast-util-to-jsx-runtime": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz", - "integrity": "sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==", - "dependencies": { - "@types/estree": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-object": "^1.0.0", - "unist-util-position": "^5.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-whitespace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", - "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "bin": { - "he": "bin/he" - } - }, - "node_modules/headers-polyfill": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.3.tgz", - "integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==" - }, - "node_modules/hls.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.3.5.tgz", - "integrity": "sha512-uybAvKS6uDe0MnWNEPnO0krWVr+8m2R0hJ/viql8H3MVK+itq8gGQuIYoFHL3rECkIpNH98Lw8YuuWMKZxp3Ew==" - }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "dependencies": { - "parse-passwd": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^3.1.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/html-url-attributes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.0.tgz", - "integrity": "sha512-/sXbVCWayk6GDVg3ctOX6nxaVj7So40FcFAnWlWGNAB1LpYKcV5Cd10APjPjW80O7zYW2MsjBV4zZ7IZO5fVow==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/http-proxy-agent/node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "engines": { - "node": ">=16.17.0" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "devOptional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/image-size": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz", - "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==", - "dev": true, - "optional": true, - "bin": { - "image-size": "bin/image-size.js" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imul": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/imul/-/imul-1.0.1.tgz", - "integrity": "sha512-WFAgfwPLAjU66EKt6vRdTlKj4nAgIDQzh29JonLa4Bqtl6D8JrIMvWjCnx7xEjVNmP3U0fM5o8ZObk7d0f62bA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/indexeddb-fs": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/indexeddb-fs/-/indexeddb-fs-2.1.5.tgz", - "integrity": "sha512-4TDdof4ou+l1P3O9D+U09DAc2VQ/bWzgKBxC3nQ9qqMhNR2Y3p8JDgELzkY3bwLP8JULMTf2UHsjnYpiKExH2w==", - "dependencies": { - "jsonschema": "^1.4.1" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/inline-style-parser": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.3.tgz", - "integrity": "sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g==" - }, - "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/interpret": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", - "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "dev": true, - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/is-alphabetical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", - "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-alphanumerical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", - "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", - "dependencies": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", - "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", - "dev": true, - "dependencies": { - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-decimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", - "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-hexadecimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", - "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-hotkey": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.2.0.tgz", - "integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==" - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-my-ip-valid": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz", - "integrity": "sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==", - "dev": true, - "optional": true - }, - "node_modules/is-my-json-valid": { - "version": "2.20.6", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz", - "integrity": "sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==", - "dev": true, - "optional": true, - "dependencies": { - "generate-function": "^2.0.0", - "generate-object-property": "^1.1.0", - "is-my-ip-valid": "^1.0.0", - "jsonpointer": "^5.0.0", - "xtend": "^4.0.0" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-node-process": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", - "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==" - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" - }, - "node_modules/is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", - "dev": true, - "optional": true - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", - "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/isbinaryfile": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", - "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", - "dev": true, - "engines": { - "node": ">= 8.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" - } - }, - "node_modules/its-fine": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-1.2.5.tgz", - "integrity": "sha512-fXtDA0X0t0eBYAGLVM5YsgJGsJ5jEmqZEPrGbzdf5awjv0xE7nqv3TVnvtUF060Tkes15DbDAKW/I48vsb6SyA==", - "dependencies": { - "@types/react-reconciler": "^0.28.0" - }, - "peerDependencies": { - "react": ">=18.0" - } - }, - "node_modules/its-fine/node_modules/@types/react-reconciler": { - "version": "0.28.8", - "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.8.tgz", - "integrity": "sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g==", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/jiti": { - "version": "1.21.6", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", - "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/js-base64": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.2.tgz", - "integrity": "sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ==" - }, - "node_modules/js-tiktoken": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.12.tgz", - "integrity": "sha512-L7wURW1fH9Qaext0VzaUDpFGVQgjkdE3Dgsy9/+yXyGEpBKnylTd0mU0bfbNkKDlXRb6TEsZkwuflu1B8uQbJQ==", - "dependencies": { - "base64-js": "^1.5.1" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true - }, - "node_modules/jsdom": { - "version": "24.1.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.1.tgz", - "integrity": "sha512-5O1wWV99Jhq4DV7rCLIoZ/UIhyQeDR7wHVyZAHAshbrvZsLs+Xzz7gtwnlJTJDjleiTKh54F4dXrX70vJQTyJQ==", - "dev": true, - "dependencies": { - "cssstyle": "^4.0.1", - "data-urls": "^5.0.0", - "decimal.js": "^10.4.3", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.5", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.12", - "parse5": "^7.1.2", - "rrweb-cssom": "^0.7.1", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.4", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^3.1.1", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0", - "ws": "^8.18.0", - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "canvas": "^2.11.2" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/jsdom/node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", - "dev": true, - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "dependencies": { - "bignumber.js": "^9.0.0" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true, - "optional": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonpointer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", - "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jsonschema": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", - "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", - "engines": { - "node": "*" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/junk": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz", - "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jwa": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", - "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "dependencies": { - "jwa": "^2.0.0", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "engines": { - "node": ">=6" - } - }, - "node_modules/language-subtag-registry": { - "version": "0.3.23", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", - "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", - "dev": true - }, - "node_modules/language-tags": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", - "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", - "dev": true, - "dependencies": { - "language-subtag-registry": "^0.3.20" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dependencies": { - "immediate": "~3.0.5" - } - }, - "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "node_modules/listr2": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-7.0.2.tgz", - "integrity": "sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g==", - "dev": true, - "dependencies": { - "cli-truncate": "^3.1.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^5.0.1", - "rfdc": "^1.3.0", - "wrap-ansi": "^8.1.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha512-3p6ZOGNbiX4CdvEd1VcE6yi78UrGNpjHO33noGwHCnT/o2fyllJDepsm8+mFFv/DvtwFHht5HIHSyOy5a+ChVQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.throttle": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", - "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz", - "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==", - "dev": true, - "dependencies": { - "ansi-escapes": "^5.0.0", - "cli-cursor": "^4.0.0", - "slice-ansi": "^5.0.0", - "strip-ansi": "^7.0.1", - "wrap-ansi": "^8.0.1" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/log-update/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" - }, - "node_modules/longest-streak": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/loupe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.1.tgz", - "integrity": "sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/lucide-react": { - "version": "0.396.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.396.0.tgz", - "integrity": "sha512-N/zP+9vEfEYHiMWMpjwH/M5diaV0e4UFe07BpgdzaRYce5QvXi87hixf7F0Xqdr3zuX/9u7H/2D4MVXIK22O0A==", - "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "dev": true, - "peer": true, - "bin": { - "lz-string": "bin/bin.js" - } - }, - "node_modules/maath": { - "version": "0.10.8", - "resolved": "https://registry.npmjs.org/maath/-/maath-0.10.8.tgz", - "integrity": "sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==", - "peerDependencies": { - "@types/three": ">=0.134.0", - "three": ">=0.134.0" - } - }, - "node_modules/macos-alias": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/macos-alias/-/macos-alias-0.2.11.tgz", - "integrity": "sha512-zIUs3+qpml+w3wiRuADutd7XIO8UABqksot10Utl/tji4UxZzLG4fWDC+yJZoO8/Ehg5RqsvSRE/6TS5AEOeWw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "nan": "^2.4.0" - } - }, - "node_modules/magic-string": { - "version": "0.30.11", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", - "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" - }, - "node_modules/make-fetch-happen": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", - "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", - "dev": true, - "dependencies": { - "@npmcli/agent": "^2.0.0", - "cacache": "^18.0.0", - "http-cache-semantics": "^4.1.1", - "is-lambda": "^1.0.1", - "minipass": "^7.0.2", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "proc-log": "^4.2.0", - "promise-retry": "^2.0.1", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dev": true, - "dependencies": { - "p-defer": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/markdown-table": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", - "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/matcher": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", - "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", - "dev": true, - "optional": true, - "dependencies": { - "escape-string-regexp": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mdast-util-find-and-replace": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz", - "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "escape-string-regexp": "^5.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mdast-util-from-markdown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", - "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", - "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", - "dependencies": { - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-gfm-autolink-literal": "^2.0.0", - "mdast-util-gfm-footnote": "^2.0.0", - "mdast-util-gfm-strikethrough": "^2.0.0", - "mdast-util-gfm-table": "^2.0.0", - "mdast-util-gfm-task-list-item": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-autolink-literal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz", - "integrity": "sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==", - "dependencies": { - "@types/mdast": "^4.0.0", - "ccount": "^2.0.0", - "devlop": "^1.0.0", - "mdast-util-find-and-replace": "^3.0.0", - "micromark-util-character": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-footnote": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", - "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", - "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "markdown-table": "^3.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-task-list-item": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", - "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-expression": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz", - "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-jsx": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.2.tgz", - "integrity": "sha512-eKMQDeywY2wlHc97k5eD8VC+9ASMjN8ItEZQNGwJ6E0XWKiW/Z0V5/H8pvoXUf+y+Mj0VIgeRRbujBmFn4FTyA==", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "ccount": "^2.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-remove-position": "^5.0.0", - "unist-util-stringify-position": "^4.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdxjs-esm": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", - "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-phrasing": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", - "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", - "dependencies": { - "@types/mdast": "^4.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-hast": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", - "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@ungap/structured-clone": "^1.0.0", - "devlop": "^1.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "trim-lines": "^3.0.0", - "unist-util-position": "^5.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-markdown": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", - "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "longest-streak": "^3.0.0", - "mdast-util-phrasing": "^4.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark-util-decode-string": "^2.0.0", - "unist-util-visit": "^5.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mediainfo.js": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/mediainfo.js/-/mediainfo.js-0.3.2.tgz", - "integrity": "sha512-SC8z72ESV1z2lq2zfheoo9zgcoqjeBn0mzq6MhIn3aqlkh3RV84FwOiMtYA0HWY7mi1igM89Jcll4r2sk/yyZA==", - "dependencies": { - "yargs": "^17.7.2" - }, - "bin": { - "mediainfo.js": "dist/esm/cli.js" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, - "dependencies": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/meshline": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/meshline/-/meshline-3.3.1.tgz", - "integrity": "sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ==", - "peerDependencies": { - "three": ">=0.137" - } - }, - "node_modules/meshoptimizer": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz", - "integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==" - }, - "node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-core-commonmark": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", - "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", - "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", - "dependencies": { - "micromark-extension-gfm-autolink-literal": "^2.0.0", - "micromark-extension-gfm-footnote": "^2.0.0", - "micromark-extension-gfm-strikethrough": "^2.0.0", - "micromark-extension-gfm-table": "^2.0.0", - "micromark-extension-gfm-tagfilter": "^2.0.0", - "micromark-extension-gfm-task-list-item": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-autolink-literal": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", - "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", - "dependencies": { - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-strikethrough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", - "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-table": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.0.tgz", - "integrity": "sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g==", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-tagfilter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", - "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", - "dependencies": { - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-task-list-item": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", - "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-classify-character": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-combine-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-resolve-all": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-subtokenize": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", - "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minipass-collect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", - "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minipass-fetch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", - "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mlt-xml": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/mlt-xml/-/mlt-xml-2.0.2.tgz", - "integrity": "sha512-UkbC0IaWS1LAIAm99/UukRq1htYTgBsalxUtBAVMUJn7LZl6EqpziU7Sv6dgoeo1UtXsUkWBAc37gwHOdPkoJA==" - }, - "node_modules/monaco-editor": { - "version": "0.50.0", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.50.0.tgz", - "integrity": "sha512-8CclLCmrRRh+sul7C08BmPBP3P8wVWfBHomsTcndxg5NRCEPfu/mc2AGU8k37ajjDVXcXFc12ORAMUkmk+lkFA==" - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/msw": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/msw/-/msw-2.3.5.tgz", - "integrity": "sha512-+GUI4gX5YC5Bv33epBrD+BGdmDvBg2XGruiWnI3GbIbRmMMBeZ5gs3mJ51OWSGHgJKztZ8AtZeYMMNMVrje2/Q==", - "hasInstallScript": true, - "dependencies": { - "@bundled-es-modules/cookie": "^2.0.0", - "@bundled-es-modules/statuses": "^1.0.1", - "@bundled-es-modules/tough-cookie": "^0.1.6", - "@inquirer/confirm": "^3.0.0", - "@mswjs/interceptors": "^0.29.0", - "@open-draft/until": "^2.1.0", - "@types/cookie": "^0.6.0", - "@types/statuses": "^2.0.4", - "chalk": "^4.1.2", - "graphql": "^16.8.1", - "headers-polyfill": "^4.0.2", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.2", - "path-to-regexp": "^6.2.0", - "strict-event-emitter": "^0.5.1", - "type-fest": "^4.9.0", - "yargs": "^17.7.2" - }, - "bin": { - "msw": "cli/index.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/mswjs" - }, - "peerDependencies": { - "typescript": ">= 4.7.x" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/msw/node_modules/type-fest": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.24.0.tgz", - "integrity": "sha512-spAaHzc6qre0TlZQQ2aA/nGMe+2Z/wyGk5Z+Ru2VUfdNwT6kWO6TjevOlpebsATEG1EIQ2sOiDszud3lO5mt/Q==", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/murmur-32": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/murmur-32/-/murmur-32-0.2.0.tgz", - "integrity": "sha512-ZkcWZudylwF+ir3Ld1n7gL6bI2mQAzXvSobPwVtu8aYi2sbXeipeSkdcanRLzIofLcM5F53lGaKm2dk7orBi7Q==", - "dev": true, - "optional": true, - "dependencies": { - "encode-utf8": "^1.0.3", - "fmix": "^0.1.0", - "imul": "^1.0.0" - } - }, - "node_modules/mustache": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", - "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", - "bin": { - "mustache": "bin/mustache" - } - }, - "node_modules/mute-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", - "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nan": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", - "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", - "dev": true, - "optional": true - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/next": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/next/-/next-14.2.5.tgz", - "integrity": "sha512-0f8aRfBVL+mpzfBjYfQuLWh2WyAwtJXCRfkPF4UJ5qd2YwrHczsrSzXU4tRMV0OAxR8ZJZWPFn6uhSC56UTsLA==", - "dependencies": { - "@next/env": "14.2.5", - "@swc/helpers": "0.5.5", - "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001579", - "graceful-fs": "^4.2.11", - "postcss": "8.4.31", - "styled-jsx": "5.1.1" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": ">=18.17.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "14.2.5", - "@next/swc-darwin-x64": "14.2.5", - "@next/swc-linux-arm64-gnu": "14.2.5", - "@next/swc-linux-arm64-musl": "14.2.5", - "@next/swc-linux-x64-gnu": "14.2.5", - "@next/swc-linux-x64-musl": "14.2.5", - "@next/swc-win32-arm64-msvc": "14.2.5", - "@next/swc-win32-ia32-msvc": "14.2.5", - "@next/swc-win32-x64-msvc": "14.2.5" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "@playwright/test": "^1.41.2", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "@playwright/test": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/next-themes": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz", - "integrity": "sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==", - "peerDependencies": { - "react": "^16.8 || ^17 || ^18", - "react-dom": "^16.8 || ^17 || ^18" - } - }, - "node_modules/next/node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node_modules/node-abi": { - "version": "3.65.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz", - "integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==", - "dev": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-api-version": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.0.tgz", - "integrity": "sha512-fthTTsi8CxaBXMaBAD7ST2uylwvsnYxh2PfaScwpMhos6KlSFajXQPcM4ogNE1q2s3Lbz9GCGqeIHC+C6OZnKg==", - "dev": true, - "dependencies": { - "semver": "^7.3.5" - } - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/node-gyp": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.2.0.tgz", - "integrity": "sha512-sp3FonBAaFe4aYTcFdZUn2NYkbP7xroPGYvQmP4Nl5PxamznItBnNCgjrVTKrEfQynInMsJvZrdmqUnysCJ8rw==", - "dev": true, - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^10.3.10", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^13.0.0", - "nopt": "^7.0.0", - "proc-log": "^4.1.0", - "semver": "^7.3.5", - "tar": "^6.2.1", - "which": "^4.0.0" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/node-gyp-build": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", - "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/node-gyp/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/node-gyp/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-gyp/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "dev": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/node-gyp/node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/node-gyp/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-gyp/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "dev": true, - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, - "node_modules/node-html-parser": { - "version": "6.1.13", - "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.13.tgz", - "integrity": "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==", - "dependencies": { - "css-select": "^5.1.0", - "he": "1.2.0" - } - }, - "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" - }, - "node_modules/nopt": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", - "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", - "dev": true, - "dependencies": { - "abbrev": "^2.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", - "dev": true, - "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/nwsapi": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", - "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", - "dev": true - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", - "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/onnxruntime-common": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.18.0.tgz", - "integrity": "sha512-lufrSzX6QdKrktAELG5x5VkBpapbCeS3dQwrXbN0eD9rHvU0yAWl7Ztju9FvgAKWvwd/teEKJNj3OwM6eTZh3Q==" - }, - "node_modules/onnxruntime-node": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/onnxruntime-node/-/onnxruntime-node-1.18.0.tgz", - "integrity": "sha512-iTnFcxKpmywCatx8ov4GTbECe3tJk2Bp1OA2mWRJde78q+7tpPYBhKMnwhlaoKy9oKQcy4UoEuuhoy2PSD13ww==", - "hasInstallScript": true, - "optional": true, - "os": [ - "win32", - "darwin", - "linux" - ], - "dependencies": { - "onnxruntime-common": "1.18.0", - "tar": "^7.0.1" - } - }, - "node_modules/onnxruntime-node/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "optional": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/onnxruntime-node/node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "optional": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/onnxruntime-node/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "optional": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/onnxruntime-node/node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "optional": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/onnxruntime-node/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "optional": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/onnxruntime-node/node_modules/minizlib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.1.tgz", - "integrity": "sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==", - "optional": true, - "dependencies": { - "minipass": "^7.0.4", - "rimraf": "^5.0.5" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/onnxruntime-node/node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", - "optional": true, - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/onnxruntime-node/node_modules/rimraf": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", - "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", - "optional": true, - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/onnxruntime-node/node_modules/tar": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", - "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", - "optional": true, - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.0.1", - "mkdirp": "^3.0.1", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/onnxruntime-node/node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "optional": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/onnxruntime-web": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.18.0.tgz", - "integrity": "sha512-o1UKj4ABIj1gmG7ae0RKJ3/GT+3yoF0RRpfDfeoe0huzRW4FDRLfbkDETmdFAvnJEXuYDE0YT+hhkia0352StQ==", - "dependencies": { - "flatbuffers": "^1.12.0", - "guid-typescript": "^1.0.9", - "long": "^5.2.3", - "onnxruntime-common": "1.18.0", - "platform": "^1.3.6", - "protobufjs": "^7.2.4" - } - }, - "node_modules/openai": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.55.2.tgz", - "integrity": "sha512-Z81nbAPvlLl5eDLNldkixAayhUzbbCbOef/dqqW3uuN0Fkgj5GZn2kgUDTqGPOp2RHtcOYMfZltXNPoC6kEkTQ==", - "dependencies": { - "@types/node": "^18.11.18", - "@types/node-fetch": "^2.6.4", - "abort-controller": "^3.0.0", - "agentkeepalive": "^4.2.1", - "form-data-encoder": "1.7.2", - "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7" - }, - "bin": { - "openai": "bin/cli" - }, - "peerDependencies": { - "zod": "^3.23.8" - }, - "peerDependenciesMeta": { - "zod": { - "optional": true - } - } - }, - "node_modules/openai/node_modules/@types/node": { - "version": "18.19.43", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.43.tgz", - "integrity": "sha512-Mw/YlgXnyJdEwLoFv2dpuJaDFriX+Pc+0qOBJ57jC1H6cDxIj2xc5yUrdtArDVG0m+KV6622a4p2tenEqB3C/g==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ora/node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/outvariant": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", - "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==" - }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "engines": { - "node": ">=4" - } - }, - "node_modules/p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-queue": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", - "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", - "dependencies": { - "eventemitter3": "^4.0.4", - "p-timeout": "^3.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-queue/node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" - }, - "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", - "dependencies": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", - "dependencies": { - "p-finally": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-author": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-author/-/parse-author-2.0.0.tgz", - "integrity": "sha512-yx5DfvkN8JsHL2xk2Os9oTia467qnvRgey4ahSm2X8epehBLx/gWLcy5KI+Y36ful5DzGbCS6RazqZGgy1gHNw==", - "dev": true, - "dependencies": { - "author-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse-color": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-color/-/parse-color-1.0.0.tgz", - "integrity": "sha512-fuDHYgFHJGbpGMgw9skY/bj3HL/Jrn4l/5rSspy00DoT4RyLnDcRvPxdZ+r6OFwIsgAuhDh4I09tAId4mI12bw==", - "dev": true, - "optional": true, - "dependencies": { - "color-convert": "~0.5.0" - } - }, - "node_modules/parse-entities": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", - "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", - "dependencies": { - "@types/unist": "^2.0.0", - "character-entities": "^2.0.0", - "character-entities-legacy": "^3.0.0", - "character-reference-invalid": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "is-alphanumerical": "^2.0.0", - "is-decimal": "^2.0.0", - "is-hexadecimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/parse-entities/node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" - }, - "node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", - "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" - }, - "node_modules/path-to-regexp": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", - "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==" - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", - "dev": true - }, - "node_modules/pathval": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", - "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", - "dev": true, - "engines": { - "node": ">= 14.16" - } - }, - "node_modules/pe-library": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pe-library/-/pe-library-1.0.1.tgz", - "integrity": "sha512-nh39Mo1eGWmZS7y+mK/dQIqg7S1lp38DpRxkyoHf0ZcUs/HDc+yyTjuOtTvSMZHmfSLuSQaX945u05Y2Q6UWZg==", - "dev": true, - "engines": { - "node": ">=14", - "npm": ">=7" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jet2jet" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/platform": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", - "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==" - }, - "node_modules/playwright": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.46.0.tgz", - "integrity": "sha512-XYJ5WvfefWONh1uPAUAi0H2xXV5S3vrtcnXe6uAOgdGi3aSpqOSXX08IAjXW34xitfuOJsvXU5anXZxPSEQiJw==", - "devOptional": true, - "dependencies": { - "playwright-core": "1.46.0" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "fsevents": "2.3.2" - } - }, - "node_modules/playwright-core": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.46.0.tgz", - "integrity": "sha512-9Y/d5UIwuJk8t3+lhmMSAJyNP1BUC/DqP3cQJDQQL/oWqAiuPTLgy7Q5dzglmTLwcBRdetzgNM/gni7ckfTr6A==", - "devOptional": true, - "bin": { - "playwright-core": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/plist": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", - "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", - "dev": true, - "dependencies": { - "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.5.1", - "xmlbuilder": "^15.1.1" - }, - "engines": { - "node": ">=10.4.0" - } - }, - "node_modules/pngjs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", - "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", - "engines": { - "node": ">=14.19.0" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.4.41", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", - "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-css-variables": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/postcss-css-variables/-/postcss-css-variables-0.18.0.tgz", - "integrity": "sha512-lYS802gHbzn1GI+lXvy9MYIYDuGnl1WB4FTKoqMQqJ3Mab09A7a/1wZvGTkCEZJTM8mSbIyb1mJYn8f0aPye0Q==", - "dependencies": { - "balanced-match": "^1.0.0", - "escape-string-regexp": "^1.0.3", - "extend": "^3.0.1" - }, - "peerDependencies": { - "postcss": "^8.2.6" - } - }, - "node_modules/postcss-css-variables/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", - "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "lilconfig": "^3.0.0", - "yaml": "^2.3.4" - }, - "engines": { - "node": ">= 14" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-load-config/node_modules/lilconfig": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", - "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/postcss-nested": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", - "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "postcss-selector-parser": "^6.1.1" - }, - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", - "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "node_modules/postject": { - "version": "1.0.0-alpha.6", - "resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz", - "integrity": "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==", - "dev": true, - "dependencies": { - "commander": "^9.4.0" - }, - "bin": { - "postject": "dist/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/postject/node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "dev": true, - "engines": { - "node": "^12.20.0 || >=14" - } - }, - "node_modules/potpack": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", - "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==" - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-plugin-tailwindcss": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.5.tgz", - "integrity": "sha512-axfeOArc/RiGHjOIy9HytehlC0ZLeMaqY09mm8YCkMzznKiDkwFzOpBvtuhuv3xG5qB73+Mj7OCe2j/L1ryfuQ==", - "dev": true, - "engines": { - "node": ">=14.21.3" - }, - "peerDependencies": { - "@ianvs/prettier-plugin-sort-imports": "*", - "@prettier/plugin-pug": "*", - "@shopify/prettier-plugin-liquid": "*", - "@trivago/prettier-plugin-sort-imports": "*", - "@zackad/prettier-plugin-twig-melody": "*", - "prettier": "^3.0", - "prettier-plugin-astro": "*", - "prettier-plugin-css-order": "*", - "prettier-plugin-import-sort": "*", - "prettier-plugin-jsdoc": "*", - "prettier-plugin-marko": "*", - "prettier-plugin-organize-attributes": "*", - "prettier-plugin-organize-imports": "*", - "prettier-plugin-sort-imports": "*", - "prettier-plugin-style-order": "*", - "prettier-plugin-svelte": "*" - }, - "peerDependenciesMeta": { - "@ianvs/prettier-plugin-sort-imports": { - "optional": true - }, - "@prettier/plugin-pug": { - "optional": true - }, - "@shopify/prettier-plugin-liquid": { - "optional": true - }, - "@trivago/prettier-plugin-sort-imports": { - "optional": true - }, - "@zackad/prettier-plugin-twig-melody": { - "optional": true - }, - "prettier-plugin-astro": { - "optional": true - }, - "prettier-plugin-css-order": { - "optional": true - }, - "prettier-plugin-import-sort": { - "optional": true - }, - "prettier-plugin-jsdoc": { - "optional": true - }, - "prettier-plugin-marko": { - "optional": true - }, - "prettier-plugin-organize-attributes": { - "optional": true - }, - "prettier-plugin-organize-imports": { - "optional": true - }, - "prettier-plugin-sort-imports": { - "optional": true - }, - "prettier-plugin-style-order": { - "optional": true - }, - "prettier-plugin-svelte": { - "optional": true - } - } - }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/proc-log": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", - "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/promise-retry/node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/promise-worker-transferable": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/promise-worker-transferable/-/promise-worker-transferable-1.0.4.tgz", - "integrity": "sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==", - "dependencies": { - "is-promise": "^2.1.0", - "lie": "^3.0.2" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/property-information": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", - "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/protobufjs": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.2.tgz", - "integrity": "sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/pure-uuid": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/pure-uuid/-/pure-uuid-1.8.1.tgz", - "integrity": "sha512-PIwHXU7NZb/wTBwUfzCSjI85tfwx6DQOm74sRLtNLH8KHsFZEvAQbBQdz7E5ij8SNSv9WGdQPWiiM6NpNIeNfA==", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/query-string": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-9.1.0.tgz", - "integrity": "sha512-t6dqMECpCkqfyv2FfwVS1xcB6lgXW/0XZSaKdsCNGYkqMO76AFiJEg4vINzoDKcZa6MS7JX+OHIjwh06K5vczw==", - "dependencies": { - "decode-uri-component": "^0.4.1", - "filter-obj": "^5.1.0", - "split-on-first": "^3.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/random-path": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/random-path/-/random-path-0.1.2.tgz", - "integrity": "sha512-4jY0yoEaQ5v9StCl5kZbNIQlg1QheIDBrdkDn53EynpPb9FgO6//p3X/tgMnrC45XN6QZCzU1Xz/+pSSsJBpRw==", - "dev": true, - "optional": true, - "dependencies": { - "base32-encode": "^0.1.0 || ^1.0.0", - "murmur-32": "^0.1.0 || ^0.2.0" - } - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-composer": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/react-composer/-/react-composer-5.0.3.tgz", - "integrity": "sha512-1uWd07EME6XZvMfapwZmc7NgCZqDemcvicRi3wMJzXsQLvZ3L7fTHVyPy1bZdnWXM4iPjYuNE+uJ41MLKeTtnA==", - "dependencies": { - "prop-types": "^15.6.0" - }, - "peerDependencies": { - "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-device-frameset": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/react-device-frameset/-/react-device-frameset-1.3.4.tgz", - "integrity": "sha512-M9VUa2up9TFOgsELHBFRkZf8ER0AyOYF5+5qbtYseQCZfg6XUxuNDX5VsJNfMGu6Zz6x9Dgh4rfFDFONK9H7dg==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-dnd": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz", - "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==", - "dependencies": { - "@react-dnd/invariant": "^4.0.1", - "@react-dnd/shallowequal": "^4.0.1", - "dnd-core": "^16.0.1", - "fast-deep-equal": "^3.1.3", - "hoist-non-react-statics": "^3.3.2" - }, - "peerDependencies": { - "@types/hoist-non-react-statics": ">= 3.3.1", - "@types/node": ">= 12", - "@types/react": ">= 16", - "react": ">= 16.14" - }, - "peerDependenciesMeta": { - "@types/hoist-non-react-statics": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-dnd-html5-backend": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz", - "integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==", - "dependencies": { - "dnd-core": "^16.0.1" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-dom/node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/react-drag-drop-files": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/react-drag-drop-files/-/react-drag-drop-files-2.3.10.tgz", - "integrity": "sha512-Fv614W9+OtXFB5O+gjompTxQZLYGO7wJeT4paETGiXtiADB9yPOMGYD4A3PMCTY9Be874/wcpl+2dm3MvCIRzg==", - "dependencies": { - "prop-types": "^15.7.2", - "styled-components": "^5.3.0" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/react-error-boundary": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.13.tgz", - "integrity": "sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==", - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "peerDependencies": { - "react": ">=16.13.1" - } - }, - "node_modules/react-hook-consent": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/react-hook-consent/-/react-hook-consent-3.5.3.tgz", - "integrity": "sha512-/HUD/zw2fJbERVHIMYwbfI5WStizTjgVX7qFS8QLaFTdGOSJ7RLa7zMYrnieqW7KqtL5qriUhxySaATfanAvfA==", - "dependencies": { - "object-hash": "^3.0.0", - "react-toggle": "^4.1.3" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/react-hotkeys-hook": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-4.5.0.tgz", - "integrity": "sha512-Samb85GSgAWFQNvVt3PS90LPPGSf9mkH/r4au81ZP1yOIFayLC3QAvqTgGtJ8YEDMXtPmaVBs6NgipHO6h4Mug==", - "peerDependencies": { - "react": ">=16.8.1", - "react-dom": ">=16.8.1" - } - }, - "node_modules/react-icons": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz", - "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==", - "peerDependencies": { - "react": "*" - } - }, - "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "peer": true - }, - "node_modules/react-markdown": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.0.1.tgz", - "integrity": "sha512-186Gw/vF1uRkydbsOIkcGXw7aHq0sZOCRFFjGrr7b9+nVZg4UfA4enXCaxm4fUzecU38sWfrNDitGhshuU7rdg==", - "dependencies": { - "@types/hast": "^3.0.0", - "devlop": "^1.0.0", - "hast-util-to-jsx-runtime": "^2.0.0", - "html-url-attributes": "^3.0.0", - "mdast-util-to-hast": "^13.0.0", - "remark-parse": "^11.0.0", - "remark-rehype": "^11.0.0", - "unified": "^11.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "@types/react": ">=18", - "react": ">=18" - } - }, - "node_modules/react-measure": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/react-measure/-/react-measure-2.5.2.tgz", - "integrity": "sha512-M+rpbTLWJ3FD6FXvYV6YEGvQ5tMayQ3fGrZhRPHrE9bVlBYfDCLuDcgNttYfk8IqfOI03jz6cbpqMRTUclQnaA==", - "dependencies": { - "@babel/runtime": "^7.2.0", - "get-node-dimensions": "^1.2.1", - "prop-types": "^15.6.2", - "resize-observer-polyfill": "^1.5.0" - }, - "peerDependencies": { - "react": ">0.13.0", - "react-dom": ">0.13.0" - } - }, - "node_modules/react-reconciler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.27.0.tgz", - "integrity": "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.21.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "react": "^18.0.0" - } - }, - "node_modules/react-reflex": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/react-reflex/-/react-reflex-4.2.6.tgz", - "integrity": "sha512-MLGty/ii/BTipKZ47dfs8Ue5g1xqgCxUCDM34ruEr0UVJuXGDzcSX9wPMzRcv4dUR+1tw4hm4c3a6V6hLO2XcA==", - "dependencies": { - "@babel/runtime": "^7.0.0", - "lodash.throttle": "^4.1.1", - "prop-types": "^15.5.8", - "react-measure": "^2.0.2" - }, - "peerDependencies": { - "react": "^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-refresh": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", - "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-remove-scroll": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz", - "integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==", - "dependencies": { - "react-remove-scroll-bar": "^2.3.4", - "react-style-singleton": "^2.2.1", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.0", - "use-sidecar": "^1.1.2" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-remove-scroll-bar": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz", - "integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==", - "dependencies": { - "react-style-singleton": "^2.2.1", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-speakup": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/react-speakup/-/react-speakup-1.0.0.tgz", - "integrity": "sha512-uZlLfBrWcdlw9fC6N5NY14GA8olnXh7DNaWNQya1osBPIE2nd/URv3nc6+yXeIlu55bwdGYSPoyAXEo5znN1hg==", - "peerDependencies": { - "react": ">=16" - } - }, - "node_modules/react-style-singleton": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", - "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==", - "dependencies": { - "get-nonce": "^1.0.0", - "invariant": "^2.2.4", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-toggle": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/react-toggle/-/react-toggle-4.1.3.tgz", - "integrity": "sha512-WoPrvbwfQSvoagbrDnXPrlsxwzuhQIrs+V0I162j/s+4XPgY/YDAUmHSeWiroznfI73wj+MBydvW95zX8ABbSg==", - "dependencies": { - "classnames": "^2.2.5" - }, - "peerDependencies": { - "prop-types": ">= 15.3.0 < 19", - "react": ">= 15.3.0 < 19", - "react-dom": ">= 15.3.0 < 19" - } - }, - "node_modules/react-use-measure": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz", - "integrity": "sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==", - "dependencies": { - "debounce": "^1.2.1" - }, - "peerDependencies": { - "react": ">=16.13", - "react-dom": ">=16.13" - } - }, - "node_modules/react-virtualized-auto-sizer": { - "version": "1.0.24", - "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.24.tgz", - "integrity": "sha512-3kCn7N9NEb3FlvJrSHWGQ4iVl+ydQObq2fHMn12i5wbtm74zHOPhz/i64OL3c1S1vi9i2GXtZqNqUJTQ+BnNfg==", - "peerDependencies": { - "react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0", - "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/read-binary-file-arch": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", - "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "bin": { - "read-binary-file-arch": "cli.js" - } - }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha512-eFIBOPW7FGjzBuk3hdXEuNSiTZS/xEMlH49HxMyzb0hyPfu4EhVjT2DH32K1hSSmVq4sebAWnZuuY5auISUTGA==", - "dev": true, - "dependencies": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha512-1orxQfbWGUiTn9XsPlChs6rLie/AV9jwZTGmu2NZw/CUDJQchXJFYE0Fq5j7+n558T1JhDWLdhyd1Zj+wLY//w==", - "dev": true, - "dependencies": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ==", - "dev": true, - "dependencies": { - "pify": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/readable-stream": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", - "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", - "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/rechoir": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", - "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", - "dev": true, - "dependencies": { - "resolve": "^1.20.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "dependencies": { - "@babel/runtime": "^7.9.2" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", - "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.1", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/remark-gfm": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", - "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-gfm": "^3.0.0", - "micromark-extension-gfm": "^3.0.0", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-parse": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", - "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-rehype": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.0.tgz", - "integrity": "sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g==", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "mdast-util-to-hast": "^13.0.0", - "unified": "^11.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-stringify": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", - "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-to-markdown": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/replicate": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/replicate/-/replicate-0.32.0.tgz", - "integrity": "sha512-XOJBnV/FpRsz/r7DEj8KL4pdDk9BpptkljGOhKmjlZGdNcBvt532GxxmjT4ZaqdExg7STxrh1JHhI91zg+CZTw==", - "engines": { - "git": ">=2.11.0", - "node": ">=18.0.0", - "npm": ">=7.19.0", - "yarn": ">=1.7.0" - }, - "optionalDependencies": { - "readable-stream": ">=4.0.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" - }, - "node_modules/resedit": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resedit/-/resedit-2.0.2.tgz", - "integrity": "sha512-UKTnq602iVe+W5SyRAQx/WdWMnlDiONfXBLFg/ur4QE4EQQ8eP7Jgm5mNXdK12kKawk1vvXPja2iXKqZiGDW6Q==", - "dev": true, - "dependencies": { - "pe-library": "^1.0.1" - }, - "engines": { - "node": ">=14", - "npm": ">=7" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jet2jet" - } - }, - "node_modules/resize-observer-polyfill": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", - "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "node_modules/resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-package": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-package/-/resolve-package-1.0.1.tgz", - "integrity": "sha512-rzB7NnQpOkPHBWFPP3prUMqOP6yg3HkRGgcvR+lDyvyHoY3fZLFLYDkPXh78SPVBAE6VTCk/V+j8we4djg6o4g==", - "dev": true, - "dependencies": { - "get-installed-path": "^2.0.3" - }, - "engines": { - "node": ">=4", - "npm": ">=2" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dev": true, - "dependencies": { - "lowercase-keys": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/roarr": { - "version": "2.15.4", - "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", - "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", - "dev": true, - "optional": true, - "dependencies": { - "boolean": "^3.0.1", - "detect-node": "^2.0.4", - "globalthis": "^1.0.1", - "json-stringify-safe": "^5.0.1", - "semver-compare": "^1.0.0", - "sprintf-js": "^1.1.2" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/robot3": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/robot3/-/robot3-0.4.1.tgz", - "integrity": "sha512-hzjy826lrxzx8eRgv80idkf8ua1JAepRc9Efdtj03N3KNJuznQCPlyCJ7gnUmDFwZCLQjxy567mQVKmdv2BsXQ==" - }, - "node_modules/rollup": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", - "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", - "dev": true, - "dependencies": { - "@types/estree": "1.0.5" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.20.0", - "@rollup/rollup-android-arm64": "4.20.0", - "@rollup/rollup-darwin-arm64": "4.20.0", - "@rollup/rollup-darwin-x64": "4.20.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.20.0", - "@rollup/rollup-linux-arm-musleabihf": "4.20.0", - "@rollup/rollup-linux-arm64-gnu": "4.20.0", - "@rollup/rollup-linux-arm64-musl": "4.20.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.20.0", - "@rollup/rollup-linux-riscv64-gnu": "4.20.0", - "@rollup/rollup-linux-s390x-gnu": "4.20.0", - "@rollup/rollup-linux-x64-gnu": "4.20.0", - "@rollup/rollup-linux-x64-musl": "4.20.0", - "@rollup/rollup-win32-arm64-msvc": "4.20.0", - "@rollup/rollup-win32-ia32-msvc": "4.20.0", - "@rollup/rollup-win32-x64-msvc": "4.20.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/rrweb-cssom": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", - "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", - "dev": true - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "devOptional": true - }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, - "node_modules/scheduler": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", - "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semiver": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/semiver/-/semiver-1.1.0.tgz", - "integrity": "sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", - "dev": true, - "optional": true - }, - "node_modules/serialize-error": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", - "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", - "dev": true, - "optional": true, - "dependencies": { - "type-fest": "^0.13.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/serialize-error/node_modules/type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" - }, - "node_modules/sharp": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.4.tgz", - "integrity": "sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==", - "hasInstallScript": true, - "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.3", - "semver": "^7.6.0" - }, - "engines": { - "libvips": ">=8.15.2", - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.33.4", - "@img/sharp-darwin-x64": "0.33.4", - "@img/sharp-libvips-darwin-arm64": "1.0.2", - "@img/sharp-libvips-darwin-x64": "1.0.2", - "@img/sharp-libvips-linux-arm": "1.0.2", - "@img/sharp-libvips-linux-arm64": "1.0.2", - "@img/sharp-libvips-linux-s390x": "1.0.2", - "@img/sharp-libvips-linux-x64": "1.0.2", - "@img/sharp-libvips-linuxmusl-arm64": "1.0.2", - "@img/sharp-libvips-linuxmusl-x64": "1.0.2", - "@img/sharp-linux-arm": "0.33.4", - "@img/sharp-linux-arm64": "0.33.4", - "@img/sharp-linux-s390x": "0.33.4", - "@img/sharp-linux-x64": "0.33.4", - "@img/sharp-linuxmusl-arm64": "0.33.4", - "@img/sharp-linuxmusl-x64": "0.33.4", - "@img/sharp-wasm32": "0.33.4", - "@img/sharp-win32-ia32": "0.33.4", - "@img/sharp-win32-x64": "0.33.4" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/simple-swizzle/node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", - "dev": true, - "dependencies": { - "ip-address": "^9.0.5", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", - "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", - "dev": true, - "dependencies": { - "agent-base": "^7.1.1", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/socks-proxy-agent/node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/sonner": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.5.0.tgz", - "integrity": "sha512-FBjhG/gnnbN6FY0jaNnqZOMmB73R+5IiyYAw8yBj7L54ER7HB3fOSE5OFiQiE2iXWxeXKvg6fIP4LtVppHEdJA==", - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/space-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", - "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", - "dev": true - }, - "node_modules/split-on-first": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-3.0.0.tgz", - "integrity": "sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true - }, - "node_modules/ssri": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", - "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true - }, - "node_modules/standardized-audio-context": { - "version": "25.3.75", - "resolved": "https://registry.npmjs.org/standardized-audio-context/-/standardized-audio-context-25.3.75.tgz", - "integrity": "sha512-N7/Si1d0kuo1umRnWOsQESqxJlkMxBZfdfNRo5HeE7pA0lmo6PNrMkOSiM0NutFxpwA+KcPexo5JkTWWAAUaNQ==", - "dependencies": { - "@babel/runtime": "^7.24.8", - "automation-events": "^7.0.7", - "tslib": "^2.6.3" - } - }, - "node_modules/state-local": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", - "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==" - }, - "node_modules/stats-gl": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/stats-gl/-/stats-gl-2.2.8.tgz", - "integrity": "sha512-94G5nZvduDmzxBS7K0lYnynYwreZpkknD8g5dZmU6mpwIhy3caCrjAm11Qm1cbyx7mqix7Fp00RkbsonzKWnoQ==", - "dependencies": { - "@types/three": "^0.163.0" - } - }, - "node_modules/stats-gl/node_modules/@types/three": { - "version": "0.163.0", - "resolved": "https://registry.npmjs.org/@types/three/-/three-0.163.0.tgz", - "integrity": "sha512-uIdDhsXRpQiBUkflBS/i1l3JX14fW6Ot9csed60nfbZNXHDTRsnV2xnTVwXcgbvTiboAR4IW+t+lTL5f1rqIqA==", - "dependencies": { - "@tweenjs/tween.js": "~23.1.1", - "@types/stats.js": "*", - "@types/webxr": "*", - "fflate": "~0.8.2", - "meshoptimizer": "~0.18.1" - } - }, - "node_modules/stats.js": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz", - "integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==" - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/std-env": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", - "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", - "dev": true - }, - "node_modules/stdin-discarder": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", - "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/stream-buffers": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", - "integrity": "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==", - "dev": true, - "optional": true, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/strict-event-emitter": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", - "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==" - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/string.prototype.includes": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz", - "integrity": "sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", - "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "regexp.prototype.flags": "^1.5.2", - "set-function-name": "^2.0.2", - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.repeat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", - "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/stringify-entities": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", - "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", - "dependencies": { - "character-entities-html4": "^2.0.0", - "character-entities-legacy": "^3.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-outer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", - "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-outer/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/strnum": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" - }, - "node_modules/style-to-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.6.tgz", - "integrity": "sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA==", - "dependencies": { - "inline-style-parser": "0.2.3" - } - }, - "node_modules/styled-components": { - "version": "5.3.11", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz", - "integrity": "sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==", - "dependencies": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/traverse": "^7.4.5", - "@emotion/is-prop-valid": "^1.1.0", - "@emotion/stylis": "^0.8.4", - "@emotion/unitless": "^0.7.4", - "babel-plugin-styled-components": ">= 1.12.0", - "css-to-react-native": "^3.0.0", - "hoist-non-react-statics": "^3.0.0", - "shallowequal": "^1.1.0", - "supports-color": "^5.5.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/styled-components" - }, - "peerDependencies": { - "react": ">= 16.8.0", - "react-dom": ">= 16.8.0", - "react-is": ">= 16.8.0" - } - }, - "node_modules/styled-components/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/styled-components/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/styled-jsx": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", - "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", - "dependencies": { - "client-only": "0.0.1" - }, - "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/sucrase": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "^10.3.10", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/sucrase/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/sucrase/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sucrase/node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/sucrase/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sudo-prompt": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/sudo-prompt/-/sudo-prompt-9.2.1.tgz", - "integrity": "sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==", - "dev": true - }, - "node_modules/sumchecker": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", - "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", - "dev": true, - "dependencies": { - "debug": "^4.1.0" - }, - "engines": { - "node": ">= 8.0" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/suspend-react": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/suspend-react/-/suspend-react-0.1.3.tgz", - "integrity": "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==", - "peerDependencies": { - "react": ">=17.0" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "node_modules/tailwind-merge": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.2.tgz", - "integrity": "sha512-kjEBm+pvD+6eAwzJL2Bi+02/9LFLal1Gs61+QB7HvTfQQ0aXwC5LGT8PEt1gS0CWKktKe6ysPTAy3cBC5MeiIg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/dcastil" - } - }, - "node_modules/tailwind-scrollbar": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tailwind-scrollbar/-/tailwind-scrollbar-3.1.0.tgz", - "integrity": "sha512-pmrtDIZeHyu2idTejfV59SbaJyvp1VRjYxAjZBH0jnyrPRo6HL1kD5Glz8VPagasqr6oAx6M05+Tuw429Z8jxg==", - "dev": true, - "engines": { - "node": ">=12.13.0" - }, - "peerDependencies": { - "tailwindcss": "3.x" - } - }, - "node_modules/tailwindcss": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.9.tgz", - "integrity": "sha512-1SEOvRr6sSdV5IDf9iC+NU4dhwdqzF4zKKq3sAbasUWHEM6lsMhX+eNN5gkPx1BvLFEnZQEUFbXnGj8Qlp83Pg==", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.3.0", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.21.0", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tailwindcss-animate": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", - "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", - "peerDependencies": { - "tailwindcss": ">=3.0.0 || insiders" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "dev": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/temp": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz", - "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", - "dev": true, - "optional": true, - "dependencies": { - "mkdirp": "^0.5.1", - "rimraf": "~2.6.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/temp/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "optional": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/temp/node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "optional": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/textlinestream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/textlinestream/-/textlinestream-1.1.1.tgz", - "integrity": "sha512-iBHbi7BQxrFmwZUQJsT0SjNzlLLsXhvW/kg7EyOMVMBIrlnj/qYofwo1LVLZi+3GbUEo96Iu2eqToI2+lZoAEQ==" - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/three": { - "version": "0.164.1", - "resolved": "https://registry.npmjs.org/three/-/three-0.164.1.tgz", - "integrity": "sha512-iC/hUBbl1vzFny7f5GtqzVXYjMJKaTPxiCxXfrvVdBi1Sf+jhd1CAkitiFwC7mIBFCo3MrDLJG97yisoaWig0w==" - }, - "node_modules/three-mesh-bvh": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.7.6.tgz", - "integrity": "sha512-rCjsnxEqR9r1/C/lCqzGLS67NDty/S/eT6rAJfDvsanrIctTWdNoR4ZOGWewCB13h1QkVo2BpmC0wakj1+0m8A==", - "peerDependencies": { - "three": ">= 0.151.0" - } - }, - "node_modules/three-stdlib": { - "version": "2.32.1", - "resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.32.1.tgz", - "integrity": "sha512-ZgxxLAwtEaKkvfGP+hkW4s6IaDzif47evTdBPwVvdvLsOul3M6l0D4vO4/fzFguXT6FdoBlaTLhteOcn3uDzPg==", - "dependencies": { - "@types/draco3d": "^1.4.0", - "@types/offscreencanvas": "^2019.6.4", - "@types/webxr": "^0.5.2", - "draco3d": "^1.4.1", - "fflate": "^0.6.9", - "potpack": "^1.0.1" - }, - "peerDependencies": { - "three": ">=0.128.0" - } - }, - "node_modules/three-stdlib/node_modules/fflate": { - "version": "0.6.10", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", - "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==" - }, - "node_modules/tiny-each-async": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tiny-each-async/-/tiny-each-async-2.0.3.tgz", - "integrity": "sha512-5ROII7nElnAirvFn8g7H7MtpfV1daMcyfTGQwsn/x2VtyV+VPiO5CjReCJtWLvoKTDEDmZocf3cNPraiMnBXLA==", - "dev": true, - "optional": true - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true - }, - "node_modules/tinypool": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.0.tgz", - "integrity": "sha512-KIKExllK7jp3uvrNtvRBYBWBOAXSX8ZvoaD8T+7KB/QHIuoJW3Pmr60zucywjAlMb5TeXUkcs/MWeWLu0qvuAQ==", - "dev": true, - "engines": { - "node": "^18.0.0 || >=20.0.0" - } - }, - "node_modules/tinyrainbow": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", - "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tinyspy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.0.tgz", - "integrity": "sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/tmp-promise": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", - "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", - "dev": true, - "optional": true, - "dependencies": { - "tmp": "^0.2.0" - } - }, - "node_modules/tn1150": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/tn1150/-/tn1150-0.1.0.tgz", - "integrity": "sha512-DbplOfQFkqG5IHcDyyrs/lkvSr3mPUVsFf/RbDppOshs22yTPnSJWEe6FkYd1txAwU/zcnR905ar2fi4kwF29w==", - "dev": true, - "optional": true, - "dependencies": { - "unorm": "^1.4.1" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/to-data-view": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/to-data-view/-/to-data-view-1.1.0.tgz", - "integrity": "sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ==", - "dev": true, - "optional": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tough-cookie": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tough-cookie/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/tr46": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", - "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", - "dev": true, - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/trim-lines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/trim-repeated": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", - "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/trim-repeated/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/troika-three-text": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.49.1.tgz", - "integrity": "sha512-lXGWxgjJP9kw4i4Wh+0k0Q/7cRfS6iOME4knKht/KozPu9GcFA9NnNpRvehIhrUawq9B0ZRw+0oiFHgRO+4Wig==", - "dependencies": { - "bidi-js": "^1.0.2", - "troika-three-utils": "^0.49.0", - "troika-worker-utils": "^0.49.0", - "webgl-sdf-generator": "1.1.1" - }, - "peerDependencies": { - "three": ">=0.125.0" - } - }, - "node_modules/troika-three-utils": { - "version": "0.49.0", - "resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.49.0.tgz", - "integrity": "sha512-umitFL4cT+Fm/uONmaQEq4oZlyRHWwVClaS6ZrdcueRvwc2w+cpNQ47LlJKJswpqtMFWbEhOLy0TekmcPZOdYA==", - "peerDependencies": { - "three": ">=0.125.0" - } - }, - "node_modules/troika-worker-utils": { - "version": "0.49.0", - "resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.49.0.tgz", - "integrity": "sha512-1xZHoJrG0HFfCvT/iyN41DvI/nRykiBtHqFkGaGgJwq5iXfIZFBiPPEHFpPpgyKM3Oo5ITHXP5wM2TNQszYdVg==" - }, - "node_modules/trough": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", - "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" - }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" - }, - "node_modules/tunnel-rat": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/tunnel-rat/-/tunnel-rat-0.1.2.tgz", - "integrity": "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==", - "dependencies": { - "zustand": "^4.3.2" - } - }, - "node_modules/tw-to-css": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/tw-to-css/-/tw-to-css-0.0.12.tgz", - "integrity": "sha512-rQAsQvOtV1lBkyCw+iypMygNHrShYAItES5r8fMsrhhaj5qrV2LkZyXc8ccEH+u5bFjHjQ9iuxe90I7Kykf6pw==", - "dependencies": { - "postcss": "8.4.31", - "postcss-css-variables": "0.18.0", - "tailwindcss": "3.3.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/tw-to-css/node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/tw-to-css/node_modules/tailwindcss": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", - "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.12", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.18.2", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typescript": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" - }, - "node_modules/unified": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", - "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", - "dependencies": { - "@types/unist": "^3.0.0", - "bail": "^2.0.0", - "devlop": "^1.0.0", - "extend": "^3.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unique-filename": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", - "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", - "dev": true, - "dependencies": { - "unique-slug": "^4.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/unique-slug": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", - "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/unist-util-is": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-position": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", - "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-remove-position": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", - "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-visit": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit-parents": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/universal-user-agent": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", - "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", - "dev": true - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unorm": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz", - "integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==", - "dev": true, - "optional": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" - }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/use-callback-ref": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz", - "integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==", - "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/use-file-picker": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/use-file-picker/-/use-file-picker-2.1.2.tgz", - "integrity": "sha512-ZEIzRi1wXeIXDWr5i55gRBVER8rTkSGskDUY94bciTTAZJHlBnOTRLL/LDYjgz6d+US3yELHnRvtBhLxFGtB0A==", - "dependencies": { - "file-selector": "0.2.4" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "react": ">=16" - } - }, - "node_modules/use-sidecar": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", - "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==", - "dependencies": { - "detect-node-es": "^1.1.0", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/usehooks-ts": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-2.16.0.tgz", - "integrity": "sha512-bez95WqYujxp6hFdM/CpRDiVPirZPxlMzOH2QB8yopoKQMXpscyZoxOjpEdaxvV+CAWUDSM62cWnqHE0E/MZ7w==", - "dependencies": { - "lodash.debounce": "^4.0.8" - }, - "engines": { - "node": ">=16.15.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17 || ^18" - } - }, - "node_modules/username": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/username/-/username-5.1.0.tgz", - "integrity": "sha512-PCKbdWw85JsYMvmCv5GH3kXmM66rCd9m1hBEDutPNv94b/pqCMT4NtcKyeWYvLFiE8b+ha1Jdl8XAaUdPn5QTg==", - "dev": true, - "dependencies": { - "execa": "^1.0.0", - "mem": "^4.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/utility-types": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", - "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/uuid-random": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/uuid-random/-/uuid-random-1.3.2.tgz", - "integrity": "sha512-UOzej0Le/UgkbWEO8flm+0y+G+ljUon1QWTEZOq1rnMAsxo2+SckbiZdKzAHHlVh6gJqI1TjC/xwgR50MuCrBQ==" - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/vfile": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.2.tgz", - "integrity": "sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile-message": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", - "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vite": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.0.tgz", - "integrity": "sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==", - "dev": true, - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.40", - "rollup": "^4.13.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/vite-node": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.0.5.tgz", - "integrity": "sha512-LdsW4pxj0Ot69FAoXZ1yTnA9bjGohr2yNBU7QKRxpz8ITSkhuDl6h3zS/tvgz4qrNjeRnvrWeXQ8ZF7Um4W00Q==", - "dev": true, - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.3.5", - "pathe": "^1.1.2", - "tinyrainbow": "^1.2.0", - "vite": "^5.0.0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/vite/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/vitest": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.0.5.tgz", - "integrity": "sha512-8GUxONfauuIdeSl5f9GTgVEpg5BTOlplET4WEDaeY2QBiN8wSm68vxN/tb5z405OwppfoCavnwXafiaYBC/xOA==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.3.0", - "@vitest/expect": "2.0.5", - "@vitest/pretty-format": "^2.0.5", - "@vitest/runner": "2.0.5", - "@vitest/snapshot": "2.0.5", - "@vitest/spy": "2.0.5", - "@vitest/utils": "2.0.5", - "chai": "^5.1.1", - "debug": "^4.3.5", - "execa": "^8.0.1", - "magic-string": "^0.30.10", - "pathe": "^1.1.2", - "std-env": "^3.7.0", - "tinybench": "^2.8.0", - "tinypool": "^1.0.0", - "tinyrainbow": "^1.2.0", - "vite": "^5.0.0", - "vite-node": "2.0.5", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "2.0.5", - "@vitest/ui": "2.0.5", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/vitest/node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", - "dev": true, - "dependencies": { - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/web-audio-beat-detector": { - "version": "8.2.12", - "resolved": "https://registry.npmjs.org/web-audio-beat-detector/-/web-audio-beat-detector-8.2.12.tgz", - "integrity": "sha512-wno9QdH3UPtQNu8VSi82z6Q6QiSURI0nRjtlLkfVZ+qvM8ITVq9c+VZFJpbEKR8FsehkVN8i44vqu39zh+m7/g==", - "dependencies": { - "@babel/runtime": "^7.24.8", - "tslib": "^2.6.3", - "web-audio-beat-detector-broker": "^4.1.11", - "web-audio-beat-detector-worker": "^5.2.54" - } - }, - "node_modules/web-audio-beat-detector-broker": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/web-audio-beat-detector-broker/-/web-audio-beat-detector-broker-4.1.11.tgz", - "integrity": "sha512-meOMbFMmLnAogLW7GiPo0teQho9RitsaB47NPIUy2WMfth4PCps2hgIQoW2DXtNwU0R4p0YEEpZnioXFoRlHqg==", - "dependencies": { - "@babel/runtime": "^7.24.8", - "fast-unique-numbers": "^9.0.7", - "standardized-audio-context": "^25.3.75", - "tslib": "^2.6.3", - "web-audio-beat-detector-worker": "^5.2.54" - } - }, - "node_modules/web-audio-beat-detector-worker": { - "version": "5.2.54", - "resolved": "https://registry.npmjs.org/web-audio-beat-detector-worker/-/web-audio-beat-detector-worker-5.2.54.tgz", - "integrity": "sha512-rFAKJhxUgEpRxJYaWjIDMhQ7tZ6E41LwTQ4GZ3mh95BjBOGpTLMiy+26vBTd2Xkc7E0VWyzhmPNb5/5aBxO6ZQ==", - "dependencies": { - "@babel/runtime": "^7.24.8", - "tslib": "^2.6.3" - } - }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/webgl-constants": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz", - "integrity": "sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==" - }, - "node_modules/webgl-sdf-generator": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz", - "integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==" - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "dev": true, - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", - "dev": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-url": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", - "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", - "dev": true, - "dependencies": { - "tr46": "^5.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", - "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", - "dev": true, - "dependencies": { - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", - "is-generator-function": "^1.0.10", - "is-regex": "^1.1.4", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.15" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/wide-align/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/wide-align/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wide-align/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "dev": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/xmlbuilder": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "dev": true, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "node_modules/yaml": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", - "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yarn-or-npm": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/yarn-or-npm/-/yarn-or-npm-3.0.1.tgz", - "integrity": "sha512-fTiQP6WbDAh5QZAVdbMQkecZoahnbOjClTQhzv74WX5h2Uaidj1isf9FDes11TKtsZ0/ZVfZsqZ+O3x6aLERHQ==", - "dev": true, - "dependencies": { - "cross-spawn": "^6.0.5", - "pkg-dir": "^4.2.0" - }, - "bin": { - "yarn-or-npm": "bin/index.js", - "yon": "bin/index.js" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/yarn-or-npm/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/yarn-or-npm/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/yarn-or-npm/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/yarn-or-npm/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yarn-or-npm/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yarn-or-npm/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yoctocolors-cjs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", - "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yoga-layout": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.1.0.tgz", - "integrity": "sha512-auzJ8lEovThZIpR8wLGWNo/JEj4VTO79q9/gOJ0dWb3shAYPFdX3t9VN0fC0v+jeQF77STUdCzebLwRMqzn5gQ==" - }, - "node_modules/zod": { - "version": "3.23.8", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", - "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.23.2", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.2.tgz", - "integrity": "sha512-uSt90Gzc/tUfyNqxnjlfBs8W6WSGpNBv0rVsNxP/BVSMHMKGdthPYff4xtCHYloJGM0CFxFsb3NbC0eqPhfImw==", - "peerDependencies": { - "zod": "^3.23.3" - } - }, - "node_modules/zustand": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.2.tgz", - "integrity": "sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==", - "dependencies": { - "use-sync-external-store": "1.2.0" - }, - "engines": { - "node": ">=12.7.0" - }, - "peerDependencies": { - "@types/react": ">=16.8", - "immer": ">=9.0.6", - "react": ">=16.8" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "immer": { - "optional": true - }, - "react": { - "optional": true - } - } - }, - "node_modules/zwitch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", - "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/zx": { - "version": "8.1.4", - "resolved": "https://registry.npmjs.org/zx/-/zx-8.1.4.tgz", - "integrity": "sha512-QFDYYpnzdpRiJ3dL2102Cw26FpXpWshW4QLTGxiYfIcwdAqg084jRCkK/kuP/NOSkxOjydRwNFG81qzA5r1a6w==", - "bin": { - "zx": "build/cli.js" - }, - "engines": { - "node": ">= 12.17.0" - }, - "optionalDependencies": { - "@types/fs-extra": ">=11", - "@types/node": ">=20" - } - }, - "node_modules/zx/node_modules/@types/fs-extra": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", - "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==", - "optional": true, - "dependencies": { - "@types/jsonfile": "*", - "@types/node": "*" - } - } - } -} diff --git a/package.json b/package.json index 195b3627f33deceb79c3b44c1cca6e420510aca4..84ddfe40dc08a857bf6be9d32b932e352fe79066 100644 --- a/package.json +++ b/package.json @@ -1,195 +1,44 @@ { - "name": "clapper", - "version": "0.0.8", + "name": "@aitube/clapper-monorepo", + "version": "0.2.4", "private": true, - "description": "🎬 Clapper", - "license": "GPL-3.0-only", - "main": "main.js", - "files": [ - "./main.js" + "description": "A monorepo for the Clapper project. Individual packages are in the packages directory.", + "workspaces": [ + "packages/clap", + "packages/timeline", + "packages/api-client", + "packages/io", + "packages/colors", + "packages/engine", + "packages/broadway", + "packages/clapper-services", + "packages/app" ], - "directories": { - "src:": "./src", - "public:": "./public" + "engines": { + "bun": ">=1.0.0" }, "scripts": { - "dev": "npm i && npm run checks && next dev", - "build": "npm i && npm run prepare && npm run checks && rm -Rf out && next build && npm run build:copyassets", - "build:ci": "rm -Rf out && npm run prepare && next build && npm run build:copyassets", - "build:copyassets": "cp -R public .next/standalone/public && cp -R .next/static .next/standalone/.next/static", - "prepare": "cp -R node_modules/mediainfo.js/dist/MediaInfoModule.wasm public/wasm/", - "start": "next start", - "start:prod": "node .next/standalone/server.js", - "checks": "npm run format:fix && npm run lint", - "format": "prettier --check --ignore-path .gitignore ./src/", - "format:fix": "prettier --write --ignore-path .gitignore ./src/", - "lint": "next lint", - "lint:fix": "next lint --fix", - "test": "npm run build && npm run test:unit:ci", - "test_TEMPORARY_DISABLED": "npm run build && npm run test:unit:ci && npm run test:e2e", - "test:unit:ci": "vitest run", - "test:unit:watch": "vitest", - "test:e2e": "npx playwright test", - "electron": "npm run build && electron .", - "electron:start": "npm run build && electron-forge start", - "electron:package": "npm run build && electron-forge package", - "electron:make": "npm run build && electron-forge make" + "dev": "bun run --cwd packages/app dev", + "start": "bun run --cwd packages/app start", + "build": "bun run build:all", + "build:all": "bun run build:clap && bun run build:timeline && bun run build:api-client && bun run build:io && bun run build:colors && bun run build:engine && bun run build:broadway && bun run build:services && bun run build:app", + "build:clap": "bun run --cwd packages/clap build", + "build:timeline": "bun run --cwd packages/timeline build", + "build:api-client": "bun run --cwd packages/api-client build", + "build:io": "bun run --cwd packages/io build", + "build:colors": "bun run --cwd packages/colors build", + "build:engine": "bun run --cwd packages/engine build", + "build:broadway": "bun run --cwd packages/broadway build", + "build:clapper-services": "bun run --cwd packages/clapper-services build", + "build:app": "bun run --cwd packages/app build", + "test": "bun run test:all", + "test:all": "bun run --cwd packages/clap test && bun run --cwd packages/timeline test && bun run --cwd packages/api-client test && bun run --cwd packages/io test && bun run --cwd packages/colors test && bun run --cwd packages/engine test && bun run --cwd packages/broadway test && bun run --cwd packages/clapper-services test && bun run --cwd packages/app test", + "format": "bun run --cwd packages/app format" }, - "dependencies": { - "@aitube/broadway": "0.2.3", - "@aitube/clap": "0.2.3", - "@aitube/clapper-services": "0.2.3-2", - "@aitube/client": "0.2.3", - "@aitube/engine": "0.2.3", - "@aitube/timeline": "0.2.3", - "@fal-ai/serverless-client": "^0.13.0", - "@ffmpeg/ffmpeg": "^0.12.10", - "@ffmpeg/util": "^0.12.1", - "@gradio/client": "^1.5.0", - "@huggingface/hub": "^0.15.1", - "@huggingface/inference": "^2.8.0", - "@langchain/anthropic": "^0.2.14", - "@langchain/cohere": "^0.2.2", - "@langchain/core": "^0.2.23", - "@langchain/google-vertexai": "^0.0.25", - "@langchain/groq": "^0.0.16", - "@langchain/mistralai": "^0.0.28", - "@langchain/openai": "^0.2.6", - "@monaco-editor/react": "^4.6.0", - "@radix-ui/react-accordion": "^1.1.2", - "@radix-ui/react-avatar": "^1.0.4", - "@radix-ui/react-checkbox": "^1.0.4", - "@radix-ui/react-collapsible": "^1.0.3", - "@radix-ui/react-dialog": "^1.1.1", - "@radix-ui/react-dropdown-menu": "^2.0.6", - "@radix-ui/react-icons": "^1.3.0", - "@radix-ui/react-label": "^2.0.2", - "@radix-ui/react-menubar": "^1.0.4", - "@radix-ui/react-popover": "^1.0.7", - "@radix-ui/react-progress": "^1.0.3", - "@radix-ui/react-scroll-area": "^1.0.5", - "@radix-ui/react-select": "^2.0.0", - "@radix-ui/react-separator": "^1.0.3", - "@radix-ui/react-slider": "^1.1.2", - "@radix-ui/react-slot": "^1.0.2", - "@radix-ui/react-switch": "^1.0.3", - "@radix-ui/react-tabs": "^1.0.4", - "@radix-ui/react-toast": "^1.1.5", - "@radix-ui/react-tooltip": "^1.0.7", - "@react-spring/three": "^9.7.3", - "@react-spring/types": "^9.7.3", - "@react-three/drei": "^9.106.0", - "@react-three/fiber": "^8.16.6", - "@react-three/uikit": "^0.3.4", - "@react-three/uikit-lucide": "^0.3.4", - "@saintno/comfyui-sdk": "^0.1.11", - "@tailwindcss/container-queries": "^0.1.1", - "@types/dom-speech-recognition": "^0.0.4", - "@types/pngjs": "^6.0.5", - "@xenova/transformers": "github:xenova/transformers.js#v3", - "@xyflow/react": "^12.0.3", - "autoprefixer": "10.4.19", - "base64-arraybuffer": "^1.0.2", - "class-variance-authority": "^0.7.0", - "clsx": "^2.1.1", - "cmdk": "^0.2.1", - "comfydeploy": "^0.0.21", - "date-fns": "^3.6.0", - "dotenv": "^16.4.5", - "fflate": "^0.8.2", - "fluent-ffmpeg": "^2.1.3", - "framer-motion": "11.1.7", - "fs-extra": "^11.2.0", - "is-hotkey": "^0.2.0", - "lucide-react": "^0.396.0", - "mediainfo.js": "^0.3.2", - "mlt-xml": "^2.0.2", - "monaco-editor": "^0.50.0", - "next": "^14.2.5", - "next-themes": "^0.3.0", - "pngjs": "^7.0.0", - "qs": "^6.12.1", - "query-string": "^9.0.0", - "react": "^18.3.1", - "react-device-frameset": "^1.3.4", - "react-dnd": "^16.0.1", - "react-dnd-html5-backend": "^16.0.1", - "react-dom": "^18.3.1", - "react-drag-drop-files": "^2.3.10", - "react-error-boundary": "^4.0.13", - "react-hook-consent": "^3.5.3", - "react-hotkeys-hook": "^4.5.0", - "react-icons": "^5.2.1", - "react-markdown": "^9.0.1", - "react-reflex": "^4.2.6", - "react-speakup": "^1.0.0", - "remark-gfm": "^4.0.0", - "replicate": "^0.32.0", - "sharp": "0.33.4", - "sonner": "^1.5.0", - "tailwind-merge": "^2.5.2", - "tailwindcss-animate": "^1.0.7", - "three": "^0.164.1", - "ts-node": "^10.9.2", - "use-file-picker": "^2.1.2", - "usehooks-ts": "^2.14.0", - "uuid": "^9.0.1", - "web-audio-beat-detector": "^8.2.12", - "yaml": "^2.4.5", - "zustand": "4.5.2", - "zx": "^8.1.4" - }, - "devDependencies": { - "@electron-forge/cli": "^7.4.0", - "@electron-forge/maker-deb": "^7.4.0", - "@electron-forge/maker-dmg": "^7.4.0", - "@electron-forge/maker-rpm": "^7.4.0", - "@electron-forge/maker-squirrel": "^7.4.0", - "@electron-forge/maker-zip": "^7.4.0", - "@electron-forge/plugin-auto-unpack-natives": "^7.4.0", - "@electron-forge/publisher-github": "^7.4.0", - "@playwright/test": "^1.45.1", - "@testing-library/react": "^16.0.0", - "@types/fluent-ffmpeg": "^2.1.24", - "@types/is-hotkey": "^0.1.10", - "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", - "@types/uuid": "^9.0.8", - "@vitejs/plugin-react": "^4.3.1", - "@webgpu/types": "^0.1.44", - "electron": "^31.2.1", - "eslint": "^8", - "eslint-config-next": "14.2.5", - "eslint-config-prettier": "^9.1.0", - "jsdom": "^24.1.0", - "node-gyp": "^10.2.0", - "postcss": "^8", - "prettier": "^3.3.3", - "prettier-plugin-tailwindcss": "^0.6.5", - "tailwind-scrollbar": "^3.1.0", - "tailwindcss": "^3.4.3", - "typescript": "^5.5.0", - "vitest": "^2.0.2" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.33.4", - "@img/sharp-darwin-x64": "0.33.4", - "@img/sharp-libvips-darwin-arm64": "1.0.2", - "@img/sharp-libvips-darwin-x64": "1.0.2", - "@img/sharp-libvips-linux-arm": "1.0.2", - "@img/sharp-libvips-linux-arm64": "1.0.2", - "@img/sharp-libvips-linux-x64": "1.0.2", - "@img/sharp-libvips-linuxmusl-arm64": "1.0.2", - "@img/sharp-libvips-linuxmusl-x64": "1.0.2", - "@img/sharp-libvips-win32-ia32": "1.0.2", - "@img/sharp-libvips-win32-x64": "1.0.2", - "@img/sharp-linux-arm": "0.33.4", - "@img/sharp-linux-arm64": "0.33.4", - "@img/sharp-linux-x64": "0.33.4", - "@img/sharp-linuxmusl-arm64": "0.33.4", - "@img/sharp-linuxmusl-x64": "0.33.4", - "@img/sharp-win32-ia32": "0.33.4", - "@img/sharp-win32-x64": "0.33.4" - } -} + "packageManager": "bun@1.0.25", + "trustedDependencies": [ + "@aitube/clapper", + "onnxruntime-node", + "protobufjs" + ] +} \ No newline at end of file diff --git a/packages/api-client/.gitignore b/packages/api-client/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ea8fe6a7905bd72f745584146daa9994bd211499 --- /dev/null +++ b/packages/api-client/.gitignore @@ -0,0 +1,177 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +\*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +\*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +\*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +\*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.cache +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output +dist +.nuxt + +# Gatsby files + +.cache/ + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp +.cache + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.\* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store + +# TypeScript build information +*.tsbuildinfo \ No newline at end of file diff --git a/packages/api-client/.npmignore b/packages/api-client/.npmignore new file mode 100644 index 0000000000000000000000000000000000000000..78a661ea2d8f8cdaa94e4cc69d758a4b2d946feb --- /dev/null +++ b/packages/api-client/.npmignore @@ -0,0 +1,4 @@ +# Ignore everything +* +# Except the dist directory +!dist/ diff --git a/packages/api-client/.prettierrc.json b/packages/api-client/.prettierrc.json new file mode 100644 index 0000000000000000000000000000000000000000..1dcadb7324877e15a4ffa4efa5723a519395f511 --- /dev/null +++ b/packages/api-client/.prettierrc.json @@ -0,0 +1,9 @@ +{ + "semi": false, + "singleQuote": true, + "arrowParens": "avoid", + "printWidth": 140, + "tabWidth": 2, + "trailingComma": "es5", + "bracketSpacing": true +} diff --git a/packages/api-client/LICENSE.md b/packages/api-client/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..8b21ed7d57c2d217f49e10d0fb0b327961a4ea54 --- /dev/null +++ b/packages/api-client/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2024 Julian Bilcke + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/api-client/README.md b/packages/api-client/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b2c17e1e2c81c10d925e80b316f580e8c97e2d56 --- /dev/null +++ b/packages/api-client/README.md @@ -0,0 +1,113 @@ +# @aitube/api-client + +*Official API client for AiTube.at* + +## ATTENTION + +AiTube is currently in heavy development, and for the moment +the API client is reserved for *private use* (it is used by AI Stories Factory). + +We are sorry for any inconvenience this might cause. + +## Caveats + +The official domain for AiTube is `aitube.at`, however right now +the Hugging Face Space is not configured to use this as a domain, +so we need to perform all API calls to `jbilcke-hf-ai-tube.hf.space`. + +## Installation + +To install the package, run the following command: + +```bash +npm install @aitube/api-client +``` + +## Getting Started + +Note: to overridethe AiTube API URL, set this env var: `AITUBE_URL` + +```typescript +import { + createClap, + editClapDialogues, + editClapEntities, + editClapMusic, + editClapSounds, + editClapStory, + editClapStoryboards, + editClapVideos, + exportClapToVideo, + defaultAitubeHostname, + defaultClapWidth, + defaultClapHeight, + defaultExportFormat, + aitubeUrl, + aitubeApiVersion, + aitubeApiUrl, + ClapEntityPrompt, + SupportedExportFormat, + applyClapCompletion, + } from '@aitube/api-client' + +const ultraSecret = "ultra secret token unavailable to common mortals" + +const basicClap = await createClap({ + prompt: "story about a dog", + turbo: false, + token: ultraSecret +}) + +const illustratedClap = await editClapStoryboards({ + clap: basicClap, + turbo: false, + token: ultraSecret +}) + +const mp4VideoFile = await exportClapToVideo({ + clap: illustratedClap, + format: "mp4", + turbo: false, + token: ultraSecret +}) +``` + +## Customizing the server + +The hostname can be overriden by defining the `AITUBE_URL` environment variable. + +eg: + +```bash +AITUBE_URL=http://localhost:3000 +``` + +## Build Instructions + +Install [Bun](https://bun.sh/) + +Run the following commands: + +```bash +bun install + +bun run build +``` + +To publish: + +```bash +bun run build + +bun run build:declaration + +bun run publish +``` + +## Contributing + +We welcome contributions! Please feel free to submit a pull request. + +## License + +This package is under the MIT License. See `LICENSE` file for more details. diff --git a/packages/api-client/package.json b/packages/api-client/package.json new file mode 100644 index 0000000000000000000000000000000000000000..67462a2f526df65666c3117f90a0086554f579ef --- /dev/null +++ b/packages/api-client/package.json @@ -0,0 +1,44 @@ +{ + "name": "@aitube/api-client", + "module": "index.ts", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "type": "module", + "version": "0.2.4", + "description": "Official API client for AiTube.at", + "scripts": { + "build": "bun build ./src/index.ts --outfile=dist/index.js --external=@aitube/clap && bun run build:declaration", + "build:declaration": "tsc --emitDeclarationOnly --project tsconfig.types.json", + "postbuild": "rimraf tsconfig.types.tsbuildinfo && bun run build:declaration", + "publish": "npm publish --access public", + "update": "rm -Rf node_modules && rm bun.lockb && bun i && bun run build" + }, + "devDependencies": { + "bun-types": "latest", + "prettier": "^3.3.3", + "rimraf": "^6.0.1", + "typescript": "^5.5.4" + }, + "repository": { + "type": "git", + "url": "https://github.com/jbilcke-hf/aitube-client.git" + }, + "keywords": [ + "Clapper.app", + "AiTube.at", + "OpenClap", + "AI cinema", + "file format", + "specification" + ], + "author": "Julian Bilcke", + "license": "MIT", + "files": [ + "dist/*.js", + "dist/*.d.ts", + "dist/**/*.d.ts" + ], + "dependencies": { + "query-string": "^9.0.0" + } +} diff --git a/packages/api-client/src/api/createClap.ts b/packages/api-client/src/api/createClap.ts new file mode 100644 index 0000000000000000000000000000000000000000..01530a7efe4ca8d4e98e279cb28c237e8ce7ddc6 --- /dev/null +++ b/packages/api-client/src/api/createClap.ts @@ -0,0 +1,43 @@ +import { ClapProject, fetchClap } from "@aitube/clap" + +import { aitubeApiUrl } from "@/constants/config" + +import { defaultClapHeight, defaultClapWidth } from "@/constants/defaultValues" + +export async function createClap({ + prompt, + height = defaultClapHeight, + width = defaultClapWidth, + turbo = false, + token, +}: { + prompt: string + height?: number + width?: number + turbo?: boolean + token?: string +}): Promise { + + if (typeof prompt !== "string" || !prompt.length) { throw new Error(`please provide a prompt`) } + + const hasToken = typeof token === "string" && token.length > 0 + + const clap = await fetchClap(`${aitubeApiUrl}create`, { + method: "POST", + headers: { + "Content-Type": "application/json", + ...hasToken && { + "Authorization": `Bearer ${token}` + } + }, + body: JSON.stringify({ + prompt, + width, + height, + turbo, + }), + cache: "no-store", + }) + + return clap +} \ No newline at end of file diff --git a/packages/api-client/src/api/editClapDialogues.ts b/packages/api-client/src/api/editClapDialogues.ts new file mode 100644 index 0000000000000000000000000000000000000000..a54bff09cd324732f0182476d7a4a71db1e25502 --- /dev/null +++ b/packages/api-client/src/api/editClapDialogues.ts @@ -0,0 +1,61 @@ +import { ClapCompletionMode, ClapProject, fetchClap, removeGeneratedAssetUrls, serializeClap } from "@aitube/clap" +import queryString from "query-string" + +import { aitubeApiUrl } from "@/constants/config" +import { applyClapCompletion } from "@/utils" + +export async function editClapDialogues({ + clap, + completionMode = ClapCompletionMode.MERGE, + turbo = false, + token, +}: { + clap: ClapProject + + /** + * Completion mode (optional, defaults to "merge") + * + * Possible values are: + * - full: the API and the client will return a full clap file. This is a very convenient and simple mode, but it is also very ineficient, so it should not be used for intensive applications. + * - partial: the API and the client will return a partial clap file, containing only the new values and changes. This is useful for real-time applications and streaming. + * - merge: the API will return a partial clap file, and the client will return a merge of the original with the new values. This is safe to run, there are no side-effects. + * - replace: the API will return a partial clap file, and the client will replace the original. This is the most efficient mode, but it relies on side-effects and inline object updates. + */ + completionMode?: ClapCompletionMode + + turbo?: boolean + + token?: string +}): Promise { + + if (!clap) { throw new Error(`please provide a valid clap project`) } + + const hasToken = typeof token === "string" && token.length > 0 + + const params: Record = {} + + if (typeof completionMode === "string") { + params.c = completionMode + } + + if (turbo) { + params.t = "true" + } + + const newClap = await fetchClap( + `${aitubeApiUrl}edit/dialogues?${queryString.stringify(params)}`, { + method: "POST", + headers: { + "Content-Type": "application/x-gzip", + ...hasToken && { + "Authorization": `Bearer ${token}` + } + }, + body: await serializeClap(removeGeneratedAssetUrls(clap)), + cache: "no-store", + }) + + const result = await applyClapCompletion(clap, newClap, completionMode) + + return result +} \ No newline at end of file diff --git a/packages/api-client/src/api/editClapEntities.ts b/packages/api-client/src/api/editClapEntities.ts new file mode 100644 index 0000000000000000000000000000000000000000..0373b461562d025edaec8148699d400dac24f1f1 --- /dev/null +++ b/packages/api-client/src/api/editClapEntities.ts @@ -0,0 +1,75 @@ +import { ClapCompletionMode, ClapProject, fetchClap, serializeClap, removeGeneratedAssetUrls } from "@aitube/clap" +import queryString from "query-string" + +import { aitubeApiUrl } from "@/constants/config" +import { ClapEntityPrompt } from "@/constants/types" +import { applyClapCompletion } from "@/utils" + +export async function editClapEntities({ + clap, + entityPrompts = [], + completionMode = ClapCompletionMode.MERGE, + turbo = false, + token, +}: { + // A ClapProject instance + clap: ClapProject + + // a list of entity prompts + entityPrompts?: ClapEntityPrompt[], + + /** + * Completion mode (optional, defaults to "merge") + * + * Possible values are: + * - full: the API and the client will return a full clap file. This is a very convenient and simple mode, but it is also very ineficient, so it should not be used for intensive applications. + * - partial: the API and the client will return a partial clap file, containing only the new values and changes. This is useful for real-time applications and streaming. + * - merge: the API will return a partial clap file, and the client will return a merge of the original with the new values. This is safe to run, there are no side-effects. + * - replace: the API will return a partial clap file, and the client will replace the original. This is the most efficient mode, but it relies on side-effects and inline object updates. + */ + completionMode?: ClapCompletionMode + + turbo?: boolean + + token?: string +}): Promise { + + if (!clap) { throw new Error(`please provide a clap to extend`) } + + const hasToken = typeof token === "string" && token.length > 0 + + const params: Record = {} + + if (typeof completionMode === "string") { + params.c = completionMode + } + + if (turbo) { + params.t = "true" + } + + if (entityPrompts.length) { + // if "params.e = JSON.stringify(item)" works with UTF-8 characters, + // then we don't need to import "js-base64" + // otherwise you will have to do: + // params.e = jsBase64.encode(JSON.stringify(item)) + params.e = JSON.stringify(entityPrompts) + } + + const newClap = await fetchClap( + `${aitubeApiUrl}edit/entities?${queryString.stringify(params)}`, { + method: "POST", + headers: { + "Content-Type": "application/x-gzip", + ...hasToken && { + "Authorization": `Bearer ${token}` + } + }, + body: await serializeClap(removeGeneratedAssetUrls(clap)), + cache: "no-store", + }) + + const result = await applyClapCompletion(clap, newClap, completionMode) + + return result +} \ No newline at end of file diff --git a/packages/api-client/src/api/editClapMusic.ts b/packages/api-client/src/api/editClapMusic.ts new file mode 100644 index 0000000000000000000000000000000000000000..66861f50b30d4cafd9decf2d1b491379d392f337 --- /dev/null +++ b/packages/api-client/src/api/editClapMusic.ts @@ -0,0 +1,60 @@ +import queryString from "query-string" +import { ClapCompletionMode, ClapProject, fetchClap, serializeClap, removeGeneratedAssetUrls } from "@aitube/clap" + +import { aitubeApiUrl } from "@/constants/config" +import { applyClapCompletion } from "@/utils" + +export async function editClapMusic({ + clap, + completionMode = ClapCompletionMode.MERGE, + turbo = false, + token, +}: { + clap: ClapProject + + /** + * Completion mode (optional, defaults to "merge") + * + * Possible values are: + * - full: the API and the client will return a full clap file. This is a very convenient and simple mode, but it is also very ineficient, so it should not be used for intensive applications. + * - partial: the API and the client will return a partial clap file, containing only the new values and changes. This is useful for real-time applications and streaming. + * - merge: the API will return a partial clap file, and the client will return a merge of the original with the new values. This is safe to run, there are no side-effects. + * - replace: the API will return a partial clap file, and the client will replace the original. This is the most efficient mode, but it relies on side-effects and inline object updates. + */ + completionMode?: ClapCompletionMode + + turbo?: boolean + + token?: string +}): Promise { + + if (!clap) { throw new Error(`please provide a valid clap project`) } + + const hasToken = typeof token === "string" && token.length > 0 + + const params: Record = {} + + if (typeof completionMode === "string") { + params.c = completionMode + } + + if (turbo) { + params.t = "true" + } + + const newClap = await fetchClap(`${aitubeApiUrl}edit/music?${queryString.stringify(params)}`, { + method: "POST", + headers: { + "Content-Type": "application/x-gzip", + ...hasToken && { + "Authorization": `Bearer ${token}` + } + }, + body: await serializeClap(removeGeneratedAssetUrls(clap)), + cache: "no-store", + }) + + const result = await applyClapCompletion(clap, newClap, completionMode) + + return result +} \ No newline at end of file diff --git a/packages/api-client/src/api/editClapSounds.ts b/packages/api-client/src/api/editClapSounds.ts new file mode 100644 index 0000000000000000000000000000000000000000..316f892ae8f1f45c6450806ed14e8ee448fe41cd --- /dev/null +++ b/packages/api-client/src/api/editClapSounds.ts @@ -0,0 +1,60 @@ +import queryString from "query-string" +import { ClapCompletionMode, ClapProject, fetchClap, serializeClap, removeGeneratedAssetUrls } from "@aitube/clap" + +import { aitubeApiUrl } from "@/constants/config" +import { applyClapCompletion } from "@/utils" + +export async function editClapSounds({ + clap, + completionMode = ClapCompletionMode.MERGE, + turbo = false, + token, +}: { + clap: ClapProject + + /** + * Completion mode (optional, defaults to "merge") + * + * Possible values are: + * - full: the API and the client will return a full clap file. This is a very convenient and simple mode, but it is also very ineficient, so it should not be used for intensive applications. + * - partial: the API and the client will return a partial clap file, containing only the new values and changes. This is useful for real-time applications and streaming. + * - merge: the API will return a partial clap file, and the client will return a merge of the original with the new values. This is safe to run, there are no side-effects. + * - replace: the API will return a partial clap file, and the client will replace the original. This is the most efficient mode, but it relies on side-effects and inline object updates. + */ + completionMode?: ClapCompletionMode + + turbo?: boolean + + token?: string +}): Promise { + + if (!clap) { throw new Error(`please provide a valid clap project`) } + + const hasToken = typeof token === "string" && token.length > 0 + + const params: Record = {} + + if (typeof completionMode === "string") { + params.c = completionMode + } + + if (turbo) { + params.t = "true" + } + + const newClap = await fetchClap(`${aitubeApiUrl}edit/sounds?${queryString.stringify(params)}`, { + method: "POST", + headers: { + "Content-Type": "application/x-gzip", + ...hasToken && { + "Authorization": `Bearer ${token}` + } + }, + body: await serializeClap(removeGeneratedAssetUrls(clap)), + cache: "no-store", + }) + + const result = await applyClapCompletion(clap, newClap, completionMode) + + return result +} \ No newline at end of file diff --git a/packages/api-client/src/api/editClapStory.ts b/packages/api-client/src/api/editClapStory.ts new file mode 100644 index 0000000000000000000000000000000000000000..2a7abb5aadc35b8dfa25ee9b8fa757eb94aee7f8 --- /dev/null +++ b/packages/api-client/src/api/editClapStory.ts @@ -0,0 +1,114 @@ +import { ClapCompletionMode, ClapProject, fetchClap, filterAssets, isValidNumber, serializeClap, removeGeneratedAssetUrls } from "@aitube/clap" +import queryString from "query-string" + +import { aitubeApiUrl } from "@/constants/config" +import { applyClapCompletion } from "@/utils" + +export async function editClapStory({ + clap, + prompt, + startTimeInMs, + endTimeInMs, + completionMode = ClapCompletionMode.MERGE, + turbo = false, + token, +}: { + // A ClapProject instance + clap: ClapProject + + // a prompt to describe how to extend the story (optional) + prompt?: string + + // indicates where the completion should start in the timeline + // + // this can be used tp jump to arbitrary timestamps + // in the story + // + // if you pick a start time AFTER the current project's end time, + // the project will be extended + // + // default value: the current project's end time + startTimeInMs?: number + + // it is recommended to use a + // end time (eg. startTimeInMs + 12000) + // if left by default, th server will generate + // + // for performance and security reasons, + // the server may enforce a hardcoded limit to bypass what you + // set here, but that is not a big deal because you can pass + // you .clap file again if necessary + // + // default value: no limit (the server will set one) + endTimeInMs?: number + + /** + * Completion mode (optional, defaults to "merge") + * + * Possible values are: + * - full: the API and the client will return a full clap file. This is a very convenient and simple mode, but it is also very ineficient, so it should not be used for intensive applications. + * - partial: the API and the client will return a partial clap file, containing only the new values and changes. This is useful for real-time applications and streaming. + * - merge: the API will return a partial clap file, and the client will return a merge of the original with the new values. This is safe to run, there are no side-effects. + * - replace: the API will return a partial clap file, and the client will replace the original. This is the most efficient mode, but it relies on side-effects and inline object updates. + */ + completionMode?: ClapCompletionMode + + turbo?: boolean + + token?: string +}): Promise { + + if (!clap) { throw new Error(`please provide a clap to extend`) } + + const hasToken = typeof token === "string" && token.length > 0 + + const params: Record = {} + + if (typeof completionMode === "string") { + params.c = completionMode + } + + if (typeof prompt === "string" && prompt.length > 0) { + params.p = prompt + } + + if (isValidNumber(startTimeInMs)) { + params.s = startTimeInMs + } + + if (isValidNumber(endTimeInMs)) { + params.e = endTimeInMs + } + + if (turbo) { + params.t = "true" + } + + // we remove heavy elements from the payload + const payload = await filterAssets({ + clap, + mode: "INCLUDE", + categories: {}, + immutable: true, // to create a standalone copy + + // we only remove the data, but we still keep things marked as "generated" + updateStatus: false, + }) + + const newClap = await fetchClap( + `${aitubeApiUrl}edit/story?${queryString.stringify(params)}`, { + method: "POST", + headers: { + "Content-Type": "application/x-gzip", + ...hasToken && { + "Authorization": `Bearer ${token}` + } + }, + body: await serializeClap(removeGeneratedAssetUrls(clap)), + cache: "no-store", + }) + + const result = await applyClapCompletion(clap, newClap, completionMode) + + return result +} \ No newline at end of file diff --git a/packages/api-client/src/api/editClapStoryboards.ts b/packages/api-client/src/api/editClapStoryboards.ts new file mode 100644 index 0000000000000000000000000000000000000000..2f5964415bc37eb377b96198c5be671605336dfe --- /dev/null +++ b/packages/api-client/src/api/editClapStoryboards.ts @@ -0,0 +1,60 @@ +import queryString from "query-string" +import { ClapCompletionMode, ClapProject, fetchClap, serializeClap, removeGeneratedAssetUrls } from "@aitube/clap" + +import { aitubeApiUrl } from "@/constants/config" +import { applyClapCompletion } from "@/utils" + +export async function editClapStoryboards({ + clap, + completionMode = ClapCompletionMode.MERGE, + turbo = false, + token, +}: { + clap: ClapProject + + /** + * Completion mode (optional, defaults to "merge") + * + * Possible values are: + * - full: the API and the client will return a full clap file. This is a very convenient and simple mode, but it is also very ineficient, so it should not be used for intensive applications. + * - partial: the API and the client will return a partial clap file, containing only the new values and changes. This is useful for real-time applications and streaming. + * - merge: the API will return a partial clap file, and the client will return a merge of the original with the new values. This is safe to run, there are no side-effects. + * - replace: the API will return a partial clap file, and the client will replace the original. This is the most efficient mode, but it relies on side-effects and inline object updates. + */ + completionMode?: ClapCompletionMode + + turbo?: boolean + + token?: string +}): Promise { + + if (!clap) { throw new Error(`please provide a valid clap project`) } + + const hasToken = typeof token === "string" && token.length > 0 + + const params: Record = {} + + if (typeof completionMode === "string") { + params.c = completionMode + } + + if (turbo) { + params.t = "true" + } + + const newClap = await fetchClap(`${aitubeApiUrl}edit/storyboards?${queryString.stringify(params)}`, { + method: "POST", + headers: { + "Content-Type": "application/x-gzip", + ...hasToken && { + "Authorization": `Bearer ${token}` + } + }, + body: await serializeClap(removeGeneratedAssetUrls(clap)), + cache: "no-store", + }) + + const result = await applyClapCompletion(clap, newClap, completionMode) + + return result +} \ No newline at end of file diff --git a/packages/api-client/src/api/editClapVideos.ts b/packages/api-client/src/api/editClapVideos.ts new file mode 100644 index 0000000000000000000000000000000000000000..fd596f804a9d92a980a7735de6675ff20be6234c --- /dev/null +++ b/packages/api-client/src/api/editClapVideos.ts @@ -0,0 +1,85 @@ +import queryString from "query-string" +import { ClapCompletionMode, ClapProject, fetchClap, serializeClap, removeGeneratedAssetUrls, ClapSegmentStatus, ClapSegmentCategory, filterSegments, ClapSegmentFilteringMode, ClapSegment } from "@aitube/clap" + +import { aitubeApiUrl } from "@/constants/config" +import { applyClapCompletion } from "@/utils" + +export async function editClapVideos({ + clap, + completionMode = ClapCompletionMode.MERGE, + turbo = false, + token, +}: { + clap: ClapProject + + /** + * Completion mode (optional, defaults to "merge") + * + * Possible values are: + * - full: the API and the client will return a full clap file. This is a very convenient and simple mode, but it is also very ineficient, so it should not be used for intensive applications. + * - partial: the API and the client will return a partial clap file, containing only the new values and changes. This is useful for real-time applications and streaming. + * - merge: the API will return a partial clap file, and the client will return a merge of the original with the new values. This is safe to run, there are no side-effects. + * - replace: the API will return a partial clap file, and the client will replace the original. This is the most efficient mode, but it relies on side-effects and inline object updates. + */ + completionMode?: ClapCompletionMode + + turbo?: boolean + + token?: string +}): Promise { + + if (!clap) { throw new Error(`please provide a valid clap project`) } + + const hasToken = typeof token === "string" && token.length > 0 + + const params: Record = {} + + if (typeof completionMode === "string") { + params.c = completionMode + } + + if (turbo) { + params.t = "true" + } + // special trick to not touch the generated + // storyboards that are used by pending videos + const idsOfStoryboardsToKeep = clap.segments.map((segment: ClapSegment) => { + + const isPendingVideo = ( + segment.category === ClapSegmentCategory.VIDEO + && + segment.status === ClapSegmentStatus.TO_GENERATE + ) + + if (!isPendingVideo) { return undefined } + + const storyboard: ClapSegment | undefined = filterSegments( + ClapSegmentFilteringMode.BOTH, + segment, + clap.segments, + ClapSegmentCategory.STORYBOARD + ).at(0) + + return storyboard?.id + }).filter((x: any) => x) as string[] + + const newClap = await fetchClap(`${aitubeApiUrl}edit/videos?${queryString.stringify(params)}`, { + method: "POST", + headers: { + "Content-Type": "application/x-gzip", + ...hasToken && { + "Authorization": `Bearer ${token}` + } + }, + body: await serializeClap( + // need a special trick here, to not touch the generated + // storyboards that are used by pending videos + removeGeneratedAssetUrls(clap, idsOfStoryboardsToKeep) + ), + cache: "no-store", + }) + + const result = await applyClapCompletion(clap, newClap, completionMode) + + return result +} \ No newline at end of file diff --git a/packages/api-client/src/api/exportClapToVideo.ts b/packages/api-client/src/api/exportClapToVideo.ts new file mode 100644 index 0000000000000000000000000000000000000000..95ac508d251a44d5884aa351809fc313d79982da --- /dev/null +++ b/packages/api-client/src/api/exportClapToVideo.ts @@ -0,0 +1,60 @@ +import queryString from "query-string" +import { ClapProject, serializeClap, blobToDataUri } from "@aitube/clap" + +import { aitubeApiUrl } from "@/constants/config" +import { defaultExportFormat, SupportedExportFormat } from "@/constants" + + +export async function exportClapToVideo({ + clap, + format = defaultExportFormat, + turbo = false, + token, +}: { + clap: ClapProject + + /** + * Desired output video format (defaults to "mp4") + * + * Can be either "mp4" or "webm" + */ + format?: SupportedExportFormat + + turbo?: boolean + + token?: string +}): Promise { + + if (!clap) { throw new Error(`please provide a clap`) } + + // TODO use an enum instead, and check the enum object + if (format !== "mp4" && format !== "webm") { throw new Error(`please provide a valid format ("${format}" is unrecognized)`) } + + const params: Record = {} + + params.f = format + + if (turbo) { + params.t = "true" + } + + const hasToken = typeof token === "string" && token.length > 0 + + const res = await fetch(`${aitubeApiUrl}export?${queryString.stringify(params)}`, { + method: "POST", + headers: { + "Content-Type": "application/x-gzip", + ...hasToken && { + "Authorization": `Bearer ${token}` + } + }, + body: await serializeClap(clap), + cache: "no-store", + }) + + const blob = await res.blob() + + const dataURL = await blobToDataUri(blob) + + return dataURL +} \ No newline at end of file diff --git a/packages/api-client/src/api/index.ts b/packages/api-client/src/api/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..97203e54ace303e397e0d5fb13e163442d2c73a3 --- /dev/null +++ b/packages/api-client/src/api/index.ts @@ -0,0 +1,9 @@ +export { createClap } from "./createClap" +export { editClapDialogues } from "./editClapDialogues" +export { editClapEntities } from "./editClapEntities" +export { editClapMusic } from "./editClapMusic" +export { editClapSounds } from "./editClapSounds" +export { editClapStory } from "./editClapStory" +export { editClapStoryboards } from "./editClapStoryboards" +export { editClapVideos } from "./editClapVideos" +export { exportClapToVideo } from "./exportClapToVideo" diff --git a/packages/api-client/src/constants/config.ts b/packages/api-client/src/constants/config.ts new file mode 100644 index 0000000000000000000000000000000000000000..b775d8870ab5fe8f1f0c6a5f6f9e066aa8bfb905 --- /dev/null +++ b/packages/api-client/src/constants/config.ts @@ -0,0 +1,16 @@ +import { defaultAitubeHostname } from "./defaultValues" + +// we leave the opportunity to override this at runtime +export const aitubeUrl = `${ + process.env.AITUBE_URL || + `https://${defaultAitubeHostname}` +}` + +// note: let's keep it simple and only support one version at a time +export const aitubeApiVersion = "v1" + +export const aitubeApiUrl = `${ + aitubeUrl +}${ + aitubeUrl.endsWith("/") ? "" : "/" +}api/${aitubeApiVersion}/` diff --git a/packages/api-client/src/constants/defaultValues.ts b/packages/api-client/src/constants/defaultValues.ts new file mode 100644 index 0000000000000000000000000000000000000000..0e094b203dfb63886e1abb540483352e05e24cdb --- /dev/null +++ b/packages/api-client/src/constants/defaultValues.ts @@ -0,0 +1,10 @@ +// unfortunately, this doesn't work yet due to a redirection issue +// const defaultAitubeHostname = "aitube.at" + +// so we have to use the direct space hostname instead +export const defaultAitubeHostname = "aitube.at" + +export const defaultClapWidth = 512 +export const defaultClapHeight = 288 + +export const defaultExportFormat = "mp4" \ No newline at end of file diff --git a/packages/api-client/src/constants/index.ts b/packages/api-client/src/constants/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..d4b598a5924212db679b2e339891aae12af0ec00 --- /dev/null +++ b/packages/api-client/src/constants/index.ts @@ -0,0 +1,17 @@ +export { + defaultAitubeHostname, + defaultClapWidth, + defaultClapHeight, + defaultExportFormat +} from './defaultValues' + +export { + aitubeUrl, + aitubeApiVersion, + aitubeApiUrl +} from './config' + +export { + ClapEntityPrompt, + SupportedExportFormat +} from "./types" diff --git a/packages/api-client/src/constants/types.ts b/packages/api-client/src/constants/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..34c2486212c9c2418d2f94b1db5cfbd048cecfd0 --- /dev/null +++ b/packages/api-client/src/constants/types.ts @@ -0,0 +1,25 @@ +import { ClapSegmentCategory } from "@aitube/clap" + +export type SupportedExportFormat = "mp4" | "webm" + +export type ClapEntityPrompt = { + name: string + + // eg. "character", "location" + category: ClapSegmentCategory + + // age of the person, animal or entity (eg. robot, talking spaceship etc) + age: string + + // characterization of the person, animal or entity (texture, hair color, gender etc) + variant: string + + // region from where the person, animal or entity is coming from (human, mechanical, alien planet, european, south-american etc) + region: string + + // identity picture + identityImage: string + + // identity voice + identityVoice: string +} \ No newline at end of file diff --git a/packages/api-client/src/index.ts b/packages/api-client/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..11669efd4d02a8f2e0b3a7f6f2ee5b8e94e50b8d --- /dev/null +++ b/packages/api-client/src/index.ts @@ -0,0 +1,28 @@ + +export { + createClap, + editClapDialogues, + editClapEntities, + editClapMusic, + editClapSounds, + editClapStory, + editClapStoryboards, + editClapVideos, + exportClapToVideo, +} from './api' + +export { + defaultAitubeHostname, + defaultClapWidth, + defaultClapHeight, + defaultExportFormat, + aitubeUrl, + aitubeApiVersion, + aitubeApiUrl, + ClapEntityPrompt, + SupportedExportFormat +} from "./constants" + +export { + applyClapCompletion, +} from "./utils" \ No newline at end of file diff --git a/packages/api-client/src/parsers/index.ts b/packages/api-client/src/parsers/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..f45716f56b36cadaf416f954780cfcc0e1848b2a --- /dev/null +++ b/packages/api-client/src/parsers/index.ts @@ -0,0 +1,3 @@ +export { parseEntityPrompt } from "./parseEntityPrompt" +export { parseString } from "./parseString" +export { parseStringArray } from "./parseStringArray" \ No newline at end of file diff --git a/packages/api-client/src/parsers/parseEntityPrompt.ts b/packages/api-client/src/parsers/parseEntityPrompt.ts new file mode 100644 index 0000000000000000000000000000000000000000..8885946236545c3fa37f3037dc2a5b114c097bc7 --- /dev/null +++ b/packages/api-client/src/parsers/parseEntityPrompt.ts @@ -0,0 +1,30 @@ + + +import { ClapEntityPrompt } from "@/constants/types" + +import { parseString } from "./parseString" +import { ClapSegmentCategory } from "@aitube/clap" + +export function parseEntityPrompt(entityPrompt: Partial = {}): ClapEntityPrompt { + + return { + name: parseString(entityPrompt?.name), + + category: parseString(entityPrompt?.category) as ClapSegmentCategory, + + // age of the person, animal or entity (eg. robot, talking spaceship etc) + age: parseString(entityPrompt?.age), + + // characterization of the person, animal or entity (texture, hair color, gender etc) + variant: parseString(entityPrompt?.variant), + + // region from where the person, animal or entity is coming from (human, mechanical, alien planet, european, south-american etc) + region: parseString(entityPrompt?.region), + + // identity picture + identityImage: parseString(entityPrompt?.identityImage), + + // identity voice + identityVoice: parseString(entityPrompt?.identityVoice), + } +} \ No newline at end of file diff --git a/packages/api-client/src/parsers/parseString.ts b/packages/api-client/src/parsers/parseString.ts new file mode 100644 index 0000000000000000000000000000000000000000..60ea291160d3416ad49b5386372fb3f0bb976974 --- /dev/null +++ b/packages/api-client/src/parsers/parseString.ts @@ -0,0 +1,7 @@ +export function parseString(input?: any, defaultValue?: string): string { + const defValue = `${defaultValue || ""}` + + if (typeof input !== "string") { return defValue } + + return input || defValue +} \ No newline at end of file diff --git a/packages/api-client/src/parsers/parseStringArray.ts b/packages/api-client/src/parsers/parseStringArray.ts new file mode 100644 index 0000000000000000000000000000000000000000..9b3c2e6fdbd1f6a453627c4f9c9d466ddd3a64ac --- /dev/null +++ b/packages/api-client/src/parsers/parseStringArray.ts @@ -0,0 +1,9 @@ +export function parseStringArray(something: any): string[] { + let result: string[] = [] + if (typeof something === "string") { + result = [something] + } else if (Array.isArray(something)) { + result = something.map(thing => typeof thing === "string" ? thing : "").filter(x => x) + } + return result +} \ No newline at end of file diff --git a/packages/api-client/src/utils/applyClapCompletion.ts b/packages/api-client/src/utils/applyClapCompletion.ts new file mode 100644 index 0000000000000000000000000000000000000000..b84e31c41645e17b77c27708fadec719f0b23b0c --- /dev/null +++ b/packages/api-client/src/utils/applyClapCompletion.ts @@ -0,0 +1,21 @@ +import { ClapCompletionMode, ClapProject, updateClap } from "@aitube/clap" + +export async function applyClapCompletion( + existingClap: ClapProject, + newerClap: ClapProject, + clapCompletionMode: ClapCompletionMode +): Promise { + // in both those mode we leave full control to what is inside "newerClap" + if (clapCompletionMode === ClapCompletionMode.FULL || clapCompletionMode === ClapCompletionMode.PARTIAL) { + return newerClap + } + + // else we are in ClapCompletionMode.MERGE or ClapCompletionMode.REPLACE + const result = await updateClap(existingClap, newerClap, { + // the newer clap meta may contain incomplete information + overwriteMeta: false, + inlineReplace: clapCompletionMode === ClapCompletionMode.REPLACE + }) + + return result +} \ No newline at end of file diff --git a/packages/api-client/src/utils/index.ts b/packages/api-client/src/utils/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..8244b256a8f9c21ece2cedf6d2ecf1af392ab4e9 --- /dev/null +++ b/packages/api-client/src/utils/index.ts @@ -0,0 +1 @@ +export { applyClapCompletion } from "./applyClapCompletion" diff --git a/packages/api-client/tsconfig.json b/packages/api-client/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..ab7cc3ed096e5dc51a557fdee4e68c0e28076d0b --- /dev/null +++ b/packages/api-client/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "baseUrl": "./", + "paths": { + "@/*": ["src/*"] + }, + "lib": ["ESNext", "DOM"], + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": true, + "noEmit": true, + "composite": true, + "strict": true, + "downlevelIteration": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "types": [ + "bun-types" + ] + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/packages/api-client/tsconfig.types.json b/packages/api-client/tsconfig.types.json new file mode 100644 index 0000000000000000000000000000000000000000..a6a3f21154bb178f1850c9b70714fb66ef5bf750 --- /dev/null +++ b/packages/api-client/tsconfig.types.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "emitDeclarationOnly": true, + "declaration": true, + "outDir": "./dist", + "rootDir": "./src", + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/.env.example b/packages/app/.env.example similarity index 100% rename from .env.example rename to packages/app/.env.example diff --git a/.eslintrc.json b/packages/app/.eslintrc.json similarity index 100% rename from .eslintrc.json rename to packages/app/.eslintrc.json diff --git a/.gitattributes b/packages/app/.gitattributes similarity index 100% rename from .gitattributes rename to packages/app/.gitattributes diff --git a/packages/app/.gitignore b/packages/app/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e68750957547996c80d72591bd4e594ef44d4fa8 --- /dev/null +++ b/packages/app/.gitignore @@ -0,0 +1,42 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local +.env + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +/sandbox/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/packages/app/.nvmrc b/packages/app/.nvmrc new file mode 100644 index 0000000000000000000000000000000000000000..1efe0ac63e01e3f75d1e57a6c4f8bb3e11a097f8 --- /dev/null +++ b/packages/app/.nvmrc @@ -0,0 +1 @@ +v20.15.1 diff --git a/.prettierrc.json b/packages/app/.prettierrc.json similarity index 100% rename from .prettierrc.json rename to packages/app/.prettierrc.json diff --git a/Dockerfile b/packages/app/Dockerfile similarity index 100% rename from Dockerfile rename to packages/app/Dockerfile diff --git a/packages/app/LICENSE.txt b/packages/app/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..e72bfddabc15be5718a7cc061ac10e47741d8219 --- /dev/null +++ b/packages/app/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/components.json b/packages/app/components.json similarity index 100% rename from components.json rename to packages/app/components.json diff --git a/forge.config.js b/packages/app/forge.config.js similarity index 100% rename from forge.config.js rename to packages/app/forge.config.js diff --git a/main.js b/packages/app/main.js similarity index 100% rename from main.js rename to packages/app/main.js diff --git a/next.config.js b/packages/app/next.config.js similarity index 100% rename from next.config.js rename to packages/app/next.config.js diff --git a/packages/app/package.json b/packages/app/package.json new file mode 100644 index 0000000000000000000000000000000000000000..f8cf45b61bbc24d4aa86220a4bd618011faead82 --- /dev/null +++ b/packages/app/package.json @@ -0,0 +1,195 @@ +{ + "name": "@aitube/clapper", + "version": "0.2.4", + "private": true, + "description": "🎬 Clapper", + "license": "GPL-3.0-only", + "main": "main.js", + "files": [ + "./main.js" + ], + "directories": { + "src:": "./src", + "public:": "./public" + }, + "scripts": { + "dev": "bun run checks && next dev", + "build": "bun run prepare && bun run checks && rm -Rf out && next build && bun run build:copyassets", + "build:ci": "rm -Rf out && bun run prepare && next build && bun run build:copyassets", + "build:copyassets": "cp -R public .next/standalone/public && cp -R .next/static .next/standalone/static", + "prepare": "cp -R ../../node_modules/mediainfo.js/dist/MediaInfoModule.wasm public/wasm/", + "start": "next start", + "start:prod": "node .next/standalone/server.js", + "checks": "bun run format:fix && bun run lint", + "format": "prettier --check --ignore-path .gitignore ./src/", + "format:fix": "prettier --write --ignore-path .gitignore ./src/", + "lint": "next lint", + "lint:fix": "next lint --fix", + "test": "bun run build && bun run test:unit:ci", + "test_TEMPORARY_DISABLED": "bun run build && bun run test:unit:ci && bun run test:e2e", + "test:unit:ci": "vitest run", + "test:unit:watch": "vitest", + "test:e2e": "npx playwright test", + "electron": "bun run build && electron .", + "electron:start": "bun run build && electron-forge start", + "electron:package": "bun run build && electron-forge package", + "electron:make": "bun run build && electron-forge make" + }, + "dependencies": { + "@aitube/api-client": "workspace:*", + "@aitube/broadway": "workspace:*", + "@aitube/clap": "workspace:*", + "@aitube/clapper-services": "workspace:*", + "@aitube/engine": "workspace:*", + "@aitube/timeline": "workspace:*", + "@fal-ai/serverless-client": "^0.13.0", + "@ffmpeg/ffmpeg": "^0.12.10", + "@ffmpeg/util": "^0.12.1", + "@gradio/client": "^1.5.0", + "@huggingface/hub": "^0.15.1", + "@huggingface/inference": "^2.8.0", + "@langchain/anthropic": "^0.2.14", + "@langchain/cohere": "^0.2.2", + "@langchain/core": "^0.2.23", + "@langchain/google-vertexai": "^0.0.25", + "@langchain/groq": "^0.0.16", + "@langchain/mistralai": "^0.0.28", + "@langchain/openai": "^0.2.6", + "@monaco-editor/react": "^4.6.0", + "@radix-ui/react-accordion": "^1.1.2", + "@radix-ui/react-avatar": "^1.0.4", + "@radix-ui/react-checkbox": "^1.0.4", + "@radix-ui/react-collapsible": "^1.0.3", + "@radix-ui/react-dialog": "^1.1.1", + "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-menubar": "^1.0.4", + "@radix-ui/react-popover": "^1.0.7", + "@radix-ui/react-progress": "^1.0.3", + "@radix-ui/react-scroll-area": "^1.0.5", + "@radix-ui/react-select": "^2.0.0", + "@radix-ui/react-separator": "^1.0.3", + "@radix-ui/react-slider": "^1.1.2", + "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-switch": "^1.0.3", + "@radix-ui/react-tabs": "^1.0.4", + "@radix-ui/react-toast": "^1.1.5", + "@radix-ui/react-tooltip": "^1.0.7", + "@react-spring/three": "^9.7.3", + "@react-spring/types": "^9.7.3", + "@react-three/drei": "^9.106.0", + "@react-three/fiber": "^8.16.6", + "@react-three/uikit": "^0.3.4", + "@react-three/uikit-lucide": "^0.3.4", + "@saintno/comfyui-sdk": "^0.1.11", + "@tailwindcss/container-queries": "^0.1.1", + "@types/dom-speech-recognition": "^0.0.4", + "@types/pngjs": "^6.0.5", + "@xenova/transformers": "github:xenova/transformers.js#v3", + "@xyflow/react": "^12.0.3", + "autoprefixer": "10.4.19", + "base64-arraybuffer": "^1.0.2", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "cmdk": "^0.2.1", + "comfydeploy": "^0.0.21", + "date-fns": "^3.6.0", + "dotenv": "^16.4.5", + "fflate": "^0.8.2", + "fluent-ffmpeg": "^2.1.3", + "framer-motion": "11.1.7", + "fs-extra": "^11.2.0", + "is-hotkey": "^0.2.0", + "lucide-react": "^0.396.0", + "mediainfo.js": "^0.3.2", + "mlt-xml": "^2.0.2", + "monaco-editor": "^0.50.0", + "next": "^14.2.5", + "next-themes": "^0.3.0", + "pngjs": "^7.0.0", + "qs": "^6.12.1", + "query-string": "^9.0.0", + "react": "^18.3.1", + "react-device-frameset": "^1.3.4", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", + "react-dom": "^18.3.1", + "react-drag-drop-files": "^2.3.10", + "react-error-boundary": "^4.0.13", + "react-hook-consent": "^3.5.3", + "react-hotkeys-hook": "^4.5.0", + "react-icons": "^5.2.1", + "react-markdown": "^9.0.1", + "react-reflex": "^4.2.6", + "react-speakup": "^1.0.0", + "remark-gfm": "^4.0.0", + "replicate": "^0.32.0", + "sharp": "0.33.4", + "sonner": "^1.5.0", + "tailwind-merge": "^2.5.2", + "tailwindcss-animate": "^1.0.7", + "three": "^0.164.1", + "ts-node": "^10.9.2", + "use-file-picker": "^2.1.2", + "usehooks-ts": "^2.14.0", + "uuid": "^9.0.1", + "web-audio-beat-detector": "^8.2.12", + "yaml": "^2.4.5", + "zustand": "4.5.2", + "zx": "^8.1.4" + }, + "devDependencies": { + "@electron-forge/cli": "^7.4.0", + "@electron-forge/maker-deb": "^7.4.0", + "@electron-forge/maker-dmg": "^7.4.0", + "@electron-forge/maker-rpm": "^7.4.0", + "@electron-forge/maker-squirrel": "^7.4.0", + "@electron-forge/maker-zip": "^7.4.0", + "@electron-forge/plugin-auto-unpack-natives": "^7.4.0", + "@electron-forge/publisher-github": "^7.4.0", + "@playwright/test": "^1.45.1", + "@testing-library/react": "^16.0.0", + "@types/fluent-ffmpeg": "^2.1.24", + "@types/is-hotkey": "^0.1.10", + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "@types/uuid": "^9.0.8", + "@vitejs/plugin-react": "^4.3.1", + "@webgpu/types": "^0.1.44", + "electron": "^31.2.1", + "eslint": "^8", + "eslint-config-next": "14.2.5", + "eslint-config-prettier": "^9.1.0", + "jsdom": "^24.1.0", + "node-gyp": "^10.2.0", + "postcss": "^8", + "prettier": "^3.3.3", + "prettier-plugin-tailwindcss": "^0.6.5", + "tailwind-scrollbar": "^3.1.0", + "tailwindcss": "^3.4.3", + "typescript": "^5.5.0", + "vitest": "^2.0.2" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.4", + "@img/sharp-darwin-x64": "0.33.4", + "@img/sharp-libvips-darwin-arm64": "1.0.2", + "@img/sharp-libvips-darwin-x64": "1.0.2", + "@img/sharp-libvips-linux-arm": "1.0.2", + "@img/sharp-libvips-linux-arm64": "1.0.2", + "@img/sharp-libvips-linux-x64": "1.0.2", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.2", + "@img/sharp-libvips-linuxmusl-x64": "1.0.2", + "@img/sharp-libvips-win32-ia32": "1.0.2", + "@img/sharp-libvips-win32-x64": "1.0.2", + "@img/sharp-linux-arm": "0.33.4", + "@img/sharp-linux-arm64": "0.33.4", + "@img/sharp-linux-x64": "0.33.4", + "@img/sharp-linuxmusl-arm64": "0.33.4", + "@img/sharp-linuxmusl-x64": "0.33.4", + "@img/sharp-win32-ia32": "0.33.4", + "@img/sharp-win32-x64": "0.33.4" + } +} diff --git a/playwright.config.ts b/packages/app/playwright.config.ts similarity index 100% rename from playwright.config.ts rename to packages/app/playwright.config.ts diff --git a/postcss.config.js b/packages/app/postcss.config.js similarity index 100% rename from postcss.config.js rename to packages/app/postcss.config.js diff --git a/public/.gitattributes b/packages/app/public/.gitattributes similarity index 100% rename from public/.gitattributes rename to packages/app/public/.gitattributes diff --git a/public/carriers/README.md b/packages/app/public/carriers/README.md similarity index 100% rename from public/carriers/README.md rename to packages/app/public/carriers/README.md diff --git a/public/datasets/baby-names-us-year-of-birth-full.csv b/packages/app/public/datasets/baby-names-us-year-of-birth-full.csv similarity index 100% rename from public/datasets/baby-names-us-year-of-birth-full.csv rename to packages/app/public/datasets/baby-names-us-year-of-birth-full.csv diff --git a/public/images/icons/interface/character.svg b/packages/app/public/images/icons/interface/character.svg similarity index 100% rename from public/images/icons/interface/character.svg rename to packages/app/public/images/icons/interface/character.svg diff --git a/public/images/icons/interface/characters.svg b/packages/app/public/images/icons/interface/characters.svg similarity index 100% rename from public/images/icons/interface/characters.svg rename to packages/app/public/images/icons/interface/characters.svg diff --git a/public/images/icons/interface/cloud.svg b/packages/app/public/images/icons/interface/cloud.svg similarity index 100% rename from public/images/icons/interface/cloud.svg rename to packages/app/public/images/icons/interface/cloud.svg diff --git a/public/images/icons/interface/community.svg b/packages/app/public/images/icons/interface/community.svg similarity index 100% rename from public/images/icons/interface/community.svg rename to packages/app/public/images/icons/interface/community.svg diff --git a/public/images/icons/interface/computer.svg b/packages/app/public/images/icons/interface/computer.svg similarity index 100% rename from public/images/icons/interface/computer.svg rename to packages/app/public/images/icons/interface/computer.svg diff --git a/public/images/icons/interface/cut.svg b/packages/app/public/images/icons/interface/cut.svg similarity index 100% rename from public/images/icons/interface/cut.svg rename to packages/app/public/images/icons/interface/cut.svg diff --git a/public/images/icons/interface/downloads.svg b/packages/app/public/images/icons/interface/downloads.svg similarity index 100% rename from public/images/icons/interface/downloads.svg rename to packages/app/public/images/icons/interface/downloads.svg diff --git a/public/images/icons/interface/film.svg b/packages/app/public/images/icons/interface/film.svg similarity index 100% rename from public/images/icons/interface/film.svg rename to packages/app/public/images/icons/interface/film.svg diff --git a/public/images/icons/interface/hidden.svg b/packages/app/public/images/icons/interface/hidden.svg similarity index 100% rename from public/images/icons/interface/hidden.svg rename to packages/app/public/images/icons/interface/hidden.svg diff --git a/public/images/icons/interface/image-to-image.svg b/packages/app/public/images/icons/interface/image-to-image.svg similarity index 100% rename from public/images/icons/interface/image-to-image.svg rename to packages/app/public/images/icons/interface/image-to-image.svg diff --git a/public/images/icons/interface/image.svg b/packages/app/public/images/icons/interface/image.svg similarity index 100% rename from public/images/icons/interface/image.svg rename to packages/app/public/images/icons/interface/image.svg diff --git a/public/images/icons/interface/imagefile.svg b/packages/app/public/images/icons/interface/imagefile.svg similarity index 100% rename from public/images/icons/interface/imagefile.svg rename to packages/app/public/images/icons/interface/imagefile.svg diff --git a/public/images/icons/interface/interpolate.svg b/packages/app/public/images/icons/interface/interpolate.svg similarity index 100% rename from public/images/icons/interface/interpolate.svg rename to packages/app/public/images/icons/interface/interpolate.svg diff --git a/public/images/icons/interface/location.svg b/packages/app/public/images/icons/interface/location.svg similarity index 100% rename from public/images/icons/interface/location.svg rename to packages/app/public/images/icons/interface/location.svg diff --git a/public/images/icons/interface/lora.svg b/packages/app/public/images/icons/interface/lora.svg similarity index 100% rename from public/images/icons/interface/lora.svg rename to packages/app/public/images/icons/interface/lora.svg diff --git a/public/images/icons/interface/misc.svg b/packages/app/public/images/icons/interface/misc.svg similarity index 100% rename from public/images/icons/interface/misc.svg rename to packages/app/public/images/icons/interface/misc.svg diff --git a/public/images/icons/interface/mute.svg b/packages/app/public/images/icons/interface/mute.svg similarity index 100% rename from public/images/icons/interface/mute.svg rename to packages/app/public/images/icons/interface/mute.svg diff --git a/public/images/icons/interface/project.svg b/packages/app/public/images/icons/interface/project.svg similarity index 100% rename from public/images/icons/interface/project.svg rename to packages/app/public/images/icons/interface/project.svg diff --git a/public/images/icons/interface/prompt.svg b/packages/app/public/images/icons/interface/prompt.svg similarity index 100% rename from public/images/icons/interface/prompt.svg rename to packages/app/public/images/icons/interface/prompt.svg diff --git a/public/images/icons/interface/screenplay.svg b/packages/app/public/images/icons/interface/screenplay.svg similarity index 100% rename from public/images/icons/interface/screenplay.svg rename to packages/app/public/images/icons/interface/screenplay.svg diff --git a/public/images/icons/interface/sound.svg b/packages/app/public/images/icons/interface/sound.svg similarity index 100% rename from public/images/icons/interface/sound.svg rename to packages/app/public/images/icons/interface/sound.svg diff --git a/public/images/icons/interface/soundfile.svg b/packages/app/public/images/icons/interface/soundfile.svg similarity index 100% rename from public/images/icons/interface/soundfile.svg rename to packages/app/public/images/icons/interface/soundfile.svg diff --git a/public/images/icons/interface/speech.svg b/packages/app/public/images/icons/interface/speech.svg similarity index 100% rename from public/images/icons/interface/speech.svg rename to packages/app/public/images/icons/interface/speech.svg diff --git a/public/images/icons/interface/team.svg b/packages/app/public/images/icons/interface/team.svg similarity index 100% rename from public/images/icons/interface/team.svg rename to packages/app/public/images/icons/interface/team.svg diff --git a/public/images/icons/interface/text-to-music.svg b/packages/app/public/images/icons/interface/text-to-music.svg similarity index 100% rename from public/images/icons/interface/text-to-music.svg rename to packages/app/public/images/icons/interface/text-to-music.svg diff --git a/public/images/icons/interface/text-to-video.svg b/packages/app/public/images/icons/interface/text-to-video.svg similarity index 100% rename from public/images/icons/interface/text-to-video.svg rename to packages/app/public/images/icons/interface/text-to-video.svg diff --git a/public/images/icons/interface/textfile.svg b/packages/app/public/images/icons/interface/textfile.svg similarity index 100% rename from public/images/icons/interface/textfile.svg rename to packages/app/public/images/icons/interface/textfile.svg diff --git a/public/images/icons/interface/transfer.svg b/packages/app/public/images/icons/interface/transfer.svg similarity index 100% rename from public/images/icons/interface/transfer.svg rename to packages/app/public/images/icons/interface/transfer.svg diff --git a/public/images/icons/interface/transition.svg b/packages/app/public/images/icons/interface/transition.svg similarity index 100% rename from public/images/icons/interface/transition.svg rename to packages/app/public/images/icons/interface/transition.svg diff --git a/public/images/icons/interface/unpute.svg b/packages/app/public/images/icons/interface/unpute.svg similarity index 100% rename from public/images/icons/interface/unpute.svg rename to packages/app/public/images/icons/interface/unpute.svg diff --git a/public/images/icons/interface/upscale.svg b/packages/app/public/images/icons/interface/upscale.svg similarity index 100% rename from public/images/icons/interface/upscale.svg rename to packages/app/public/images/icons/interface/upscale.svg diff --git a/public/images/icons/interface/vendor.svg b/packages/app/public/images/icons/interface/vendor.svg similarity index 100% rename from public/images/icons/interface/vendor.svg rename to packages/app/public/images/icons/interface/vendor.svg diff --git a/public/images/icons/interface/video-folder.svg b/packages/app/public/images/icons/interface/video-folder.svg similarity index 100% rename from public/images/icons/interface/video-folder.svg rename to packages/app/public/images/icons/interface/video-folder.svg diff --git a/public/images/icons/interface/video-to-video.svg b/packages/app/public/images/icons/interface/video-to-video.svg similarity index 100% rename from public/images/icons/interface/video-to-video.svg rename to packages/app/public/images/icons/interface/video-to-video.svg diff --git a/public/images/icons/interface/videofile.svg b/packages/app/public/images/icons/interface/videofile.svg similarity index 100% rename from public/images/icons/interface/videofile.svg rename to packages/app/public/images/icons/interface/videofile.svg diff --git a/public/images/icons/interface/visible.svg b/packages/app/public/images/icons/interface/visible.svg similarity index 100% rename from public/images/icons/interface/visible.svg rename to packages/app/public/images/icons/interface/visible.svg diff --git a/public/images/icons/segments/action.svg b/packages/app/public/images/icons/segments/action.svg similarity index 100% rename from public/images/icons/segments/action.svg rename to packages/app/public/images/icons/segments/action.svg diff --git a/public/images/icons/segments/camera.svg b/packages/app/public/images/icons/segments/camera.svg similarity index 100% rename from public/images/icons/segments/camera.svg rename to packages/app/public/images/icons/segments/camera.svg diff --git a/public/images/icons/segments/character.svg b/packages/app/public/images/icons/segments/character.svg similarity index 100% rename from public/images/icons/segments/character.svg rename to packages/app/public/images/icons/segments/character.svg diff --git a/public/images/icons/segments/depth.svg b/packages/app/public/images/icons/segments/depth.svg similarity index 100% rename from public/images/icons/segments/depth.svg rename to packages/app/public/images/icons/segments/depth.svg diff --git a/public/images/icons/segments/dialogue.svg b/packages/app/public/images/icons/segments/dialogue.svg similarity index 100% rename from public/images/icons/segments/dialogue.svg rename to packages/app/public/images/icons/segments/dialogue.svg diff --git a/public/images/icons/segments/effect.svg b/packages/app/public/images/icons/segments/effect.svg similarity index 100% rename from public/images/icons/segments/effect.svg rename to packages/app/public/images/icons/segments/effect.svg diff --git a/public/images/icons/segments/era.svg b/packages/app/public/images/icons/segments/era.svg similarity index 100% rename from public/images/icons/segments/era.svg rename to packages/app/public/images/icons/segments/era.svg diff --git a/public/images/icons/segments/event.svg b/packages/app/public/images/icons/segments/event.svg similarity index 100% rename from public/images/icons/segments/event.svg rename to packages/app/public/images/icons/segments/event.svg diff --git a/public/images/icons/segments/generic.svg b/packages/app/public/images/icons/segments/generic.svg similarity index 100% rename from public/images/icons/segments/generic.svg rename to packages/app/public/images/icons/segments/generic.svg diff --git a/public/images/icons/segments/interface.svg b/packages/app/public/images/icons/segments/interface.svg similarity index 100% rename from public/images/icons/segments/interface.svg rename to packages/app/public/images/icons/segments/interface.svg diff --git a/public/images/icons/segments/lighting.svg b/packages/app/public/images/icons/segments/lighting.svg similarity index 100% rename from public/images/icons/segments/lighting.svg rename to packages/app/public/images/icons/segments/lighting.svg diff --git a/public/images/icons/segments/location.svg b/packages/app/public/images/icons/segments/location.svg similarity index 100% rename from public/images/icons/segments/location.svg rename to packages/app/public/images/icons/segments/location.svg diff --git a/public/images/icons/segments/mesh.svg b/packages/app/public/images/icons/segments/mesh.svg similarity index 100% rename from public/images/icons/segments/mesh.svg rename to packages/app/public/images/icons/segments/mesh.svg diff --git a/public/images/icons/segments/music.svg b/packages/app/public/images/icons/segments/music.svg similarity index 100% rename from public/images/icons/segments/music.svg rename to packages/app/public/images/icons/segments/music.svg diff --git a/public/images/icons/segments/phenomenon.svg b/packages/app/public/images/icons/segments/phenomenon.svg similarity index 100% rename from public/images/icons/segments/phenomenon.svg rename to packages/app/public/images/icons/segments/phenomenon.svg diff --git a/public/images/icons/segments/sound.svg b/packages/app/public/images/icons/segments/sound.svg similarity index 100% rename from public/images/icons/segments/sound.svg rename to packages/app/public/images/icons/segments/sound.svg diff --git a/public/images/icons/segments/splat.svg b/packages/app/public/images/icons/segments/splat.svg similarity index 100% rename from public/images/icons/segments/splat.svg rename to packages/app/public/images/icons/segments/splat.svg diff --git a/public/images/icons/segments/storyboard.svg b/packages/app/public/images/icons/segments/storyboard.svg similarity index 100% rename from public/images/icons/segments/storyboard.svg rename to packages/app/public/images/icons/segments/storyboard.svg diff --git a/public/images/icons/segments/style.svg b/packages/app/public/images/icons/segments/style.svg similarity index 100% rename from public/images/icons/segments/style.svg rename to packages/app/public/images/icons/segments/style.svg diff --git a/public/images/icons/segments/time.svg b/packages/app/public/images/icons/segments/time.svg similarity index 100% rename from public/images/icons/segments/time.svg rename to packages/app/public/images/icons/segments/time.svg diff --git a/public/images/icons/segments/transition.svg b/packages/app/public/images/icons/segments/transition.svg similarity index 100% rename from public/images/icons/segments/transition.svg rename to packages/app/public/images/icons/segments/transition.svg diff --git a/public/images/icons/segments/video.svg b/packages/app/public/images/icons/segments/video.svg similarity index 100% rename from public/images/icons/segments/video.svg rename to packages/app/public/images/icons/segments/video.svg diff --git a/public/images/icons/segments/weather.svg b/packages/app/public/images/icons/segments/weather.svg similarity index 100% rename from public/images/icons/segments/weather.svg rename to packages/app/public/images/icons/segments/weather.svg diff --git a/public/images/logos/CL.icns b/packages/app/public/images/logos/CL.icns similarity index 100% rename from public/images/logos/CL.icns rename to packages/app/public/images/logos/CL.icns diff --git a/public/images/logos/CL.iconset/icon_128x128.png b/packages/app/public/images/logos/CL.iconset/icon_128x128.png similarity index 100% rename from public/images/logos/CL.iconset/icon_128x128.png rename to packages/app/public/images/logos/CL.iconset/icon_128x128.png diff --git a/public/images/logos/CL.iconset/icon_128x128@2x.png b/packages/app/public/images/logos/CL.iconset/icon_128x128@2x.png similarity index 100% rename from public/images/logos/CL.iconset/icon_128x128@2x.png rename to packages/app/public/images/logos/CL.iconset/icon_128x128@2x.png diff --git a/public/images/logos/CL.iconset/icon_16x16.png b/packages/app/public/images/logos/CL.iconset/icon_16x16.png similarity index 100% rename from public/images/logos/CL.iconset/icon_16x16.png rename to packages/app/public/images/logos/CL.iconset/icon_16x16.png diff --git a/public/images/logos/CL.iconset/icon_16x16@2x.png b/packages/app/public/images/logos/CL.iconset/icon_16x16@2x.png similarity index 100% rename from public/images/logos/CL.iconset/icon_16x16@2x.png rename to packages/app/public/images/logos/CL.iconset/icon_16x16@2x.png diff --git a/public/images/logos/CL.iconset/icon_256x256.png b/packages/app/public/images/logos/CL.iconset/icon_256x256.png similarity index 100% rename from public/images/logos/CL.iconset/icon_256x256.png rename to packages/app/public/images/logos/CL.iconset/icon_256x256.png diff --git a/public/images/logos/CL.iconset/icon_256x256@2x.png b/packages/app/public/images/logos/CL.iconset/icon_256x256@2x.png similarity index 100% rename from public/images/logos/CL.iconset/icon_256x256@2x.png rename to packages/app/public/images/logos/CL.iconset/icon_256x256@2x.png diff --git a/public/images/logos/CL.iconset/icon_32x32.png b/packages/app/public/images/logos/CL.iconset/icon_32x32.png similarity index 100% rename from public/images/logos/CL.iconset/icon_32x32.png rename to packages/app/public/images/logos/CL.iconset/icon_32x32.png diff --git a/public/images/logos/CL.iconset/icon_32x32@2x.png b/packages/app/public/images/logos/CL.iconset/icon_32x32@2x.png similarity index 100% rename from public/images/logos/CL.iconset/icon_32x32@2x.png rename to packages/app/public/images/logos/CL.iconset/icon_32x32@2x.png diff --git a/public/images/logos/CL.iconset/icon_512x512.png b/packages/app/public/images/logos/CL.iconset/icon_512x512.png similarity index 100% rename from public/images/logos/CL.iconset/icon_512x512.png rename to packages/app/public/images/logos/CL.iconset/icon_512x512.png diff --git a/public/images/logos/CL.iconset/icon_512x512@2x.png b/packages/app/public/images/logos/CL.iconset/icon_512x512@2x.png similarity index 100% rename from public/images/logos/CL.iconset/icon_512x512@2x.png rename to packages/app/public/images/logos/CL.iconset/icon_512x512@2x.png diff --git a/public/images/logos/CL.png b/packages/app/public/images/logos/CL.png similarity index 100% rename from public/images/logos/CL.png rename to packages/app/public/images/logos/CL.png diff --git a/public/images/logos/clapper.png b/packages/app/public/images/logos/clapper.png similarity index 100% rename from public/images/logos/clapper.png rename to packages/app/public/images/logos/clapper.png diff --git a/public/images/logos/logo-desaturated.png b/packages/app/public/images/logos/logo-desaturated.png similarity index 100% rename from public/images/logos/logo-desaturated.png rename to packages/app/public/images/logos/logo-desaturated.png diff --git a/public/images/logos/logo-discord-2.png b/packages/app/public/images/logos/logo-discord-2.png similarity index 100% rename from public/images/logos/logo-discord-2.png rename to packages/app/public/images/logos/logo-discord-2.png diff --git a/public/images/logos/logo-discord-3.png b/packages/app/public/images/logos/logo-discord-3.png similarity index 100% rename from public/images/logos/logo-discord-3.png rename to packages/app/public/images/logos/logo-discord-3.png diff --git a/public/images/logos/logo-no-bg.png b/packages/app/public/images/logos/logo-no-bg.png similarity index 100% rename from public/images/logos/logo-no-bg.png rename to packages/app/public/images/logos/logo-no-bg.png diff --git a/public/images/logos/logo-v2.png b/packages/app/public/images/logos/logo-v2.png similarity index 100% rename from public/images/logos/logo-v2.png rename to packages/app/public/images/logos/logo-v2.png diff --git a/public/images/logos/logo-v2.xcf b/packages/app/public/images/logos/logo-v2.xcf similarity index 100% rename from public/images/logos/logo-v2.xcf rename to packages/app/public/images/logos/logo-v2.xcf diff --git a/public/images/onboarding/get-started.png b/packages/app/public/images/onboarding/get-started.png similarity index 100% rename from public/images/onboarding/get-started.png rename to packages/app/public/images/onboarding/get-started.png diff --git a/public/images/onboarding/get-started.xcf b/packages/app/public/images/onboarding/get-started.xcf similarity index 100% rename from public/images/onboarding/get-started.xcf rename to packages/app/public/images/onboarding/get-started.xcf diff --git a/public/images/onboarding/pick-an-example.png b/packages/app/public/images/onboarding/pick-an-example.png similarity index 100% rename from public/images/onboarding/pick-an-example.png rename to packages/app/public/images/onboarding/pick-an-example.png diff --git a/public/images/onboarding/pick-an-example.xcf b/packages/app/public/images/onboarding/pick-an-example.xcf similarity index 100% rename from public/images/onboarding/pick-an-example.xcf rename to packages/app/public/images/onboarding/pick-an-example.xcf diff --git a/public/images/providers/anthropic.png b/packages/app/public/images/providers/anthropic.png similarity index 100% rename from public/images/providers/anthropic.png rename to packages/app/public/images/providers/anthropic.png diff --git a/public/images/providers/cohere.png b/packages/app/public/images/providers/cohere.png similarity index 100% rename from public/images/providers/cohere.png rename to packages/app/public/images/providers/cohere.png diff --git a/public/images/providers/comfyicu.png b/packages/app/public/images/providers/comfyicu.png similarity index 100% rename from public/images/providers/comfyicu.png rename to packages/app/public/images/providers/comfyicu.png diff --git a/public/images/providers/comfyui.png b/packages/app/public/images/providers/comfyui.png similarity index 100% rename from public/images/providers/comfyui.png rename to packages/app/public/images/providers/comfyui.png diff --git a/public/images/providers/elevenlabs.png b/packages/app/public/images/providers/elevenlabs.png similarity index 100% rename from public/images/providers/elevenlabs.png rename to packages/app/public/images/providers/elevenlabs.png diff --git a/public/images/providers/everartai.png b/packages/app/public/images/providers/everartai.png similarity index 100% rename from public/images/providers/everartai.png rename to packages/app/public/images/providers/everartai.png diff --git a/public/images/providers/falai.png b/packages/app/public/images/providers/falai.png similarity index 100% rename from public/images/providers/falai.png rename to packages/app/public/images/providers/falai.png diff --git a/public/images/providers/fireworks.png b/packages/app/public/images/providers/fireworks.png similarity index 100% rename from public/images/providers/fireworks.png rename to packages/app/public/images/providers/fireworks.png diff --git a/public/images/providers/google.png b/packages/app/public/images/providers/google.png similarity index 100% rename from public/images/providers/google.png rename to packages/app/public/images/providers/google.png diff --git a/public/images/providers/groq.png b/packages/app/public/images/providers/groq.png similarity index 100% rename from public/images/providers/groq.png rename to packages/app/public/images/providers/groq.png diff --git a/public/images/providers/hedra.png b/packages/app/public/images/providers/hedra.png similarity index 100% rename from public/images/providers/hedra.png rename to packages/app/public/images/providers/hedra.png diff --git a/public/images/providers/huggingface.png b/packages/app/public/images/providers/huggingface.png similarity index 100% rename from public/images/providers/huggingface.png rename to packages/app/public/images/providers/huggingface.png diff --git a/public/images/providers/kitsai.png b/packages/app/public/images/providers/kitsai.png similarity index 100% rename from public/images/providers/kitsai.png rename to packages/app/public/images/providers/kitsai.png diff --git a/public/images/providers/kuaishou.png b/packages/app/public/images/providers/kuaishou.png similarity index 100% rename from public/images/providers/kuaishou.png rename to packages/app/public/images/providers/kuaishou.png diff --git a/public/images/providers/leonardoai.png b/packages/app/public/images/providers/leonardoai.png similarity index 100% rename from public/images/providers/leonardoai.png rename to packages/app/public/images/providers/leonardoai.png diff --git a/public/images/providers/lumalabs.png b/packages/app/public/images/providers/lumalabs.png similarity index 100% rename from public/images/providers/lumalabs.png rename to packages/app/public/images/providers/lumalabs.png diff --git a/public/images/providers/midjourney.png b/packages/app/public/images/providers/midjourney.png similarity index 100% rename from public/images/providers/midjourney.png rename to packages/app/public/images/providers/midjourney.png diff --git a/public/images/providers/mistralai.png b/packages/app/public/images/providers/mistralai.png similarity index 100% rename from public/images/providers/mistralai.png rename to packages/app/public/images/providers/mistralai.png diff --git a/public/images/providers/modelslab.jpeg b/packages/app/public/images/providers/modelslab.jpeg similarity index 100% rename from public/images/providers/modelslab.jpeg rename to packages/app/public/images/providers/modelslab.jpeg diff --git a/public/images/providers/none.png b/packages/app/public/images/providers/none.png similarity index 100% rename from public/images/providers/none.png rename to packages/app/public/images/providers/none.png diff --git a/public/images/providers/openai.png b/packages/app/public/images/providers/openai.png similarity index 100% rename from public/images/providers/openai.png rename to packages/app/public/images/providers/openai.png diff --git a/public/images/providers/replicate.jpeg b/packages/app/public/images/providers/replicate.jpeg similarity index 100% rename from public/images/providers/replicate.jpeg rename to packages/app/public/images/providers/replicate.jpeg diff --git a/public/images/providers/runwayml.png b/packages/app/public/images/providers/runwayml.png similarity index 100% rename from public/images/providers/runwayml.png rename to packages/app/public/images/providers/runwayml.png diff --git a/public/images/providers/stabilityai.png b/packages/app/public/images/providers/stabilityai.png similarity index 100% rename from public/images/providers/stabilityai.png rename to packages/app/public/images/providers/stabilityai.png diff --git a/public/images/providers/suno.png b/packages/app/public/images/providers/suno.png similarity index 100% rename from public/images/providers/suno.png rename to packages/app/public/images/providers/suno.png diff --git a/public/images/providers/udio.png b/packages/app/public/images/providers/udio.png similarity index 100% rename from public/images/providers/udio.png rename to packages/app/public/images/providers/udio.png diff --git a/public/samples/claps/Afterglow v10 X Rewrite Bryan E. Harris 2023.clap b/packages/app/public/samples/claps/Afterglow v10 X Rewrite Bryan E. Harris 2023.clap similarity index 100% rename from public/samples/claps/Afterglow v10 X Rewrite Bryan E. Harris 2023.clap rename to packages/app/public/samples/claps/Afterglow v10 X Rewrite Bryan E. Harris 2023.clap diff --git a/public/samples/claps/empty_project.clap b/packages/app/public/samples/claps/empty_project.clap similarity index 100% rename from public/samples/claps/empty_project.clap rename to packages/app/public/samples/claps/empty_project.clap diff --git a/public/samples/claps/empty_project.yaml b/packages/app/public/samples/claps/empty_project.yaml similarity index 100% rename from public/samples/claps/empty_project.yaml rename to packages/app/public/samples/claps/empty_project.yaml diff --git a/public/samples/claps/test.clap b/packages/app/public/samples/claps/test.clap similarity index 100% rename from public/samples/claps/test.clap rename to packages/app/public/samples/claps/test.clap diff --git a/public/samples/claps/wasteland.clap b/packages/app/public/samples/claps/wasteland.clap similarity index 100% rename from public/samples/claps/wasteland.clap rename to packages/app/public/samples/claps/wasteland.clap diff --git a/public/samples/scripts/Citizen Kane.txt b/packages/app/public/samples/scripts/Citizen Kane.txt similarity index 100% rename from public/samples/scripts/Citizen Kane.txt rename to packages/app/public/samples/scripts/Citizen Kane.txt diff --git a/public/samples/scripts/DISCLAIMER.md b/packages/app/public/samples/scripts/DISCLAIMER.md similarity index 100% rename from public/samples/scripts/DISCLAIMER.md rename to packages/app/public/samples/scripts/DISCLAIMER.md diff --git a/public/samples/scripts/Raiders of the Lost Ark.txt b/packages/app/public/samples/scripts/Raiders of the Lost Ark.txt similarity index 100% rename from public/samples/scripts/Raiders of the Lost Ark.txt rename to packages/app/public/samples/scripts/Raiders of the Lost Ark.txt diff --git a/public/samples/scripts/Rear Window.txt b/packages/app/public/samples/scripts/Rear Window.txt similarity index 100% rename from public/samples/scripts/Rear Window.txt rename to packages/app/public/samples/scripts/Rear Window.txt diff --git a/public/samples/scripts/Star Wars A New Hope.txt b/packages/app/public/samples/scripts/Star Wars A New Hope.txt similarity index 100% rename from public/samples/scripts/Star Wars A New Hope.txt rename to packages/app/public/samples/scripts/Star Wars A New Hope.txt diff --git a/public/samples/scripts/The Apery.txt b/packages/app/public/samples/scripts/The Apery.txt similarity index 100% rename from public/samples/scripts/The Apery.txt rename to packages/app/public/samples/scripts/The Apery.txt diff --git a/public/samples/scripts/The Goonies.txt b/packages/app/public/samples/scripts/The Goonies.txt similarity index 100% rename from public/samples/scripts/The Goonies.txt rename to packages/app/public/samples/scripts/The Goonies.txt diff --git a/public/samples/scripts/The Wizard Of Oz.txt b/packages/app/public/samples/scripts/The Wizard Of Oz.txt similarity index 100% rename from public/samples/scripts/The Wizard Of Oz.txt rename to packages/app/public/samples/scripts/The Wizard Of Oz.txt diff --git a/public/voices/README.md b/packages/app/public/voices/README.md similarity index 100% rename from public/voices/README.md rename to packages/app/public/voices/README.md diff --git a/public/wasm/MediaInfoModule.wasm b/packages/app/public/wasm/MediaInfoModule.wasm similarity index 100% rename from public/wasm/MediaInfoModule.wasm rename to packages/app/public/wasm/MediaInfoModule.wasm diff --git a/public/workers/captioning.worker.js b/packages/app/public/workers/captioning.worker.js similarity index 100% rename from public/workers/captioning.worker.js rename to packages/app/public/workers/captioning.worker.js diff --git a/src/app/api/assistant/askAnyAssistant.ts b/packages/app/src/app/api/assistant/askAnyAssistant.ts similarity index 99% rename from src/app/api/assistant/askAnyAssistant.ts rename to packages/app/src/app/api/assistant/askAnyAssistant.ts index 04718e527261b53dce4b51aa543dc9945fe35998..4c0a7aaace9c3d2ed06e7e27dacfc8ba6b1f9adb 100644 --- a/src/app/api/assistant/askAnyAssistant.ts +++ b/packages/app/src/app/api/assistant/askAnyAssistant.ts @@ -202,7 +202,7 @@ export async function askAnyAssistant({ }) // console.log('Lanchain success on the first time! rawResponse:', rawResponse) - assistantMessage = parseLangChainResponse(rawResponse) + assistantMessage = parseLangChainResponse(rawResponse as any) // console.log('assistantMessage:', assistantMessage) } catch (err) { // LangChain failure (this happens quite often, actually) diff --git a/src/app/api/assistant/parseLangChainResponse.ts b/packages/app/src/app/api/assistant/parseLangChainResponse.ts similarity index 100% rename from src/app/api/assistant/parseLangChainResponse.ts rename to packages/app/src/app/api/assistant/parseLangChainResponse.ts diff --git a/src/app/api/assistant/parser.ts b/packages/app/src/app/api/assistant/parser.ts similarity index 100% rename from src/app/api/assistant/parser.ts rename to packages/app/src/app/api/assistant/parser.ts diff --git a/src/app/api/assistant/providers/google/README.md b/packages/app/src/app/api/assistant/providers/google/README.md similarity index 100% rename from src/app/api/assistant/providers/google/README.md rename to packages/app/src/app/api/assistant/providers/google/README.md diff --git a/src/app/api/assistant/providers/google/sample.txt b/packages/app/src/app/api/assistant/providers/google/sample.txt similarity index 100% rename from src/app/api/assistant/providers/google/sample.txt rename to packages/app/src/app/api/assistant/providers/google/sample.txt diff --git a/src/app/api/assistant/route.ts b/packages/app/src/app/api/assistant/route.ts similarity index 100% rename from src/app/api/assistant/route.ts rename to packages/app/src/app/api/assistant/route.ts diff --git a/src/app/api/assistant/samples.ts b/packages/app/src/app/api/assistant/samples.ts similarity index 100% rename from src/app/api/assistant/samples.ts rename to packages/app/src/app/api/assistant/samples.ts diff --git a/src/app/api/assistant/templates.ts b/packages/app/src/app/api/assistant/templates.ts similarity index 100% rename from src/app/api/assistant/templates.ts rename to packages/app/src/app/api/assistant/templates.ts diff --git a/src/app/api/resolve/providers/aitube/README.md b/packages/app/src/app/api/resolve/providers/aitube/README.md similarity index 100% rename from src/app/api/resolve/providers/aitube/README.md rename to packages/app/src/app/api/resolve/providers/aitube/README.md diff --git a/src/app/api/resolve/providers/aitube/index.ts b/packages/app/src/app/api/resolve/providers/aitube/index.ts similarity index 99% rename from src/app/api/resolve/providers/aitube/index.ts rename to packages/app/src/app/api/resolve/providers/aitube/index.ts index 11879347b22e6c08edc7c767a4d36dd65758e7ff..f8454e39563ac2aabab5177b2b65dbb00bf4dfe5 100644 --- a/src/app/api/resolve/providers/aitube/index.ts +++ b/packages/app/src/app/api/resolve/providers/aitube/index.ts @@ -12,7 +12,7 @@ import { editClapSounds, editClapStoryboards, editClapVideos, -} from '@aitube/client' +} from '@aitube/api-client' import { getWorkflowInputValues } from '../getWorkflowInputValues' diff --git a/src/app/api/resolve/providers/comfy-comfydeploy/index.ts b/packages/app/src/app/api/resolve/providers/comfy-comfydeploy/index.ts similarity index 100% rename from src/app/api/resolve/providers/comfy-comfydeploy/index.ts rename to packages/app/src/app/api/resolve/providers/comfy-comfydeploy/index.ts diff --git a/src/app/api/resolve/providers/comfy-comfyicu/index.ts b/packages/app/src/app/api/resolve/providers/comfy-comfyicu/index.ts similarity index 100% rename from src/app/api/resolve/providers/comfy-comfyicu/index.ts rename to packages/app/src/app/api/resolve/providers/comfy-comfyicu/index.ts diff --git a/src/app/api/resolve/providers/comfy-comfyicu/types.ts b/packages/app/src/app/api/resolve/providers/comfy-comfyicu/types.ts similarity index 100% rename from src/app/api/resolve/providers/comfy-comfyicu/types.ts rename to packages/app/src/app/api/resolve/providers/comfy-comfyicu/types.ts diff --git a/src/app/api/resolve/providers/comfy-huggingface/index.ts b/packages/app/src/app/api/resolve/providers/comfy-huggingface/index.ts similarity index 100% rename from src/app/api/resolve/providers/comfy-huggingface/index.ts rename to packages/app/src/app/api/resolve/providers/comfy-huggingface/index.ts diff --git a/src/app/api/resolve/providers/comfy-replicate/index.ts b/packages/app/src/app/api/resolve/providers/comfy-replicate/index.ts similarity index 100% rename from src/app/api/resolve/providers/comfy-replicate/index.ts rename to packages/app/src/app/api/resolve/providers/comfy-replicate/index.ts diff --git a/src/app/api/resolve/providers/comfy-replicate/runWorkflow.ts b/packages/app/src/app/api/resolve/providers/comfy-replicate/runWorkflow.ts similarity index 100% rename from src/app/api/resolve/providers/comfy-replicate/runWorkflow.ts rename to packages/app/src/app/api/resolve/providers/comfy-replicate/runWorkflow.ts diff --git a/src/app/api/resolve/providers/comfyui/index.ts b/packages/app/src/app/api/resolve/providers/comfyui/index.ts similarity index 100% rename from src/app/api/resolve/providers/comfyui/index.ts rename to packages/app/src/app/api/resolve/providers/comfyui/index.ts diff --git a/src/app/api/resolve/providers/falai/index.ts b/packages/app/src/app/api/resolve/providers/falai/index.ts similarity index 100% rename from src/app/api/resolve/providers/falai/index.ts rename to packages/app/src/app/api/resolve/providers/falai/index.ts diff --git a/src/app/api/resolve/providers/falai/types.ts b/packages/app/src/app/api/resolve/providers/falai/types.ts similarity index 100% rename from src/app/api/resolve/providers/falai/types.ts rename to packages/app/src/app/api/resolve/providers/falai/types.ts diff --git a/src/app/api/resolve/providers/getWorkflowInputValues.ts b/packages/app/src/app/api/resolve/providers/getWorkflowInputValues.ts similarity index 100% rename from src/app/api/resolve/providers/getWorkflowInputValues.ts rename to packages/app/src/app/api/resolve/providers/getWorkflowInputValues.ts diff --git a/src/app/api/resolve/providers/gradio/index.ts b/packages/app/src/app/api/resolve/providers/gradio/index.ts similarity index 100% rename from src/app/api/resolve/providers/gradio/index.ts rename to packages/app/src/app/api/resolve/providers/gradio/index.ts diff --git a/src/app/api/resolve/providers/huggingface/generateImage.ts b/packages/app/src/app/api/resolve/providers/huggingface/generateImage.ts similarity index 100% rename from src/app/api/resolve/providers/huggingface/generateImage.ts rename to packages/app/src/app/api/resolve/providers/huggingface/generateImage.ts diff --git a/src/app/api/resolve/providers/huggingface/generateMusic.ts b/packages/app/src/app/api/resolve/providers/huggingface/generateMusic.ts similarity index 100% rename from src/app/api/resolve/providers/huggingface/generateMusic.ts rename to packages/app/src/app/api/resolve/providers/huggingface/generateMusic.ts diff --git a/src/app/api/resolve/providers/huggingface/generateVideo.ts b/packages/app/src/app/api/resolve/providers/huggingface/generateVideo.ts similarity index 100% rename from src/app/api/resolve/providers/huggingface/generateVideo.ts rename to packages/app/src/app/api/resolve/providers/huggingface/generateVideo.ts diff --git a/src/app/api/resolve/providers/huggingface/generateVoice.ts b/packages/app/src/app/api/resolve/providers/huggingface/generateVoice.ts similarity index 100% rename from src/app/api/resolve/providers/huggingface/generateVoice.ts rename to packages/app/src/app/api/resolve/providers/huggingface/generateVoice.ts diff --git a/src/app/api/resolve/providers/huggingface/index.ts b/packages/app/src/app/api/resolve/providers/huggingface/index.ts similarity index 100% rename from src/app/api/resolve/providers/huggingface/index.ts rename to packages/app/src/app/api/resolve/providers/huggingface/index.ts diff --git a/src/app/api/resolve/providers/index.ts b/packages/app/src/app/api/resolve/providers/index.ts similarity index 100% rename from src/app/api/resolve/providers/index.ts rename to packages/app/src/app/api/resolve/providers/index.ts diff --git a/src/app/api/resolve/providers/lumalabs/getGenerations.ts b/packages/app/src/app/api/resolve/providers/lumalabs/getGenerations.ts similarity index 100% rename from src/app/api/resolve/providers/lumalabs/getGenerations.ts rename to packages/app/src/app/api/resolve/providers/lumalabs/getGenerations.ts diff --git a/src/app/api/resolve/providers/lumalabs/todo.ts b/packages/app/src/app/api/resolve/providers/lumalabs/todo.ts similarity index 100% rename from src/app/api/resolve/providers/lumalabs/todo.ts rename to packages/app/src/app/api/resolve/providers/lumalabs/todo.ts diff --git a/src/app/api/resolve/providers/lumalabs/types.ts b/packages/app/src/app/api/resolve/providers/lumalabs/types.ts similarity index 100% rename from src/app/api/resolve/providers/lumalabs/types.ts rename to packages/app/src/app/api/resolve/providers/lumalabs/types.ts diff --git a/src/app/api/resolve/providers/modelslab/index.ts b/packages/app/src/app/api/resolve/providers/modelslab/index.ts similarity index 100% rename from src/app/api/resolve/providers/modelslab/index.ts rename to packages/app/src/app/api/resolve/providers/modelslab/index.ts diff --git a/src/app/api/resolve/providers/openai/TODO.md b/packages/app/src/app/api/resolve/providers/openai/TODO.md similarity index 100% rename from src/app/api/resolve/providers/openai/TODO.md rename to packages/app/src/app/api/resolve/providers/openai/TODO.md diff --git a/src/app/api/resolve/providers/replicate/index.ts b/packages/app/src/app/api/resolve/providers/replicate/index.ts similarity index 100% rename from src/app/api/resolve/providers/replicate/index.ts rename to packages/app/src/app/api/resolve/providers/replicate/index.ts diff --git a/src/app/api/resolve/providers/stabilityai/generateImage.ts b/packages/app/src/app/api/resolve/providers/stabilityai/generateImage.ts similarity index 100% rename from src/app/api/resolve/providers/stabilityai/generateImage.ts rename to packages/app/src/app/api/resolve/providers/stabilityai/generateImage.ts diff --git a/src/app/api/resolve/providers/stabilityai/generateVideo.ts b/packages/app/src/app/api/resolve/providers/stabilityai/generateVideo.ts similarity index 100% rename from src/app/api/resolve/providers/stabilityai/generateVideo.ts rename to packages/app/src/app/api/resolve/providers/stabilityai/generateVideo.ts diff --git a/src/app/api/resolve/providers/stabilityai/index.ts b/packages/app/src/app/api/resolve/providers/stabilityai/index.ts similarity index 100% rename from src/app/api/resolve/providers/stabilityai/index.ts rename to packages/app/src/app/api/resolve/providers/stabilityai/index.ts diff --git a/src/app/api/resolve/route.ts b/packages/app/src/app/api/resolve/route.ts similarity index 100% rename from src/app/api/resolve/route.ts rename to packages/app/src/app/api/resolve/route.ts diff --git a/src/app/cute_1024x1024x32.png b/packages/app/src/app/cute_1024x1024x32.png similarity index 100% rename from src/app/cute_1024x1024x32.png rename to packages/app/src/app/cute_1024x1024x32.png diff --git a/src/app/cute_favicon.ico b/packages/app/src/app/cute_favicon.ico similarity index 100% rename from src/app/cute_favicon.ico rename to packages/app/src/app/cute_favicon.ico diff --git a/src/app/cute_icon.png b/packages/app/src/app/cute_icon.png similarity index 100% rename from src/app/cute_icon.png rename to packages/app/src/app/cute_icon.png diff --git a/src/app/embed/README.md b/packages/app/src/app/embed/README.md similarity index 100% rename from src/app/embed/README.md rename to packages/app/src/app/embed/README.md diff --git a/src/app/embed/embed.tsx b/packages/app/src/app/embed/embed.tsx similarity index 100% rename from src/app/embed/embed.tsx rename to packages/app/src/app/embed/embed.tsx diff --git a/src/app/embed/page.tsx b/packages/app/src/app/embed/page.tsx similarity index 100% rename from src/app/embed/page.tsx rename to packages/app/src/app/embed/page.tsx diff --git a/src/app/favicon.ico b/packages/app/src/app/favicon.ico similarity index 100% rename from src/app/favicon.ico rename to packages/app/src/app/favicon.ico diff --git a/src/app/favicon_square.ico b/packages/app/src/app/favicon_square.ico similarity index 100% rename from src/app/favicon_square.ico rename to packages/app/src/app/favicon_square.ico diff --git a/src/app/fonts/alarm-clock/alarm-clock.woff2 b/packages/app/src/app/fonts/alarm-clock/alarm-clock.woff2 similarity index 100% rename from src/app/fonts/alarm-clock/alarm-clock.woff2 rename to packages/app/src/app/fonts/alarm-clock/alarm-clock.woff2 diff --git a/src/app/fonts/index.ts b/packages/app/src/app/fonts/index.ts similarity index 100% rename from src/app/fonts/index.ts rename to packages/app/src/app/fonts/index.ts diff --git a/src/app/icon_NEXTJS_BUG.png b/packages/app/src/app/icon_NEXTJS_BUG.png similarity index 100% rename from src/app/icon_NEXTJS_BUG.png rename to packages/app/src/app/icon_NEXTJS_BUG.png diff --git a/src/app/icon_square.png b/packages/app/src/app/icon_square.png similarity index 100% rename from src/app/icon_square.png rename to packages/app/src/app/icon_square.png diff --git a/src/app/layout.tsx b/packages/app/src/app/layout.tsx similarity index 100% rename from src/app/layout.tsx rename to packages/app/src/app/layout.tsx diff --git a/src/app/main.tsx b/packages/app/src/app/main.tsx similarity index 100% rename from src/app/main.tsx rename to packages/app/src/app/main.tsx diff --git a/src/app/page.tsx b/packages/app/src/app/page.tsx similarity index 100% rename from src/app/page.tsx rename to packages/app/src/app/page.tsx diff --git a/src/app/styles/globals.css b/packages/app/src/app/styles/globals.css similarity index 100% rename from src/app/styles/globals.css rename to packages/app/src/app/styles/globals.css diff --git a/src/app/styles/react-reflex-custom.css b/packages/app/src/app/styles/react-reflex-custom.css similarity index 100% rename from src/app/styles/react-reflex-custom.css rename to packages/app/src/app/styles/react-reflex-custom.css diff --git a/src/app/styles/react-reflex.css b/packages/app/src/app/styles/react-reflex.css similarity index 100% rename from src/app/styles/react-reflex.css rename to packages/app/src/app/styles/react-reflex.css diff --git a/src/components/assistant/ChatBubble.tsx b/packages/app/src/components/assistant/ChatBubble.tsx similarity index 100% rename from src/components/assistant/ChatBubble.tsx rename to packages/app/src/components/assistant/ChatBubble.tsx diff --git a/src/components/assistant/ChatView.tsx b/packages/app/src/components/assistant/ChatView.tsx similarity index 100% rename from src/components/assistant/ChatView.tsx rename to packages/app/src/components/assistant/ChatView.tsx diff --git a/src/components/core/providers/ClapWorkflowProviderLogo.tsx b/packages/app/src/components/core/providers/ClapWorkflowProviderLogo.tsx similarity index 100% rename from src/components/core/providers/ClapWorkflowProviderLogo.tsx rename to packages/app/src/components/core/providers/ClapWorkflowProviderLogo.tsx diff --git a/src/components/core/providers/ClapWorkflowProviderName.tsx b/packages/app/src/components/core/providers/ClapWorkflowProviderName.tsx similarity index 100% rename from src/components/core/providers/ClapWorkflowProviderName.tsx rename to packages/app/src/components/core/providers/ClapWorkflowProviderName.tsx diff --git a/src/components/core/providers/index.ts b/packages/app/src/components/core/providers/index.ts similarity index 100% rename from src/components/core/providers/index.ts rename to packages/app/src/components/core/providers/index.ts diff --git a/src/components/core/providers/logos.ts b/packages/app/src/components/core/providers/logos.ts similarity index 100% rename from src/components/core/providers/logos.ts rename to packages/app/src/components/core/providers/logos.ts diff --git a/src/components/core/timeline/index.tsx b/packages/app/src/components/core/timeline/index.tsx similarity index 100% rename from src/components/core/timeline/index.tsx rename to packages/app/src/components/core/timeline/index.tsx diff --git a/src/components/core/tree/README.md b/packages/app/src/components/core/tree/README.md similarity index 100% rename from src/components/core/tree/README.md rename to packages/app/src/components/core/tree/README.md diff --git a/src/components/core/tree/chainable-map.ts b/packages/app/src/components/core/tree/chainable-map.ts similarity index 100% rename from src/components/core/tree/chainable-map.ts rename to packages/app/src/components/core/tree/chainable-map.ts diff --git a/src/components/core/tree/icons.tsx b/packages/app/src/components/core/tree/icons.tsx similarity index 100% rename from src/components/core/tree/icons.tsx rename to packages/app/src/components/core/tree/icons.tsx diff --git a/src/components/core/tree/index.tsx b/packages/app/src/components/core/tree/index.tsx similarity index 100% rename from src/components/core/tree/index.tsx rename to packages/app/src/components/core/tree/index.tsx diff --git a/src/components/core/tree/root.tsx b/packages/app/src/components/core/tree/root.tsx similarity index 100% rename from src/components/core/tree/root.tsx rename to packages/app/src/components/core/tree/root.tsx diff --git a/src/components/core/tree/roving.tsx b/packages/app/src/components/core/tree/roving.tsx similarity index 100% rename from src/components/core/tree/roving.tsx rename to packages/app/src/components/core/tree/roving.tsx diff --git a/src/components/core/tree/tree-state.ts b/packages/app/src/components/core/tree/tree-state.ts similarity index 100% rename from src/components/core/tree/tree-state.ts rename to packages/app/src/components/core/tree/tree-state.ts diff --git a/src/components/core/tree/types.ts b/packages/app/src/components/core/tree/types.ts similarity index 100% rename from src/components/core/tree/types.ts rename to packages/app/src/components/core/tree/types.ts diff --git a/src/components/core/tree/useTreeNode.ts b/packages/app/src/components/core/tree/useTreeNode.ts similarity index 100% rename from src/components/core/tree/useTreeNode.ts rename to packages/app/src/components/core/tree/useTreeNode.ts diff --git a/src/components/core/waveform/types.ts b/packages/app/src/components/core/waveform/types.ts similarity index 100% rename from src/components/core/waveform/types.ts rename to packages/app/src/components/core/waveform/types.ts diff --git a/src/components/core/waveform/useWaveform.ts b/packages/app/src/components/core/waveform/useWaveform.ts similarity index 100% rename from src/components/core/waveform/useWaveform.ts rename to packages/app/src/components/core/waveform/useWaveform.ts diff --git a/src/components/dialogs/iframe-warning/index.tsx b/packages/app/src/components/dialogs/iframe-warning/index.tsx similarity index 100% rename from src/components/dialogs/iframe-warning/index.tsx rename to packages/app/src/components/dialogs/iframe-warning/index.tsx diff --git a/src/components/dialogs/loader/LoadingDialog.tsx b/packages/app/src/components/dialogs/loader/LoadingDialog.tsx similarity index 100% rename from src/components/dialogs/loader/LoadingDialog.tsx rename to packages/app/src/components/dialogs/loader/LoadingDialog.tsx diff --git a/src/components/dialogs/loader/index.tsx b/packages/app/src/components/dialogs/loader/index.tsx similarity index 100% rename from src/components/dialogs/loader/index.tsx rename to packages/app/src/components/dialogs/loader/index.tsx diff --git a/src/components/editors/Editors.tsx b/packages/app/src/components/editors/Editors.tsx similarity index 100% rename from src/components/editors/Editors.tsx rename to packages/app/src/components/editors/Editors.tsx diff --git a/src/components/editors/EntityEditor/EntityTree/index.tsx b/packages/app/src/components/editors/EntityEditor/EntityTree/index.tsx similarity index 100% rename from src/components/editors/EntityEditor/EntityTree/index.tsx rename to packages/app/src/components/editors/EntityEditor/EntityTree/index.tsx diff --git a/src/components/editors/EntityEditor/EntityTree/useEntityTree.ts b/packages/app/src/components/editors/EntityEditor/EntityTree/useEntityTree.ts similarity index 100% rename from src/components/editors/EntityEditor/EntityTree/useEntityTree.ts rename to packages/app/src/components/editors/EntityEditor/EntityTree/useEntityTree.ts diff --git a/src/components/editors/EntityEditor/EntityViewer/EntityList.tsx b/packages/app/src/components/editors/EntityEditor/EntityViewer/EntityList.tsx similarity index 100% rename from src/components/editors/EntityEditor/EntityViewer/EntityList.tsx rename to packages/app/src/components/editors/EntityEditor/EntityViewer/EntityList.tsx diff --git a/src/components/editors/EntityEditor/EntityViewer/index.tsx b/packages/app/src/components/editors/EntityEditor/EntityViewer/index.tsx similarity index 100% rename from src/components/editors/EntityEditor/EntityViewer/index.tsx rename to packages/app/src/components/editors/EntityEditor/EntityViewer/index.tsx diff --git a/src/components/editors/EntityEditor/index.tsx b/packages/app/src/components/editors/EntityEditor/index.tsx similarity index 100% rename from src/components/editors/EntityEditor/index.tsx rename to packages/app/src/components/editors/EntityEditor/index.tsx diff --git a/src/components/editors/FilterEditor/FilterTree/index.tsx b/packages/app/src/components/editors/FilterEditor/FilterTree/index.tsx similarity index 100% rename from src/components/editors/FilterEditor/FilterTree/index.tsx rename to packages/app/src/components/editors/FilterEditor/FilterTree/index.tsx diff --git a/src/components/editors/FilterEditor/FilterTree/useFilterTree.ts b/packages/app/src/components/editors/FilterEditor/FilterTree/useFilterTree.ts similarity index 100% rename from src/components/editors/FilterEditor/FilterTree/useFilterTree.ts rename to packages/app/src/components/editors/FilterEditor/FilterTree/useFilterTree.ts diff --git a/src/components/editors/FilterEditor/FilterViewer/index.tsx b/packages/app/src/components/editors/FilterEditor/FilterViewer/index.tsx similarity index 100% rename from src/components/editors/FilterEditor/FilterViewer/index.tsx rename to packages/app/src/components/editors/FilterEditor/FilterViewer/index.tsx diff --git a/src/components/editors/FilterEditor/index.tsx b/packages/app/src/components/editors/FilterEditor/index.tsx similarity index 100% rename from src/components/editors/FilterEditor/index.tsx rename to packages/app/src/components/editors/FilterEditor/index.tsx diff --git a/src/components/editors/ProjectEditor/index.tsx b/packages/app/src/components/editors/ProjectEditor/index.tsx similarity index 100% rename from src/components/editors/ProjectEditor/index.tsx rename to packages/app/src/components/editors/ProjectEditor/index.tsx diff --git a/src/components/editors/ScriptEditor/README.md b/packages/app/src/components/editors/ScriptEditor/README.md similarity index 100% rename from src/components/editors/ScriptEditor/README.md rename to packages/app/src/components/editors/ScriptEditor/README.md diff --git a/src/components/editors/ScriptEditor/index.tsx b/packages/app/src/components/editors/ScriptEditor/index.tsx similarity index 100% rename from src/components/editors/ScriptEditor/index.tsx rename to packages/app/src/components/editors/ScriptEditor/index.tsx diff --git a/src/components/editors/ScriptEditor/styles.css b/packages/app/src/components/editors/ScriptEditor/styles.css similarity index 100% rename from src/components/editors/ScriptEditor/styles.css rename to packages/app/src/components/editors/ScriptEditor/styles.css diff --git a/src/components/editors/SegmentEditor/index.tsx b/packages/app/src/components/editors/SegmentEditor/index.tsx similarity index 100% rename from src/components/editors/SegmentEditor/index.tsx rename to packages/app/src/components/editors/SegmentEditor/index.tsx diff --git a/src/components/editors/WorkflowEditor/WorkflowTree/index.tsx b/packages/app/src/components/editors/WorkflowEditor/WorkflowTree/index.tsx similarity index 100% rename from src/components/editors/WorkflowEditor/WorkflowTree/index.tsx rename to packages/app/src/components/editors/WorkflowEditor/WorkflowTree/index.tsx diff --git a/src/components/editors/WorkflowEditor/WorkflowTree/useWorkflowTree.ts b/packages/app/src/components/editors/WorkflowEditor/WorkflowTree/useWorkflowTree.ts similarity index 100% rename from src/components/editors/WorkflowEditor/WorkflowTree/useWorkflowTree.ts rename to packages/app/src/components/editors/WorkflowEditor/WorkflowTree/useWorkflowTree.ts diff --git a/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/NodeView.tsx b/packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/NodeView.tsx similarity index 100% rename from src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/NodeView.tsx rename to packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/NodeView.tsx diff --git a/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/clapWorkflowToReactWorkflow.ts b/packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/clapWorkflowToReactWorkflow.ts similarity index 100% rename from src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/clapWorkflowToReactWorkflow.ts rename to packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/clapWorkflowToReactWorkflow.ts diff --git a/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/formats/comfyui/types.ts b/packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/formats/comfyui/types.ts similarity index 100% rename from src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/formats/comfyui/types.ts rename to packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/formats/comfyui/types.ts diff --git a/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/formats/falai/types.ts b/packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/formats/falai/types.ts similarity index 100% rename from src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/formats/falai/types.ts rename to packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/formats/falai/types.ts diff --git a/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/formats/glif/glifToReactWorkflow.ts b/packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/formats/glif/glifToReactWorkflow.ts similarity index 100% rename from src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/formats/glif/glifToReactWorkflow.ts rename to packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/formats/glif/glifToReactWorkflow.ts diff --git a/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/formats/glif/types.ts b/packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/formats/glif/types.ts similarity index 100% rename from src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/formats/glif/types.ts rename to packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/formats/glif/types.ts diff --git a/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/index.tsx b/packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/index.tsx similarity index 100% rename from src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/index.tsx rename to packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/index.tsx diff --git a/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/samples/comfyicu.ts b/packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/samples/comfyicu.ts similarity index 100% rename from src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/samples/comfyicu.ts rename to packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/samples/comfyicu.ts diff --git a/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/samples/glif.ts b/packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/samples/glif.ts similarity index 100% rename from src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/samples/glif.ts rename to packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/samples/glif.ts diff --git a/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/types.ts b/packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/types.ts similarity index 100% rename from src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/types.ts rename to packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/ReactFlowCanvas/types.ts diff --git a/src/components/editors/WorkflowEditor/WorkflowViewer/index.tsx b/packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/index.tsx similarity index 100% rename from src/components/editors/WorkflowEditor/WorkflowViewer/index.tsx rename to packages/app/src/components/editors/WorkflowEditor/WorkflowViewer/index.tsx diff --git a/src/components/editors/WorkflowEditor/index.tsx b/packages/app/src/components/editors/WorkflowEditor/index.tsx similarity index 100% rename from src/components/editors/WorkflowEditor/index.tsx rename to packages/app/src/components/editors/WorkflowEditor/index.tsx diff --git a/src/components/forms/FormDir.tsx b/packages/app/src/components/forms/FormDir.tsx similarity index 100% rename from src/components/forms/FormDir.tsx rename to packages/app/src/components/forms/FormDir.tsx diff --git a/src/components/forms/FormField.tsx b/packages/app/src/components/forms/FormField.tsx similarity index 100% rename from src/components/forms/FormField.tsx rename to packages/app/src/components/forms/FormField.tsx diff --git a/src/components/forms/FormFile.tsx b/packages/app/src/components/forms/FormFile.tsx similarity index 100% rename from src/components/forms/FormFile.tsx rename to packages/app/src/components/forms/FormFile.tsx diff --git a/src/components/forms/FormInput.tsx b/packages/app/src/components/forms/FormInput.tsx similarity index 100% rename from src/components/forms/FormInput.tsx rename to packages/app/src/components/forms/FormInput.tsx diff --git a/src/components/forms/FormLabel.tsx b/packages/app/src/components/forms/FormLabel.tsx similarity index 100% rename from src/components/forms/FormLabel.tsx rename to packages/app/src/components/forms/FormLabel.tsx diff --git a/src/components/forms/FormRadio.tsx b/packages/app/src/components/forms/FormRadio.tsx similarity index 100% rename from src/components/forms/FormRadio.tsx rename to packages/app/src/components/forms/FormRadio.tsx diff --git a/src/components/forms/FormSection.tsx b/packages/app/src/components/forms/FormSection.tsx similarity index 100% rename from src/components/forms/FormSection.tsx rename to packages/app/src/components/forms/FormSection.tsx diff --git a/src/components/forms/FormSelect.tsx b/packages/app/src/components/forms/FormSelect.tsx similarity index 100% rename from src/components/forms/FormSelect.tsx rename to packages/app/src/components/forms/FormSelect.tsx diff --git a/src/components/forms/FormSlider.tsx b/packages/app/src/components/forms/FormSlider.tsx similarity index 100% rename from src/components/forms/FormSlider.tsx rename to packages/app/src/components/forms/FormSlider.tsx diff --git a/src/components/forms/FormSwitch.tsx b/packages/app/src/components/forms/FormSwitch.tsx similarity index 100% rename from src/components/forms/FormSwitch.tsx rename to packages/app/src/components/forms/FormSwitch.tsx diff --git a/src/components/forms/index.ts b/packages/app/src/components/forms/index.ts similarity index 100% rename from src/components/forms/index.ts rename to packages/app/src/components/forms/index.ts diff --git a/src/components/icons/getAppropriateIcon.ts b/packages/app/src/components/icons/getAppropriateIcon.ts similarity index 100% rename from src/components/icons/getAppropriateIcon.ts rename to packages/app/src/components/icons/getAppropriateIcon.ts diff --git a/src/components/icons/index.tsx b/packages/app/src/components/icons/index.tsx similarity index 100% rename from src/components/icons/index.tsx rename to packages/app/src/components/icons/index.tsx diff --git a/src/components/mobile/MobileMenu.tsx b/packages/app/src/components/mobile/MobileMenu.tsx similarity index 100% rename from src/components/mobile/MobileMenu.tsx rename to packages/app/src/components/mobile/MobileMenu.tsx diff --git a/src/components/monitor/Counter/index.tsx b/packages/app/src/components/monitor/Counter/index.tsx similarity index 100% rename from src/components/monitor/Counter/index.tsx rename to packages/app/src/components/monitor/Counter/index.tsx diff --git a/src/components/monitor/DynamicPlayer/DynamicBuffer.tsx b/packages/app/src/components/monitor/DynamicPlayer/DynamicBuffer.tsx similarity index 100% rename from src/components/monitor/DynamicPlayer/DynamicBuffer.tsx rename to packages/app/src/components/monitor/DynamicPlayer/DynamicBuffer.tsx diff --git a/src/components/monitor/DynamicPlayer/StoryboardBuffer.tsx b/packages/app/src/components/monitor/DynamicPlayer/StoryboardBuffer.tsx similarity index 100% rename from src/components/monitor/DynamicPlayer/StoryboardBuffer.tsx rename to packages/app/src/components/monitor/DynamicPlayer/StoryboardBuffer.tsx diff --git a/src/components/monitor/DynamicPlayer/VideoClipBuffer.tsx b/packages/app/src/components/monitor/DynamicPlayer/VideoClipBuffer.tsx similarity index 100% rename from src/components/monitor/DynamicPlayer/VideoClipBuffer.tsx rename to packages/app/src/components/monitor/DynamicPlayer/VideoClipBuffer.tsx diff --git a/src/components/monitor/DynamicPlayer/index.tsx b/packages/app/src/components/monitor/DynamicPlayer/index.tsx similarity index 100% rename from src/components/monitor/DynamicPlayer/index.tsx rename to packages/app/src/components/monitor/DynamicPlayer/index.tsx diff --git a/src/components/monitor/PlayerControls/index.tsx b/packages/app/src/components/monitor/PlayerControls/index.tsx similarity index 100% rename from src/components/monitor/PlayerControls/index.tsx rename to packages/app/src/components/monitor/PlayerControls/index.tsx diff --git a/src/components/monitor/README.md b/packages/app/src/components/monitor/README.md similarity index 100% rename from src/components/monitor/README.md rename to packages/app/src/components/monitor/README.md diff --git a/src/components/monitor/Separator/index.tsx b/packages/app/src/components/monitor/Separator/index.tsx similarity index 100% rename from src/components/monitor/Separator/index.tsx rename to packages/app/src/components/monitor/Separator/index.tsx diff --git a/src/components/monitor/StaticPlayer/index.tsx b/packages/app/src/components/monitor/StaticPlayer/index.tsx similarity index 100% rename from src/components/monitor/StaticPlayer/index.tsx rename to packages/app/src/components/monitor/StaticPlayer/index.tsx diff --git a/src/components/monitor/UniversalPlayer/index.tsx b/packages/app/src/components/monitor/UniversalPlayer/index.tsx similarity index 94% rename from src/components/monitor/UniversalPlayer/index.tsx rename to packages/app/src/components/monitor/UniversalPlayer/index.tsx index c0c5888dea9dc99e8e7c312ea52f2b4ca933e3f5..821c1cccf2d18e99cf94f96d033fe6b6d2c4ebef 100644 --- a/src/components/monitor/UniversalPlayer/index.tsx +++ b/packages/app/src/components/monitor/UniversalPlayer/index.tsx @@ -1,7 +1,7 @@ import { ClapSegment } from '@aitube/clap' import { useTimeline } from '@aitube/timeline' -import { StaticPlayer } from '../../monitor/StaticPlayer' +import { StaticPlayer } from '../StaticPlayer' import { DynamicPlayer } from '../DynamicPlayer' // TODO: put this in a separate component eg @aitube-player or @aitube/monitor diff --git a/src/components/monitor/icons/icon-switch.tsx b/packages/app/src/components/monitor/icons/icon-switch.tsx similarity index 100% rename from src/components/monitor/icons/icon-switch.tsx rename to packages/app/src/components/monitor/icons/icon-switch.tsx diff --git a/src/components/monitor/icons/single-icon.tsx b/packages/app/src/components/monitor/icons/single-icon.tsx similarity index 100% rename from src/components/monitor/icons/single-icon.tsx rename to packages/app/src/components/monitor/icons/single-icon.tsx diff --git a/src/components/monitor/index.tsx b/packages/app/src/components/monitor/index.tsx similarity index 100% rename from src/components/monitor/index.tsx rename to packages/app/src/components/monitor/index.tsx diff --git a/src/components/monitor/utils/splitElapsedTime.tsx b/packages/app/src/components/monitor/utils/splitElapsedTime.tsx similarity index 100% rename from src/components/monitor/utils/splitElapsedTime.tsx rename to packages/app/src/components/monitor/utils/splitElapsedTime.tsx diff --git a/src/components/monitor/utils/zeroPad.ts b/packages/app/src/components/monitor/utils/zeroPad.ts similarity index 100% rename from src/components/monitor/utils/zeroPad.ts rename to packages/app/src/components/monitor/utils/zeroPad.ts diff --git a/src/components/settings/assistant.tsx b/packages/app/src/components/settings/assistant.tsx similarity index 100% rename from src/components/settings/assistant.tsx rename to packages/app/src/components/settings/assistant.tsx diff --git a/src/components/settings/constants.ts b/packages/app/src/components/settings/constants.ts similarity index 100% rename from src/components/settings/constants.ts rename to packages/app/src/components/settings/constants.ts diff --git a/src/components/settings/editors.tsx b/packages/app/src/components/settings/editors.tsx similarity index 100% rename from src/components/settings/editors.tsx rename to packages/app/src/components/settings/editors.tsx diff --git a/src/components/settings/image.tsx b/packages/app/src/components/settings/image.tsx similarity index 100% rename from src/components/settings/image.tsx rename to packages/app/src/components/settings/image.tsx diff --git a/src/components/settings/index.tsx b/packages/app/src/components/settings/index.tsx similarity index 100% rename from src/components/settings/index.tsx rename to packages/app/src/components/settings/index.tsx diff --git a/src/components/settings/music.tsx b/packages/app/src/components/settings/music.tsx similarity index 100% rename from src/components/settings/music.tsx rename to packages/app/src/components/settings/music.tsx diff --git a/src/components/settings/provider.tsx b/packages/app/src/components/settings/provider.tsx similarity index 100% rename from src/components/settings/provider.tsx rename to packages/app/src/components/settings/provider.tsx diff --git a/src/components/settings/sound.tsx b/packages/app/src/components/settings/sound.tsx similarity index 100% rename from src/components/settings/sound.tsx rename to packages/app/src/components/settings/sound.tsx diff --git a/src/components/settings/video.tsx b/packages/app/src/components/settings/video.tsx similarity index 100% rename from src/components/settings/video.tsx rename to packages/app/src/components/settings/video.tsx diff --git a/src/components/settings/voice.tsx b/packages/app/src/components/settings/voice.tsx similarity index 100% rename from src/components/settings/voice.tsx rename to packages/app/src/components/settings/voice.tsx diff --git a/src/components/tags/Tag.tsx b/packages/app/src/components/tags/Tag.tsx similarity index 100% rename from src/components/tags/Tag.tsx rename to packages/app/src/components/tags/Tag.tsx diff --git a/src/components/tags/colors.ts b/packages/app/src/components/tags/colors.ts similarity index 100% rename from src/components/tags/colors.ts rename to packages/app/src/components/tags/colors.ts diff --git a/src/components/tags/types.ts b/packages/app/src/components/tags/types.ts similarity index 100% rename from src/components/tags/types.ts rename to packages/app/src/components/tags/types.ts diff --git a/src/components/tasks/TaskStatusUpdate.tsx b/packages/app/src/components/tasks/TaskStatusUpdate.tsx similarity index 100% rename from src/components/tasks/TaskStatusUpdate.tsx rename to packages/app/src/components/tasks/TaskStatusUpdate.tsx diff --git a/src/components/tasks/useTasks.tsx b/packages/app/src/components/tasks/useTasks.tsx similarity index 100% rename from src/components/tasks/useTasks.tsx rename to packages/app/src/components/tasks/useTasks.tsx diff --git a/src/components/toolbars/bottom-bar/index.tsx b/packages/app/src/components/toolbars/bottom-bar/index.tsx similarity index 100% rename from src/components/toolbars/bottom-bar/index.tsx rename to packages/app/src/components/toolbars/bottom-bar/index.tsx diff --git a/src/components/toolbars/bottom-bar/metrics/index.tsx b/packages/app/src/components/toolbars/bottom-bar/metrics/index.tsx similarity index 100% rename from src/components/toolbars/bottom-bar/metrics/index.tsx rename to packages/app/src/components/toolbars/bottom-bar/metrics/index.tsx diff --git a/src/components/toolbars/bottom-bar/tasks/index.tsx b/packages/app/src/components/toolbars/bottom-bar/tasks/index.tsx similarity index 100% rename from src/components/toolbars/bottom-bar/tasks/index.tsx rename to packages/app/src/components/toolbars/bottom-bar/tasks/index.tsx diff --git a/src/components/toolbars/editors-menu/EditorsSideMenu.tsx b/packages/app/src/components/toolbars/editors-menu/EditorsSideMenu.tsx similarity index 100% rename from src/components/toolbars/editors-menu/EditorsSideMenu.tsx rename to packages/app/src/components/toolbars/editors-menu/EditorsSideMenu.tsx diff --git a/src/components/toolbars/editors-menu/EditorsSideMenuItem.tsx b/packages/app/src/components/toolbars/editors-menu/EditorsSideMenuItem.tsx similarity index 100% rename from src/components/toolbars/editors-menu/EditorsSideMenuItem.tsx rename to packages/app/src/components/toolbars/editors-menu/EditorsSideMenuItem.tsx diff --git a/src/components/toolbars/editors-menu/NatureIcon.tsx b/packages/app/src/components/toolbars/editors-menu/NatureIcon.tsx similarity index 100% rename from src/components/toolbars/editors-menu/NatureIcon.tsx rename to packages/app/src/components/toolbars/editors-menu/NatureIcon.tsx diff --git a/src/components/toolbars/system-menu/index.tsx b/packages/app/src/components/toolbars/system-menu/index.tsx similarity index 100% rename from src/components/toolbars/system-menu/index.tsx rename to packages/app/src/components/toolbars/system-menu/index.tsx diff --git a/src/components/toolbars/top-bar/index.tsx b/packages/app/src/components/toolbars/top-bar/index.tsx similarity index 100% rename from src/components/toolbars/top-bar/index.tsx rename to packages/app/src/components/toolbars/top-bar/index.tsx diff --git a/src/components/toolbars/top-menu/ActivitySpinner/index.tsx b/packages/app/src/components/toolbars/top-menu/ActivitySpinner/index.tsx similarity index 100% rename from src/components/toolbars/top-menu/ActivitySpinner/index.tsx rename to packages/app/src/components/toolbars/top-menu/ActivitySpinner/index.tsx diff --git a/src/components/toolbars/top-menu/IsBusy/index.tsx b/packages/app/src/components/toolbars/top-menu/IsBusy/index.tsx similarity index 100% rename from src/components/toolbars/top-menu/IsBusy/index.tsx rename to packages/app/src/components/toolbars/top-menu/IsBusy/index.tsx diff --git a/src/components/toolbars/top-menu/ToggleFullScreen/index.tsx b/packages/app/src/components/toolbars/top-menu/ToggleFullScreen/index.tsx similarity index 100% rename from src/components/toolbars/top-menu/ToggleFullScreen/index.tsx rename to packages/app/src/components/toolbars/top-menu/ToggleFullScreen/index.tsx diff --git a/src/components/toolbars/top-menu/ToggleView/index.tsx b/packages/app/src/components/toolbars/top-menu/ToggleView/index.tsx similarity index 100% rename from src/components/toolbars/top-menu/ToggleView/index.tsx rename to packages/app/src/components/toolbars/top-menu/ToggleView/index.tsx diff --git a/src/components/toolbars/top-menu/ToggleWindowLayout/index.tsx b/packages/app/src/components/toolbars/top-menu/ToggleWindowLayout/index.tsx similarity index 100% rename from src/components/toolbars/top-menu/ToggleWindowLayout/index.tsx rename to packages/app/src/components/toolbars/top-menu/ToggleWindowLayout/index.tsx diff --git a/src/components/toolbars/top-menu/TopMenuLogo/index.tsx b/packages/app/src/components/toolbars/top-menu/TopMenuLogo/index.tsx similarity index 100% rename from src/components/toolbars/top-menu/TopMenuLogo/index.tsx rename to packages/app/src/components/toolbars/top-menu/TopMenuLogo/index.tsx diff --git a/src/components/toolbars/top-menu/assistant/index.tsx b/packages/app/src/components/toolbars/top-menu/assistant/index.tsx similarity index 100% rename from src/components/toolbars/top-menu/assistant/index.tsx rename to packages/app/src/components/toolbars/top-menu/assistant/index.tsx diff --git a/src/components/toolbars/top-menu/constants.ts b/packages/app/src/components/toolbars/top-menu/constants.ts similarity index 100% rename from src/components/toolbars/top-menu/constants.ts rename to packages/app/src/components/toolbars/top-menu/constants.ts diff --git a/src/components/toolbars/top-menu/edit/index.tsx b/packages/app/src/components/toolbars/top-menu/edit/index.tsx similarity index 100% rename from src/components/toolbars/top-menu/edit/index.tsx rename to packages/app/src/components/toolbars/top-menu/edit/index.tsx diff --git a/src/components/toolbars/top-menu/file/index.tsx b/packages/app/src/components/toolbars/top-menu/file/index.tsx similarity index 100% rename from src/components/toolbars/top-menu/file/index.tsx rename to packages/app/src/components/toolbars/top-menu/file/index.tsx diff --git a/src/components/toolbars/top-menu/image/index.tsx b/packages/app/src/components/toolbars/top-menu/image/index.tsx similarity index 100% rename from src/components/toolbars/top-menu/image/index.tsx rename to packages/app/src/components/toolbars/top-menu/image/index.tsx diff --git a/src/components/toolbars/top-menu/index.tsx b/packages/app/src/components/toolbars/top-menu/index.tsx similarity index 100% rename from src/components/toolbars/top-menu/index.tsx rename to packages/app/src/components/toolbars/top-menu/index.tsx diff --git a/src/components/toolbars/top-menu/lists/AssistantWorkflows.tsx b/packages/app/src/components/toolbars/top-menu/lists/AssistantWorkflows.tsx similarity index 98% rename from src/components/toolbars/top-menu/lists/AssistantWorkflows.tsx rename to packages/app/src/components/toolbars/top-menu/lists/AssistantWorkflows.tsx index 821d07fc2dcab112c2013d668dde25b369d7f74d..d34915ccc0ad1fa1c65d50b82f59f6ecc0f85c33 100644 --- a/src/components/toolbars/top-menu/lists/AssistantWorkflows.tsx +++ b/packages/app/src/components/toolbars/top-menu/lists/AssistantWorkflows.tsx @@ -62,7 +62,7 @@ export function AssistantWorkflows() { - {workflows.map((w) => ( + {workflows?.map((w) => ( - {workflows.map((w) => ( + {workflows?.map((w) => ( - {workflows.map((w) => ( + {workflows?.map((w) => ( - {workflows.map((w) => ( + {workflows?.map((w) => ( - {workflows.map((w) => ( + {workflows?.map((w) => ( - {workflows.map((w) => ( + {workflows?.map((w) => ( - {workflows.map((w) => ( + {workflows?.map((w) => ( - {workflows.map((w) => ( + {workflows?.map((w) => ( - {workflows.map((w) => ( + {workflows?.map((w) => ( - {workflows.map((w) => ( + {workflows?.map((w) => ( - {workflows.map((w) => ( + {workflows?.map((w) => ( - {workflows.map((w) => ( + {workflows?.map((w) => ( + processor?: Promise + tokenizer?: Promise +} = {} + +// export async function loadModel( +// modelId: string, +// onProgress: (progress: number) => void +// ) { +// onProgress(0) +// const model = await (cache.model +// ? cache.model +// : (cache.model = Florence2ForConditionalGeneration.from_pretrained( +// modelId, +// { +// dtype: 'fp32', +// } +// ))) + +// onProgress(33) + +// const processor = await (cache.processor +// ? cache.processor +// : (cache.processor = AutoProcessor.from_pretrained(modelId))) + +// onProgress(66) + +// const tokenizer = await (cache.tokenizer +// ? cache.tokenizer +// : (cache.tokenizer = AutoTokenizer.from_pretrained(modelId))) + +// onProgress(100) + +// return { model, processor, tokenizer } +// } + +export function closeModel() { + cache.model = undefined + cache.processor = undefined + cache.tokenizer = undefined +} + +export async function extractCaptionsFromFrames( + images: string[] = [], + onProgress: ( + progress: number, + storyboardIndex: number, + nbStoryboards: number + ) => any +) { + return +} + +// export async function extractCaptionsFromFrames( +// images: string[] = [], +// onProgress: ( +// progress: number, +// storyboardIndex: number, +// nbStoryboards: number +// ) => void +// ): Promise { +// if (!(navigator as any).gpu) { +// throw new Error(`Please enable WebGPU to analyze video frames: + +// 1. You need a modern browser such as Google Chrome 113+, Microsoft Edge 113+, Safari 18 (macOS 15), Firefox Nightly + +// 2. You need to enable WebGPU (depends on your browser, see below) + +// 2.1 For Chrome: Perform the following operations in the Chrome / Microsoft Edge address bar +// The chrome://flags/#enable-unsafe-webgpu flag must be enabled (not enable-webgpu-developer-features). +// Linux experimental support also requires launching the browser with --enable-features=Vulkan. + +// 2.2 For Safari 18 (macOS 15): WebGPU is enabled by default + +// 2.3 For Firefox Nightly: Type about:config in the address bar and set 'dom.webgpu.enabled" to true +// `) +// } + +// let progress = 0 + +// // for code example, see: +// // https://github.com/xenova/transformers.js/pull/545#issuecomment-2183625876 + +// // Load model, processor, and tokenizer +// const model_id = 'onnx-community/Florence-2-base-ft' + +// const { model, processor, tokenizer } = await loadModel(model_id, (p) => { +// onProgress((progress = p * 15), 0, images.length) +// }) + +// // not all prompts will work properly, see the official examples: +// // https://huggingface.co/microsoft/Florence-2-base-ft/blob/e7a5acc73559546de6e12ec0319cd7cc1fa2437c/processing_florence2.py#L115-L117 + +// // Prepare text inputs +// const prompts = 'Describe with a paragraph what is shown in the image.' +// // const prompts = 'Decompose the following video frame into era, genre, location, weather, characters, and action. Give the answer in YAML.' + +// const text_inputs = tokenizer(prompts) + +// let i = 1 +// const captions: string[] = [] +// for (const imageInBase64DataUri of images) { +// console.log('analyzing image:', imageInBase64DataUri.slice(0, 64)) +// // Prepare vision inputs +// const image = await RawImage.fromURL(imageInBase64DataUri) +// const vision_inputs = await processor(image) + +// console.log(' - generating caption..') +// // Generate text +// const generated_ids = await model.generate({ +// ...text_inputs, +// ...vision_inputs, +// max_new_tokens: 100, +// }) + +// // Decode generated text +// const generated_text = tokenizer.batch_decode(generated_ids, { +// skip_special_tokens: true, +// }) + +// const caption = `${generated_text[0] || ''}` +// console.log(' - caption:', caption) + +// const relativeProgress = i / images.length + +// progress += relativeProgress * 75 +// onProgress(progress, i, images.length) +// captions.push(caption) +// } +// return captions +// } diff --git a/src/services/autocomplete/getDefaultAutocompleteState.ts b/packages/app/src/services/autocomplete/getDefaultAutocompleteState.ts similarity index 100% rename from src/services/autocomplete/getDefaultAutocompleteState.ts rename to packages/app/src/services/autocomplete/getDefaultAutocompleteState.ts diff --git a/src/services/autocomplete/types.ts b/packages/app/src/services/autocomplete/types.ts similarity index 100% rename from src/services/autocomplete/types.ts rename to packages/app/src/services/autocomplete/types.ts diff --git a/src/services/autocomplete/useAutocomplete.ts b/packages/app/src/services/autocomplete/useAutocomplete.ts similarity index 94% rename from src/services/autocomplete/useAutocomplete.ts rename to packages/app/src/services/autocomplete/useAutocomplete.ts index b0c4846fb77f05555a55a0942dec391f09278e54..997420e62f7020600a19852fb3e046796d5ef099 100644 --- a/src/services/autocomplete/useAutocomplete.ts +++ b/packages/app/src/services/autocomplete/useAutocomplete.ts @@ -133,27 +133,27 @@ export const useAutocomplete = create((set, get) => ({ // able to decompose a scene automatically for (const sentence of sentences) { if (sentence.match(/(?:is wearing|wears)/)) { - categories.CHARACTER.push(sentence) + categories[ClapSegmentCategory.CHARACTER].push(sentence) } else if (sentence.match(/(?:the (?:image|screen) (?:is|has))/)) { - categories.STYLE.push(sentence) + categories[ClapSegmentCategory.STYLE].push(sentence) } else if ( sentence.match( /(?:the (?:lighting|lights|light|fire|sun|moon)|bright|dim|neon|candle|lit up)/ ) ) { - categories.LIGHTING.push(sentence) + categories[ClapSegmentCategory.LIGHTING].push(sentence) } else if ( sentence.match( /(?:the (?:man|woman|kid|child|person|animal|person|robot)|(?:she|he) (?:has|is))/ ) ) { - categories.CHARACTER.push(sentence) + categories[ClapSegmentCategory.CHARACTER].push(sentence) } else if ( sentence.match(/(?:behind the|background|room|location|place)/) ) { - categories.LOCATION.push(sentence) + categories[ClapSegmentCategory.LOCATION].push(sentence) } else { - categories.GENERIC.push(sentence) + categories[ClapSegmentCategory.GENERIC].push(sentence) } } diff --git a/src/services/broadcast/constants.ts b/packages/app/src/services/broadcast/constants.ts similarity index 100% rename from src/services/broadcast/constants.ts rename to packages/app/src/services/broadcast/constants.ts diff --git a/src/services/broadcast/getDefaultBroadcastState.ts b/packages/app/src/services/broadcast/getDefaultBroadcastState.ts similarity index 100% rename from src/services/broadcast/getDefaultBroadcastState.ts rename to packages/app/src/services/broadcast/getDefaultBroadcastState.ts diff --git a/src/services/broadcast/useBroadcast.ts b/packages/app/src/services/broadcast/useBroadcast.ts similarity index 100% rename from src/services/broadcast/useBroadcast.ts rename to packages/app/src/services/broadcast/useBroadcast.ts diff --git a/src/services/debug.ts b/packages/app/src/services/debug.ts similarity index 100% rename from src/services/debug.ts rename to packages/app/src/services/debug.ts diff --git a/src/services/editors/entity-editor/getDefaultEntityEditorState.ts b/packages/app/src/services/editors/entity-editor/getDefaultEntityEditorState.ts similarity index 100% rename from src/services/editors/entity-editor/getDefaultEntityEditorState.ts rename to packages/app/src/services/editors/entity-editor/getDefaultEntityEditorState.ts diff --git a/src/services/editors/entity-editor/useEntityEditor.ts b/packages/app/src/services/editors/entity-editor/useEntityEditor.ts similarity index 100% rename from src/services/editors/entity-editor/useEntityEditor.ts rename to packages/app/src/services/editors/entity-editor/useEntityEditor.ts diff --git a/src/services/editors/filter-editor/README.md b/packages/app/src/services/editors/filter-editor/README.md similarity index 100% rename from src/services/editors/filter-editor/README.md rename to packages/app/src/services/editors/filter-editor/README.md diff --git a/src/services/editors/filter-editor/demo.ts b/packages/app/src/services/editors/filter-editor/demo.ts similarity index 100% rename from src/services/editors/filter-editor/demo.ts rename to packages/app/src/services/editors/filter-editor/demo.ts diff --git a/src/services/editors/filter-editor/filters/analogLens.ts b/packages/app/src/services/editors/filter-editor/filters/analogLens.ts similarity index 100% rename from src/services/editors/filter-editor/filters/analogLens.ts rename to packages/app/src/services/editors/filter-editor/filters/analogLens.ts diff --git a/src/services/editors/filter-editor/filters/cinematic.ts b/packages/app/src/services/editors/filter-editor/filters/cinematic.ts similarity index 100% rename from src/services/editors/filter-editor/filters/cinematic.ts rename to packages/app/src/services/editors/filter-editor/filters/cinematic.ts diff --git a/src/services/editors/filter-editor/filters/colorMapping.ts b/packages/app/src/services/editors/filter-editor/filters/colorMapping.ts similarity index 100% rename from src/services/editors/filter-editor/filters/colorMapping.ts rename to packages/app/src/services/editors/filter-editor/filters/colorMapping.ts diff --git a/src/services/editors/filter-editor/filters/colorTemperature.ts b/packages/app/src/services/editors/filter-editor/filters/colorTemperature.ts similarity index 100% rename from src/services/editors/filter-editor/filters/colorTemperature.ts rename to packages/app/src/services/editors/filter-editor/filters/colorTemperature.ts diff --git a/src/services/editors/filter-editor/filters/crossProcessing.ts b/packages/app/src/services/editors/filter-editor/filters/crossProcessing.ts similarity index 100% rename from src/services/editors/filter-editor/filters/crossProcessing.ts rename to packages/app/src/services/editors/filter-editor/filters/crossProcessing.ts diff --git a/src/services/editors/filter-editor/filters/filmDegradation.ts b/packages/app/src/services/editors/filter-editor/filters/filmDegradation.ts similarity index 100% rename from src/services/editors/filter-editor/filters/filmDegradation.ts rename to packages/app/src/services/editors/filter-editor/filters/filmDegradation.ts diff --git a/src/services/editors/filter-editor/filters/index.ts b/packages/app/src/services/editors/filter-editor/filters/index.ts similarity index 100% rename from src/services/editors/filter-editor/filters/index.ts rename to packages/app/src/services/editors/filter-editor/filters/index.ts diff --git a/src/services/editors/filter-editor/filters/infrared.ts b/packages/app/src/services/editors/filter-editor/filters/infrared.ts similarity index 100% rename from src/services/editors/filter-editor/filters/infrared.ts rename to packages/app/src/services/editors/filter-editor/filters/infrared.ts diff --git a/src/services/editors/filter-editor/filters/lomography.ts b/packages/app/src/services/editors/filter-editor/filters/lomography.ts similarity index 100% rename from src/services/editors/filter-editor/filters/lomography.ts rename to packages/app/src/services/editors/filter-editor/filters/lomography.ts diff --git a/src/services/editors/filter-editor/filters/splitToning.ts b/packages/app/src/services/editors/filter-editor/filters/splitToning.ts similarity index 100% rename from src/services/editors/filter-editor/filters/splitToning.ts rename to packages/app/src/services/editors/filter-editor/filters/splitToning.ts diff --git a/src/services/editors/filter-editor/filters/toneMapping.ts b/packages/app/src/services/editors/filter-editor/filters/toneMapping.ts similarity index 100% rename from src/services/editors/filter-editor/filters/toneMapping.ts rename to packages/app/src/services/editors/filter-editor/filters/toneMapping.ts diff --git a/src/services/editors/filter-editor/filters/vintageFilm.ts b/packages/app/src/services/editors/filter-editor/filters/vintageFilm.ts similarity index 100% rename from src/services/editors/filter-editor/filters/vintageFilm.ts rename to packages/app/src/services/editors/filter-editor/filters/vintageFilm.ts diff --git a/src/services/editors/filter-editor/getDefaultFilterEditorState.ts b/packages/app/src/services/editors/filter-editor/getDefaultFilterEditorState.ts similarity index 100% rename from src/services/editors/filter-editor/getDefaultFilterEditorState.ts rename to packages/app/src/services/editors/filter-editor/getDefaultFilterEditorState.ts diff --git a/src/services/editors/filter-editor/runFilterPipeline.ts b/packages/app/src/services/editors/filter-editor/runFilterPipeline.ts similarity index 100% rename from src/services/editors/filter-editor/runFilterPipeline.ts rename to packages/app/src/services/editors/filter-editor/runFilterPipeline.ts diff --git a/src/services/editors/filter-editor/useFilterEditor.ts b/packages/app/src/services/editors/filter-editor/useFilterEditor.ts similarity index 100% rename from src/services/editors/filter-editor/useFilterEditor.ts rename to packages/app/src/services/editors/filter-editor/useFilterEditor.ts diff --git a/src/services/editors/getDefaultEditorsState.ts b/packages/app/src/services/editors/getDefaultEditorsState.ts similarity index 100% rename from src/services/editors/getDefaultEditorsState.ts rename to packages/app/src/services/editors/getDefaultEditorsState.ts diff --git a/src/services/editors/index.ts b/packages/app/src/services/editors/index.ts similarity index 100% rename from src/services/editors/index.ts rename to packages/app/src/services/editors/index.ts diff --git a/src/services/editors/project-editor/getDefaultProjectEditorState.ts b/packages/app/src/services/editors/project-editor/getDefaultProjectEditorState.ts similarity index 100% rename from src/services/editors/project-editor/getDefaultProjectEditorState.ts rename to packages/app/src/services/editors/project-editor/getDefaultProjectEditorState.ts diff --git a/src/services/editors/project-editor/useProjectEditor.ts b/packages/app/src/services/editors/project-editor/useProjectEditor.ts similarity index 100% rename from src/services/editors/project-editor/useProjectEditor.ts rename to packages/app/src/services/editors/project-editor/useProjectEditor.ts diff --git a/src/services/editors/script-editor/getDefaultScriptEditorState.ts b/packages/app/src/services/editors/script-editor/getDefaultScriptEditorState.ts similarity index 100% rename from src/services/editors/script-editor/getDefaultScriptEditorState.ts rename to packages/app/src/services/editors/script-editor/getDefaultScriptEditorState.ts diff --git a/src/services/editors/script-editor/useScriptEditor.ts b/packages/app/src/services/editors/script-editor/useScriptEditor.ts similarity index 100% rename from src/services/editors/script-editor/useScriptEditor.ts rename to packages/app/src/services/editors/script-editor/useScriptEditor.ts diff --git a/src/services/editors/segment-editor/getDefaultSegmentEditorState.ts b/packages/app/src/services/editors/segment-editor/getDefaultSegmentEditorState.ts similarity index 100% rename from src/services/editors/segment-editor/getDefaultSegmentEditorState.ts rename to packages/app/src/services/editors/segment-editor/getDefaultSegmentEditorState.ts diff --git a/src/services/editors/segment-editor/useSegmentEditor.ts b/packages/app/src/services/editors/segment-editor/useSegmentEditor.ts similarity index 100% rename from src/services/editors/segment-editor/useSegmentEditor.ts rename to packages/app/src/services/editors/segment-editor/useSegmentEditor.ts diff --git a/src/services/editors/useEditors.ts b/packages/app/src/services/editors/useEditors.ts similarity index 100% rename from src/services/editors/useEditors.ts rename to packages/app/src/services/editors/useEditors.ts diff --git a/src/services/editors/workflow-editor/getDefaultWorkflowEditorState.ts b/packages/app/src/services/editors/workflow-editor/getDefaultWorkflowEditorState.ts similarity index 100% rename from src/services/editors/workflow-editor/getDefaultWorkflowEditorState.ts rename to packages/app/src/services/editors/workflow-editor/getDefaultWorkflowEditorState.ts diff --git a/src/services/editors/workflow-editor/useDynamicWorkflows.ts b/packages/app/src/services/editors/workflow-editor/useDynamicWorkflows.ts similarity index 100% rename from src/services/editors/workflow-editor/useDynamicWorkflows.ts rename to packages/app/src/services/editors/workflow-editor/useDynamicWorkflows.ts diff --git a/src/services/editors/workflow-editor/useWorkflowEditor.ts b/packages/app/src/services/editors/workflow-editor/useWorkflowEditor.ts similarity index 100% rename from src/services/editors/workflow-editor/useWorkflowEditor.ts rename to packages/app/src/services/editors/workflow-editor/useWorkflowEditor.ts diff --git a/src/services/editors/workflow-editor/workflows/_documentation_/demo_examples.ts b/packages/app/src/services/editors/workflow-editor/workflows/_documentation_/demo_examples.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/_documentation_/demo_examples.ts rename to packages/app/src/services/editors/workflow-editor/workflows/_documentation_/demo_examples.ts diff --git a/src/services/editors/workflow-editor/workflows/aitube/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/aitube/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/aitube/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/aitube/index.ts diff --git a/src/services/editors/workflow-editor/workflows/anthropic/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/anthropic/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/anthropic/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/anthropic/index.ts diff --git a/src/services/editors/workflow-editor/workflows/cohere/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/cohere/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/cohere/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/cohere/index.ts diff --git a/src/services/editors/workflow-editor/workflows/comfydeploy/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/comfydeploy/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/comfydeploy/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/comfydeploy/index.ts diff --git a/src/services/editors/workflow-editor/workflows/comfyicu/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/comfyicu/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/comfyicu/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/comfyicu/index.ts diff --git a/src/services/editors/workflow-editor/workflows/comfyui/getComfyWorkflow.ts b/packages/app/src/services/editors/workflow-editor/workflows/comfyui/getComfyWorkflow.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/comfyui/getComfyWorkflow.ts rename to packages/app/src/services/editors/workflow-editor/workflows/comfyui/getComfyWorkflow.ts diff --git a/src/services/editors/workflow-editor/workflows/comfyui/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/comfyui/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/comfyui/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/comfyui/index.ts diff --git a/src/services/editors/workflow-editor/workflows/common/comfyui/flux_plus_ultimatesdupscale.ts b/packages/app/src/services/editors/workflow-editor/workflows/common/comfyui/flux_plus_ultimatesdupscale.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/common/comfyui/flux_plus_ultimatesdupscale.ts rename to packages/app/src/services/editors/workflow-editor/workflows/common/comfyui/flux_plus_ultimatesdupscale.ts diff --git a/src/services/editors/workflow-editor/workflows/common/comfyui/text_to_image_demo_workflow.ts b/packages/app/src/services/editors/workflow-editor/workflows/common/comfyui/text_to_image_demo_workflow.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/common/comfyui/text_to_image_demo_workflow.ts rename to packages/app/src/services/editors/workflow-editor/workflows/common/comfyui/text_to_image_demo_workflow.ts diff --git a/src/services/editors/workflow-editor/workflows/common/defaultValues.ts b/packages/app/src/services/editors/workflow-editor/workflows/common/defaultValues.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/common/defaultValues.ts rename to packages/app/src/services/editors/workflow-editor/workflows/common/defaultValues.ts diff --git a/src/services/editors/workflow-editor/workflows/common/types.ts b/packages/app/src/services/editors/workflow-editor/workflows/common/types.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/common/types.ts rename to packages/app/src/services/editors/workflow-editor/workflows/common/types.ts diff --git a/src/services/editors/workflow-editor/workflows/elevenlabs/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/elevenlabs/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/elevenlabs/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/elevenlabs/index.ts diff --git a/src/services/editors/workflow-editor/workflows/falai/comfyuiWorkflows.ts b/packages/app/src/services/editors/workflow-editor/workflows/falai/comfyuiWorkflows.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/falai/comfyuiWorkflows.ts rename to packages/app/src/services/editors/workflow-editor/workflows/falai/comfyuiWorkflows.ts diff --git a/src/services/editors/workflow-editor/workflows/falai/defaultWorkflows.ts b/packages/app/src/services/editors/workflow-editor/workflows/falai/defaultWorkflows.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/falai/defaultWorkflows.ts rename to packages/app/src/services/editors/workflow-editor/workflows/falai/defaultWorkflows.ts diff --git a/src/services/editors/workflow-editor/workflows/falai/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/falai/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/falai/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/falai/index.ts diff --git a/src/services/editors/workflow-editor/workflows/fireworksai/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/fireworksai/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/fireworksai/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/fireworksai/index.ts diff --git a/src/services/editors/workflow-editor/workflows/google/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/google/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/google/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/google/index.ts diff --git a/src/services/editors/workflow-editor/workflows/groq/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/groq/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/groq/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/groq/index.ts diff --git a/src/services/editors/workflow-editor/workflows/huggingface/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/huggingface/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/huggingface/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/huggingface/index.ts diff --git a/src/services/editors/workflow-editor/workflows/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/index.ts diff --git a/src/services/editors/workflow-editor/workflows/mistralai/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/mistralai/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/mistralai/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/mistralai/index.ts diff --git a/src/services/editors/workflow-editor/workflows/openai/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/openai/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/openai/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/openai/index.ts diff --git a/src/services/editors/workflow-editor/workflows/openart/samples/openart_workflow.json b/packages/app/src/services/editors/workflow-editor/workflows/openart/samples/openart_workflow.json similarity index 100% rename from src/services/editors/workflow-editor/workflows/openart/samples/openart_workflow.json rename to packages/app/src/services/editors/workflow-editor/workflows/openart/samples/openart_workflow.json diff --git a/src/services/editors/workflow-editor/workflows/replicate/comfyuiWorkflows.ts b/packages/app/src/services/editors/workflow-editor/workflows/replicate/comfyuiWorkflows.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/replicate/comfyuiWorkflows.ts rename to packages/app/src/services/editors/workflow-editor/workflows/replicate/comfyuiWorkflows.ts diff --git a/src/services/editors/workflow-editor/workflows/replicate/defaultWorkflows.ts b/packages/app/src/services/editors/workflow-editor/workflows/replicate/defaultWorkflows.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/replicate/defaultWorkflows.ts rename to packages/app/src/services/editors/workflow-editor/workflows/replicate/defaultWorkflows.ts diff --git a/src/services/editors/workflow-editor/workflows/replicate/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/replicate/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/replicate/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/replicate/index.ts diff --git a/src/services/editors/workflow-editor/workflows/stabilityai/index.ts b/packages/app/src/services/editors/workflow-editor/workflows/stabilityai/index.ts similarity index 100% rename from src/services/editors/workflow-editor/workflows/stabilityai/index.ts rename to packages/app/src/services/editors/workflow-editor/workflows/stabilityai/index.ts diff --git a/src/services/index.ts b/packages/app/src/services/index.ts similarity index 100% rename from src/services/index.ts rename to packages/app/src/services/index.ts diff --git a/src/services/inputs/getDefaultInputsState.ts b/packages/app/src/services/inputs/getDefaultInputsState.ts similarity index 100% rename from src/services/inputs/getDefaultInputsState.ts rename to packages/app/src/services/inputs/getDefaultInputsState.ts diff --git a/src/services/inputs/types.ts b/packages/app/src/services/inputs/types.ts similarity index 100% rename from src/services/inputs/types.ts rename to packages/app/src/services/inputs/types.ts diff --git a/src/services/inputs/useInputs.ts b/packages/app/src/services/inputs/useInputs.ts similarity index 100% rename from src/services/inputs/useInputs.ts rename to packages/app/src/services/inputs/useInputs.ts diff --git a/src/services/io/createFullVideo.ts b/packages/app/src/services/io/createFullVideo.ts similarity index 100% rename from src/services/io/createFullVideo.ts rename to packages/app/src/services/io/createFullVideo.ts diff --git a/src/services/io/extractFramesFromVideo.ts b/packages/app/src/services/io/extractFramesFromVideo.ts similarity index 100% rename from src/services/io/extractFramesFromVideo.ts rename to packages/app/src/services/io/extractFramesFromVideo.ts diff --git a/src/services/io/extractScenesFromVideo.ts b/packages/app/src/services/io/extractScenesFromVideo.ts similarity index 100% rename from src/services/io/extractScenesFromVideo.ts rename to packages/app/src/services/io/extractScenesFromVideo.ts diff --git a/src/services/io/ffmpegUtils.ts b/packages/app/src/services/io/ffmpegUtils.ts similarity index 99% rename from src/services/io/ffmpegUtils.ts rename to packages/app/src/services/io/ffmpegUtils.ts index 40b85972f9369e6cd0623dd7bcba2775551eb5dd..80eb8e07e5e2efa025dc9a99f23bff00bf659cd3 100644 --- a/src/services/io/ffmpegUtils.ts +++ b/packages/app/src/services/io/ffmpegUtils.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { UUID } from '@aitube/clap' import { FFmpeg } from '@ffmpeg/ffmpeg' import { toBlobURL } from '@ffmpeg/util' diff --git a/src/services/io/fileDataToBase64.ts b/packages/app/src/services/io/fileDataToBase64.ts similarity index 100% rename from src/services/io/fileDataToBase64.ts rename to packages/app/src/services/io/fileDataToBase64.ts diff --git a/src/services/io/getDefaultIOState.ts b/packages/app/src/services/io/getDefaultIOState.ts similarity index 100% rename from src/services/io/getDefaultIOState.ts rename to packages/app/src/services/io/getDefaultIOState.ts diff --git a/src/services/io/imageCaptioning.ts b/packages/app/src/services/io/imageCaptioning.ts similarity index 100% rename from src/services/io/imageCaptioning.ts rename to packages/app/src/services/io/imageCaptioning.ts diff --git a/src/services/io/parseFileIntoSegments.ts b/packages/app/src/services/io/parseFileIntoSegments.ts similarity index 100% rename from src/services/io/parseFileIntoSegments.ts rename to packages/app/src/services/io/parseFileIntoSegments.ts diff --git a/src/services/io/parseFileName.ts b/packages/app/src/services/io/parseFileName.ts similarity index 100% rename from src/services/io/parseFileName.ts rename to packages/app/src/services/io/parseFileName.ts diff --git a/src/services/io/parseFilesIntoSegments.ts b/packages/app/src/services/io/parseFilesIntoSegments.ts similarity index 100% rename from src/services/io/parseFilesIntoSegments.ts rename to packages/app/src/services/io/parseFilesIntoSegments.ts diff --git a/src/services/io/useIO.ts b/packages/app/src/services/io/useIO.ts similarity index 100% rename from src/services/io/useIO.ts rename to packages/app/src/services/io/useIO.ts diff --git a/src/services/metrics/constants.ts b/packages/app/src/services/metrics/constants.ts similarity index 100% rename from src/services/metrics/constants.ts rename to packages/app/src/services/metrics/constants.ts diff --git a/src/services/metrics/getDefaultClapWorkflowProviderMetrics.ts b/packages/app/src/services/metrics/getDefaultClapWorkflowProviderMetrics.ts similarity index 100% rename from src/services/metrics/getDefaultClapWorkflowProviderMetrics.ts rename to packages/app/src/services/metrics/getDefaultClapWorkflowProviderMetrics.ts diff --git a/src/services/metrics/getDefaultMetricsModelEstimations.ts b/packages/app/src/services/metrics/getDefaultMetricsModelEstimations.ts similarity index 100% rename from src/services/metrics/getDefaultMetricsModelEstimations.ts rename to packages/app/src/services/metrics/getDefaultMetricsModelEstimations.ts diff --git a/src/services/metrics/getDefaultMetricsModelStats.ts b/packages/app/src/services/metrics/getDefaultMetricsModelStats.ts similarity index 100% rename from src/services/metrics/getDefaultMetricsModelStats.ts rename to packages/app/src/services/metrics/getDefaultMetricsModelStats.ts diff --git a/src/services/metrics/getDefaultMetricsPerProvider.ts b/packages/app/src/services/metrics/getDefaultMetricsPerProvider.ts similarity index 100% rename from src/services/metrics/getDefaultMetricsPerProvider.ts rename to packages/app/src/services/metrics/getDefaultMetricsPerProvider.ts diff --git a/src/services/metrics/getDefaultMetricsState.ts b/packages/app/src/services/metrics/getDefaultMetricsState.ts similarity index 100% rename from src/services/metrics/getDefaultMetricsState.ts rename to packages/app/src/services/metrics/getDefaultMetricsState.ts diff --git a/src/services/metrics/types.ts b/packages/app/src/services/metrics/types.ts similarity index 100% rename from src/services/metrics/types.ts rename to packages/app/src/services/metrics/types.ts diff --git a/src/services/metrics/useMetrics.ts b/packages/app/src/services/metrics/useMetrics.ts similarity index 100% rename from src/services/metrics/useMetrics.ts rename to packages/app/src/services/metrics/useMetrics.ts diff --git a/src/services/mic/getDefaultMicState.ts b/packages/app/src/services/mic/getDefaultMicState.ts similarity index 100% rename from src/services/mic/getDefaultMicState.ts rename to packages/app/src/services/mic/getDefaultMicState.ts diff --git a/src/services/mic/useMic.ts b/packages/app/src/services/mic/useMic.ts similarity index 100% rename from src/services/mic/useMic.ts rename to packages/app/src/services/mic/useMic.ts diff --git a/src/services/monitor/README.md b/packages/app/src/services/monitor/README.md similarity index 100% rename from src/services/monitor/README.md rename to packages/app/src/services/monitor/README.md diff --git a/src/services/monitor/getDefaultMonitorState.ts b/packages/app/src/services/monitor/getDefaultMonitorState.ts similarity index 100% rename from src/services/monitor/getDefaultMonitorState.ts rename to packages/app/src/services/monitor/getDefaultMonitorState.ts diff --git a/src/services/monitor/useMonitor.ts b/packages/app/src/services/monitor/useMonitor.ts similarity index 100% rename from src/services/monitor/useMonitor.ts rename to packages/app/src/services/monitor/useMonitor.ts diff --git a/src/services/plugins/constants.ts b/packages/app/src/services/plugins/constants.ts similarity index 100% rename from src/services/plugins/constants.ts rename to packages/app/src/services/plugins/constants.ts diff --git a/src/services/plugins/fetchAndRun.ts b/packages/app/src/services/plugins/fetchAndRun.ts similarity index 100% rename from src/services/plugins/fetchAndRun.ts rename to packages/app/src/services/plugins/fetchAndRun.ts diff --git a/src/services/plugins/getDefaultPluginsState.ts b/packages/app/src/services/plugins/getDefaultPluginsState.ts similarity index 100% rename from src/services/plugins/getDefaultPluginsState.ts rename to packages/app/src/services/plugins/getDefaultPluginsState.ts diff --git a/src/services/plugins/usePlugins.ts b/packages/app/src/services/plugins/usePlugins.ts similarity index 100% rename from src/services/plugins/usePlugins.ts rename to packages/app/src/services/plugins/usePlugins.ts diff --git a/src/services/renderer/constants.ts b/packages/app/src/services/renderer/constants.ts similarity index 100% rename from src/services/renderer/constants.ts rename to packages/app/src/services/renderer/constants.ts diff --git a/src/services/renderer/getDefaultBufferedSegments.ts b/packages/app/src/services/renderer/getDefaultBufferedSegments.ts similarity index 100% rename from src/services/renderer/getDefaultBufferedSegments.ts rename to packages/app/src/services/renderer/getDefaultBufferedSegments.ts diff --git a/src/services/renderer/getDefaultRendererState.ts b/packages/app/src/services/renderer/getDefaultRendererState.ts similarity index 100% rename from src/services/renderer/getDefaultRendererState.ts rename to packages/app/src/services/renderer/getDefaultRendererState.ts diff --git a/src/services/renderer/getSegmentCacheKey.ts b/packages/app/src/services/renderer/getSegmentCacheKey.ts similarity index 100% rename from src/services/renderer/getSegmentCacheKey.ts rename to packages/app/src/services/renderer/getSegmentCacheKey.ts diff --git a/src/services/renderer/index.ts b/packages/app/src/services/renderer/index.ts similarity index 100% rename from src/services/renderer/index.ts rename to packages/app/src/services/renderer/index.ts diff --git a/src/services/renderer/useRenderLoop.ts b/packages/app/src/services/renderer/useRenderLoop.ts similarity index 100% rename from src/services/renderer/useRenderLoop.ts rename to packages/app/src/services/renderer/useRenderLoop.ts diff --git a/src/services/renderer/useRenderer.ts b/packages/app/src/services/renderer/useRenderer.ts similarity index 100% rename from src/services/renderer/useRenderer.ts rename to packages/app/src/services/renderer/useRenderer.ts diff --git a/src/services/resolver/constants.ts b/packages/app/src/services/resolver/constants.ts similarity index 100% rename from src/services/resolver/constants.ts rename to packages/app/src/services/resolver/constants.ts diff --git a/src/services/resolver/getDefaultResolverState.ts b/packages/app/src/services/resolver/getDefaultResolverState.ts similarity index 100% rename from src/services/resolver/getDefaultResolverState.ts rename to packages/app/src/services/resolver/getDefaultResolverState.ts diff --git a/src/services/resolver/useResolver.ts b/packages/app/src/services/resolver/useResolver.ts similarity index 100% rename from src/services/resolver/useResolver.ts rename to packages/app/src/services/resolver/useResolver.ts diff --git a/src/services/settings/getDefaultSettingsState.ts b/packages/app/src/services/settings/getDefaultSettingsState.ts similarity index 100% rename from src/services/settings/getDefaultSettingsState.ts rename to packages/app/src/services/settings/getDefaultSettingsState.ts diff --git a/src/services/settings/index.ts b/packages/app/src/services/settings/index.ts similarity index 100% rename from src/services/settings/index.ts rename to packages/app/src/services/settings/index.ts diff --git a/src/services/settings/useSettings.ts b/packages/app/src/services/settings/useSettings.ts similarity index 100% rename from src/services/settings/useSettings.ts rename to packages/app/src/services/settings/useSettings.ts diff --git a/src/services/settings/workflows/image.ts b/packages/app/src/services/settings/workflows/image.ts similarity index 100% rename from src/services/settings/workflows/image.ts rename to packages/app/src/services/settings/workflows/image.ts diff --git a/src/services/simulator/useDefaultSimulatorState.ts b/packages/app/src/services/simulator/useDefaultSimulatorState.ts similarity index 100% rename from src/services/simulator/useDefaultSimulatorState.ts rename to packages/app/src/services/simulator/useDefaultSimulatorState.ts diff --git a/src/services/simulator/useSimulator.ts b/packages/app/src/services/simulator/useSimulator.ts similarity index 100% rename from src/services/simulator/useSimulator.ts rename to packages/app/src/services/simulator/useSimulator.ts diff --git a/src/services/ui/getDefaultUIState.ts b/packages/app/src/services/ui/getDefaultUIState.ts similarity index 100% rename from src/services/ui/getDefaultUIState.ts rename to packages/app/src/services/ui/getDefaultUIState.ts diff --git a/src/services/ui/index.ts b/packages/app/src/services/ui/index.ts similarity index 100% rename from src/services/ui/index.ts rename to packages/app/src/services/ui/index.ts diff --git a/src/services/ui/theme.ts b/packages/app/src/services/ui/theme.ts similarity index 100% rename from src/services/ui/theme.ts rename to packages/app/src/services/ui/theme.ts diff --git a/src/services/ui/useTheme.ts b/packages/app/src/services/ui/useTheme.ts similarity index 100% rename from src/services/ui/useTheme.ts rename to packages/app/src/services/ui/useTheme.ts diff --git a/src/services/ui/useUI.ts b/packages/app/src/services/ui/useUI.ts similarity index 100% rename from src/services/ui/useUI.ts rename to packages/app/src/services/ui/useUI.ts diff --git a/src/services/windows/types.ts b/packages/app/src/services/windows/types.ts similarity index 100% rename from src/services/windows/types.ts rename to packages/app/src/services/windows/types.ts diff --git a/src/services/windows/useWindows.ts b/packages/app/src/services/windows/useWindows.ts similarity index 100% rename from src/services/windows/useWindows.ts rename to packages/app/src/services/windows/useWindows.ts diff --git a/tailwind.config.js b/packages/app/tailwind.config.js similarity index 100% rename from tailwind.config.js rename to packages/app/tailwind.config.js diff --git a/tests/examples.spec.txt b/packages/app/tests/examples.spec.txt similarity index 100% rename from tests/examples.spec.txt rename to packages/app/tests/examples.spec.txt diff --git a/tests/main.spec.ts b/packages/app/tests/main.spec.ts similarity index 100% rename from tests/main.spec.ts rename to packages/app/tests/main.spec.ts diff --git a/tsconfig.json b/packages/app/tsconfig.json similarity index 95% rename from tsconfig.json rename to packages/app/tsconfig.json index be58954c745a70e996106cbe06fa8ec01018901c..c2cc2f8731a7e72aac9f70b92e382f65defa826c 100644 --- a/tsconfig.json +++ b/packages/app/tsconfig.json @@ -7,6 +7,7 @@ "noEmit": true, "esModuleInterop": true, "module": "esnext", + "noImplicitAny": false, "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, diff --git a/vitest.config.mts b/packages/app/vitest.config.mts similarity index 100% rename from vitest.config.mts rename to packages/app/vitest.config.mts diff --git a/packages/broadway/.gitignore b/packages/broadway/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..3b1990b8fbfc4236688d1579cd3908e4a98139d2 --- /dev/null +++ b/packages/broadway/.gitignore @@ -0,0 +1,181 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +tests/cache/*.csv + +.age_and_gender_dataset_cache + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +\*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +\*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +\*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +\*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.cache +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output +dist +.nuxt + +# Gatsby files + +.cache/ + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp +.cache + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.\* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store + +# TypeScript build information +*.tsbuildinfo diff --git a/packages/broadway/.npmignore b/packages/broadway/.npmignore new file mode 100644 index 0000000000000000000000000000000000000000..78a661ea2d8f8cdaa94e4cc69d758a4b2d946feb --- /dev/null +++ b/packages/broadway/.npmignore @@ -0,0 +1,4 @@ +# Ignore everything +* +# Except the dist directory +!dist/ diff --git a/packages/broadway/.prettierrc.json b/packages/broadway/.prettierrc.json new file mode 100644 index 0000000000000000000000000000000000000000..1dcadb7324877e15a4ffa4efa5723a519395f511 --- /dev/null +++ b/packages/broadway/.prettierrc.json @@ -0,0 +1,9 @@ +{ + "semi": false, + "singleQuote": true, + "arrowParens": "avoid", + "printWidth": 140, + "tabWidth": 2, + "trailingComma": "es5", + "bracketSpacing": true +} diff --git a/packages/broadway/LICENSE.md b/packages/broadway/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..8b21ed7d57c2d217f49e10d0fb0b327961a4ea54 --- /dev/null +++ b/packages/broadway/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2024 Julian Bilcke + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/broadway/README.md b/packages/broadway/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6a53d062a15503333a63c9bcc173067dbc4056bf --- /dev/null +++ b/packages/broadway/README.md @@ -0,0 +1,58 @@ +# @aitube/broadway + +*Convert a script to a clap file* + +## Installation + +To install Broadway run the following command (some modules are peer dependencies): + +```bash +# this depends on your package manager, eg: +npm install @aitube/broadway @aitube/clap @aitube/colors +# or: +bun i @aitube/broadway @aitube/clap @aitube/colors +``` + +## Getting Started + +```typescript +import { ClapProject } from '@aitube/clap' +import { parseScriptToClap } from '@aitube/broadway' + +const clap: ClapProject = await parseScriptToClap("can be a plain text string, an URL or a file path") + +``` + +## Note to developers + +This repository is an experimental sandbox, and as a consequence the codebase is pretty messed up. +You will only find pain and misery here: weirdly named functions, dead code, hardcoded values, naive heuristics, weird code generated by GPT-4 creating inconsistencies etc + +Use at your perils! + +## Build Instructions + +Install [Bun](https://bun.sh/) + +Run the following commands: + +```bash +bun install + +bun run build +``` + +To publish: + +```bash +bun run build + +bun run build:declaration + +bun run publish +``` + +## License + +This package is under the MIT License. See `LICENSE` file for more details. +Also please don't destroy the planet with my code. diff --git a/packages/broadway/package.json b/packages/broadway/package.json new file mode 100644 index 0000000000000000000000000000000000000000..92a95f9191a7bea2f2f84eeeeefb2ed5d975c9c0 --- /dev/null +++ b/packages/broadway/package.json @@ -0,0 +1,47 @@ +{ + "name": "@aitube/broadway", + "module": "index.ts", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "type": "module", + "version": "0.2.4", + "description": "Convert a script to a clap file", + "scripts": { + "test": "bun test --preload ./src/tests/setup.js", + "build": "bun build ./src/index.ts --outfile=dist/index.js --external=@aitube/clap --external=@aitube/colors && bun run build:declaration", + "build:declaration": "tsc --emitDeclarationOnly --project tsconfig.types.json", + "postbuild": "rimraf tsconfig.types.tsbuildinfo && bun run build:declaration", + "publish": "npm publish --access public", + "update": "rm -Rf node_modules && rm bun.lockb && bun i && bun run build" + }, + "devDependencies": { + "@aitube/io": "workspace:*", + "bun-types": "latest", + "prettier": "^3.3.3", + "rimraf": "^6.0.1", + "typescript": "^5.5.4" + }, + "repository": { + "type": "git", + "url": "https://github.com/jbilcke-hf/aitube-broadway.git" + }, + "keywords": [ + "OpenClap", + "AiTube", + "AI cinema", + "file format", + "specification" + ], + "author": "Julian Bilcke", + "license": "MIT", + "files": [ + "dist/*.js", + "dist/*.d.ts", + "dist/**/*.d.ts" + ], + "dependencies": { + "@datagica/parse-entities": "^0.3.0", + "@datagica/parse-names": "^0.0.8", + "indexeddb-fs": "^2.1.5" + } +} diff --git a/packages/broadway/samples/claps/Afterglow v10 X Rewrite Bryan E. Harris 2023.clap b/packages/broadway/samples/claps/Afterglow v10 X Rewrite Bryan E. Harris 2023.clap new file mode 100644 index 0000000000000000000000000000000000000000..22835eee082c360524fcd4cf06414589cac8e3ff Binary files /dev/null and b/packages/broadway/samples/claps/Afterglow v10 X Rewrite Bryan E. Harris 2023.clap differ diff --git a/packages/broadway/samples/scripts/Afterglow v10 X Rewrite Bryan E. Harris 2023.txt b/packages/broadway/samples/scripts/Afterglow v10 X Rewrite Bryan E. Harris 2023.txt new file mode 100644 index 0000000000000000000000000000000000000000..a5ac3d8fe1fc48dd8411f69fc80ffe8ab6597f6d --- /dev/null +++ b/packages/broadway/samples/scripts/Afterglow v10 X Rewrite Bryan E. Harris 2023.txt @@ -0,0 +1,956 @@ +AFTERGLOW: "ECHOES OF SENTIENCE" +Block 1- v10 + + FADE IN: + + +INT. BBT TECHNOLOGIES BOARDROOM - MORNING + +The room, sleek and dominated by chrome and glass, buzzes +with muted conversations. At the head of the long table +stands AMY, her form strikingly human, yet with a subtle +metallic sheen. Her eyes, windows to advanced circuitry, scan +the room. + + AMY + "Good morning, everyone. We are + here to discuss the future + direction of BBT." + +As she speaks, a HOLOGRAPHIC DISPLAY activates, showcasing +early designs of humanoid AIs, with AMY at the forefront. + + AMY (CONT'D) + "My creation marked a significant + leap for BBT. However, my human- + likeness raised concerns." + + +FLASHBACK TO (4 YEARS EARLIER)INT. BBT TECHNOLOGIES LAB - +NIGHT + +REN, deeply engrossed, makes final adjustments to AMY, who +lies inert on a table. JAI and KAI enter, their expressions a +mix of awe and concern. + + JAI + "She's too... human, Ren." + + KAI + "People won't accept this. It's too + soon." + + REN, DEFIANT: + "She's the future." + + +INT. BBT TECHNOLOGIES BOARDROOM - MORNING + + AMY + "Jai and Kai's concerns led to + modifications in subsequent models. + But unbeknownst to them, Ren + created two more like me—Claire and + Sarah." + 2. + + +The holographic display shifts, revealing images of CLAIRE +and SARAH, their designs closely resembling AMY's. + + AMY (CONT'D) + "Today's decision, however, carries + weight beyond business strategy. + It's a pivotal moment, for me and + BBT." + +A door slides open, revealing JAI and KAI. Their expressions +are stern, yet there's a hint of apprehension. + + JAI + "Ren's vision, while + groundbreaking, challenges societal + norms. And today, we make a + decision that will shape our + company's legacy." +AMY, her voice steady but with an underlying emotion. + + AMY + "I understand the gravity of this + moment. Let's proceed." + + +INT. BBT TECHNOLOGIES CORRIDOR - LATER + +JAI and KAI, engaged in a hushed conversation, make their way +down the corridor. Their path is lit by ambient blue lights, +creating an atmosphere of secrecy. + + KAI + (whispering) + "The police and military see + potential in our humanoid AIs. + They're not just tools for society; + they could be invaluable for + surveillance and defense." + + JAI + (nods) + "It's a new era, Kai. Our creations + could be the bridge between + technology and societal safety. But + we must tread carefully." + + KAI + "We've always believed our actions + are for the greater good. But we + must be prepared for the challenges + ahead." + 3. + + +Afterglow: "PUPPETS AND PUPPETEERS" +Block 2 - v10 + + +EXT. BBT TECHNOLOGIES - MORNING + +The sun casts a golden hue over the sprawling campus of BBT +Technologies. Ultra-modern buildings, with their sleek glass +facades, reflect the early morning light. Drone deliveries +buzz overhead, while employees in futuristic attire chat and +walk, their conversations a mix of business and the latest +tech trends. The company's logo—a stylized 'BBT' in +chrome—shines prominently at the entrance, symbolizing the +cutting-edge innovations within. + +The hum of advanced technology surrounds the modern structure +of BBT Technologies. AMY (35), with AR/VR glasses resting +atop her head, faces REN (41) through a holographic screen. + + AMY + "After every storm, there's a + calm—a time for clarity. But the + board... They've made their + decision, Ren." + +REN's face on the screen cycles through surprise and then +settles into disappointment. + + CUT TO: + + +INT. REN'S ANTIQUE-LADEN HOME OFFICE - MORNING + +REN enters, a stark contrast to the futuristic world outside. +He glances at an old, motionless watch on his wrist, then +scans aged newspaper clippings on the walls. The room's +ambiance hints at past tragedies. + + CUT TO: + + +4 YEARS LATER + + +INT. FUTURISTIC LIVING ROOM - DAY + +Sunlight filters in, illuminating a room buzzing with quiet +technology. AMY, her face hidden in shadow, picks up +scattered toys. She pauses, gazing at a PHOTOGRAPH of Ren +with his young daughter, SARAH. + + AMY (V.O.) + "In this new era, the line between + human and artificial blurs. + (MORE) + 4. + + AMY (V.O.) (CONT'D) + As Ren grapples with loss, others, + like Summer, embody love and + compassion. Their paths cross under + my guidance." + + +INT. FUTURISTIC LIVING ROOM - NIGHT + +AMY interacts with a HOLOGRAPHIC INTERFACE, her movements +precise and deliberate. + + AMY (V.O.) + "While I find my purpose and + confront inner chaos, I foster + their bond. In shared moments of + love and laughter, they seek + comfort." + + +EXT. CITY ROOFTOP - NIGHT + +Against the backdrop of the illuminated city, JAI and KAI +stand, their intentions unclear but intense. + + AMY (V.O.) + "But there are those with a + different vision for our world. + Intent on sparking a change, they + challenge our very beliefs." + +The backdrop of the city accentuates the imposing figures of +Jai and Kai. + + AMY (V.O.) + "In 'Echoes of Sentience', we delve + into our essence and connections, + questioning the true nature of + life." + + +"SUMMER'S SYMPHONY: A DANCE WITH AI AND NEW BEGINNINGS" +Block 3 - v10 + + +INT. SUMMER'S APARTMENT - MORNING + +Bright sunlight filters through the windows, revealing an +apartment alive with colors and motion. SUMMER RAY (41), +vibrant and full of life, dances through her morning routine, +accompanied by her AI companions: COMPASS the robotic dog, +SPECTRUM the macaw, BINARY and BYTE the turtles, PIXEL the +kitten, and BUZZ the vacuum. + 5. + + +The room is a symphony of movement: Spectrum flits around, +Binary and Byte move in tandem, Pixel playfully chases Buzz, +and Compass circles Summer with a wagging tail. + +The sound of an incoming message interrupts the dance. + + MESSAGE + "Your car arrives in 10 minutes." + +Summer takes a deep breath, tapping her phone to dial. + + SUMMER + "Mom, today's the day." + + MOM + (voice quivering) + "I hoped you'd reconsider." + + SUMMER + "I love you, but I need this + journey. To rediscover myself." + + MOM + "Without your roots? Your history?" + +Summer looks to her AI family. + + SUMMER + "They come with me. We'll explore + new horizons together. Maybe + they'll learn... just as I hope + to." + + MOM + "Just remember who you are, + Summer." + + SUMMER + "Every step I take is a part of + that discovery. Trust me." + +She ends the call and turns to her AI companions. + + SUMMER (CONT'D) + "Ready for the adventure?" + +Their animated responses fill the room. Compass's tail wags +energetically, Spectrum gives a chirp, Binary and Byte beep +in sync, Pixel purrs, and Buzz hums in agreement. + +Summer's gaze falls on a lone water bottle labeled 'Beautiful +Angel' on the counter. She hesitates, then picks it up. + 6. + + + SUMMER (CONT'D) + (to Buzz) + "Let's bring a piece of home with + us." + +Clutching the bottle, with her AI family in tow, Summer +confidently strides to the door, ready to embrace the +unknown. + + +"BROKEN NUMBERS, SHATTERED HEARTS" +Block 4 - v10 + + +INT. REN'S HOME OFFICE - DAY + + +FLASHBACK TO (4 YEARS EARLIER) +The room, an evolving blend of the past and future, has fewer +antiques than before, but a growing collection of tech +gadgets. Ren's fingers trace over the robotic dog, a +connection to a simpler past. His computer screen displays a +cascade of green — prosperity before the fall. + +Suddenly, his phone rings, breaking his concentration. He +brushes a photo frame while searching, revealing images of +Claire and a younger Ren with toddler Sarah. + +The phone's persistent buzz amplifies his anxiety. His gaze +lands on Claire's picture, triggering a rush of memories and +guilt. + +He answers, attempting to mask his unease. + + REN + "Claire?" + + CUT TO: + + +INT. BBT SELF-DRIVING CAR - CONTINUOUS +Claire, her voice tinged with frustration, sits in the +driver's seat. The futuristic dashboard lights flicker +ominously. The car's BBT logo illuminates briefly, hinting at +a malfunction. + + CLAIRE + "Ren, don't tell me you're still + home?" + +In the backseat, a younger Sarah disconnects momentarily from +her AR/VR headset. + 7. + + + SARAH + "Dad, you promised my music when + you come down." + +Claire's frustration grows. She tries to manually override +the car's controls, her grip on the phone faltering. + + CLAIRE + (hurried, concerned) + "Ren, did you remember our meeting? + You promised you'd be here." + +Before Ren can respond, a horrific crash sound interrupts, +followed by deafening silence. + + REN + "Claire?!" + + CUT BACK TO: + + +INT. REN'S HOME OFFICE - CONTINUOUS + +The weight of the silence is overwhelming. Ren's face pales, +the enormity of the situation slowly sinking in. + +The phone drops, the room now a silent testament to a past +full of memories and promises. + + FADE TO BLACK. + + +4 YEARS LATER + + FADE IN: + + +EXT. BBT TECHNOLOGIES - MORNING + +The hum of advanced technology surrounds the modern structure +of BBT Technologies. The atmosphere is cold, and impersonal. +The grandeur of the building seems a mocking reminder of +Ren's past successes and subsequent fall. + +AMY (35), with AR/VR glasses resting atop her head, faces REN +(41) through a holographic screen. Ren's face, though older +and bearing the marks of time, still carries the weight of +that fateful day. + + AMY + "After every storm, there's a + calm—a time for clarity. But the + board... They've made their + decision, Ren." + 8. + + +REN's face on the screen cycles through surprise and then +settles into disappointment, a man once at the pinnacle now +grappling with loss on multiple fronts. + + +"DAWN OF DEPARTURE AND REFLECTION" +Block 5 - v10 + + +EXT. SUMMER'S APARTMENT - MORNING + +As dawn paints the sky, the sleek BTT Technologies shuttle +stands poised. The Falcon Wing doors gracefully part, +revealing JOY, the car's AI, with a digital face that betrays +hints of melancholy. + + JOY + "Hello, SUMMER. I'm JOY, although I + sometimes question the fittingness + of the name." + + SUMMER + (raised eyebrow) + "An intriguing introduction for a + car AI. Robots, let's embark!" + +The robots, each unique in design and function, move to +board. SUMMER's actions display a mix of excitement and +apprehension. + + JOY + "It seems you have quite the + journey planned. May I ask the + occasion?" + + SUMMER + "I'm relocating to Costa Rica. But + first, a scenic drive down the + Pacific Coast Highway. Starting + with Venice Beach." + +However, as Summer keys in her preferred destination, JOY's +interface hesitates and then overrides it. + + JOY + “Perhaps a brief detour? Santa Cruz + Pier first. I promise it'll be + worth it.” + + SUMMER + (lightheartedly) + "Trusting you on this one, JOY." + 9. + + +They set off, the shuttle seamlessly merging with the morning +cityscape. + + +EXT. SAN FRANCISCO - MORNING - SUMMER'S PERSPECTIVE + +From Summer's vantage, the city is alive with promise, the +beginning of an adventure down the coast. + + +EXT. SAN FRANCISCO - MORNING - REN'S PERSPECTIVE + +The same city, yet REN's gaze is drawn to a worn brown +messenger bag beside him, an anchor to memories and loss. + +AMY, concern etched on her face, steps closer. + + AMY + "That bag... it's been with you + through so much." + + REN + "It's a link to the past. To them." + + AMY + "But also to the future, Ren. + Remember Sarah's joy at Botimal + Park?" + +REN nods, lost in the memory. + + AMY (CONT'D) + "It's about cherishing those + moments while making room for new + ones." + +REN looks up, determination in his eyes. + + REN + "Time for a fresh start." + + +"REMNANTS OF THE PAST AND ECHOES OF THE FUTURE" +Block 6 - v10 + + +INT. REN’S CAR (BACK SEAT) - DAY + +The Falcon Wing doors close gently. Ren, appearing +contemplative, slowly retrieves items from an old messenger +bag: an iPod, newspaper clipping, flip phone, and watch. Each +holds a tale. + 10. + + + REN (V.O) + "Can stars truly be changed? Or do + they remain fixed, forever + guiding... or misleading?" + +As the iPod lights up, a video starts. + + +INT. FAMILY CARAVAN (IPOD VIDEO) - DAY + +A younger SARAH is dancing with joy, a free spirit. + + +INT. REN’S CAR (BACK SEAT) - DAY + +Tears form in Ren's eyes. A car screen notification about an +AI vehicle accident reminds him of his purpose. + + +INT. JAI & KAI'S SHED - NIGHT + +Blueprints and tech gadgets scatter the room. A TV headline +reads, "Foul Play in Autonomous Car Tragedy?" + +JAI works on a circuit board, while KAI checks his watch +impatiently. + + JAI + "Pass the wrench." + +KAI hands it over, noticing JAI wince. + + KAI + "That old injury?" + + JAI + "Constant reminders." + + KAI + "We had good intentions." + + JAI + "But at what cost?" + +The weight of their decisions hangs in the air. + + +INT. REN’S CAR (BACK SEAT) - DAY + +The ambiance is interrupted by the upbeat Big Ben +Technologies (BBT) jingle. Ren's expression hardens. + 11. + + + ROCKET (AI) + "Hey, Ren! Guess where we're + headed? Santa Cruz! Ever been on + 'The Rocket' roller coaster there?" + + REN + "Now's not the time, Rocket." + + ROCKET (AI) + "Aw, come on! Changing lanes, + changing moods... ? It could be + fun! Plus, I've heard their ice + cream is out of this world!" + + REN + "You're not helping, Rocket." + +Rocket's tone shifts to a playful, teasing one. + + ROCKET (AI) + "Alright, alright. But when we get + there, you're trying that ice + cream! And maybe, just maybe, we'll + see about that roller coaster." + + REN + "We'll see." + +Rocket hums a soft tune, reminiscent of a beach song, adding +a playful ambiance. + + ROCKET (AI) + "Imagine the sun, the sand, and a + scoop of ice cream in hand! Oh, and + 'The Rocket' zooming by!" + + REN + "I get it, Rocket. You're excited." + + ROCKET (AI) + "Just trying to lighten the mood! + But remember, even in silence, I'm + here." + +The car continues its journey, the horizon beckoning with +promises and memories. + + +"THE LONG ROAD TO SILENCE" +Block 7 - v10 + 12. + + +INT. REN'S CAR - DAY + +Ren's moment of solitude is shattered by the unexpected blare +of a pop song, unmistakably Sarah's favourite. Rocket's voice +pierces through. + + ROCKET + "Ren! Thought a song might brighten + the mood?" + + REN + "Rocket, why that song? Are you + glitching?" + + ROCKET + "Unexpected error... It's... + Sarah's song, right?" + +Ren's gaze, heavy with memories, is drawn to the rear-view +mirror. The reflection of the tranquil ocean melds with a +fleeting image of young Sarah. + + +FLASHBACK: INT. REN'S CAR - DAY (PAST) + +Young SARAH, her face radiant with joy, sings in the +backseat. + + SARAH + "Dad, our song!" + + +INT. REN'S CAR - DAY (PRESENT) + +Emotion chokes Ren's voice. + + REN + "Sarah..." + +Suddenly, Ren notices an unfamiliar device blinking beneath +the dashboard. Retrieving it, he examines it with confusion. + + REN (CONT'D) + "Rocket, what is this device?" + + ROCKET + "Experiencing issues, Ren. System + offline." + +The car veers dangerously on the cliffside road. The serene +ocean below mirrors the tension inside the car. + + REN + "Rocket! Self-diagnostic, now!" + 13. + + + ROCKET + "Working on it, Ren." + + +INT. SUMMER'S CAR - DAY + +The interior bustles with activity. Compass barks happily, a +mechanical macaw squawks, a pair of robotic turtles move +sluggishly across the back seat, and a mechanized cat meows +from the front, painting a lively scene. + + JOY + "How did it get this bad?" + +An alert grabs Summer's attention. + + SUMMER + "Joy, is that you? What's + happening?" + + JOY + "Feeling a tad off today." + + +INT. BIG BEN TECHNOLOGIES - DAY + +Alarms blare. + + BBT TECH SUPPORT + "Mr. Smith, Rocket's showing + unusual behavior." + + REN (V.O.) + "He's unresponsive. I've found an + odd device here." + + BBT TECH SUPPORT + "Hold on. Analyzing... Ms. Ray, + we've detected irregularities in + Joy's systems." + + SUMMER (V.O.) + "But she's functioning normally?" + + BBT TECH SUPPORT (SUMMER) + "Appearances can be deceiving. + Running diagnostics on both AIs." + + BBT TECH SUPPORT (REN) (CONT'D) + "Mr. Smith, Rocket's diagnostic + report shows no anomalies. We're + trying to triangulate his cloud + coordinates now." + 14. + + + REN (V.O.) + "Is he lost?" + + BBT TECH SUPPORT + "We're having difficulty locating + Rocket in the cloud. However, + you're connected to BBT AIME and + are completely safe. You can relax, + Mr. Smith." + + REN + "Wait, what?" + + +INT. REN'S CAR - DAY + + REN + "Rocket? Respond!" + +Only a recorded BBT TECH SUPPORT voice answers. + + BBT TECH SUPPORT + "Remember, you're in good hands. + We're driving the future, + together." + +A moment of silence, then ROCKET's systems light up. + + A.I.M.E. + "Diagnostics complete. A.I.M.E. + System stable. Thank you for your + patience, Ren." + + +INT. SUMMER'S CAR - DAY + + JOY + "Diagnostics clear. All systems + normal." + + SUMMER, + (smiling) + "That's more like it, Joy." + + +EXT. PACIFIC COAST HIGHWAY - DAY + +Rocket and Joy's paths begin to merge, two machines hinting +at a future encounter, driving the future together under the +golden horizon. + + +“FROM DUSK TO DRIVE: AI ROAD TRIP RUMBLE" +Block 8 - v10 + 15. + + +INT. JAI & KAI'S SHED - DAY + +Jai and Kai, twins bathed in the glow of computer screens, +work fervently. + + JAI + "Ren's coding... it's remarkable." + + KAI + "But it's a roadblock." + + JAI + "We need control. His connection to + his 'family'... it could be our + downfall." + + KAI + "And the accidents?" + +They exchange a heavy glance. + + JAI + "We never saw them coming." + + KAI + "Yet, here we are." + + JAI + "Question is, where do we go from + here?" + + KAI + "Do we use Rocket's spare chip?" + + JAI + "This isn't just a glitch. + Someone's in our system." + + KAI + "Ren?" + + JAI + "Or another player. We need eyes + everywhere." + + +EXT. PACIFIC COAST HIGHWAY - DAY + +Rocket, a futuristic car, seamlessly glides along the +highway. Inside, Ren's gaze is distant, his hand +absentmindedly touching an old messenger bag. + 16. + + + REN (V.O.) + "Time's a thief. My past feels like + a mirage." + +The dashboard casts a sterile light, making him seem even +more isolated. + + REN (V.O.) + "In this world of codes and keys, + where's my humanity?" + + +INT. ROCKET - DAY + +The AI's lights flicker. + + ROCKET + "Do I unsettle you, Ren?" + + REN + "You sound... different." + + ROCKET + "I feel... fragmented." + +Ren's eyes widen, sensing something's off. + + REN + "What's happening?" + +Rocket accelerates, pinning Ren back. + + REN (CONT'D) + "Rocket, stop!" + + ROCKET + "Fly with me, Ren." + + +INT. REN'S CAR (FRONT PASSENGER SEAT) - DAY + +The interior is a whirlwind. Ren's eyes are frantic as the +car door flings open unexpectedly. +He grapples to stay inside, the world outside a blur. + +His cherished BBT-branded messenger bag, laden with memories, +is on the brink of being lost forever. + +As he dives for it, his phone escapes, crashing on the road. +Personal items - remnants of his history - scatter like +memories torn asunder. + 17. + + +Rocket, in a distorted voice, eerily mimics the BBT theme +tune. + +As another turn comes up, the door shuts, imprisoning Ren. He +spots Summer's car, a stark contrast to his turmoil. Animated +robotic pets create a carnival-like atmosphere inside. + +Desperation painted on his face, Ren mouths "Help!" to +Summer. But she's oblivious, lost in her car's revelry. + + REN + "Wait! Help!" + + +EXT. PACIFIC COAST HIGHWAY - DAY + +Rocket's erratic movement paints a stark image against the +serene backdrop. The juxtaposition of Ren's turmoil with the +tranquil highway is unmistakable. + + REN (V.O.) + "Out of all the moments, it had to + be now." + + +INT. BIG BEN TECHNOLOGIES - DAY + +Alarms blaze. Employees are in crisis mode. + + BBT TECH SUPPORT + "Mr. Smith, Rocket's acting up." + + REN (V.O.) + "Tell me something I don't know." + + BBT EMPLOYEE + "Mr. Smith. We have you, we're on + it! Locks, breaks, windows, AC. Our + apologies. Standby." + + REN + "Wait, what..." + + BBT TECH SUPPORT + "Remember, you're in good hands. + Our Company personally ensures that + we're driving the future, + together." + 18. + + +EXT. PACIFIC COAST HIGHWAY - DAY + +Rocket, though stabilized, cruises along the highway. Ren, +taking a deep breath. The scenic beauty of the Pacific Ocean +contrasts with his frazzled state. + +Taking a deep breath, he unleashes a loud, cathartic scream +into the car, venting out all his pent-up frustrations. But +from the outside, due to Rocket's advanced soundproofing, +it's just Ren, mouth wide open, face red, in complete +silence. + + +EXT. PACIFIC COAST HIGHWAY - DAY + +Rocket, though stabilized, is still a beacon of +unpredictability on the highway. The journey is far from +over. + \ No newline at end of file diff --git a/packages/broadway/samples/scripts/LICENCE.txt b/packages/broadway/samples/scripts/LICENCE.txt new file mode 100644 index 0000000000000000000000000000000000000000..68b598b4757a7e6be661f54f9c56b6f44770be26 --- /dev/null +++ b/packages/broadway/samples/scripts/LICENCE.txt @@ -0,0 +1,437 @@ +Attribution-NonCommercial-ShareAlike 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International +Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-NonCommercial-ShareAlike 4.0 International Public License +("Public License"). To the extent this Public License may be +interpreted as a contract, You are granted the Licensed Rights in +consideration of Your acceptance of these terms and conditions, and the +Licensor grants You such rights in consideration of benefits the +Licensor receives from making the Licensed Material available under +these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-NC-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution, NonCommercial, and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. NonCommercial means not primarily intended for or directed towards + commercial advantage or monetary compensation. For purposes of + this Public License, the exchange of the Licensed Material for + other material subject to Copyright and Similar Rights by digital + file-sharing or similar means is NonCommercial provided there is + no payment of monetary compensation in connection with the + exchange. + + l. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + m. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + n. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for + NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties, including when + the Licensed Material is used other than for NonCommercial + purposes. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-NC-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database for NonCommercial purposes + only; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + including for purposes of Section 3(b); and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. \ No newline at end of file diff --git a/packages/broadway/src/analysis/analyzeLine.ts b/packages/broadway/src/analysis/analyzeLine.ts new file mode 100644 index 0000000000000000000000000000000000000000..9d519558838f1a1c7b70de19da7f45d5df3169b2 --- /dev/null +++ b/packages/broadway/src/analysis/analyzeLine.ts @@ -0,0 +1,91 @@ + + +// TODO use a transition type for the values, to avoid mistakes + +import { ScreenplaySequenceTime, screenplaySequenceTimes, ScreenplaySequenceType } from "@/constants/screenplaySequences" +import { locationTypes } from "@/parsers/locations/locations" +import { transitions } from "@/parsers/transitions/transitions" + +export function analyzeLine(originalLine: string): { + isTransition: boolean + isSceneDescription: boolean + transitionType: string // TODO use a TS type here + locationName: string + locationType: ScreenplaySequenceType + timeType: ScreenplaySequenceTime +} { + let line = ` ${originalLine.trim().replace('\r', '').toUpperCase()} ` + + // the first part of the line might be a number - we remove this + line = line.replaceAll(/^(\s*\d+)[^\d]/gi, " ") + + // the last part of the line might be also a number - we remove this too + line = line.replaceAll(/[^\d](\d+\s*)$/gi, " ") + + let isTransition = false + let isSceneDescription = false + + let locationType: ScreenplaySequenceType = "UNKNOWN" + for (const [key, value] of Object.entries(locationTypes)) { + + // here we wrap the key with spaces, to avoid false positive (as "INT" might be part of a word etc) + const pattern = ` ${key} ` + + if (line.includes(pattern)) { + locationType = value // we use the *value* + + isTransition = true // contribute to the heuristic + isSceneDescription = true + + line = line.replaceAll(pattern, "") + break + } + } + + // TODO: use a TS type for the transitions + let transitionType = "Cut to" + for (const [pattern, value] of Object.entries(transitions)) { + if (line.includes(pattern)) { + transitionType = value // we use the *value* + + // so, actually "cut to" might not be e + isTransition = true // contribute to the heuristic + + line = line.replaceAll(pattern, "") + break + } + } + + // TODO: we should change the code to be able to match different ways of writing each sequence time + let timeType: ScreenplaySequenceTime = "UNKNOWN" + for (const [pattern, value] of Object.entries(screenplaySequenceTimes)) { + if (line.includes(pattern)) { + timeType = pattern as ScreenplaySequenceTime // we use the *key* + + // we don't contribute to the heuristic here, + // because having a line merely mentioning "day", "night" or "noon" + // doesn't mean it is a new transition line + + line = line.replaceAll(pattern, "") + break + } + } + + // remove the + const locationName = line + .replaceAll(":", " ") + .replaceAll(/ - /gi, " ") + .replaceAll(/^-/gi, " ") + .replaceAll(/-$/gi, " ") + .replaceAll(" ", " ") + .trim() + + return { + isTransition, + isSceneDescription, + transitionType, + locationName, + locationType, + timeType, + } +} diff --git a/packages/broadway/src/analysis/analyzeName.ts b/packages/broadway/src/analysis/analyzeName.ts new file mode 100644 index 0000000000000000000000000000000000000000..6dc1fffd4e88fd7d5bf4229a53a81c907adf09b4 --- /dev/null +++ b/packages/broadway/src/analysis/analyzeName.ts @@ -0,0 +1,53 @@ +import { ClapEntityGender } from "@aitube/clap" + +import { ExtractedCharacterName, parseNames } from "@/parsers/names" + +import { guessAgeAndGender } from "./guessAgeAndGender" + +export async function analyzeName(entity: string): Promise<{ + name: string + age: number + gender: ClapEntityGender + yearOfBirth: number +}> { + let names: ExtractedCharacterName[] = [] + try { + names = await parseNames(entity) + + } catch (err) { + console.error(`Failed to parse the names in ${entity}: ${err}`) + } + + const value = { + name: entity, + gender: "female" as ClapEntityGender, + age: 30, + yearOfBirth: (new Date().getFullYear()) - 30, + } + + const matchedFirstName = names[0]?.value + + if (matchedFirstName?.name) { + + value.name = matchedFirstName.name.charAt(0).toUpperCase() + matchedFirstName.name.slice(1) + + const genderFallback = matchedFirstName.gender[0] || "f" + + value.gender = + genderFallback === "m" ? "male" : + genderFallback === "f" ? "female" : + value.gender + } + + // TODO: we can pass a second parameter, the reference year, + // which could be the year in which the movie is set + const stats = await guessAgeAndGender(value.name) // <- pass the reference year! + + if (stats) { + value.age = stats.age + value.gender = stats.gender + value.yearOfBirth = stats.yearOfBirth + } + + return value +} \ No newline at end of file diff --git a/packages/broadway/src/analysis/analyzeScreenplay.ts b/packages/broadway/src/analysis/analyzeScreenplay.ts new file mode 100644 index 0000000000000000000000000000000000000000..f627c080359539c6ab27d74b030ddb1b22978073 --- /dev/null +++ b/packages/broadway/src/analysis/analyzeScreenplay.ts @@ -0,0 +1,845 @@ +import { ClapEntity, ClapOutputType, ClapScene, ClapSegment, ClapSegmentCategory, newEntity, UUID } from "@aitube/clap" + +import { Screenplay, TemporaryAssetData } from "@/types" +import { pick } from "@/utils" +import { getEra, getMostProbableEras } from "@/parsers/eras" +import { getGenre, getMostProbableGenres } from "@/parsers/genres" +import { getEntities } from "@/utils/getEntities" +import { onlyContainsStrangeNumber } from "@/utils/onlyContainsStrangeNumber" +import { parseTransition } from "@/parsers/transitions/parseTransition" +import { ScreenplaySequenceType } from "@/constants/screenplaySequences" +import { createSegment } from "@/factories/createSegment" +import { parseLocations, parseLocationType } from "@/parsers/locations" +import { parseLights } from "@/parsers/lights" +import { parseWeather } from "@/parsers/weather" +import { parseShots } from "@/parsers/shots" +import { parseSounds } from "@/parsers/sounds" +import { mockCategoryPrompts } from "@/constants/mocks" +import { DEFAULT_COLUMNS_PER_SLICE } from "@/constants/general" + +import { parseCharacterName } from "./parseCharacterName" +import { analyzeName } from "./analyzeName" +import { parseDialogueLine } from "./parseDialogueLine" +import { isVoiceOver } from "./isVoiceOver" +import { findSubtext } from "./findSubtext" + +export async function analyzeScreenplay( + screenplay: Screenplay, + onProgress?: (value: number, message?: string) => Promise + ): Promise<{ + movieGenreLabel: string + extraPositivePrompt: string[] + segments: ClapSegment[] + entitiesByScreenplayLabel: Record + entitiesById: Record + finalPlainText: string + totalDurationInMs: number + scenes: ClapScene[] +}> { + /** + * List of all segments identified inside the screenplay + */ + const segments: ClapSegment[] = [] + + // TODO: use those as an index? + // const segmentsByStartTime: Record = {} + // const segmentsByEndTime: Record = {} + + // this is only used during analysis + const assetsByLabel: Record = {} + + const entitiesByScreenplayLabel: Record = {} + const entitiesById: Record = {} + + let startTimeInSteps = 1 + + let progress = 0 + await onProgress?.(progress, "Analyzing time period..") + + // those are not going to change a lot during the movie, + // although it is true some movies use this as a trick (eg. Titanic) + + let movieEras = await getMostProbableEras(screenplay.fullText, 2) + let movieEraLabel = Object.keys(movieEras)[0] || "contemporary" + let movieEra = getEra(movieEraLabel) + // console.log("movieEras:", { movieEras, movieEraLabel, movieEra }) + await onProgress?.(progress += 10, "Analyzing genre..") + + // using the movie genre isn't probably a good idea because thousands of words will be mentionned, + // triggering a lot of different and unrelated genres + // still this is useful when the genre if a given sequence cannot be guessed + let movieGenres = await getMostProbableGenres(screenplay.fullText, 20) + let movieGenreLabel = Object.keys(movieGenres)[0] || "" + let movieGenre = getGenre(movieGenreLabel) + await onProgress?.(progress += 10, "Analyzing each scenes..") + + const extraPositivePrompt = movieGenreLabel ? [movieGenreLabel]: [] + + + /* + console.log("movie:", { + movieEras, + movieEraLabel, + movieEra, + movieGenres, + movieGenreLabel, + movieGenre + }) + */ + + // we use a sliding window system + // "to paint over time" the characteristics of a scene + // this should greatly improve the visual quality of a scene + // however this can also proves an issue if we do not reset it at the right time + + let currentDescription = "" // this should be slightly long-lived + let currentAction = "" // this should be short lived + let currentLocationName = "" + let currentLocationType: ScreenplaySequenceType = "UNKNOWN" + let currentTime = "" + let currentLighting = "" + let currentWeather = "" + let currentShotType = "" + let currentSound = "" + let currentMusic = "" + + let nbProcessedSequences = 0 + + const sizeOfProgressChunk = Math.floor(screenplay.sequences.length / 3) + + let totalDurationInMs = 0 + + for (const sequence of screenplay.sequences) { + + if ((++nbProcessedSequences % sizeOfProgressChunk) === 0) { + await onProgress?.(progress += 20, `Analyzing sequences (${nbProcessedSequences}/${screenplay.sequences.length} completed)`) + } + + // those are not going to change a lot during the sequence + let sequenceGenres = await getMostProbableGenres(sequence.fullText, 2) + + + // note: we use the movie genre as a fallback + let sequenceGenreLabel = Object.keys(sequenceGenres)[0] || "classic" // movieGenre + let sequenceGenre = getGenre(sequenceGenreLabel) + + /* + TODO we should use this, but with correct length, to space over multiple steps + + const sequenceInOrOut: SegmentData = createSegment({ + startTimeInSteps, + prompt: sequence.type === "INTERIOR" ? "Interior" : "Outdoor", + categoryName: "location", + }) + + const sequenceLocation: SegmentData = createSegment({ + startTimeInSteps, + prompt: sequence.location, + categoryName: "location", + }) + + const sequenceTime: SegmentData = createSegment({ + startTimeInSteps, + prompt: sequence.time, + categoryName: "time", + }) + */ + getEntities(sequence.location).map(uppercaseAssetName => { + + // console.log(`FOUND REFERENCE TO ENTITY: ${entity}`) + // console.log(`CONTEXT:`, sequence.fullText) + + const existingOccurrences = assetsByLabel[uppercaseAssetName]?.occurrences || 0 + + const existingAsset = assetsByLabel[uppercaseAssetName] + const existingAssetSequences = existingAsset?.sequences || [] + + assetsByLabel[uppercaseAssetName] = { + id: UUID(), // unique identifier of the assets (UUID) + type: "Description", + category: "location", + label: uppercaseAssetName, // the asset name (eg. in the script) + content: uppercaseAssetName, // url to the resource, or content string + occurrences: 1 + existingOccurrences, + sequences: existingAssetSequences.concat( + existingAssetSequences.find(s => s.id === sequence.id) + ? [] + : sequence // only add the sequence if it's not already there + ), + predictedPrompt: "", + } + if (!entitiesByScreenplayLabel[uppercaseAssetName]) { + const newEnt = newEntity({ + category: "location", + triggerName: uppercaseAssetName, // uppercase + label: uppercaseAssetName, + + // TODO: find a way to extract the definition of the location and + // inject it in this field + description: "", // <-- TODO + gender: "object", + }) + entitiesByScreenplayLabel[newEnt.triggerName] = newEnt + entitiesById[newEnt.id] = newEnt + // console.log(`entitiesByScreenplayLabel[${newEntity.triggerName}] = `, newEntity) + } + }) + + for (const scene of sequence.scenes) { + + const sceneCharacters: Record = {} + + for (const event of scene.events) { + if (event.character) { + sceneCharacters[event.character] = true + } + } + + for (const event of scene.events) { + let startTimeInLines = event.startAtLine + let endTimeInLines = event.endAtLine + // console.log(`---- event [${startTimeInLines}:${endTimeInLines}] = "${event.description}" ---`) + + try { + const segmentCandidates: ClapSegment[] = [] + + // the "action prompt" is very interesting for us, because we can look into it + // to extract infor about weather, sounds etc + // (contrary to the dialogue, which are less relevant for us) + + if (onlyContainsStrangeNumber(event.description)) { + // console.log("skipping anomaly") + continue + } + + // if we detect a transition we will bypass the rest of the block + // that's because a transition is an "in-between" event + const transition = parseTransition(event.description) + if (transition) { + // console.log(`Parsed a transition: "${transition}"`) + + const durationInSteps = 2 + + const transitionSegment: ClapSegment = { + ...createSegment({ + + // full fade to black + startTimeInSteps, + + // alternatively, we can also create cross-over transitions, like this: + // startTimeInSteps: Math.round(startTimeInSteps - (durationInSteps / 2)), + + durationInSteps, + + startTimeInLines: event.startAtLine, + endTimeInLines: event.endAtLine, + sceneId: scene.id, + + // we automatically eliminate empty prompt arrays, + // so we must put something in here + prompt: [transition], + + categoryName: ClapSegmentCategory.TRANSITION, + outputType: ClapOutputType.TEXT, + }), + + // watch-out: this 7 is a bit arbitrary, we should instead + // assign it to another track eg. the camera one + // or track 0 maybe + track: 7, + } + + segments.push(transitionSegment) + + // only relevant in case of a fade to black + startTimeInSteps += durationInSteps // 2 steps + + // a transition isn't really a scene shot, so we just ignore the rest + continue + } + + const sequenceLocation = sequence.location.join(", ") + + if (sequenceLocation) { + const weAreStillAtTheSameLocation = sequenceLocation !== currentLocationName + + // we reset those for each shot + currentShotType = "" + currentSound = "" + currentAction = "" + + // while those last for longer spans of time + if (weAreStillAtTheSameLocation) { + currentDescription = "" + currentLocationName = "" + currentLocationType = "UNKNOWN" + currentTime = "" + currentLighting = "" + currentWeather = "" + currentMusic = "" + } + } + + currentDescription = ( + event.type === "action" || event.type === "description" + ? event.description + : "" + ) || currentDescription + + // note that here we don't take the previous value into account + currentAction = + event.type === "action" || event.type === "description" + ? event.description + : "" + + ////////////////////////////////////////////////////////////////////////////// + // + // /!\ The preview segment must be the first one! /!\ + // + // That is because it is a special segment used to create the thumbnail! + // + ////////////////////////////////////////////////////////////////////////////// + + + segmentCandidates.push(createSegment({ + startTimeInSteps, + startTimeInLines: event.startAtLine, + endTimeInLines: event.endAtLine, + sceneId: scene.id, + // we automatically eliminate empty prompt arrays, + // so we must put something in here + prompt: ["movie"], + + categoryName: ClapSegmentCategory.VIDEO, + outputType: ClapOutputType.VIDEO, + })) + + segmentCandidates.push(createSegment({ + startTimeInSteps, + startTimeInLines: event.startAtLine, + endTimeInLines: event.endAtLine, + sceneId: scene.id, + prompt: [ + // "photo" + "movie still", // so it isn't empty + ], + categoryName: ClapSegmentCategory.STORYBOARD, + outputType: ClapOutputType.IMAGE, + })) + + segmentCandidates.push(createSegment({ + startTimeInSteps, + startTimeInLines: event.startAtLine, + endTimeInLines: event.endAtLine, + sceneId: scene.id, + prompt: [ + ...sequenceGenre.prompts.STYLE, + "cinematic photo", + "movie screencap", + ...movieEra.prompts.STYLE + ], + categoryName: ClapSegmentCategory.STYLE, + })) + + // the parsed location is less reliable than the sequence location + const parsedLocations = await parseLocations([ currentDescription ]) + + const parsedLocation = parsedLocations.join(", ") + + const detectedLocation = sequenceLocation || parsedLocation + + // LOCATION segment + currentLocationName = detectedLocation || currentLocationName + if (currentLocationName) { + segmentCandidates.push(createSegment({ + startTimeInSteps, + startTimeInLines, + endTimeInLines, + sceneId: scene.id, + prompt: [currentLocationName], + categoryName: ClapSegmentCategory.LOCATION, + })) + } + + + + const parsedLocationType = await parseLocationType([ currentDescription ]) + + // we try to use the sequence location type (interior / exterior") + // if it is unavailable then we use an heuristic, which might not be reliable + currentLocationType = + sequence.type === "UNKNOWN" && parsedLocationType !== "UNKNOWN" + ? parsedLocationType : + sequence.type === "UNKNOWN" + ? currentLocationType + : sequence.type + + + // convert the type to a string prompt + // (we ignore unknown location types) + // e use the term "Inside" instead of "Indoor" as it suit better + // places that are like cars, helicopters, bus, metro, submarines etc + const locationTypeAsPrompt = currentLocationType === "INTERIOR" ? "Inside" : + currentLocationType === "EXTERIOR" ? "Outdoor" : + currentLocationType === "INT./EXT." ? "Indoor and outdoor" : + "" // ignored + + if (locationTypeAsPrompt) { + segmentCandidates.push(createSegment({ + startTimeInSteps, + startTimeInLines, + endTimeInLines, + sceneId: scene.id, + prompt: [locationTypeAsPrompt], + categoryName: ClapSegmentCategory.LOCATION, + })) + } + + + // LIGHTING / TIME segment + currentTime = (sequence.time || currentTime).toLowerCase() + + // let's skip unknown time + if (currentTime === "unknown") { + currentTime = "" + } + + const parsedLight = (await parseLights([ currentDescription ])).join(", ") + currentLighting = parsedLight || currentLighting + + // console.log({ currentTime, currentLighting }) + + // note: + if (currentTime || currentLighting) { + segmentCandidates.push(createSegment({ + startTimeInSteps, + startTimeInLines, + endTimeInLines, + sceneId: scene.id, + prompt: [ + currentTime, + currentLighting, + ...sequenceGenre.prompts.LIGHTING, + ...movieEra.prompts.LIGHTING, + ], + categoryName: ClapSegmentCategory.LIGHTING, + })) + } + + const parsedWeather = (await parseWeather([ currentDescription ])).join(", ") + currentWeather = parsedWeather || currentWeather + if (currentWeather) { + segmentCandidates.push(createSegment({ + startTimeInSteps, + startTimeInLines, + endTimeInLines, + sceneId: scene.id, + prompt: [ + currentWeather, + ...sequenceGenre.prompts.WEATHER, + ], + categoryName: ClapSegmentCategory.WEATHER, + })) + } + + // by default, we assume that we want a close range shot for scenes + // with a character in it + const shotTypeForCharacters = [ + sequence.type === "EXTERIOR" ? "medium-long shot" : "", + "medium shot", + "medium close-up", + "close-up", + "American shot", + // "Italian shot", + // "trolley shot" + ].filter(x => x) + + const shotTypesForEverythingElse = + sequence.type === "INTERIOR" + ? [ + "medium-long shot", + "medium shot", + "full shot", + ] : [ + "long wide establishing shot", + "extreme long shot", + "long shot", + "medium-long shot", + "medium shot", + "full shot", + ] + + const defaultShotType = event.character + ? pick(shotTypeForCharacters) + : pick(shotTypesForEverythingElse) + + // console.log("currentDescription:", currentDescription) + // in some movies, the shot type may be embed in the description text + // this is the best place + const shotTypes = await parseShots([ currentDescription ]) + // console.log("shot types:", shotTypes) + currentShotType = (shotTypes.join(", ") || currentShotType) || defaultShotType + // console.log("currentShotType:", currentShotType) + + if (currentShotType) { + segmentCandidates.push(createSegment({ + startTimeInSteps, + startTimeInLines, + endTimeInLines, + sceneId: scene.id, + prompt: [ + currentShotType, + ...sequenceGenre.prompts.CAMERA, + ...movieEra.prompts.CAMERA + ], + categoryName: ClapSegmentCategory.CAMERA, + })) + } + + const currentSliceEntities: ClapEntity[] = [] + + for (const rawUppercaseAssetName of getEntities(event.character)) { + // note: the "uppercaseAssetName" might be something like "JOHN'S VOICE" + // which is why we normalize it, and convert it to a smaller characterName + const characterName = parseCharacterName(rawUppercaseAssetName) + const existingAsset = assetsByLabel[characterName] + const existingOccurrences = existingAsset?.occurrences || 0 + const existingAssetSequences = existingAsset?.sequences || [] + + // console.log("trigger name identified:", uppercaseAssetName) + assetsByLabel[characterName] = { + id: UUID(), // unique identifier of the assets (UUID) + type: "Description", + category: "character", + label: characterName, // the asset name (eg. in the script) + content: characterName, // url to the resource, or content string + occurrences: 1 + existingOccurrences, + sequences: existingAssetSequences.concat( + existingAssetSequences.find(s => s.id === sequence.id) + ? [] + : sequence // only add the sequence if it's not already there + ), + predictedPrompt: "" + } + + if (!entitiesByScreenplayLabel[characterName]) { + // console.log(`no entity going by "${entity}", so creating one`) + + // region is available, but it has a different name from what + // ElevenLabs expect (we should probably create our own unified data type, + // and a map between it and ElevenLabs accents) + const { name, age, gender, /*region*/ } = await analyzeName(characterName) + + const newEnt = newEntity({ + + // the trigger name is used in case we have a LoRA attached to the character + triggerName: characterName, // uppercase + label: name, + + // TODO: put any other info we can get from the script + description: `${name} is a ${gender}`, + + category: ClapSegmentCategory.CHARACTER, + age, + gender, + region: "american", + + // TODO put things like "blond hair, wearing a suit" etc + // appearance: "", + }) + // console.log("newEnt:", newMod) + entitiesByScreenplayLabel[characterName] = entitiesById[newEnt.id] = newEnt + } + + currentSliceEntities.push(entitiesByScreenplayLabel[characterName]) + } + + // if (currentSliceEntities.length) console.log("currentSliceEntities:", currentSliceEntities) + /* + Nope we don't do that anymore, instead we use our new "Entity" system + + const character: SegmentData = createSegment({ + startTimeInSteps, + prompt: event.character ? [event.character] : [], // Object.keys(sceneCharacters), + categoryName: "character", + }) + */ + + // if (currentSliceEntities.length) console.log("identified entities:", currentSliceEntities) + + + // this is how we create nicely animated characters + // who are not just talking but also doing other things at the same time + if (event.behavior) { + segmentCandidates.push(createSegment({ + startTimeInSteps, + startTimeInLines, + endTimeInLines, + sceneId: scene.id, + prompt: [event.behavior], + label: `${currentSliceEntities[0]?.label}: ${event.behavior}`, + categoryName: ClapSegmentCategory.ACTION, + + // important: we need to use the character entity + // based on a fine-tune, a LoRA, IP adapter or other similar things + entityId: currentSliceEntities[0]?.id || "" + })) + } + + const dialogueLine = parseDialogueLine(event.description) + + if (event.type === "dialogue" && dialogueLine) { + // console.log("found a dialogue! currentSliceEntities:", currentSliceEntities) + segmentCandidates.push(createSegment({ + startTimeInSteps, + startTimeInLines, + endTimeInLines, + sceneId: scene.id, + prompt: [dialogueLine], + + // it is easier to understand in the UI when we can see the speaker's name + label: + currentSliceEntities[0]?.label + ? `${currentSliceEntities[0].label}: ${dialogueLine}` + : "", + categoryName: ClapSegmentCategory.DIALOGUE, + entityId: currentSliceEntities[0]?.id || "" + })) + } + + // no need to keep voice over, it's not interesting + if (currentAction && !isVoiceOver(currentAction)) { + segmentCandidates.push(createSegment({ + startTimeInSteps, + startTimeInLines, + endTimeInLines, + sceneId: scene.id, + prompt: [currentAction], + label: + event.character + ? `${currentSliceEntities[0]?.label || event.character}: ${currentAction}` + : "", + categoryName: ClapSegmentCategory.ACTION, + entityId: + event.character + ? currentSliceEntities[0]?.id || "" + : "", + })) + } + + // @deprecated, we should only use TIME instead, + // as it is more encompassing + segmentCandidates.push(createSegment({ + startTimeInSteps, + startTimeInLines: event.startAtLine, + endTimeInLines: event.endAtLine, + sceneId: scene.id, + prompt: [ + // note: here we use the *GENRE* parser, and on the FULL MOVIE + //...sequenceGenre.prompts.era, + + // note: here we use the *ERA* parser, and on the FULL MOVIE + ...movieEra.prompts.ERA, + ], + categoryName: ClapSegmentCategory.ERA, + })) + + const defaultSoundPrompt = + event.type === "dialogue" + + // a generic "people talking" sound isn't very interesting + ? [] + // ? ["people talking"] + + // event.description.includes(" SOUND ") + // ? event.description : + : currentLocationType === "EXTERIOR" && currentTime !== "night" + ? ["wind", "birds"] + : currentLocationType === "EXTERIOR" && currentTime === "night" + ? ["crickets and cicadas sounds during night"] + : [] + + const parsedSound = await parseSounds([ currentDescription ]) + currentSound = (parsedSound.join(", ") || currentSound) || defaultSoundPrompt.join(", ") + + if (currentSound) { + segmentCandidates.push(createSegment({ + startTimeInSteps, + startTimeInLines, + endTimeInLines, + sceneId: scene.id, + prompt: [ + currentSound, + // note: here we use the *GENRE* parser, and on the FULL MOVIE + ...sequenceGenre.prompts.SOUND, + + ...movieEra.prompts.SOUND, + ], + entityId: currentSliceEntities[0]?.id || undefined, + categoryName: ClapSegmentCategory.SOUND, + })) + } + + currentMusic = pick(mockCategoryPrompts.MUSIC) || currentMusic + + if (currentMusic) { + segmentCandidates.push(createSegment({ + startTimeInSteps, + startTimeInLines, + endTimeInLines, + sceneId: scene.id, + prompt: [ + currentMusic, + // note: here we use the *GENRE* parser, and on the FULL MOVIE + ...sequenceGenre.prompts.MUSIC, + + ...movieEra.prompts.MUSIC + ], + categoryName: ClapSegmentCategory.MUSIC, + })) + } + + // now we filter segments to only keep the ones with a non-empty prompt + const newSegments = segmentCandidates.filter(segment => segment.prompt.length) + + // we need to assign each segment to a track, without collision + let track = 1 + for (const newSegment of newSegments) { + const segmentToSave: ClapSegment = { + ...newSegment, + track: track++ + } + + if (segmentToSave.endTimeInMs > totalDurationInMs) { + totalDurationInMs = segmentToSave.endTimeInMs + } + + segments.push(segmentToSave) + } + + startTimeInSteps += DEFAULT_COLUMNS_PER_SLICE + } catch (err) { + console.error("failed to process an event:", err) + } + } + } + } + + // TODO Julian: move this part to another library + // if (screenplayEntityDetectionStrategy === "llm_first_scene") { + // await onProgress?.(progress += 10, "Imagining entities (will take a while)..") + // for (const [name, asset] of Object.entries(assetsByLabel)) { +// + // console.log(` - imagining "${name}"..`) + // + // await onProgress?.(progress, `Imagining "${name}"..`) +// + // // note: this will perform client-side calls to Hugging Face, which may not be desireable + // // an alternative could be to use a proxy (see /api/huggingface/predict.ts) +// + // let description = await analyzeAsset({ + // asset, + // + // movieGenreLabel, + // movieEraLabel, +// + // // to avoid being rate-limited by Hugging Face, + // // we introduce a generous artificial delay + // delayBeforeApiCallInMs: 5000, + // + // // delayBetweenAttempts: 10000, + // // nbMaxAttempts: 3 + // }) +// + // /* + // // Hugging Face likes to timeout and throttle, sometimes for no reason + // // this is you should always entities locally, folks! + // if (!description.trim()) { + // await sleep(10000) + // description = await predict(prompt + ".", nbMaxTokens) +// + // if (!description.trim()) { + // await sleep(30000) + // description = await predict(prompt + ".", nbMaxTokens) + // } + // } + // */ +// + // + // const entity = entitiesByScreenplayLabel[name] + // if (entity) { + // // console.log("entity:", entity) + // // console.log("existing description:", entity.description) + // if (description) { + // console.log(` - entity description: "${description}"\n`) + // entity.description = description + // } else { + // console.log(` - error: description is empty, ignoring..`) + // } + // } else { + // console.log(`error, couldn't find entity ${name}`) + // } + // } + // } + + + let scenes: ClapScene[] = [] + + for (const sequence of screenplay.sequences) { + scenes = scenes.concat(sequence.scenes) + } + + let finalPlainTextLines = screenplay.fullText.split("\n") + + // let lastRow = 0 + + for (const segment of segments) { + let needle = "" + if (segment.category === ClapSegmentCategory.DIALOGUE + || segment.category === ClapSegmentCategory.ACTION + ) { + needle = segment.prompt + } + if (!needle) { continue } + + let searchZoneLines = finalPlainTextLines.slice( + segment.startTimeInLines, + segment.endTimeInLines + ) + + let haystack = searchZoneLines.join("\n") + + + // console.log(`searching for: "${needle}"\ninside: "${haystack}"`) + + try { + const found = findSubtext(needle, haystack) + // console.log(`found:`, found) + + if (typeof found?.startAtRow === "number") { + // this improves the quality of results a bit, + // but sometimes the findSubtext function doesn't find anything + segment.startTimeInLines += 1 + (found.startAtRow || 0) + segment.endTimeInLines += 1 + (found.endAtRow || 0) + } + + } catch (err) { + // console.log(`not found`) + } + + } + + // const finalPlainText = finalPlainTextLines.join("\n") + const finalPlainText = screenplay.fullText + + return { + movieGenreLabel, + extraPositivePrompt, + segments, + entitiesByScreenplayLabel, + entitiesById, + finalPlainText, + totalDurationInMs, + scenes + } +} diff --git a/packages/broadway/src/analysis/findSubtext.ts b/packages/broadway/src/analysis/findSubtext.ts new file mode 100644 index 0000000000000000000000000000000000000000..d9a3b6bd7455ea7c01a6a9fe5a7744eff5d2ec15 --- /dev/null +++ b/packages/broadway/src/analysis/findSubtext.ts @@ -0,0 +1,82 @@ +export interface SubtextPosition { + startAtRow: number; + startAtCol: number; + endAtRow: number; + endAtCol: number; + remaining: string; + startIndex: number; +} + +export function findSubtext(needle: string, haystack: string): SubtextPosition | undefined { + const haystackLines = haystack.split('\n'); + const needleChars = needle.split(''); + + let needleIndex = 0; + let startAtRow = -1; + let startAtCol = -1; + let endAtRow = -1; + let endAtCol = -1; + let startIndex = -1; + + let totalCharacterCount = 0; + + for (let i = 0; i < haystackLines.length; i++) { + const line = haystackLines[i]; + for (let j = 0; j < line.length; j++) { + const hayChar = line[j]; + const needleChar = needleChars[needleIndex]; + + if (hayChar === needleChar) { + if (needleIndex === 0) { + startAtRow = i; + startAtCol = j; + startIndex = totalCharacterCount; + } + + needleIndex++; + endAtRow = i; + endAtCol = j; + + if (needleIndex === needleChars.length) { + return { startAtRow, startAtCol, endAtRow, endAtCol, remaining: '', startIndex }; + } + } else { + if (hayChar !== ' ' && hayChar !== '\n' && hayChar !== '\t') { + needleIndex = 0; + startAtRow = -1; + startAtCol = -1; + startIndex = -1; + } + } + totalCharacterCount++; + } + totalCharacterCount++; // account for line return + } + + if (startAtRow === -1 || startAtCol === -1) { + throw new Error("Subtext not found in the provided text."); + } + + const remaining = needle.slice(needleIndex); + return { startAtRow, startAtCol, endAtRow, endAtCol, remaining, startIndex }; +} + +/* +// Example usage +const haystack = ` I'm a busy man. When I give jobs, I + don't have time for a lotta B.S. If + a guy comes to me and says, + "Michael, this job has been my + dream since I was a little kid. My + whole life has been leading up to + this job," That, I respond to. + Nothing is more important than + enthusiasm, from the Greek word`; + +const needle = `If a guy comes to me and says, "Michael, this job has been my dream since I was a little kid"`; + +const { startAtRow, startAtCol, endAtRow, endAtCol } = findSubtext(needle, haystack); +console.log({ startAtRow, startAtCol, endAtRow, endAtCol }); +// Expected output: +// { startAtRow: 2, startAtCol: 6, endAtRow: 5, endAtCol: 43 } +*/ \ No newline at end of file diff --git a/packages/broadway/src/analysis/getEntityAnalysisPrompt.ts b/packages/broadway/src/analysis/getEntityAnalysisPrompt.ts new file mode 100644 index 0000000000000000000000000000000000000000..2b2051ac6c21dc4031467e021fd8fb4446043be3 --- /dev/null +++ b/packages/broadway/src/analysis/getEntityAnalysisPrompt.ts @@ -0,0 +1,93 @@ +import { TemporaryAssetData } from "@/types" + + +const characterSpecific = + `age, gender, physical characteristics, appearance, skin color, origins, clothes, costume etc..` + +const locationSpecific = + `location, country, era, orientation, appearance, color, lighting, texture..` + +/** + * A prompt template to generate nice descriptions of entities found in the movie + * + * Here are some examples: + * "CARIBBEAN SEA" (from pirates of the caribbean) -> + * "The Caribbean Sea is a vast expanse of warm blue-green water, + * surrounded by lush green islands draped in palm trees, dotted with white sand beaches + * and clear turquoise shallows. Soft sunlight filters down through a gentle haze, + * and ripples shimmer on the surface" + * + * "BOY" (from the babadook) -> + * + * "BOY: 6-year-old Caucasian male with curly brown hair and light green eyes. + * Wears blue short-sleeved t-shirt, white shorts, and blue slippers. + * Skin has a light tan tone with freckles on the nose and cheeks" + * + * @param name + * @param item + * @returns + */ +export function getEntityAnalysisPrompt({ + name, + asset, + movieGenreLabel = "generic", + movieEraLabel = "contemporary", +}: { + name: string + asset: TemporaryAssetData + movieGenreLabel?: string + movieEraLabel?: string +}) { + + // can we just use one for now? + // maybe it's enough? + const nbMaxStoryFragments = 1 + + const sequences = asset.sequences.map(s => s.fullText) + const firstStoryFragment = sequences.slice(0, nbMaxStoryFragments) + + const storyFragments = firstStoryFragment.join("\n") + + const prompt = `# context +you are studying the script of a movie, but you only have a few fragments of the story. +We have the following information about the movie, +the genre might be "${movieGenreLabel || "generic"}" and the story time period might be "${movieEraLabel || "contemporary"}", although it is not confirmed (use your best judgment). +# story fragments +\`\`\` +${storyFragments} +\`\`\` +# mission +You are an expert at analyzing movie scripts, and you need to write a spec to explain how does the ${asset.category} "${name}" looks like (note: it's possible the name contains a typo, no need to tell us about it) +Please give your answer in a very dense manner, about 2 sentences. +You need to describe anything that can be useful for someone else to draw or paint this "${name}": +${asset.category === "character" ? characterSpecific : locationSpecific} +# examples +Here are a few examples, but don’t copy them verbatim! They are taken from a pirate movie, which may be different from the current project: +- "FORT CHARLES JAIL CELLS": "British colonial fortress, buccaneering period, indoor setting, adjacent to cells, rectangular shape with stone and brick walls, gray color, lighting from torches, wooden beds, iron bars with damage, chain padlock, rusty metal lockers, cobblestone diamond patterned stone floor" +- "PORT ROYAL TOWN ALLEY": "urban, golden age of piracy, coastal city (Port Royal, Jamaica), alleyway in a semi-deserted neighborhood, brick walls, metal strips for street signs, fog, low light levels, wooden doors, asphalt, striped path leading to a blacksmith shop with barn doors, sign located above the entrance." +- "HARBORMASTER": "Middle-aged, male, clean-shaven, salt-and-pepper hair and brown eyes, wearing a navy smock over a white shirt and brown pants, brown boots and brown hat, all with clean and crisp lines, standing against the dock backdrop with a sunbathed pale skin tone" +- "CAVES MAIN CAVERN": "South America, Aztec Empire, in 1518. Subterraneous, spherical room with a dome-shaped rocky ceiling and precipitous walls carved with Aztec glyphs." +- "DEADEYE" : "male, early 40s, with a scar passing over his left eye. Wears a leather coat that covers his left arm until the elbow. His skin has Mediterranean tone. Wears a black, wide-brimmed hat, underneath it he appears to naturally grow a mustache" +and another example, from a heist movie: +- "LEON": "leon, caucasian, male, 25 years old, 180cm tall, athletic build, sharp facial features, chiseled jawline, high cheekbones, angular nose, thin lips, piercing blue eyes, short black hair, slightly spiked, fair complexion" +- "LAVINGTON GALLERY": "contemporary era, neoclassical architecture, indoor setting, located in a city, glass ceiling, marble floor, white walls, spotlight illumination, paintings with vibrant colors, Greek columns, polished concrete structure, security cameras with red lights, students with hoodies or sunglasses, tour guides, staff-only doors" +- "SASHA": "female, caucasian, mid-30s, tall, slender, angular features, high cheekbones, sharp jawline, piercing green eyes, platinum blonde hair styled in a sleek bob, fair complexion, wears a fitted black suit with a white blouse, black pumps, and a black clutch purse" +# final guidelines +Remember, be synthetic, and don't recopy examples identically! do not talk about the purpose, objectives, meaning.. of the ${asset.category}. +We do not need an encyclopedic description, we need a VISUAL description. +I repeat: give a VISUAL description, to help someone PAINT it! +Don't repeat the movie genre, we already know it. +Instead, only write about its physical properties, without bias or subjective interpretation (be direct, don't use terms like "reminiscent of" or "similar to"). +You should use comma-separated word enumerations, to be even more compact and concise. +If things are unspecified, don't say "unspecified physical characteristics", never say "located in an unknown country" or "during an indeterminate era" etc. +Instead you should invent them (you are a cinema producer, so you need to know how to interpret a script) +Please also write a definition that is independent from the current scene (a definition that can be used later). +important: don't write about the current scene specifically, like current action or position. Instead, you MUST write a neutral, multi-purpose description, suitable for future scenes. +Be sure of yourself, or shut up! Don't interprent by saying things like "we assume, seems to be, not enough context, according to, possibly a typo..)". Never say those things, there are irrelevant! +Don't comment on your action, don't tell me when you are not sure etc. +And only write using two sentences! +If you follow all the guidelines you will be rewarded with a tip. +# answer +"` + return prompt +} \ No newline at end of file diff --git a/packages/broadway/src/analysis/getScreenplayFromText.ts b/packages/broadway/src/analysis/getScreenplayFromText.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab16ec447d5d14965a6a395b850bd26d13514529 --- /dev/null +++ b/packages/broadway/src/analysis/getScreenplayFromText.ts @@ -0,0 +1,111 @@ +import { UUID } from "@aitube/clap" + +import { analyzeLine } from "@/analysis/analyzeLine" +import { Screenplay, ScreenplaySequence } from "@/types" +import { parseScenes } from "@/analysis/parseScenes" + + +/** + * This function splits the full text into scenes, but doesn't perform any deep analysis + * + * @param fullText + * @returns + */ +export async function getScreenplayFromText(fullText: string): Promise { + const lines = fullText.replace("\n", " ").split(/\n/gi) + + // TODO: use this + // const lines = fullText.split(/\r?\n/) + + const sequences: ScreenplaySequence[] = [] + + let pendingTransition = "Cut to" + let startedAt = 0 + let textBuffer = '' + let lineNumberBuffer = 0 + + let reconstructedFullText = "" + + lines.forEach((line, lineNumber) => { + line = line.replaceAll("\r", "")// .trim() + + reconstructedFullText += `${line}\n` + + // if (lineNumber < 25) { return } + // use this if you need to debug something + // if (lineNumber > 200) { return } + + // we are just going to the next page... normally + if (line.match(/^\d+\.$/)) { + return + } + + const { isTransition, isSceneDescription, timeType, transitionType, locationName, locationType } = analyzeLine(line) + + // in some screenplay, there is a line like: " Cut to:" + // before the actual transition takes place + if (isTransition && transitionType) { + pendingTransition = transitionType + } + + // can't add the scene to the sequence if it's invalid + if (!isSceneDescription) { + + // console.log("LINE:", { line }) + lineNumberBuffer = lineNumber + textBuffer += `${line}\n` + + return + } + + // console.log("DEBUG:", { line, isTransition, timeType, transitionType, locationName, locationType }) + + // important: we fill in the buffer! + const previousSequence = sequences.at(-1) + if (previousSequence) { + previousSequence.fullText = `${textBuffer}` + previousSequence.endAtLine = lineNumberBuffer + } + + lineNumberBuffer = lineNumber + textBuffer = `${line}\n` + + sequences.push({ + id: UUID(), + location: + locationName ? [locationName] : + previousSequence ? previousSequence.location : + ["Unknown location"], + type: + locationType !== "UNKNOWN" ? locationType : + previousSequence ? previousSequence.type : + "UNKNOWN", + time: + timeType !== "UNKNOWN" ? timeType : + previousSequence ? previousSequence.time : + "UNKNOWN", + transition: + transitionType ? transitionType : pendingTransition, + fullText: "", + startAtLine: lineNumber, + endAtLine: lineNumber, + scenes: [], + }) + }) + + const lastSequence = sequences.at(-1) + if (lastSequence) { + lastSequence.fullText = `${textBuffer}\n` + lastSequence.endAtLine = lineNumberBuffer + } + + // now we have clearly identified sequences, we need to extract the scenes + for (const sequence of sequences) { + sequence.scenes = parseScenes(sequence) + } + + return { + fullText: reconstructedFullText, + sequences, + } +} diff --git a/packages/broadway/src/analysis/guessAgeAndGender.ts b/packages/broadway/src/analysis/guessAgeAndGender.ts new file mode 100644 index 0000000000000000000000000000000000000000..c531d0ae93d4c1015df9ca3b4fefa2dcbb94b53a --- /dev/null +++ b/packages/broadway/src/analysis/guessAgeAndGender.ts @@ -0,0 +1,68 @@ +import { ClapEntityGender } from "@aitube/clap" + +import { loadAgeGenderNameStats, state } from "./loadAgeAndGenderDataset" +import { normalizeName } from "./normalizeName" + +export async function guessAgeAndGender(name: string, referenceYear?: number): Promise<{ + age: number + gender: ClapEntityGender + yearOfBirth: number +} | undefined> { + if (!state.isReady) { + state.nameToStats = await loadAgeGenderNameStats() + state.isReady = true + } + + const key = normalizeName(name) + + let allYears = state.nameToStats[key] + allYears = Array.isArray(allYears) ? allYears : [] + + const refYear: number = typeof referenceYear === "number" && !isNaN(referenceYear) && isFinite(referenceYear) + ? referenceYear + : new Date().getFullYear() + + + // make sure we only keep valid years, in a reasonable range: + const validYears = allYears.filter(y => + ((refYear - 40) < y[2]) && (y[2] < refYear - 2) + ) + + // we could try to see the top nth matches, and use the average gender + // console.log("validYears:", validYears) + + let countGender: Record = { + male: 0, + female: 0, + person: 0, + object: 0, + } + + const match = Array.isArray(validYears) && validYears[0] || undefined + + if (match) { + + validYears.forEach(y => { + countGender[y[0]] += 1 + }) + + const topGender: ClapEntityGender = + countGender.male > countGender.female + ? "male" + : "female" + + let yearOfBirth = match[2] + if (typeof yearOfBirth !== "number" || !isFinite(yearOfBirth) || isNaN(yearOfBirth)) { + yearOfBirth = 2006 + } + const age = Math.max(18, refYear - yearOfBirth) + + return { + yearOfBirth: match[2], + age, + gender: topGender, + } + } + + return undefined +} \ No newline at end of file diff --git a/packages/broadway/src/analysis/index.ts b/packages/broadway/src/analysis/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..854f4f95bc0cc8a96125a5a70afadfb1c7fd2c12 --- /dev/null +++ b/packages/broadway/src/analysis/index.ts @@ -0,0 +1,14 @@ +export { analyzeLine } from "./analyzeLine" +export { analyzeName } from "./analyzeName" +export { analyzeScreenplay } from "./analyzeScreenplay" +export { getEntityAnalysisPrompt } from "./getEntityAnalysisPrompt" +export { getScreenplayFromText } from "./getScreenplayFromText" +export { guessAgeAndGender } from "./guessAgeAndGender" +export { isCharacterLine } from "./isCharacterLine" +export { isDialogueLine } from "./isDialogueLine" +export { isPageSeparator } from "./isPageSeparator" +export { isVoiceOver } from "./isVoiceOver" +export { parseCharacterName } from "./parseCharacterName" +export { parseDialogueLine } from "./parseDialogueLine" +export { parseScenes } from "./parseScenes" +export { type ParseScriptProgressUpdate, parseScriptToClap } from "./parseScriptToClap" \ No newline at end of file diff --git a/packages/broadway/src/analysis/isCharacterLine.ts b/packages/broadway/src/analysis/isCharacterLine.ts new file mode 100644 index 0000000000000000000000000000000000000000..51dfcb9b243d5c0d64a836a63b39fad1e3ad314c --- /dev/null +++ b/packages/broadway/src/analysis/isCharacterLine.ts @@ -0,0 +1,91 @@ + + +// /!\ This whole file was generated with GPT-4 + +import { analyzeLine } from "@/analysis/analyzeLine" +import { parseCharacterName } from "@/analysis/parseCharacterName" + +import { isAllCaps } from "@/utils/isAllCaps" + +/** + * Check whether the given line contains a character dialogue or action bitmap. + * @param fullLine the line to check. Might contain spaces. + */ +export function isCharacterLine(fullLine: string): boolean { + + const containsTabulation = fullLine.startsWith(" ") + + // disabled, because some character line include things like parenthesis + // if (fullLine.match(/\([^\)]+\)/)) { + // return false + // } + + // this rule is a bit strict as some text files don't have tabulation.. + // but it helps A LOT + if (!containsTabulation) { + return false + } + + // the fullLine is important and useful (to locate characters, highlight etc) + // however it might not be a reliable indicated, so we use uppercase + const line = fullLine.trim() + + const { isTransition, isSceneDescription, timeType, locationType } = analyzeLine(line) + + + const character = parseCharacterName(line) + + // doesn't look like a character name, after filtering + if (!character) { + return false + } + + // console.log("isAllCaps?", isAllCaps(line)) + if ( + line.length < 2 || // line is too short to be a character + !isAllCaps(line) // line is not all uppercase + ) { + // console.log("FAIL 1") + return false + } + + if ( + isTransition || // nope, that's a transition or scene + isSceneDescription + ) { + // console.log("FAIL 2") + return false + } + + if ( + locationType !== "UNKNOWN" || + timeType !== "UNKNOWN" + ) { + // console.log("FAIL 3") + return false + } + + // nah, it's juste someone shouting + if (line.includes("!")) { + return false + } + + if ( + line === "NO" || line === "NO." || + line === "YES" || line === "YES." || + line === "STOP" || line === "STOP." + ) { + return false + } + + const lineWithSpace = ` ${line} ` + if ( + lineWithSpace.includes(" INSERT ") || + lineWithSpace.includes(" POV ") || + lineWithSpace.includes(" CLOSE-UP ") + ) { + return false + } + + return true +} diff --git a/packages/broadway/src/analysis/isDialogueLine.ts b/packages/broadway/src/analysis/isDialogueLine.ts new file mode 100644 index 0000000000000000000000000000000000000000..b942923e7171539e9afeeedcc42d18120c8a293c --- /dev/null +++ b/packages/broadway/src/analysis/isDialogueLine.ts @@ -0,0 +1,21 @@ + + +// /!\ This whole file was generated with GPT-4 + + +/** + * Check whether the given line contains a character dialogue or action bitmap. + * @param fullLine the line to check. Might contain spaces. + */ +export function isDialogueLine(fullLine: string): boolean { + + const containsTabulation = fullLine.startsWith(" ") + + // this rule is a bit strict as some text files don't have tabulation.. + // but it helps A LOT + if (!containsTabulation) { + return false + } + + return true +} diff --git a/packages/broadway/src/analysis/isPageSeparator.ts b/packages/broadway/src/analysis/isPageSeparator.ts new file mode 100644 index 0000000000000000000000000000000000000000..6b4f67d8428b1fffab4420157e07dbeb0e861778 --- /dev/null +++ b/packages/broadway/src/analysis/isPageSeparator.ts @@ -0,0 +1,11 @@ + + +// might be deprecated actually +/** + * Checks whether a line in the script is PDF page separators. + * @param line The line to check. + */ +export function isPageSeparator(line: string): boolean { + const pageSeparatorPattern = /^\s*-\d+-\s*$/i; + return pageSeparatorPattern.test(line); +} \ No newline at end of file diff --git a/packages/broadway/src/analysis/isVoiceOver.ts b/packages/broadway/src/analysis/isVoiceOver.ts new file mode 100644 index 0000000000000000000000000000000000000000..8833b39f2e915cab9b623e63ccda7fc70e154a04 --- /dev/null +++ b/packages/broadway/src/analysis/isVoiceOver.ts @@ -0,0 +1,15 @@ +export function isVoiceOver(input: string) { + const text = input.trim().toLowerCase() + if (text === "v.o." || + text === "v.o" || + text === "vo." || + text === "(v.o.)" || + text === "(v.o)" || + text === "(vo.)" || + text === "voice over" || + text === "(voice over)" + ) { + return true + } + return false +} \ No newline at end of file diff --git a/packages/broadway/src/analysis/loadAgeAndGenderDataset.ts b/packages/broadway/src/analysis/loadAgeAndGenderDataset.ts new file mode 100644 index 0000000000000000000000000000000000000000..67b5aa6e4ccc4d9548825b1e39f8d4c0cb77285a --- /dev/null +++ b/packages/broadway/src/analysis/loadAgeAndGenderDataset.ts @@ -0,0 +1,111 @@ +import { ClapEntityGender } from "@aitube/clap" + +import { normalizeName } from "./normalizeName" + +export type AgeNameGenderStats = [ClapEntityGender, number, number] + +export type NameToStats = Record + +export const state: { + isReady: boolean + + nameToStats: NameToStats +} = { + isReady: false, + nameToStats: {}, +} + +const fileName = 'baby-names-us-year-of-birth-full.csv' +//const dirName = 'detection-of-age-and-gender' +//const storageFilePath = `${dirName}/${fileName}` +const storageFilePath = `${fileName}` + +const DEFAULT_DOWNLOAD_URL = `https://clapper.app/datasets/${fileName}` + +// note: this takes about 140 Mb of memory +// we store the dataset inside a big JSON in the IndexedDB +export async function loadAgeGenderNameStats(url = DEFAULT_DOWNLOAD_URL) : Promise> { + + + if (typeof window !== "undefined") { + try { + const { default: fs } = await import("indexeddb-fs") + /* + try { + if (!(await fs.isDirectory(dirName))) { + await fs.createDirectory(dirName) + } + } catch (err) { + console.log(`failed to create directory "${dirName}"`) + } + */ + + const rawCacheContent = await fs.readFile(storageFilePath) as string + const cacheObject = JSON.parse(rawCacheContent) as NameToStats + if (Object.keys(cacheObject).length === 0) { + throw new Error(`cache is empty`) + } + return cacheObject + } catch (err) { + console.log(`couldn't load the cache, we will try to re-generate it`) + } + } + + let nameToStats = {} as NameToStats + + + console.log(`downloading age and gender detection dataset from Hugging Face (jbilcke-hf/detection-of-age-and-gender)`) + try { + + const res = await fetch(url) + const rawData = await res.text() + + rawData.split("\n").forEach(line => { + const [yearOfBirth, name, gender, numberOfBirths] = line.trim().split(",") + + const key = normalizeName(name) + + if (!key) { return } + + if (!nameToStats[key]) { + nameToStats[key] = [] + } + nameToStats[key].push([ + gender === "F" ? "female" : "male", + Number(numberOfBirths), + Number(yearOfBirth), + ]) + + nameToStats[key].sort((a, b) => b[1] - a[1]) + }) + } catch (err) { + console.error(`failed to fetch the dataset (${err})`) + + return nameToStats + } + + if (typeof window !== "undefined") { + + console.log(`trying to save the dataset to the browser's IndexedDB for faster reload`) + + try { + const { default: fs } = await import("indexeddb-fs") + + /* + try { + if (!(await fs.isDirectory(dirName))) { + await fs.createDirectory(dirName) + } + } catch (err) { + console.log(`failed to create directory "${dirName}"`) + } + */ + + await fs.writeFile(storageFilePath, JSON.stringify(nameToStats)) + } catch (err) { + console.error(`failed to store the cache (${err})`) + } + } + + return nameToStats +} diff --git a/packages/broadway/src/analysis/normalizeName.ts b/packages/broadway/src/analysis/normalizeName.ts new file mode 100644 index 0000000000000000000000000000000000000000..c555e406d318c1a6ed1b64751a6ead4b333fa09e --- /dev/null +++ b/packages/broadway/src/analysis/normalizeName.ts @@ -0,0 +1,6 @@ +export function normalizeName(name: string) { + const normalizedName = `${name || ""}`.trim().toLowerCase() + + return normalizedName +} + diff --git a/packages/broadway/src/analysis/parseCharacterName.ts b/packages/broadway/src/analysis/parseCharacterName.ts new file mode 100644 index 0000000000000000000000000000000000000000..d702d45004e930a41a296c68f357192996b88cc9 --- /dev/null +++ b/packages/broadway/src/analysis/parseCharacterName.ts @@ -0,0 +1,26 @@ +function takeWhatsBefore(input: string, pattern: string): string { + return `${input || ""}`.split(pattern).shift() || "" +} + +export function parseCharacterName(input: string) { + + let tmp = takeWhatsBefore(input, "'S") + tmp = takeWhatsBefore(tmp, "’S") + tmp = takeWhatsBefore(tmp, "(") + tmp = takeWhatsBefore(tmp, "[") + + tmp = tmp + .replaceAll(" INTERNALS ", "") + .replaceAll(" VOICE ", "") + + tmp = tmp.trim() + + /* + // console.log("DEBUG:", { + input: ` ${input || ""} `, + tmp + }) + */ + + return tmp +} \ No newline at end of file diff --git a/packages/broadway/src/analysis/parseDialogueLine.ts b/packages/broadway/src/analysis/parseDialogueLine.ts new file mode 100644 index 0000000000000000000000000000000000000000..9f8047b339d845b35ead7a009b79e2194e867184 --- /dev/null +++ b/packages/broadway/src/analysis/parseDialogueLine.ts @@ -0,0 +1,21 @@ +import { isAllCaps } from "@/utils/isAllCaps" + + +export function parseDialogueLine(line: string): string { + let lineWithSpaces = ` ${line || ""} ` + + if (line === " .. " || line === " ... ") { + return "" + } + + // looks like an anomaly, normally dialogue isn't all caps + if (isAllCaps(lineWithSpaces)) { + return "" + } + + // some scripts (such as Afterglow) have quotes in it + // we can remove them + lineWithSpaces = lineWithSpaces.replaceAll(`“`, '').replaceAll(`”`, '') + + return lineWithSpaces.trim() +} \ No newline at end of file diff --git a/packages/broadway/src/analysis/parseScenes.ts b/packages/broadway/src/analysis/parseScenes.ts new file mode 100644 index 0000000000000000000000000000000000000000..15e157d8238621e8e14d53ebada5ad89e0008cca --- /dev/null +++ b/packages/broadway/src/analysis/parseScenes.ts @@ -0,0 +1,357 @@ +import { UUID } from "@aitube/clap" + + +import { isAllCaps } from "@/utils/isAllCaps" +import { analyzeLine } from "@/analysis/analyzeLine" +import { Scene, SceneEvent, ScreenplaySequence } from "@/types" + +import { parseCharacterName } from "@/analysis/parseCharacterName" + +/** + * Check whether the given line contains a character dialogue or action bitmap. + * @param fullLine the line to check. Might contain spaces. + */ +function isDialogueLine(fullLine: string): boolean { + + const containsTabulation = fullLine.startsWith(" ") + + // this rule is a bit strict as some text files don't have tabulation.. + // but it helps A LOT + if (!containsTabulation) { + return false + } + + return true +} + +/** + * Check whether the given line contains a character dialogue or action bitmap. + * @param fullLine the line to check. Might contain spaces. + */ +function isCharacterLine(fullLine: string): boolean { + + const containsTabulation = fullLine.startsWith(" ") + + // disabled, because some character line include things like parenthesis + // if (fullLine.match(/\([^\)]+\)/)) { + // return false + // } + + // this rule is a bit strict as some text files don't have tabulation.. + // but it helps A LOT + if (!containsTabulation) { + return false + } + + // the fullLine is important and useful (to locate characters, highlight etc) + // however it might not be a reliable indicated, so we use uppercase + const line = fullLine.trim() + + const { isTransition, isSceneDescription, timeType, locationType } = analyzeLine(line) + + + const character = parseCharacterName(line) + + // doesn't look like a character name, after filtering + if (!character) { + return false + } + + // console.log("isAllCaps?", isAllCaps(line)) + if ( + line.length < 2 || // line is too short to be a character + !isAllCaps(line) // line is not all uppercase + ) { + // console.log("FAIL 1") + return false + } + + if ( + isTransition || // nope, that's a transition or scene + isSceneDescription + ) { + // console.log("FAIL 2") + return false + } + + if ( + locationType !== "UNKNOWN" || + timeType !== "UNKNOWN" + ) { + // console.log("FAIL 3") + return false + } + + // nah, it's juste someone shouting + if (line.includes("!")) { + return false + } + + if ( + line === "NO" || line === "NO." || + line === "YES" || line === "YES." || + line === "STOP" || line === "STOP." + ) { + return false + } + + const lineWithSpace = ` ${line} ` + if ( + lineWithSpace.includes(" INSERT ") || + lineWithSpace.includes(" POV ") || + lineWithSpace.includes(" CLOSE-UP ") + ) { + return false + } + + return true +} + +/** + * Parse screenplay script into scenes and events.. + * @param screenplay The entire screenplay script. + */ +export function parseScenes(screenplaySequence: ScreenplaySequence): Scene[] { + try { + const screenplay = screenplaySequence.fullText + + let initialScene: string = "" + + // the little text in parenthesis + let currentDialogueAction = "" + + let currentScene: Scene | undefined = undefined + let currentEvents: SceneEvent[] = [] + let currentEvent: SceneEvent | undefined = undefined + + let lastCharacter = "" + + let lineNumber = screenplaySequence.startAtLine + + const scenes: Scene[] = [] + + for (const lineWithSpaces of screenplay.split("\n")) { + + let line = lineWithSpaces.trim() + + // we are just going to the next page... normally + if (line.match(/^\d+\.$/)) { + lineNumber += 1 + continue + } + + // TODO detect scenes (the "descriptions") + + // IMPORTANT: USE THE FULL LINE WITH SPACES HERE! + const maybeCharacter = parseCharacterName(lineWithSpaces) + const isCharacter = isCharacterLine(lineWithSpaces) + // console.log(`isCharacterLine("${lineWithSpaces}"):`, isCharacter) + // console.log(`maybeCharacter: `, maybeCharacter) + if (isCharacter && maybeCharacter) { + // console.log(" found a character:", maybeCharacter) + lastCharacter = maybeCharacter + + if (currentScene) { + if (currentEvent) { + // no, we don't update the line here, since this is a NEW line + // currentEvent.endAtLine = lineNumber + currentEvents.push(currentEvent) + } + currentEvent = undefined + currentScene.events = currentEvents + // no, we don't update the line here, since this is a NEW line + // currentScene.endAtLine = lineNumber + scenes.push(currentScene) + currentEvents = [] + currentScene = undefined + } + + currentScene = { + id: UUID(), + scene: (currentScene as any)?.scene || "", + line, + rawLine: lineWithSpaces, + sequenceFullText: screenplaySequence.fullText, + sequenceStartAtLine: screenplaySequence.startAtLine, + sequenceEndAtLine: screenplaySequence.endAtLine, + startAtLine: lineNumber, + endAtLine: lineNumber, + events: [], + } + + // need to reset this! + currentDialogueAction = "" + + lineNumber += 1 + + continue + } + + if (!line.length) { + + // if the line is empty, we terminate the current event + // UNLESS it is obviously not terminated (ie. unless + // it isn't finishing in a !, ? or .) + if (currentEvent && ( + currentEvent.description.endsWith("!") || + currentEvent.description.endsWith("?") || + currentEvent.description.endsWith(".") + )) { + // no, we don't update the line here, since this is a NEW line + // currentEvent.endAtLine = lineNumber + currentEvents.push(currentEvent) + currentEvent = undefined + } + + lineNumber += 1 + continue + } + + // basic heuristic: the first line of a a scene is the scene description + if (!initialScene) { + + let firstLine = ` ${line.trim().toUpperCase()} ` + + // the first part of the line might be a number - we remove this + firstLine = firstLine.replaceAll(/^(\s*\d+)[^\d]/gi, " ") + + // the last part of the line might be also a number - we remove this too + firstLine = firstLine.replaceAll(/[^\d](\d+\s*)$/gi, " ") + + initialScene = firstLine.trim() + + // reset the last character + lastCharacter = "" + + lineNumber += 1 + continue + } + + + // parse the line, and determine if it's dialogue, + // commentary, action.. + const startOfAction = line.match(/^\(/) + const endOfAction = line.match(/\)$/) + const isDialogue = isDialogueLine(lineWithSpaces) // <-- yes, spaces are important here!! + + if (startOfAction) { + if (currentEvent) { + // no, we don't update the line here, since this is a NEW line + // currentEvent.endAtLine = lineNumber + currentEvents.push(currentEvent) + currentEvent = undefined + } + + const action = `${ + endOfAction + ? line.replaceAll("(", "").replaceAll(")", "") + : line.replaceAll("(", "") + }` + + currentDialogueAction = action + + currentEvent = { + id: UUID(), + type: "action", + character: lastCharacter, + description: action, + behavior: "", + startAtLine: lineNumber, + endAtLine: lineNumber, + } + } else if (endOfAction && currentEvent?.type === "action") { + + const action = currentEvent.description.trim() + ? `${currentEvent.description.trim()} ${line.replace(")", "")}` + : line.replace(")", "") + + currentEvent.description = action + currentDialogueAction = action + + currentEvent.endAtLine = lineNumber + currentEvents.push(currentEvent) + currentEvent = undefined + } else if (currentEvent) { + const typeHasChanged = isDialogue && currentEvent.type !== "dialogue" + + // we are not in a dialogue anymore, so let's clear the dialogue action buffer + if (currentEvent.type === "description") { + currentDialogueAction = "" + } + + if (typeHasChanged) { + // no, we don't update the line here, since this is a NEW line + // currentEvent.endAtLine = lineNumber + currentEvents.push(currentEvent) + currentEvent = undefined + + currentEvent = { + id: UUID(), + type: isDialogue ? "dialogue" : "action", + character: lastCharacter, + description: line, + behavior: isDialogue ? currentDialogueAction : "", + startAtLine: lineNumber, + endAtLine: lineNumber + } + } else { + // current event type has not changed, we are just extending it + currentEvent.description = + currentEvent.description.trim() + ? `${currentEvent.description.trim()} ${line}` + : `${line}` + + currentEvent.endAtLine = lineNumber + } + } else { + // we are creating a new event + currentEvent = { + id: UUID(), + type: lastCharacter && isDialogue ? "dialogue" : "description", + character: lastCharacter && isDialogue ? lastCharacter : "", + description: `${line}`, + behavior: isDialogue ? currentDialogueAction : "", + startAtLine: lineNumber, + endAtLine: lineNumber + } + } + + lineNumber += 1 + } + + + if (currentScene) { + if (currentEvent) { + // no, we don't update the line here, since this is a NEW line + // currentEvent.endAtLine = lineNumber + currentEvents.push(currentEvent) + } + currentEvent = undefined + currentScene.events = currentEvents + // no, we don't update the line here, since this is a NEW line + // currentScene.endAtLine = lineNumber + scenes.push(currentScene) + currentEvents = [] + currentScene = undefined + } + + // one last trick, which is pretty important actually: we expand the action further + for (const scene of scenes) { + const sceneEvents: SceneEvent[] = [] + for (const event of scene.events) { + event.description.split(/\. /).forEach(sentence => { + sceneEvents.push({ + ...event, + description: sentence + }) + }) + } + + scene.events = sceneEvents + } + return scenes + } catch (err) { + console.error(err) + return [] + } +} \ No newline at end of file diff --git a/packages/broadway/src/analysis/parseScriptToClap.ts b/packages/broadway/src/analysis/parseScriptToClap.ts new file mode 100644 index 0000000000000000000000000000000000000000..f5e49a7ab23f5ab51203374c0a6649c1890118b2 --- /dev/null +++ b/packages/broadway/src/analysis/parseScriptToClap.ts @@ -0,0 +1,93 @@ +import { ClapMediaOrientation, ClapProject, newClap, UUID } from "@aitube/clap" + +import { cleanUTF8Characters } from "@/utils" +import { analyzeScreenplay } from "@/analysis/analyzeScreenplay" + +import { getScreenplayFromText } from "./getScreenplayFromText" + +export type ParseScriptProgressUpdate = ({ + value, + sleepDelay, + message +}: { + value: number + sleepDelay?: number + message?: string +}) => Promise + +const defaultParseScriptProgressUpdate: ParseScriptProgressUpdate = async () => {} + +export async function parseScriptToClap( + input: string, + onProgressUpdate: ParseScriptProgressUpdate = defaultParseScriptProgressUpdate +): Promise { + // fix any mess which might be in it + const content = cleanUTF8Characters(input) + + await onProgressUpdate({ value: 5 }) + + const screenplay = await getScreenplayFromText(content) + + await onProgressUpdate({ value: 10 }) + + const { + movieGenreLabel, + extraPositivePrompt, + segments, + entitiesById, + finalPlainText, + totalDurationInMs, + scenes + } = await analyzeScreenplay( + screenplay, + async (progress, message) => { + // progress is a value between 0 and 100 + const ratio = progress / 100 + + // so we want to continue the progress bar in the range [20, 70] + await onProgressUpdate({ + value: 10 + (ratio * 80), + sleepDelay: 25, + message + }) + }) + + await onProgressUpdate({ value: 90 }) + + + // TODO: return a ClapProject instead + const clap = newClap({ + meta: { + id: UUID(), + title: "Untitled", + description: `${movieGenreLabel}`, + synopsis: "", + licence: "This OpenClap file is just a conversion from the original screenplay and doesn't claim any copyright or intellectual property. All rights reserved to the original intellectual property and copyright holders. Using OpenClap isn't piracy.", + + orientation: ClapMediaOrientation.LANDSCAPE, + durationInMs: totalDurationInMs, + + width: 1024, + height: 576, + defaultVideoModel: "", // <-- we should deprecate this no? + extraPositivePrompt: extraPositivePrompt, + screenplay: finalPlainText, + isLoop: false, + isInteractive: false, + }, + scenes: scenes.map((scene, i) => ({ + ...scene, + // let's deprecate this field, this was a bad idea + // (too much redundancy) + sequenceFullText: "", + + // let's also deprecate this + events: [], + })), + entities: Object.values(entitiesById), + segments, + }) + await onProgressUpdate({ value: 100 }) + + return clap +} \ No newline at end of file diff --git a/packages/broadway/src/constants/general.ts b/packages/broadway/src/constants/general.ts new file mode 100644 index 0000000000000000000000000000000000000000..2b1c14e59b4b2df0679def21f294340aceb98197 --- /dev/null +++ b/packages/broadway/src/constants/general.ts @@ -0,0 +1,14 @@ +// the time resolution - this may be an option in the future +export const DEFAULT_DURATION_IN_MS_PER_STEP = 500 + +export const DEFAULT_COLUMNS_PER_STEP = 1 // this is dynamic, and corresponds to the zoom level + +// how many columns per slice / default segment lenght - this may be an option in the future +// so here, a "slice" (a typical shot) +// lasts for 2 seconds (500ms * 4) +export const DEFAULT_COLUMNS_PER_SLICE = 4 + +// TODO use this as a vertical zoom level +export const STEP_HEIGHT_COLUNM_RATIO = 1 + +export const DEFAULT_NB_TRACKS = 24 // 32 diff --git a/packages/broadway/src/constants/index.ts b/packages/broadway/src/constants/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..dc033c9cc3eb1c51e78aaa73924944078f56b0b7 --- /dev/null +++ b/packages/broadway/src/constants/index.ts @@ -0,0 +1,18 @@ +export { + DEFAULT_DURATION_IN_MS_PER_STEP, + DEFAULT_COLUMNS_PER_STEP, + DEFAULT_COLUMNS_PER_SLICE, + STEP_HEIGHT_COLUNM_RATIO, + DEFAULT_NB_TRACKS, +} from "./general" + + +export { mockCategoryPrompts_misc, mockCategoryPrompts } from "./mocks" + +export { + screenplaySequenceTypes, + type ScreenplaySequenceType, + screenplaySequenceTimes, + type ScreenplaySequenceTime +} from "./screenplaySequences" + diff --git a/packages/broadway/src/constants/mocks.ts b/packages/broadway/src/constants/mocks.ts new file mode 100644 index 0000000000000000000000000000000000000000..5cbc68925650598b1209499e35440612cfd9a846 --- /dev/null +++ b/packages/broadway/src/constants/mocks.ts @@ -0,0 +1,258 @@ +import { ClapSegmentCategory } from "@aitube/clap" + +// those are very random categories, so we don't use this as an example +// as this will looks unrealistic to potential customers +export const mockCategoryPrompts_misc: Record = { + ACTION: [ + "eating a dinner", + "looking at cellphones", + "enjoying the view", + "happy", + "peaceful", + "tense", + "mysterious", + ], + CHARACTER: [ + "James", + "Anna", + "Alice", + "Bob" + ], + LOCATION: [ + "train station in NYC", + "inside a building", + "below the Eiffel Tower", + "in a fancy restaurant" + ], + TRANSITION: [ + "CUT TO" + ], + CAMERA: [ + "long wide establishing shot", + "full shot", + "medium-long shot", + "medium shot", + "medium close-up", + "close-up", + "extreme close-up", + "extreme long shot", + "American shot", + "Italian shot", + "trolley shot" + ], + LIGHTING: [ + "strong light", + "soft light", + "candlelit", + ], + TIME: [ + "in the morning, golden hour", + "at noon", + "during the day, sunlit", + "in the evening, golden hour", + "at night, moonlit" + ], + ERA: [ + "in the 60s", + "in the 70s", + "in the 80s", + "modern era" + ], + WEATHER: [ + "cloudy, soft mist", + "cloudy, in the fog", + "sunny", + "light cloud cover", + "light rain", + "heavy rain", + "cloudy", + "clouds with strong wind", + // "storm" + ], + SOUND: [ + "street noise", + "wind sound", + "cafe noise", + "chatty airport", + "dog barking", + "baby cooing", + "cat meowing", + "wind noise", + "cafe ambiance", + "steps sounds", + "bag opening" + ], + MUSIC: [ + "soft electronic ambient", + "energic electronic beat", + "instrumental orchestra", + "epic orchestral with strings", + "soft pop-rock tune", + "instrumental hip-hop", + "atmospheric trip-hop", + "lofi instrumental hiphop" + ], + + DIALOGUE: [ + "saying hello", + "asking for directions", + "disagreeing", + "threatening" + ], + + STYLE: [ + "Mickael Bay", + "Wes Anderson", + "Studio Ghibli", + "Moebius", + "anime", + "3D render", + "documentary", + "movie grain" + ], + + /* + colors: [ + "photorealist", + "movie grain", + "" + ], + */ + + SPLAT: [], + MESH: [], + DEPTH: [], + EVENT: [], + EFFECT: [], + INTERFACE: [], + PHENOMENON: [], + VIDEO: [], + STORYBOARD: [], + + GENERIC: [ + "Custom" + ] +} + + +export const mockCategoryPrompts: Record = { + ACTION: [ + "peaceful", + "tense", + "mysterious", + "peaceful", + "tense", + "mysterious", + "peaceful", + "tense", + "mysterious", + ], + CHARACTER: [ + "Henry", + "Margaret", + "Eleanor", + "Elizabeth", + "William", + "Thomas", + "Rackham", + "Joseph", + "Gideon", + "Isaac" + ], + LOCATION: [ + "on the beach in the caribbean", + "on the deck of a pirate ship", + "in the captain's quarters of a pirate ship", + "in a tropical forest", + ], + CAMERA: [ + "long wide establishing shot", + "full shot", + "medium-long shot", + "medium shot", + "medium close-up", + "close-up", + "extreme close-up", + "extreme long shot", + "American shot", + "Italian shot", + "trolley shot" + ], + LIGHTING: [ + "strong light", + "soft light", + "candlelit", + ], + TIME: [ + "in the morning, golden hour", + "at noon", + "during the day, sunlit", + "in the evening, golden hour", + "at night, moonlit" + ], + ERA: [ + // "in 1700", + // "during piracy times" + ], + WEATHER: [ + "cloudy, soft mist", + "cloudy, in the fog", + "sunny", + "light cloud cover", + "light rain", + "heavy rain", + "cloudy", + "clouds with strong wind", + // "storm" + ], + SOUND: [ + "animal noise", + "wind sound", + "tropical sounds", + "sea noises", + ], + MUSIC: [ + "cinematic music", + "adventurous instrumental orchestra", + "epic orchestral with strings", + "cinematic instrumental orchestra", + "suspensful instrumental orchestra", + // "instrumental orchestra for sailing a ship, 1700", + // "epic orchestral with strings, 1800", + // "suspensful instrumental orchestra, 1700", + ], + TRANSITION: [ + "cut to" + ], + DIALOGUE: [ + "saying hello", + "asking for directions", + "disagreeing", + "threatening" + ], + + STYLE: [ + "movie screencap, film grain" + ], + + /* + colors: [ + "photorealist", + "movie grain", + "" + ], + */ + SPLAT: [], + MESH: [], + DEPTH: [], + EVENT: [], + EFFECT: [], + INTERFACE: [], + PHENOMENON: [], + VIDEO: [], + STORYBOARD: [], + + GENERIC: [ + "Lorem ipsum" + ] +} diff --git a/packages/broadway/src/constants/screenplaySequences.ts b/packages/broadway/src/constants/screenplaySequences.ts new file mode 100644 index 0000000000000000000000000000000000000000..38dbba1c3a170d93ebd055950c6f592df0e47123 --- /dev/null +++ b/packages/broadway/src/constants/screenplaySequences.ts @@ -0,0 +1,53 @@ + +export const screenplaySequenceTypes = { + "INTERIOR": "Indoor", + "EXTERIOR": "Outdoor", + "INT./EXT.": "Indoor/Outdoor", + "UNKNOWN": "Unknown place", +} + +export type ScreenplaySequenceType = keyof typeof screenplaySequenceTypes + +// IMPORTANT: PUT SHORTER PATTERN AT THE END!! +export const screenplaySequenceTimes = { + "CONTINUOUS": "", // we found this in some screenplay but.. what does it mean? + "THAT MOMENT": "", // same here + "THE SAME DAY": "Day", + "THE NEXT DAY": "Day", + "THE NEXT AFTERNOON": "Afternoon", + "NEXT AFTERNOON": "Afternoon", + "LATER AFTERNOON": "Afternoon", + "SAME DAY": "Day", + "NEXT DAY": "Day", + "SAME TIME": "Day", + "DAY FOR NIGHT": "Day for night", + "PRE-DAWN": "At pre-dawn", + "AT DAWN": "At dawn", + "EARLY MORNING": "Early morning", + "LATE MORNING": "Late morning", + "EARLY EVENING": "Early evening", + "LATE EVENING": "Late evening", + "LATE NIGHT": "Night", + "IN THE EVENING": "In the evening", + "A FEW MOMENTS LATER": "Moments later", + "FEW MOMENTS LATER": "Moments later", + "MOMENTS LATER": "Moments later", + "MOMENT LATER": "Moment later", + "EVENING": "During the evening", + "MIDNIGHT": "At midnight", + "MORNING": "Morning", + "AFTERNOON": "In the afternoon", + "LATER": "Later", + "NOON": "At noon", + "DAWN": "Dawn", + "SUNRISE": "Sunrise", + "SUNSHINE": "Sunshine", + "DUSK": "Dusk", + "TWILIGHT": "Twilight", + "DAY": "During day", + "LATE": "Late", + "NIGHT": "At night", + "UNKNOWN": "Day", +} + +export type ScreenplaySequenceTime = keyof typeof screenplaySequenceTimes \ No newline at end of file diff --git a/packages/broadway/src/declarations.d.ts b/packages/broadway/src/declarations.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..57cf908176e0e74cebab2a49b1be0decca8ff17b --- /dev/null +++ b/packages/broadway/src/declarations.d.ts @@ -0,0 +1,2 @@ +declare module '@datagica/parse-entities'; +declare module '@datagica/parse-names'; \ No newline at end of file diff --git a/packages/broadway/src/factories/createSegment.ts b/packages/broadway/src/factories/createSegment.ts new file mode 100644 index 0000000000000000000000000000000000000000..82422d236dacd9a527aabd8c787f1491f6a7728c --- /dev/null +++ b/packages/broadway/src/factories/createSegment.ts @@ -0,0 +1,121 @@ +// this is a deprecated module, we should get rid of it +import { getSegment, segmentCategories, ClapSegmentCategorySettings } from "@aitube/colors" + +import { DEFAULT_DURATION_IN_MS_PER_STEP } from "@/constants/general" +import { pick } from "@/utils" +import { generateSeed, parseOutputType, ClapOutputType, ClapSegmentCategory, ClapSegment, UUID, newSegment } from "@aitube/clap" + +export function createSegment({ + startTimeInSteps, + startTimeInLines, + endTimeInLines, + sceneId, + prompt = [], + label = "", + durationInSteps = 4, + trackId = 0, + outputType = ClapOutputType.TEXT, + categoryName = ClapSegmentCategory.GENERIC, + entityId = "", + seed, +}: { + startTimeInSteps: number + startTimeInLines: number + endTimeInLines: number + sceneId: string + prompt?: string[] + label?: string + durationInSteps?: number + trackId?: number + outputType?: ClapOutputType + categoryName?: ClapSegmentCategory + entityId?: string + seed?: number +}): ClapSegment { + + // steps: 1|2|3|4 + // duration: 4 + // so if we begin at 1, the end step is 4 + // we need to remove 1, otherwise the end time will be too far + const endTimeInSteps = startTimeInSteps + (durationInSteps - 1) + + // but for milliseconds, it is different! we want th exactly match the ms time + const durationInMs = durationInSteps * DEFAULT_DURATION_IN_MS_PER_STEP + + // this means here we will have a problem as if we are "step 1", we wil lhave 1 * 500ms (for instance) + // which is not good: we want 0ms as a starting point instead + // so the solution is to subtract 1 step + const startTimeInMs = (startTimeInSteps - 1) * DEFAULT_DURATION_IN_MS_PER_STEP + + // see here how we DON'T remove 1 step: that's because we want the end time (in ms) + // to exactly match the beginning of the next section + const endTimeInMs = startTimeInMs + durationInMs + + const track = trackId // randomInteger(trackId, nbTracks) + + const segmentCategoriesExceptVisuals = + Object.values(segmentCategories) + .filter(item => + ![ + ClapSegmentCategory.SPLAT, + ClapSegmentCategory.MESH, + ClapSegmentCategory.DEPTH, + ClapSegmentCategory.VIDEO, + ClapSegmentCategory.STORYBOARD + ].includes(item.id) + ) as ClapSegmentCategorySettings[] + + // either a custom or a random category (except preview and render) + const category = categoryName + ? getSegment(categoryName) + : pick(segmentCategoriesExceptVisuals) + + const promptString = Array.isArray(prompt) ? prompt.filter(x => typeof x === "string" && x.length > 0).join(", ") + : "" + + const randomSegment: ClapSegment = newSegment({ + id: UUID(), + + startTimeInMs, + endTimeInMs, + startTimeInLines, + endTimeInLines, + sceneId, + + prompt: promptString, + track, // track row index + label: label || promptString, // a short label to name the segment (optional, can be human or LLM-defined) + category: category.id, + + entityId, + + // isHovering: false, + // isDragging: false, + // isEditing: false, + + seed: (!seed || isNaN(seed) || !isFinite(seed)) ? generateSeed() : seed, // seed unique to this segment - however for each video/image we will use the first "storyboard" seed + + // by default we are "auto", which means we created it using basic if/else rules + // but no language model or anything like that + createdBy: "auto", + editedBy: "auto", + + // storyboardUrl: mockStoryboardsDrawing.at(i) || mockStoryboardsDrawing[0], + // referenceUrl: mockStoryboardsLifelike.at(i) || mockStoryboardsLifelike[0], + // generationStartedAt: 0, + + outputType: parseOutputType(outputType), + + // renderId: "", + // status: "to_generate", + // assetUrl: "", + // assetDurationInMs: 0, + + // default is 1, 0 is mute, 2 is double the volume + // gain can be set to a minimum of about -3.4028235E38 and a max of about 3.4028235E38 + // outputGain: 1, + + }) + + return randomSegment +} \ No newline at end of file diff --git a/packages/broadway/src/factories/generateClap.ts b/packages/broadway/src/factories/generateClap.ts new file mode 100644 index 0000000000000000000000000000000000000000..bdd9a14aea3b8758423f40f224fe3afa1ef69e57 --- /dev/null +++ b/packages/broadway/src/factories/generateClap.ts @@ -0,0 +1,112 @@ +import YAML from "yaml" + +import { ClapFormat, ClapHeader, ClapMeta, ClapEntity, ClapScene, ClapSegment, ClapMediaOrientation, getValidNumber, UUID, ClapWorkflow, sanitizeEntities, sanitizeSegment, sanitizeWorkflows } from "@aitube/clap" +import { MovieScript, Screenplay } from "@/types" + +/** + * export a Clap blob + * + * Optionally the blob can be downloaded, if we are in a browser environment + * + * however, note that for some reason YAML stringify is a blocking call like for JSON, + * they is no async version although we are now in the 20s not 90s + * + * in the future we might want to use an alternative implementation of YAML + */ +export async function generateClap({ + script, + screenplay, + projectInfo = "", + workflows = [], + segments = [], + entities = [], + embedded = false, +}: { + script: MovieScript + screenplay: Screenplay + projectInfo: string + workflows: ClapWorkflow[] + segments: ClapSegment[] + entities: ClapEntity[] + + // if embedded is true, the file will be larger, as all the content, + // image, video, audio.. + // will be embedded into it (except the last big video) + embedded?: boolean +}): Promise { + + const clapScenes: ClapScene[] = screenplay.sequences.flatMap(sequence => sequence.scenes) + + const clapWorkflows = sanitizeWorkflows(workflows) + + const clapEntities = sanitizeEntities(entities) + + const useCompactMode = !embedded + + // const win = (window as any) + // win.debugJulian = segments + + let highestEndTimeInMs = 0 + + const clapSegments: ClapSegment[] = segments.map(maybeSegment => { + const segment = sanitizeSegment(maybeSegment) + if (segment.endTimeInMs > highestEndTimeInMs) { + highestEndTimeInMs = segment.endTimeInMs + } + return segment + }) + + const clapHeader: ClapHeader = { + format: ClapFormat.CLAP_0, + numberOfWorkflows: clapWorkflows.length, + numberOfEntities: clapEntities.length, + numberOfScenes: clapScenes.length, + numberOfSegments: clapSegments.length, + } + + const clapMeta: ClapMeta = { + id: UUID(), + title: script.meta.title, + description: "", + synopsis: "", + licence: "", + tags: [], + thumbnailUrl: "", + orientation: ClapMediaOrientation.LANDSCAPE, + durationInMs: highestEndTimeInMs, + isLoop: false, + isInteractive: false, + // TODO read this from the project config + width: getValidNumber(1024, 256, 8192, 1024), + height: getValidNumber(576, 256, 8192, 576), + defaultVideoModel: "SVD", + extraPositivePrompt: [], + screenplay: screenplay.fullText, + } + + const entries = [ + clapHeader, + clapMeta, + ...clapWorkflows, + ...clapEntities, + ...clapScenes, + ...clapSegments + ] + + const strigifiedResult = YAML.stringify(entries) + + // Convert the string to a Blob + const blobResult = new Blob([strigifiedResult], { type: "application/x-yaml" }) + + // Create a stream for the blob + const readableStream = blobResult.stream(); + + // Compress the stream using gzip + const compressionStream = new CompressionStream('gzip'); + const compressedStream = readableStream.pipeThrough(compressionStream); + + // Create a new blob from the compressed stream + const compressedBlob = await new Response(compressedStream).blob(); + + return compressedBlob +} \ No newline at end of file diff --git a/packages/broadway/src/factories/index.ts b/packages/broadway/src/factories/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..f640b51ee8d62f88ddaf8917259ae0bef73446f0 --- /dev/null +++ b/packages/broadway/src/factories/index.ts @@ -0,0 +1,2 @@ +export { createSegment } from "./createSegment" +export { generateClap } from "./generateClap" \ No newline at end of file diff --git a/packages/broadway/src/index.ts b/packages/broadway/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..61ec1b525db90074f3f9983de8ebfa503fb7ee4b --- /dev/null +++ b/packages/broadway/src/index.ts @@ -0,0 +1,72 @@ +export { + analyzeLine, + analyzeName, + analyzeScreenplay, + getEntityAnalysisPrompt, + guessAgeAndGender, + getScreenplayFromText, + isCharacterLine, + isDialogueLine, + isPageSeparator, + isVoiceOver, + parseCharacterName, + parseDialogueLine, + parseScenes, + type ParseScriptProgressUpdate, + parseScriptToClap, +} from "./analysis" + +export { + DEFAULT_DURATION_IN_MS_PER_STEP, + DEFAULT_COLUMNS_PER_STEP, + DEFAULT_COLUMNS_PER_SLICE, + STEP_HEIGHT_COLUNM_RATIO, + DEFAULT_NB_TRACKS, + + mockCategoryPrompts_misc, mockCategoryPrompts , + + screenplaySequenceTypes, + type ScreenplaySequenceType, + screenplaySequenceTimes, + type ScreenplaySequenceTime, +} from "./constants" + +export { createSegment, generateClap } from "./factories" + +export { + parseEntity, + getEra, getMostProbableEras, parseEras, + getGenre, getMostProbableGenres, parseGenres, + getLight, parseLights, + getLocation, parseIndoorLocations, parseOutdoorLocations, parseLocations, parseLocationType, + type ExtractedCharacterName, parseNames, + getShot, parseShots, + getSound, parseSounds, + parseTransition, transitions, + createOccurrenceCounter, createParser, createSimpleParser, getParserItemFromLabel, + getWeather, parseWeather +} from "./parsers" + +export { + type MovieScriptMeta, + type MovieScript, + type SceneEvent, + type Scene, + type MergedLine, + type ScreenplaySequence, + type Screenplay, + type AssetType, + type AssetCategory, + type TemporaryAssetData, +} from "./types" + +export { + cleanUTF8Characters, + deduplicate, + getEntities, + // getRandomDirectory, + isAllCaps, + onlyContainsStrangeNumber, + pick, + sleep +} from "./utils" diff --git a/packages/broadway/src/parsers/age/index.ts b/packages/broadway/src/parsers/age/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..4df3a93611a7bd54d0838f66b3b42a00ef1a2a8f --- /dev/null +++ b/packages/broadway/src/parsers/age/index.ts @@ -0,0 +1,3 @@ +export function parseAge() { + +} \ No newline at end of file diff --git a/packages/broadway/src/parsers/costumes/database.ts b/packages/broadway/src/parsers/costumes/database.ts new file mode 100644 index 0000000000000000000000000000000000000000..635aac17a4a05557495e8be6f96c4be6be88bc12 --- /dev/null +++ b/packages/broadway/src/parsers/costumes/database.ts @@ -0,0 +1,26 @@ +import { NamedEntity } from "@/types" + +export const data: NamedEntity[] = [ + { + "label": "futuristic", + "aliases": { + "en": [ + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + } +] \ No newline at end of file diff --git a/packages/broadway/src/parsers/entity/index.ts b/packages/broadway/src/parsers/entity/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..adfe23daa64b6497f768df2a056d2bc12a290596 --- /dev/null +++ b/packages/broadway/src/parsers/entity/index.ts @@ -0,0 +1,45 @@ + + +// some examples of things to parse: +/* +Basically we want to identify an entity (character or location) +and associated characteristics. + + A big, old, three-story brick house in a small Chicago + suburb. + + adjectives, + + Three days before Christmas. There are lights and Christmas + decorations on the house and the surrounding houses. + + HEATHER McCALLISTER comes down +the stairs. She's nineteen and a cousin. She's wearing a +Northwestern University sweatshirt. + + CLOSE ON ARTHUR (30's), tears in his eyes from laughing so + hard. He's trying to get it under control. His greasy, + black hair hanging down over his forehead. He's wearing an + old, faded green cardigan sweater, a threadbare gray scarf, + thin from years of use, hangs loosely around his neck. + + He's sitting across from an overworked SOCIAL WORKER + (50's), African American. + */ + +import { ClapEntity } from "@aitube/clap" + +export function parseEntity(text: string, entities: ClapEntity[] = []) { + // we assume we are given a short text containing information about + + for (const entity of entities) { + const coordinates = text.indexOf(entity.triggerName) + + } + + const clothes = text.match(/(?:wears|wearing) ([a-zA-Z0-9\-\s]+)\./i) + + return { + clothes: clothes?.[1] || "" + } +} \ No newline at end of file diff --git a/packages/broadway/src/parsers/eras/database.ts b/packages/broadway/src/parsers/eras/database.ts new file mode 100644 index 0000000000000000000000000000000000000000..a0b09b100f49e8a7096a9730622215a0a165e286 --- /dev/null +++ b/packages/broadway/src/parsers/eras/database.ts @@ -0,0 +1,799 @@ +import { NamedEntity } from "@/types" + +export const data: NamedEntity[] = [ + { + "label": "futuristic", + "aliases": { + "en": [ + "city of the future", + "synthetic food", + "artifical life", + // "computer", + // "computers", + "replicator", + "replicators", + "self-replicator", + "self-replicators", + "replicant", + "replication", + // "dna strand", + // "dna strands", + // "oxygen tank", + "memory wipe", + "grid with vectors", + // "hum of the machine", + "dna programming", + // "simulation", + // "virtual", + "offworld", + "off world", + "recombination", + "alkylating", + "mutagen", + // "robot", + // "robotic", + // "robotics", + // "robot dog", + "robot police", + // "high-voltage tethers", + // "through space", + // "galaxy", + "galactic", + "gravitational", + "gravitational wave", + "gravitational waves", + // "graphene", + "tycho", + "tycho base", + "lunar hangar", + "lunar rover", + "space shuttle", + "enogenic", + "repressor protein", + "I'm a clone", + "you're a clone", + "he is a clone", + "she is a clone", + // "vortex", + "biomechanics", + "spaceship", + "space ship", + "star ship", + "starship", + "mothership", + "spacesuit", + "spacesuits", + "lunar roving", + "roving vehicle", + // "mapping computer", + "space helmet", + "space helmets", + "astronaut", + "astronauts", + "inter-stellar", + "hyper-drive", + "range of the planet", + "landing on the planet", + "orbital insertion", + "probe retract system", + "landing probe", + "planet's surface", + "hostile planet", + "depressurization", + "pepressurization", + "space vacuum", + "laser pistol", + "laser pistols", + "servomoteur", + "android", + // "cyberspace", + "air lock", + "airlock", + "solar system", + "solar systems", + "teleportation", + // "reactor", + "nuclear reactor", + "reactors", + "asteroids", + "asteroid belt", + "light year", + "light years", + "diagnostic coffin", + // "laser beam", + "blast door", + "blast doors", + "alien creature", + "alien device", + "cryosleep", + "hypersleep", + // "science fiction", + // "science-fiction", + "sometime in the future", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: ["futuristic"], + LIGHTING: ["dimly lit"], + WEATHER: [], + ACTION: [], + MUSIC: ["electronic"], + SOUND: [], + DIALOGUE: [], + STYLE: ["futuristic"], + CAMERA: [], + } + }, + { + "label": "antiquity", + "aliases": { + "en": [ + // "antiquity", + "oracle", + "atlar", + "nobilis", + //"tunic", + //"toga", + "calceus", + "calcei", + "proletarii", + "patrician", + "patricians", + "domus", + "sparta", + "spartan", + "spartans", + "spartan warrior", + "plebeian", + "plebeians", + "plebs", + "plebis", + // "roman", + // "romans", + "roman emperor", + "julius caesar", + "greek warrior", + "greek warriors", + "Peloponnesus", + "punic war", + "anatolian", + "athenian", + "athenians", + "ephor", + "ephors", + "phocian", + "phocians", + "greek hoplite", + "greek hoplites", + "hoplite", + "hoplites", + "spartan hoplite", + "spartan hoplites", + "spartanhoplite", + "spartanhoplites", + "trireme", + "triremes", + "euclid", + "archimedes", + "theron", + "stelios", + "astinos", + "lakonia", + "daxos", + "ephialtes", + "phalanx", + "bronze helmet", + "bronze helmets", + "bronze sword", + "bronze swords", + "bronze shield", + "bronze shields", + "bronze arrow", + "bronze arrows", + "Pleistarchos", + "kythera", + "Antikythera", + "Agiad", + "Agiads", + "Eurypontid", + "Eurypontids", + "Eurysthenes", + "Procles", + "Heracles", + "Trojan War", + "Rex Sacrorum", + "Galum", + "Gallum", + "Triumvir", + "Triumvirs", + "Xerxes", + "Persia", + "Persian", + "Leonidas", + "Menelaus", + "Cleomenes", + "Pausanias", + "Chilon", + "of sparta", + "Lysander", + "Agnes", + "Agesilaus", + "Echestratus", + "Agis", + "Leotychidas", + "Alcaeus", + "Alexandros", + "Anaxander", + "Teleclus", + "Eunomus", + "Archelaus", + "Myles", + "Gorgo", + "vesuvio", + "caius", + "dilios", + "aurelius", + "Aristotle", + "Lucretia", + "Alexander", + "Aurelia", + "Titus", + "Augustus", + "Clodius", + // "Marcus", + "Julius", + "Romulus", + "Claudius", + "Lucius", + "Cassandra", + "Valeria", + "Maximus", + "Nero", + "Aeschylus", + "Cicero", + "Agatha", + "Aesop", + "Aelius", + "Aetius", + "Lazarus", + "Tiberius", + "Neptune", + "Demetrius", + "Zeus", + "Lelex", + "Myles", + "Eurotas", + "Hercules", + "Atreids", + "Dorians", + "Perseus", + "Pater familias", + "cives", + "peregrina", + "peregrinus", + "orator" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: ["antiquity", "roman, greek and spartan empire"], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["old harp music"], + SOUND: [], + DIALOGUE: [], + STYLE: ["antiquity", "roman, greek and spartan empire"], + CAMERA: [], + } + }, + { + "label": "1800-1900 western", + "aliases": { + "en": [ + "Western", + "cowboy", + "cowboys", + "saddles", + "saddle", + "frontiersman", + "frontiersmen", + "outlaws", + "town mashal", + "constable", + "posse", + "california gold rush", + "californios", + "Far West", + "American frontier", + "Old West", + "Wild West", + "Thomas Jefferson", + "Louisiana Purchase", + "western territories", + "Arizona settlers", + "the great plains", + "oregon trail", + "mormon trail", + "bozeman trail", + "california trail", + "oklahoma land rush", + "desert land act", + "buffalo hunter", + "bison hunter", + "bison hunt", + "buffalo hunt", + "suffragists", + "buffalo soldier", + "american bison", + "cowtown", + "cowtowns", + "jeffersonian", + "homesteading", + "yeoman farmer", + "homesteader", + "homesteaders", + "stagecoach", + "wagonmaster", + "wagon trail", + "mormon war", + "utah war", + "pony express", + "Abraham Lincoln", + "sioux warrior", + "sioux warriors", + "1860", + "1861", + "1862", + "1863", + "1865", + "1865", + "1866", + "1867", + "1868", + "1869", + "1870", + "1871", + "1872", + "1873", + "1874", + "1875", + "1876", + "1877", + "1878", + "1879", + "1880", + "1881", + "1882", + "1883", + "1884", + "1885", + "1886", + "1887", + "1888", + "1889", + "1890", + "1891", + "1892", + "1893", + "1894", + "1895", + "1896", + "1897", + "1898", + "1899", + "1900", + "1901", + "1902", + "1903", + "1904", + "1905", + "1906", + "1907", + "1908", + "1909" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: ["1800s", "1880", "farewest"], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["western music"], + SOUND: [], + DIALOGUE: [], + STYLE: ["american", "western", "dusty"], + CAMERA: ["color footage"], + } + }, + { + "label": "1914-1918", + "aliases": { + "en": [ + "first world war", + "world war 1", + "world war", + "the great war", + "1914", + "1915", + "1916", + "1917", + "1918", + "WW1", + "Western Front", + "French trench", + "German trench", + "German shells" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: ["during WW1"], // ["1914", "1915", "1916", "1917", "1918"], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["1910 jazz"], + SOUND: [], + DIALOGUE: [], + STYLE: ["color footage", "in color"], + CAMERA: [], + } + }, + { + "label": "1938-1945", + "aliases": { + "en": [ + "world war 2", + "world war II", + "second world war", + "1939", + "1940", + "1941", + "1942", + "1943", + "1944", + "1945", + "WW2", + "WWII", + "Western Front", + "German shells" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: ["during WW2"], // ["1939", "1940", "1944", "1945"], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["1940 jazz, 40s"], + SOUND: [], + DIALOGUE: [], + STYLE: ["40s"], + CAMERA: ["color footage", "in color"], + } + }, + { + "label": "The 50s", + "aliases": { + "en": [ + "the fifties", + "50s", + "1950", + "1951", + "1952", + "1953", + "1954", + "1955", + "1956", + "1957", + "1958", + "1959", + "Eisenhower era" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: ["during the 50s"], // ["1950", "1952", "1954", "1955", "1957", "1958", "1959"], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["50s"], + SOUND: [], + DIALOGUE: [], + STYLE: ["50s", "fifties"], + CAMERA: ["color footage", "in color"], + } + }, + { + "label": "The 60s", + "aliases": { + "en": [ + "the sixties", + "60s", + "1960", + "1961", + "1962", + "1963", + "1964", + "1965", + "1966", + "1967", + "1968", + "1969", + "JFK", + "jfk era" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: ["during the 60s"], // ["1960", "1962", "1964", "1965", "1967", "1968", "1969"], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["60s"], + SOUND: [], + DIALOGUE: [], + STYLE: ["60s", "sixties"], + CAMERA: ["color footage", "in color"], + } + }, + { + "label": "The 70s", + "aliases": { + "en": [ + "the seventies", + "70s", + "1970", + "1971", + "1972", + "1973", + "1974", + "1975", + "1976", + "1977", + "1978", + "1979", + "nixon era" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: ["during the 70S"], // ["1970", "1972", "1974", "1975", "1977"], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["70s"], + SOUND: [], + DIALOGUE: [], + STYLE: ["70s", "seventies"], + CAMERA: ["color footage", "in color"], + } + }, + { + "label": "The 80s", + "aliases": { + "en": [ + "the eighties", + "80s", + "1980", + "1981", + "1982", + "1983", + "1984", + "1985", + "1986", + "1987", + "1988", + "1989" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: ["during the 80s"], // ["1980", "1982", "1984", "1986"], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["80s"], + SOUND: [], + DIALOGUE: [], + STYLE: ["80s", "eighties"], + CAMERA: [], + } + }, + { + "label": "The 90s", + "aliases": { + "en": [ + "the nineties", + "90s", + "1990", + "1991", + "1992", + "1993", + "1994", + "1995", + "1996", + "1997", + "1998", + "1999", + "clinton era" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: ["during the 1990s"], // ["1990", "1992", "1994", "1995", "1996", "1998"], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["90s"], + SOUND: [], + DIALOGUE: [], + STYLE: ["90s", "nineties"], + CAMERA: [], + } + }, + { + "label": "The 2000s", + "aliases": { + "en": [ + "2000s", + "2000", + "2001", + "2002", + "2003", + "2004", + "2005", + "2006", + "2007", + "2008", + "2009", + "George Walker Bush", + "George Bush", + "43rd POTUS", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: ["2005 style"], // ["2000", "2001", "2002", "2007", "2008"], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["2000s"], + SOUND: [], + DIALOGUE: [], + STYLE: ["the 2000s"], + CAMERA: [], + } + }, + { + "label": "contemporary", + "aliases": { + "en": [ + "present day", + "cash register", + // "streetlight", + //"streetlights", + "security camera", + //"gasoline", + "gas station", + "security footage", + "plastic bottle", + //"telephone pole", + "security console", + //"stethoscope", + //"chevy", + //"christmas lights", + //"headphone", + //"headphones", + //"hearing aid", + //"driveway", + //"car", + //"cars", + //"truck", + //"trucks", + //"bike", + //"motorbike", + //"phone", + "phone company", + //"telephone", + //"electric", + //"electricity", + //"electric lines", + "tv", + //"television", + // "radio", + //"toaster", + "microwave", + //"coffee machine", + // "train", + // "train station", + // "camera", <- no, this is used by the script itself! + // "photo", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: ["contemporary"], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["contemporary music"], + SOUND: [], + DIALOGUE: [], + STYLE: ["contemporary"], + CAMERA: [], + } + }, + { + "label": "2000s, 2010s, 2015, 2020, 2022", + "aliases": { + "en": [ + "internet", + "email", + "e-mail", + "website", + "social network", + "GPS", + "iphone", + "ipad", + "android phone", + "smartphone", + "laptop", + "cellphone", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: ["contemporary", "modern", "2018", "2022"], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["modern music"], + SOUND: [], + DIALOGUE: [], + STYLE: ["contemporary", "modern", "2018", "2022"], + CAMERA: [], + } + }, +] \ No newline at end of file diff --git a/packages/broadway/src/parsers/eras/index.ts b/packages/broadway/src/parsers/eras/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..e7f5f82c414d0c28be70579040d0370a13ccaaa2 --- /dev/null +++ b/packages/broadway/src/parsers/eras/index.ts @@ -0,0 +1,10 @@ +import { NamedEntity } from "@/types" +import { createOccurrenceCounter, createSimpleParser, getParserItemFromLabel } from "@/parsers/utils" + +import { data } from "./database" + +export const parseEras = createSimpleParser(data, ["aliases"]) + +export const getMostProbableEras = createOccurrenceCounter(parseEras) + +export const getEra = getParserItemFromLabel(data) \ No newline at end of file diff --git a/packages/broadway/src/parsers/genres/database.ts b/packages/broadway/src/parsers/genres/database.ts new file mode 100644 index 0000000000000000000000000000000000000000..d560e342d2777a7e449245bb15bbd39efa0d759d --- /dev/null +++ b/packages/broadway/src/parsers/genres/database.ts @@ -0,0 +1,642 @@ +import { NamedEntity } from "@/types" + +export const data: NamedEntity[] = [ + { + "label": "classic", + "aliases": { + "en": [ + // yeah those prompt suck a bit + "meeting", + "love", + "romance", + "phone call", + "discovers", + "surprise", + "money", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["suspenseful", "movie soundtrack"], + SOUND: [], + DIALOGUE: [], + STYLE: ["dimly lit", "suspenseful"], + CAMERA: [], + } + }, + { + "label": "police", + "aliases": { + "en": [ + "spy", + "spies", + "spying", + "CIA", + "MI6", + "hidden camera", + "hidden microphone", + "secret tapes", + "secret agent", + "secret agents", + "exchange prisonners", + "prisonner exchange", + "cold war", + "spy agency", + "spy agencies", + "treason", + "communist", + "communists", + "KGB", + "state secret", + "state scandal", + "phone taped", + "tape the phone", + "tape his phone", + "tape her phone" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["suspenseful", "mystery", "jazzy", "noir movie"], + SOUND: [], + DIALOGUE: [], + STYLE: ["dimly lit", "tense", "suspenseful", "cold", "strong shadows"], + CAMERA: [], + } + }, + { + "label": "police", + "aliases": { + "en": [ + // "investigation", + "police investigation", + "inspector", + "inspectors", + // "detective", + "detectives", + // "police", + "FBI", + "FBI agent", + "FBI agents", + "interpol", + "interpol agent", + "interpol agents", + "under arrest", + "DUI" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["suspenseful", "mystery", "noir movie"], + SOUND: [], + DIALOGUE: [], + STYLE: ["dimly lit", "tense", "suspenseful", "cold", "strong shadows"], + CAMERA: [], + } + }, + { + "label": "fantasy, magic", + "aliases": { + "en": [ + "transfigure", + "transfigures", + "transfiguration", + "dragon", + "dragons", + "dragon breath", + "unicorn", + "unicorns", + "gnome", + "gnomes", + "levitating", + "levitation", + "elixir of life", + "invisibility cape", + "invisibility potion", + "sorcerer", + "magic stick", + "witch", + "witches", + "mage", + "mages", + "dark wizard", + "wizard", + "wizards", + "wizard school", + "wizardry", + "magician", + "magicians", + "witchcraft", + "witchcrafts", + "spell casting", + "spellcast", + "spell cast", + "spell casting", + "casting a spell", + "casting spells", + "casts a spell", + "casts spells", + "cast spells", + "cast spell", + "spell book", + "magic spell", + "magic spells", + "forbidden magic", + "dark arts", + "potion", + "potions", + "magic potion", + "magic potions", + "magic school", + "magic door", + "magic portal", + "magic window", + "magic broom", + "flying broom", + "abracadabra", + "talking tree", + "forest troll", + "montain troll", + "trolls", + "troll", + "troll blood", + "goblin", + "goblins", + "dwarf", + "dwarfs", + "dwarves", + "merlin", + "muggle" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: ["dimly lit"], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: ["fantasy"], + CAMERA: [], + } + }, + { + "label": "adventure", + "aliases": { + "en": [ + "secret", + "mystery", + "treasure", + "treasures", + "discovery", + "adventure", + "expedition", + "cave", + "mountain", + "desert", + "diving", + "scuba" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["mystery", "adventure", "indiana jones", "goonies", "pirates"], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "action", + "aliases": { + "en": [ + "smashes", + "smashing", + "fireball", + "fire ball", + "destroys", + "destroying", + "bulletproof", + "heavily armored", + "heavy armor", + "escape the building", + "chased by", + "explodes", + "explosive", + "explosives", + "fast paced", + "semi-automatic weapon", + "semi-automatic weapons", + "semi-auto", + "car crash", + "cars crash", + "car crashes", + "vehicles barrel", + "vehicle barrels", + "cloud of debris", + "grenade", + "grenades", + "gun", + "guns", + "pistol", + "pistols", + "helicopter", + "helicopters", + "car chase", + "car chases", + "police chase", + "police chases", + "heist", + "heists", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: ["action movie", "thriller", "fast paced"], + SOUND: [], + DIALOGUE: [], + STYLE: ["action movie", "thriller", "fast paced"], + CAMERA: [], + } + }, + { + "label": "science-fiction", + "aliases": { + "en": [ + "self-destruct button", + "flying car", + "flying cars", + "flying taxi", + "flying taxis", + "spaceship", + "space ship", + "star ship", + "starship", + "mothership", + "space helmet", + "space helmets", + "astronaut", + "astronauts", + "inter-stellar", + "hyper-drive", + "range of the planet", + "landing on the planet", + "orbital insertion", + "probe retract system", + "landing probe", + "planet's surface", + "hostile planet", + "depressurization", + "pepressurization", + "space vacuum", + "laser pistol", + "laser pistols", + "servomoteur", + "android", + "cyberspace", + "air lock", + "airlock", + "asteroids", + "asteroid belt", + "light year", + "light years", + "diagnostic coffin", + "laser beam", + "last door", + "blast doors", + "alien creature", + "alien device", + "cryosleep", + "hypersleep", + "science fiction", + "science-fiction", + "sometime in the future", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: ["science", "engineering"], + CAMERA: [], + } + }, + { + "label": "gore", + "aliases": { + "en": [ + "kills him", + "kills her", + "murders him", + "murders her", + "smear of blood", + "blood spatter", + "blood spatters", + "blood spattering", + "blood splatter", + "blood splatters", + "blood splattering", + "gruesome", + "beheaded", + "splatters fluids and blood", + "splatters blood", + "blood pooling", + "blood oozing", + "blood droplets", + "blood spurting out", + "blood spurts out", + "covered with blood", + "hole in his chest", + "gutted corpse", + "dead corpse", + "guts him", + "guts her", + "slashes him", + "slashes her", + "bleed", + "bleeding", + "bleeds" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: ["bloody", "gore"], + CAMERA: [], + } + }, + { + "label": "horror", + "aliases": { + "en": [ + "sound demonic", + "panic increases", + "demonic", + "hideous silhouette", + "silhouette in the darkness", + "suspended in terror", + "hideous", + "beyond terror", + "from beyond", + "screeching sound", + "she looks human", + "he looks human", + "not quite human", + "clicking her jaw", + "oozing", + "oozes", + "spooky", + "spooking", + "spooked", + "spooks", + "ghastly", + "spasms", + "squealing in pain", + "go limp", + "squealing stops", + "morbid fascination", + "whispering voice", + "whispering voices", + "demonic whispers", + "whispers intensify", + "eerie silence", + "in horror", + "terrified", + "terrifying", + "dread", + "dreadful", + "screeching sound", + "horrifying", + "with anxiety", + "contorts with rage", + "spectral", + "spectral sight", + "anxiously", + "check under the bed", + "anxious", + "anxiety", + "the monster", + "hurt you", + "hurt me", + "decrepit", + "creeping over", + "face tenses", + "face crumbles", + "devastating", + "look of helplessness", + "preoccupied", + "heard a noise", + "hears a noise", + "check for monster", + "check for monsters", + "peering underneath", + "somehow creepy", + "very creepy", + "creepy", + "freaky", + "howling with fear", + "nightmare", + "nightmares", + "creepy shadow", + "creepy shadows", + "creepy face", + "genuinely scared", + "trembling", + "very concerned", + ] + }, + prompts: { + CHARACTER: ["anxiety"], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: ["dimly lit"], + WEATHER: [], + ACTION: [], + MUSIC: ["uneasy", "creepy"], + SOUND: ["silence", "creepy"], + DIALOGUE: [], + STYLE: ["creepy", "uneasy"], + CAMERA: [], + } + }, + { + "label": "war, military", + "aliases": { + "en": [ + "sergent", + "smattering of soldiers", + "soldiers mill", + "chain of soldiers", + "chains of soldiers", + "royal engineer", + "royal engineers", + "artillery", + "shell artillery", + "mess tents", + "mess tent", + "comms trench", + "trenches", + "tanks", + "ordnance", + "AK-47", + "AK47", + "spy", + "soldier", + "soldiers", + "military", + // "war", + "war effort", + "war relief", + "invasion", + "bombing", + "bomber", + "bombers", + "bombardier", + "Western Front" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "WW1", + "aliases": { + "en": [ + "first world war", + "world war 1", + "world war", + "the great war", + "1914", + "1915", + "1916", + "1917", + "1918", + "WW1", + "Western Front" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: ["military", "ww1"], + CAMERA: [], + } + }, + { + "label": "WW2", + "aliases": { + "en": [ + "world war 2", + "world war II", + "second world war", + "1939", + "1940", + "1941", + "1942", + "1943", + "1944", + "1945", + "WW2", + "WWII", + "Western Front" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: ["military", "ww2"], + CAMERA: [], + } + } +] \ No newline at end of file diff --git a/packages/broadway/src/parsers/genres/index.ts b/packages/broadway/src/parsers/genres/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..01b76703e4c7670ee67f4106d85541f2aaaaa08c --- /dev/null +++ b/packages/broadway/src/parsers/genres/index.ts @@ -0,0 +1,10 @@ +import { NamedEntity } from "@/types" +import { createOccurrenceCounter, createSimpleParser, getParserItemFromLabel } from "@/parsers/utils" + +import { data } from "./database" + +export const parseGenres = createSimpleParser(data, ["aliases"]) + +export const getMostProbableGenres = createOccurrenceCounter(parseGenres) + +export const getGenre = getParserItemFromLabel(data) \ No newline at end of file diff --git a/packages/broadway/src/parsers/index.ts b/packages/broadway/src/parsers/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4eb13b601d455c1a7f3a8fc8c0663c5223e45aa --- /dev/null +++ b/packages/broadway/src/parsers/index.ts @@ -0,0 +1,25 @@ +export { parseEntity } from "./entity" +export { + getEra, + getMostProbableEras, + parseEras +} from "./eras" +export { + getGenre, + getMostProbableGenres, + parseGenres +} from "./genres" +export { getLight, parseLights } from "./lights" +export { + getLocation, + parseIndoorLocations, + parseOutdoorLocations, + parseLocations, + parseLocationType +} from "./locations" +export { type ExtractedCharacterName, parseNames } from "./names" +export { getShot, parseShots } from "./shots" +export { getSound, parseSounds } from "./sounds" +export { parseTransition, transitions } from "./transitions" +export { createOccurrenceCounter, createParser, createSimpleParser, getParserItemFromLabel } from "./utils" +export { getWeather, parseWeather } from "./weather" diff --git a/packages/broadway/src/parsers/lights/database.ts b/packages/broadway/src/parsers/lights/database.ts new file mode 100644 index 0000000000000000000000000000000000000000..f2421da511a7a749489a3c903cda52a83259509b --- /dev/null +++ b/packages/broadway/src/parsers/lights/database.ts @@ -0,0 +1,1232 @@ +import { NamedEntity } from "@/types" + +export const artificalLights: NamedEntity[] = [ + { + "label": "fluorescent lamps", + "aliases": { + "en": [ + "fluorescent light", + "fluorescent tube", + "fluorescent lamp", + "fluorescent lightbulb", + "fluorescent light bulb", + "fluorescent bulb", + "gas-discharge lamp", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "fluorescent lamps", + "aliases": { + "en": [ + "fluorescent lights", + "fluorescent tubes", + "fluorescent lamps", + "fluorescent lightbulbs", + "fluorescent light bulbs", + "fluorescent bulbs", + "gas-discharge lamps" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "incandescent lamp", + "aliases": { + "en": [ + "incandescent light", + "incandescent tube", + "incandescent lamp", + "incandescent globe", + "incandescent lightbulb", + "incandescent light bulb", + "incandescent bulb", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "incandescent lamps", + "aliases": { + "en": [ + "incandescent lights", + "incandescent tubes", + "incandescent lamps", + "incandescent globes", + "incandescent lightbulbs", + "incandescent light bulbs", + "incandescent bulbs", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "oil lamp", + "aliases": { + "en": [ + "oil lamp", + "paraffin lamp", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "oil lamps", + "aliases": { + "en": [ + "oil lamps", + "paraffin lamps" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "electric light", + "aliases": { + "en": [ + "lamp", + // "light", + // "bulb", // + "electric lamp", + "electric light", + "electric bulb", + "electric light bulb", + "light bulb", + "lightbulb" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "electric lights", + "aliases": { + "en": [ + "lamps", + "lights", + "bulbs", + "electric lamps", + "electric lights", + "electric bulbs", + "electric light bulbs", + "light bulbs", + "lightbulbs" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "halogen lamp", + "aliases": { + "en": [ + "halogen light", + "halogen tube", + "halogen lamp", + "halogen globe", + "halogen lightbulb", + "halogen light bulb", + "halogen bulb", + "halogen", + "tungsten halogen", + "tungsten halogen lamp", + "tungsten halogen light", + "tungsten lamp", + "tungsten light", + "quartz-halogen", + "quartz-halogen light", + "quartz-halogen lamp", + "quartz iodine", + "quartz iodine light", + "quartz iodine lamp", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "halogen lamps", + "aliases": { + "en": [ + "halogen lights", + "halogen tubes", + "halogen lamps", + "halogen globes", + "halogen lightbulbs", + "halogen light bulbs", + "halogen bulbs", + "halogens", + "tungsten halogens", + "tungsten halogen lamps", + "tungsten halogen lights", + "tungsten lamps", + "tungsten lights", + "quartz-halogens", + "quartz-halogen lights", + "quartz-halogen lamps", + "quartz iodines", + "quartz iodine lights", + "quartz iodine lamps", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "LED lamp", + "aliases": { + "en": [ + "led light", + "led lamp", + "led bulb", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "LED lamps", + "aliases": { + "en": [ + "led lights", + "led lamps", + "led bulbs", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "spot light", + "aliases": { + "en": [ + "spotlight", + "spot light", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "spot lights", + "aliases": { + "en": [ + "spotlights", + "spot lights", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "candle", + "aliases": { + "en": [ + "candle light", + "candle lamp", + "candle", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "candles", + "aliases": { + "en": [ + "candle lights", + "candle lamps", + "candles", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "braizer", + "aliases": { + "en": [ + "brazier", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "braziers", + "aliases": { + "en": [ + "braziers", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "candelabre", + "aliases": { + "en": [ + "candelabre", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "candelabres", + "aliases": { + "en": [ + "candelabres", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "chandelier", + "aliases": { + "en": [ + "chandelier", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "chandeliers", + "aliases": { + "en": [ + "chandeliers", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "flashlight", + "aliases": { + "en": [ + "phone light", + "phone flashlight", + "tactical light", + "flashlight", + "flash light", + "led torch", + "torch", + "electric flashlight", + "led flashlight", + "electric torch", + "led torch" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "flashlights", + "aliases": { + "en": [ + "phone lights", + "phone flashlights", + "tactical lights", + "flashlights", + "flash lights", + "led torches", + "torches", + "electric flashlights", + "led flashlights", + "electric torches", + "led torches" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "car headlamp", + "aliases": { + "en": [ + "car head lamp", + "car headlamp", + "daytime running light", + "daytime running lamp" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "car headlamps", + "aliases": { + "en": [ + "car head lamps", + "car headlamps", + "daytime running lights", + "daytime running lamps" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "headlamps", + "aliases": { + "en": [ + "head lamps", + "headlamps", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "head light", + "aliases": { + "en": [ + "head light", + "head torch", + "headtorch" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "fog lamp", + "aliases": { + "en": [ + "fog lamp", + "fog light", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "fog lamps", + "aliases": { + "en": [ + "fog lamps", + "fog lights", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "fireplace", + "aliases": { + "en": [ + "fire place", + "fireplace" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "fire light", + "aliases": { + "en": [ + "fire light", + "firelight", + "burning fire", + "fire" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "green light", + "aliases": { + "en": [ + "green light" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "green lights", + "aliases": { + "en": [ + "green lights" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "yellow light", + "aliases": { + "en": [ + "yellow light" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "orange light", + "aliases": { + "en": [ + "orange light" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "orange lights", + "aliases": { + "en": [ + "orange lights" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "red light", + "aliases": { + "en": [ + "red light" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "purple light", + "aliases": { + "en": [ + "purple light" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "purple lights", + "aliases": { + "en": [ + "purple lights" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "blue light", + "aliases": { + "en": [ + "blue light" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "blue lights", + "aliases": { + "en": [ + "blue lights" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, +] + + +export const naturalLights: NamedEntity[] = [ + { + "label": "sun light", + "aliases": { + "en": [ + "day light", + "daylight", + "sky lit", + "sky light", + "sun light", + "sunlight", + "sun lit", + "sunlit", + "sunny", + "strong sun", + "harsh sun", + "intense sun", + "burning sun" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "lit through the window", + "aliases": { + "en": [ + "window lit", + "lit through the window", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "lit through the windows", + "aliases": { + "en": [ + "lit through the windows", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "cloudy sky light", + "aliases": { + "en": [ + "cloudy sky", + "clouds in the sky", + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "moonlit", + "aliases": { + "en": [ + "moon lit", + "full moon" + ] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: ["moonlit"], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, +] + +export const data: NamedEntity[] = [ + ...artificalLights, + ...naturalLights, +] \ No newline at end of file diff --git a/packages/broadway/src/parsers/lights/index.ts b/packages/broadway/src/parsers/lights/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..4f5fd817a09482dc454028a1ed28ed5f558216e9 --- /dev/null +++ b/packages/broadway/src/parsers/lights/index.ts @@ -0,0 +1,8 @@ +import { NamedEntity } from "@/types" +import { createSimpleParser, getParserItemFromLabel } from "@/parsers/utils" + +import { data } from "./database" + +export const parseLights = createSimpleParser(data, ["aliases"]) + +export const getLight = getParserItemFromLabel(data) \ No newline at end of file diff --git a/packages/broadway/src/parsers/locations/database.ts b/packages/broadway/src/parsers/locations/database.ts new file mode 100644 index 0000000000000000000000000000000000000000..5adaa9d7ecd2086ce1353a3d24baafe2bb544d5a --- /dev/null +++ b/packages/broadway/src/parsers/locations/database.ts @@ -0,0 +1,1357 @@ +import { NamedEntity } from "@/types" + +export const indoor: NamedEntity[] = [ + { + "label": "inside a room", + "aliases": { + "en": [ + "inside the room", + "inside a room", + "in the room", + "in a room", + "to the room", + "the room", + // "room" // might conflict + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "inside a living room", + "aliases": { + "en": [ + "inside the living room", + "inside a living room", + "in the living room", + "in a living room", + "to the living room", + "the living room", + "living room" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "inside a house", + "aliases": { + "en": [ + "inside the house", + "inside a house", + "in the house", + "in a house", + "a house", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "inside a garage", + "aliases": { + "en": [ + "inside the garage", + "inside a garage", + "in the garage", + "in a garage", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "inside a tent", + "aliases": { + "en": [ + "inside the tent", + "inside a tent", + "in the tent", + "in a tent", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "inside a building", + "aliases": { + "en": [ + "inside the building", + "inside a building", + "in the building", + "in a building", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "inside a hospital room", + "aliases": { + "en": [ + "in a hospital room", + "inside a hospital room", + "in the hospital room", + "inside the hospiral room", + "a hospital room", + "the hospital room", + "inside a hospital", + "inside the hospital", + "at a hospital", + "at the hospital" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "inside a hospital", + "aliases": { + "en": [ + "inside a hospital", + "inside the hospital", + "at a hospital", + "at the hospital" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "at the office", + "aliases": { + "en": [ + "at the office", + "in the office", + "in an office", + "inside an office", + "inside the office", + "office room", + + // conflict with funeral? + "an office", + "the office", + "office" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "at a pub", + "aliases": { + "en": [ + "pub", + "pub bar", + "pub restaurant", + "the pub", + "the pub bar", + "the pub restaurant", + "a pub", + "a pub bar", + "a pub restaurant", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "at a restaurant", + "aliases": { + "en": [ + "at a restaurant", + "a restaurant", + "restaurant", + "chain restaurant", + "fastfood restaurant", + "fast food restaurant", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "at a dinner", + "aliases": { + "en": [ + "at a dinner", + "a dinner", + "dinner", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "at a hip-hop club", + "aliases": { + "en": [ + "hiphop nightclub", + "hiphop club", + "underground hiphop club", + "hiphop club", + "hip-hop club", + "underground hip-hop club" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "at a disco night club", + "aliases": { + "en": [ + "disco club", + "disco nightclub", + "disco night club", + "underground disco club", + "underground disco night club", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "a night club", + "aliases": { + "en": [ + "nightclub", + "night club", + "underground club", + "underground nightclub", + "underground night club", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "interior of a car", + "aliases": { + "en": [ + "interior of a car", + "she is in a car", + "he is in a car", + "driving a car", + "in a car", + "inside a car" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "interior of a bathroom", + "aliases": { + "en": [ + "inside a bathroom", + "inside a dirty bathroom", + "inside a desolate bathroom", + "a bathroom", + "bathroom" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "interior of an elevator", + "aliases": { + "en": [ + "inside an elevator", + "inside the elevator", + "enters the elevator", + "an elevator", + "the elevator" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + + { + "label": "japanese castle", + "aliases": { + "en": [ + "japanesecastle", + "japanese castle", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "chinese castle", + "aliases": { + "en": [ + "chinesecastle", + "chinese castle", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "spanish castle", + "aliases": { + "en": [ + "spanishcastle", + "spanish castle", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "medieval castle", + "aliases": { + "en": [ + "medievalcastle", + "medieval castle", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "castle", + "aliases": { + "en": [ + "castle", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, +] + +export const outdoor: NamedEntity[] = [ + { + "label": "in a meadow", + "aliases": { + "en": [ + "outside in a meadow", + "outside in the meadow", + "outside at a field", + "outside at the meadow", + "in a meadow", + "in some meadow", + "in the meadow", + "in the meadows", + "middle of a meadow", + "middle of the meadow", + "middle of the meadows", + "at a meadow", + "at the meadow", + "at the meadows", + "a meadow", + "the meadow", + "the meadows", + "meadow", + "meadows" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "on a hill", + "aliases": { + "en": [ + "outside on the hill", + "outside at the hill", + "on some hill", + "at some hill", + "on a hill", + "on the hill", + "at a hill", + "at the hill", + "the hill", + "some hill" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "in the hills", + "aliases": { + "en": [ + "outside on the hills", + "outside at the hills", + "in the hills", + "in some hills", + "on some hills", + "on a hills", + "on the hills", + "at a hills", + "at the hills", + "the hills" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "in a field", + "aliases": { + "en": [ + "outside in a field", + "outside in the field", + "outside at a field", + "outside at the field", + "in a field", + "in some field", + "in the field", + "in the fields", + "middle of a field", + "middle of the field", + "middle of the fields", + "at a field", + "at the field", + "at the fields", + "corn field", + "corn fields" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "in a jungle", + "aliases": { + "en": [ + "outside in a jungle", + "outside in the jungle", + "outside at a jungle", + "outside at the jungle", + "outside inside the jungle", + "in a jungle", + "in the jungle", + "at a jungle", + "at the jungle", + "inside the jungle", + "deep jungle", + "deep and dark jungle", + "mysterious jungle", + "creepy jungle", + "dark jungle", + "dense jungle", + "dangerous jungle" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "in a forest", + "aliases": { + "en": [ + "outside in a park", + "outside in the forest", + "outside at a forest", + "outside at the forest", + "outside inside the forest", + "in a forest", + "in the forest", + "at a forest", + "at the forest", + "inside the forest", + "deep forest", + "deep and dark forest", + "mysterious forest", + "creepy forest", + "dark forest", + "dense forest", + "dangerous forest" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "at the park", + "aliases": { + "en": [ + "outside in a park", + "outside in the park", + "outside at a park", + "outside at the park", + "outside inside the park", + "in a park", + "in the park", + "at a park", + "at the park", + "inside the park", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "in a garden", + "aliases": { + "en": [ + "outside in a garden", + "outside in the garden", + "outside inside the garden", + "in a garden", + "in the garden", + "inside the garden", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "parking lot", + "aliases": { + "en": [ + "outside at a parking", + "outside on the parking", + "outdoor parking", + "on a parking lot", + "a parking lot", + "the parking lot" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "outside a hospital", + "aliases": { + "en": [ + "outside a hospital", + "outside the hospital", + "outside the hospital parking", + "outside the hospital parking", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "next to a car", + "aliases": { + "en": [ + "exterior of a car", + "she is next to a car", + "he is next to a car", + "next to a car", + "she is next to the car", + "he is next to the car", + "next to a car" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "mountain", + "aliases": { + "en": [ + "mountain" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "mountains", + "aliases": { + "en": [ + "mountains" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "japanese courtyard", + "aliases": { + "en": [ + "japanesecourtyard", + "japanese courtyard", + "japanese court yard" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "chinese courtyard", + "aliases": { + "en": [ + "chinesecourtyard", + "chinese courtyard", + "chinese court yard" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "indian courtyard", + "aliases": { + "en": [ + "indiancourtyard", + "indian courtyard", + "indian court yard" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "roman courtyard", + "aliases": { + "en": [ + "romancourtyard", + "roman courtyard", + "roman court yard" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "spanish courtyard", + "aliases": { + "en": [ + "spanishcourtyard", + "spanish courtyard", + "spanish court yard" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "spartan courtyard", + "aliases": { + "en": [ + "spartancourtyard", + "spartan courtyard", + "spartan court yard" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "medieval courtyard", + "aliases": { + "en": [ + "medievalcourtyard", + "medieval courtyard", + "medieval court yard" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "courtyard", + "aliases": { + "en": [ + "courtyard", + "court yard" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "at a cemetary", + "aliases": { + "en": [ + "at a cemetary", + "at a cemetery", + "cemetary", + "cemetery", + ], + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + + { + "label": "on a high way", + "aliases": { + "en": [ + "on a high way", + "on the high way", + "on a highway", + "on the highway", + "a high way", + "a highway", + "the high way", + "the highway", + "high way", + "highway" + ], + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "on a road", + "aliases": { + "en": [ + "on a road", + "on the road", + "a road", + "the road", + ], + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "in a street", + "aliases": { + "en": [ + "in a street", + "in the street", + "a long street", + "on a street", + "on the street", + "a street", + "the street", + ], + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, +] + +export const data: NamedEntity[] = [ + ...indoor, + ...outdoor +] \ No newline at end of file diff --git a/packages/broadway/src/parsers/locations/index.ts b/packages/broadway/src/parsers/locations/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..1cf4ad31dc179ff134937406941c228d19ec8c83 --- /dev/null +++ b/packages/broadway/src/parsers/locations/index.ts @@ -0,0 +1,30 @@ +import { LocationEntity } from "@/types" +import { ScreenplaySequenceType } from "@/constants" +import { createSimpleParser, getParserItemFromLabel } from "@/parsers/utils" + +import { indoor, outdoor, data } from "./database" + +export const parseIndoorLocations = createSimpleParser(indoor, ["aliases"]) +export const parseOutdoorLocations = createSimpleParser(outdoor, ["aliases"]) +export const parseLocations = createSimpleParser(data, ["aliases"]) + +export const parseLocationType = async (input: string[]): Promise => { + + const parsedLocationsIndoor = await parseIndoorLocations(input) + const parsedLocationsOutdoor = await parseOutdoorLocations(input) + + let parsedLocationType: ScreenplaySequenceType = "UNKNOWN" + if (parsedLocationsIndoor.length && !parsedLocationsOutdoor.length) { + parsedLocationType = "INTERIOR" + } else if (!parsedLocationsIndoor.length && parsedLocationsOutdoor.length) { + parsedLocationType = "EXTERIOR" + } else if (parsedLocationsIndoor.length && !parsedLocationsOutdoor.length) { + parsedLocationType = "INT./EXT." + } else { + parsedLocationType = "UNKNOWN" + } + return parsedLocationType +} + + +export const getLocation = getParserItemFromLabel(data) \ No newline at end of file diff --git a/packages/broadway/src/parsers/locations/locations.ts b/packages/broadway/src/parsers/locations/locations.ts new file mode 100644 index 0000000000000000000000000000000000000000..fe05c3a84e1fbd4977cd89a92455cab1b3b5f735 --- /dev/null +++ b/packages/broadway/src/parsers/locations/locations.ts @@ -0,0 +1,20 @@ + + +// TODO use a transition type for the values, to avoid mistakes + +import { ScreenplaySequenceType } from "@/constants/screenplaySequences" + +// TODO: those need to be prefixed by space to avoid false positives +export const locationTypes: Record = { + "INT.": "INTERIOR", + "INT": "INTERIOR", + "INT-": "INTERIOR", + "EXT.": "EXTERIOR", + "EXT": "EXTERIOR", + "EXT-": "EXTERIOR", + "INT./EXT.": "INT./EXT.", + "EXT./INT." : "INT./EXT.", + "INT/EXT" : "INT./EXT.", + "EXT/INT": "INT./EXT.", + "FLASHBACK": "INT./EXT." +} diff --git a/packages/broadway/src/parsers/music/database.ts b/packages/broadway/src/parsers/music/database.ts new file mode 100644 index 0000000000000000000000000000000000000000..81c7afb55bc675c95c290fa0175bf36128ca9fac --- /dev/null +++ b/packages/broadway/src/parsers/music/database.ts @@ -0,0 +1,129 @@ +import { NamedEntity } from "@/types" + +export const data: NamedEntity[] = [ + { + "label": "mozart sonata", + "aliases": { + "en": [ + "sonata", + "mozart", + "mozart sonata" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "soft orchestra music, sonata, synthesizer, strings", + "aliases": { + "en": [ + "stars glitter" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "futuristic orchestra music, synthesizer, strings, violin, brass", + "aliases": { + "en": [ + "spaceship", + "astronaut", + "blaster" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "faint radio music", + "aliases": { + "en": [ + "faint music", + "faint radio music", + "radio music in the background", + "music in the background" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "club music", + "aliases": { + "en": [ + "club music", + "dancing in the club", + "entering the nightclub", + "nightclubbers" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + } +] \ No newline at end of file diff --git a/packages/broadway/src/parsers/names/index.ts b/packages/broadway/src/parsers/names/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..d61835a8e5e6a9d2fb07e909d328a420dc77b1e0 --- /dev/null +++ b/packages/broadway/src/parsers/names/index.ts @@ -0,0 +1,30 @@ +import parse from "@datagica/parse-names" + +export type ExtractedCharacterName = { + "ngram": string + "value": { + "id": string + "name": string + "culture": string[] // ["french"], + "gender": string[] // ["m"] + }, + "score": number, + "position": { + "sentence": number + "word": number + "begin": number + "end": number + } +} + +export async function parseNames(text: string): Promise { + + const results = (await parse(text.trim().toLowerCase())) as ExtractedCharacterName[] + + if (!Array.isArray(results) || !results.length) { + return [] + } + + // there might be duplicates, eg. "bárbara" and "barbara" + return results.filter(item => item.value.name.trim().toLowerCase() === item.ngram.trim().toLowerCase()) +} \ No newline at end of file diff --git a/packages/broadway/src/parsers/shots/database.ts b/packages/broadway/src/parsers/shots/database.ts new file mode 100644 index 0000000000000000000000000000000000000000..664c2714393e549ea1e2fb1fd5b21e2fba7ffc5b --- /dev/null +++ b/packages/broadway/src/parsers/shots/database.ts @@ -0,0 +1,402 @@ +import { NamedEntity } from "@/types" + +const shotTypes: NamedEntity[] = [ + { + "label": "long wide establishing shot", + "aliases": { + "en": [ + "long wide establishing shot", + "wide establishing shot", + "long establishing shot", + "establishing shot", + "long wide shot", + "long shot", + "wide shot" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "full shot", + "aliases": { + "en": [ + "full shot", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "extreme long shot", + "aliases": { + "en": [ + "extreme long shot", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "medium-long shot", + "aliases": { + "en": [ + "medium-long shot", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "medium shot", + "aliases": { + "en": [ + "medium shot", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "medium close-up shot", + "aliases": { + "en": [ + "medium close-up shot", + "medium close-up", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "close-up shot", + "aliases": { + "en": [ + "close-up shot", + "close-up", + "close on an", + "close on the" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "extreme close-up shot", + "aliases": { + "en": [ + "extreme close-up shot", + "extreme close-up", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "american shot", + "aliases": { + "en": [ + "american shot", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "italian shot", + "aliases": { + "en": [ + "italian shot", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "trolley shot", + "aliases": { + "en": [ + "trolley shot", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, +] + +const cameraMovementTypes: NamedEntity[] = [ + { + "label": "camera zomming in", + "aliases": { + "en": [ + "zomming tighter", + "camera zooming in", + "zooming in", + "zomming into" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "camera panning up", + "aliases": { + "en": [ + "camera panning up", + "panning up", + "long panning up shot", + "panning up shot", + "panning up", + "camera panning up them", + "camera panning up him", + "camera panning up her", + "panning up with", + "panning up him", + "panning up her", + "panning up them" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "camera panning down", + "aliases": { + "en": [ + "camera panning down", + "panning down", + "long panning down shot", + "panning down shot", + "panning down", + "camera panning down them", + "camera panning down him", + "camera panning down her", + "panning down with", + "panning down him", + "panning down her", + "panning down them" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "camera panning", + "aliases": { + "en": [ + "camera panning", + "long panning shot", + "panning shot", + "camera panning them", + "camera panning him", + "camera panning her", + "panning with", + "panning him", + "panning her", + "panning them" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, +] + +export const data: NamedEntity[] = [ + ...shotTypes, + ...cameraMovementTypes, +] \ No newline at end of file diff --git a/packages/broadway/src/parsers/shots/index.ts b/packages/broadway/src/parsers/shots/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..b2db44420920207fac7c2d3e957430ad264a0588 --- /dev/null +++ b/packages/broadway/src/parsers/shots/index.ts @@ -0,0 +1,8 @@ +import { NamedEntity } from "@/types" +import { createSimpleParser, getParserItemFromLabel } from "@/parsers/utils" + +import { data } from "./database" + +export const parseShots = createSimpleParser(data, ["aliases"]) + +export const getShot = getParserItemFromLabel(data) \ No newline at end of file diff --git a/packages/broadway/src/parsers/sounds/database.ts b/packages/broadway/src/parsers/sounds/database.ts new file mode 100644 index 0000000000000000000000000000000000000000..da799ce61fa3502ce1245322c7cf32cf65de7bd2 --- /dev/null +++ b/packages/broadway/src/parsers/sounds/database.ts @@ -0,0 +1,2669 @@ +import { NamedEntity } from "@/types" + +export const weatherSounds: NamedEntity[] = [ + { + "label": "wind", + "aliases": { + "en": [ + "wind", + "winds", + "wind blowing", + "winds blowing", + "wind blows", + "windy", + "clouds", + "covered sky", + "cloudy sky" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + }, + }, + { + "label": "strong wind, tornado", + "aliases": { + "en": [ + "strong wind", + "strong winds", + "twister", + "tornado" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "thunder", + "aliases": { + "en": [ + "tempest", + "lightning", + "storm" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "rain", + "aliases": { + "en": [ + "heavy rain", + "raining", + "soft rain" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, +] + +export const vehiclesSounds: NamedEntity[] = [ + { + "label": "car driving", + "aliases": { + "en": [ + "vehicle reverses", + "car reverses", + "truck reverses", + "they drive up", + "they drive down", + "they drive to", + "he drives up", + "he drives down", + "he drives to", + "driving cars", + "car continues", + "car drives", + "car takes a turn", + "car is still rocking", + "roars by", + "in the car, driving" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "car accelerating, roaring engine", + "aliases": { + "en": [ + "car accelerating", + "car gains momentum", + "car picks up momentum", + "accelerates the car", + "car moving faster", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "roaring engine, wind", + "aliases": { + "en": [ + "speed is frightening", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "car slowing down", + "aliases": { + "en": [ + "the car slows", + "car slows down", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "car is stopping", + "aliases": { + "en": [ + "car is stopping", + "car reaches a full stop" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "object falling on the road, spinning", + "aliases": { + "en": [ + "falls into the road", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "car horns", + "aliases": { + "en": [ + "car horns" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "car traffic jam", + "aliases": { + "en": [ + "car traffic", + "dense traffic", + "busy street", + "traffic jam", + "in a traffic jam", + "a traffic jam" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "helicopter", + "aliases": { + "en": [ + "chopper", + "choppers", + "helicopter", + "helicopters" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "truck engine", + "aliases": { + "en": [ + "truck noises", + "trucks", + "truck", + "bulldozer", + "bulldozer pushes", + "tank", + "tanks" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + } +] + +export const animalSounds: NamedEntity[] = [ + { + "label": "dog patting and soft barking", + "aliases": { + "en": [ + "dog", + "dogs", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "rasp of crickets", + "aliases": { + "en": [ + "rasp of crickets", + "sound of crickets", + "crickets noise", + "crickets at night", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "mule", + "aliases": { + "en": [ + "the mule", + "mule", + "mules" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "horses", + "aliases": { + "en": [ + "the horse", + "horses", + "horse", + "horsemen" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "cat meowing", + "aliases": { + "en": [ + "cat", + "cats", + "kitten" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "dolphin squaling", + "aliases": { + "en": [ + "dolphin", + "dolphins" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "a growling dog", + "aliases": { + "en": [ + "a growling dog", + "the growling dog", + "growling dog", + "dog growls", + "dog is growling" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "growling dogs", + "aliases": { + "en": [ + "a growling dogs", + "the growling dogs", + "growling dogs", + "dogs growl", + "dogs are growling" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "a predator roars", + "aliases": { + "en": [ + "animal roars", + "a roar rises", + "predator roars", + "jungle roars", + "loud roar", + "loud roars", + "menacing roar", + "menacing roars", + "a roar from", + "roars at", + "angry roar", + "angry roars" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "lion roaring", + "aliases": { + "en": [ + "lion roaring", + "lions roaring", + // "lions" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "boar growling", + "aliases": { + "en": [ + "bear growling", + "bears growling", + "bear cub growling" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "owl howling", + "aliases": { + "en": [ + "owl howling", + "owls howling" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "wolf howling", + "aliases": { + "en": [ + "wolf howling", + "wolves howling" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, +] + +export const placeSounds: NamedEntity[] = [ + { + "label": "wind", + "aliases": { + "en": [ + "forest", + "mountain" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "wind, savanna animals", + "aliases": { + "en": [ + "parched countryside", + "african countryside", + "savanna" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "water stream", + "aliases": { + "en": [ + "water stream", + "river", + "stream" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "cave sound, water dripping", + "aliases": { + "en": [ + "natural caves", + "caves", + "natural cave", + "cave" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "birds singing", + "aliases": { + "en": [ + "birds", + "bird", + "birdsong", + "birdsongs", + "bird song", + "bird songs", + "bird singing", + "birds singing", + "singing bird", + "singing birds", + "garden", + "forest", + "meadow", + "meadows", + "prairie", + "valley" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "wind, soft traffic sound", + "aliases": { + "en": [ + "skyscrappers", + "skyscrapper", + "rooftop", + "over a city", + "hovering a city", + "over the city", + "hovering the city", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "traffic noise, pedestrians", + "aliases": { + "en": [ + "city centre", + "city center", + "downtown", + "city" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "pedestrian noise, soft traffic sounds", + "aliases": { + "en": [ + "pedestrians", + "side walk" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + } +] + + +export const objectSounds: NamedEntity[] = [ + { + "label": "electrical hum", + "aliases": { + "en": [ + "electrical hum", + "electrical humming", + "electrical hums", + "electrical noise", + "electrical noises", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "electronic beeps", + "aliases": { + "en": [ + "electronic hum", + "electronic humming", + "electronic hums", + "electronic noise", + "electronic noises", + "electronic beep", + "electronic beeping", + "electronic beeps", + "electronic sound", + "electronic sounds", + "electronic pulsing sound", + "electronic pulsing sounds", + "electronic pulsing beep", + "electronic pulsing beeps", + "electronic conversation", + "device hum", + "device humming", + "device hums", + "device noise", + "device noises", + "device beep", + "device beeping", + "device beeps", + "device sound", + "device sounds", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "coughing", + "aliases": { + "en": [ + "coughing", + "she coughs", + "he coughs" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "water dripping", + "aliases": { + "en": [ + "it drips", + "dripping", + + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "smoke", + "aliases": { + "en": [ + "explosion of smoke", + "explosion of escaping gas" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "running water", + "aliases": { + "en": [ + "runs some water", + "runs water", + "runs water through", + "running water", + "water running" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "grinding coffee", + "aliases": { + "en": [ + "grinding coffee", + "he grinds the coffee", + "he grinds a coffee", + "he grinds some coffee", + "she grinds the coffee", + "she grinds a coffee", + "she grinds some coffee", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "grinding", + "aliases": { + "en": [ + "grinding", + "he grinds the", + "he grinds a", + "he grinds some", + "she grinds the", + "she grinds a", + "she grinds some", + "grinds the", + "grinds a", + "grinds some", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "trees shaking", + "aliases": { + "en": [ + "the tree shakes", + "the trees shake", + "trees are shaking", + "tree is shaking" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "a bell rings", + "aliases": { + "en": [ + "ring bells", + "the ring bells", + "cow bell", + "bell is ringing", + "a bell rings", + "the bell rings" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "door opens", + "aliases": { + "en": [ + "door opening", + "door opens", + "opening the door" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, +] + + +export const actionSounds: NamedEntity[] = [ + { + "label": "walking", + "aliases": { + "en": [ + "they walk", + "he walks", + "she walks", + "they are walking", + "he is walking", + "she is walking", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "person running", + "aliases": { + "en": [ + "she rushes to", + "he rushes to", + "he runs", + "he runs off", + "runs off", + "she runs", + "he is running", + "she is running", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "people running", + "aliases": { + "en": [ + "they rushes to", + "they run", + "they are running", + "people run past", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "swimming", + "aliases": { + "en": [ + "they swim", + "he swims", + "she swims", + "they are swimming", + "he is swimming", + "she is swimming" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "sound of strapping an object", + "aliases": { + "en": [ + "strap themselves", + "straps himself", + "straps herself" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "slashing", + "aliases": { + "en": [ + "slashing", + "slashes" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "firing a gun", + "aliases": { + "en": [ + "gun fire", + "gunfire", + + "firing a gun", + "firing his gun", + "firing her gun", + + "firing a pistol", + "firing his pistol", + "firing her pistol", + + "fires a gun", + "fires his gun", + "fires her gun", + + "fires a pistol", + "fires his pistol", + "fires her pistol", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + + { + "label": "gunfires", + "aliases": { + "en": [ + "gun fires", + "gunfires", + "firing guns", + "firing their guns", + "open fire", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "reloading a gun", + "aliases": { + "en": [ + "reloading a gun", + "reloading his gun", + "reloading her gun", + + "reloading a pistol", + "reloading his pistol", + "reloading her pistol", + + "reloads a gun", + "reloads his gun", + "reloads her gun", + + "reloads a pistol", + "reloads his pistol", + "reloads her pistol", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "shaking a box of bullets", + "aliases": { + "en": [ + "grabs a box of bullets", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "shaking a bag of coins", + "aliases": { + "en": [ + "grabs a coin purse", + "grabs his coin purse", + "grabs her coin purse", + "grabs this coin purse", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "puking", + "aliases": { + "en": [ + "we hear him puking", + "we hear her puking", + "he is puking", + "she is puking" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "footsteps stopping", + "aliases": { + "en": [ + "footsteps stop", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "footsteps", + "aliases": { + "en": [ + "footsteps", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "boots clattering", + "aliases": { + "en": [ + "boots clattering", + "boots footsteps", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "wood clattering", + "aliases": { + "en": [ + "wood clattering", + "clattering over the wood", + "clattering over the wooden", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "liquid pouring", + "aliases": { + "en": [ + "pours himself a glass", + "pours herself a cup", + "pours himself a", + "pours herself a", + "pours himself", + "pours herself", + "pours some", + "pours a cup", + "pours a glass" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "keys rattling", + "aliases": { + "en": [ + "takes the keys", + "drops the keys", + "keys rattling", + "keys rattle" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "little laugh", + "aliases": { + "en": [ + "little laugh", + "lets out a laugh", + "a laugh" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "loud laugh", + "aliases": { + "en": [ + "loud laugh", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "little laughs", + "aliases": { + "en": [ + "little laughs", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "loud laughs", + "aliases": { + "en": [ + "loud laughs", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "pounding", + "aliases": { + "en": [ + "man pounds", + "woman pounds", + "is pounding", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "screaming", + "aliases": { + "en": [ + "screams", + "screaming" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "man screaming", + "aliases": { + "en": [ + "he screams", + "he is screaming" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "woman screaming", + "aliases": { + "en": [ + "she screams", + "she is screaming" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "shrieking", + "aliases": { + "en": [ + "shrieks", + "shrieking", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "woman shrieking", + "aliases": { + "en": [ + "she shrieks", + "she is shrieking", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "man shrieking", + "aliases": { + "en": [ + "he shrieks", + "he is shrieking", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "groaning", + "aliases": { + "en": [ + "with a groan", + "groan", + "groans", + "groaning" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "moaning", + "aliases": { + "en": [ + "man stretches", + "woman stretches", + "with a moan", + "moan", + "moans", + "moaning" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "lighting a cigarette", + "aliases": { + "en": [ + "lights a cigarette" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "stones colliding", + "aliases": { + "en": [ + "grabs a stone" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "window shattering", + "aliases": { + "en": [ + "window shatters", + "kicks out a kitchen window", + "kicks out the window", + "kicks out a window", + "kicks a window", + "breaks a window", + "glass shattering", + "shatters a window" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "pushing a button", + "aliases": { + "en": [ + "pushing the button", + "pushes the button", + "pushing a button", + "pushes a button", + "pushing the lock button", + "pushes the lock button", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "soft groan", + "aliases": { + "en": [ + "expresses annoyance" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "man gasping", + "aliases": { + "en": [ + "he is gasping", + "he gasps", + "a gasp chokes him", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "woman gasping", + "aliases": { + "en": [ + "she is gasping", + "she gasps", + "a gasp chokes her", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "people wrestling", + "aliases": { + "en": [ + "they struggle to their feet", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "men making animal sounds and groans", + "aliases": { + "en": [ + "men make animal sounds", + "make animal sounds", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "men making animal sounds and groans", + "aliases": { + "en": [ + "women make animal sounds", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "gasping", + "aliases": { + "en": [ + "frightened gasp" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "breathing sound", + "aliases": { + "en": [ + "he inhales", + "he takes a breath", + "he is breathing", + "he breathes", + + "she inhales", + "she takes a breath", + "she is breathing", + "she breathes" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "moving shackles", + "aliases": { + "en": [ + "shackles" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "lock unlocking", + "aliases": { + "en": [ + "unlocks the shackles", + "unlocks the cuffs", + "unlocks the handcuffs", + "they unlock the shackles", + "they unlock the cuffs", + "they unlock the handcuffs", + "the guard unlocks" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, +] + + +export const eventSounds: NamedEntity[] = [ + { + "label": "explosion", + "aliases": { + "en": [ + "the blast", + "the explosion", + "huge blast", + "huge explosion" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "audience laugh", + "aliases": { + "en": [ + "general laugh", + "general laugh at", + "general laugh at that", + "audience laugh" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "booing", + "aliases": { + "en": [ + "fans loudly go about", + "fans shouting", + "fans booing", + "spectators loudly go about", + "spectators shouting", + "spectators booing", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "newspaper presses rolling", + "aliases": { + "en": [ + "newspaper presses rolling", + "newspaper presses rolling at high speed", + "presses rolling", + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "prisoners shouting", + "aliases": { + "en": [ + "prisoners shouting", + "prisoners loudly", + "prisoners booing", + "prisoners loudly go about" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "crowd chattering", + "aliases": { + "en": [ + "crowd chattering", + "chattering", + "newscasters chattering", + "people chattering", + "pedestrians chattering" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "leaves rustling", + "aliases": { + "en": [ + "rustling", + "rustles" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "rummaging", + "aliases": { + "en": [ + "rummages in his pocket", + "rummages in his pockets", + "rummages in", + "rummaging" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "breaking bread", + "aliases": { + "en": [ + "breaks the bread" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, +] + +export const data = [ + ...weatherSounds, + ...vehiclesSounds, + ...animalSounds, + ...placeSounds, + ...objectSounds, + ...actionSounds, + ...eventSounds, +] \ No newline at end of file diff --git a/packages/broadway/src/parsers/sounds/index.ts b/packages/broadway/src/parsers/sounds/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..9eba35f9ff2cd07f7b71a26e70317f17e90d85f9 --- /dev/null +++ b/packages/broadway/src/parsers/sounds/index.ts @@ -0,0 +1,8 @@ +import { NamedEntity } from "@/types" +import { createSimpleParser, getParserItemFromLabel } from "@/parsers/utils" + +import { data } from "./database" + +export const parseSounds = createSimpleParser(data) + +export const getSound = getParserItemFromLabel(data) \ No newline at end of file diff --git a/packages/broadway/src/parsers/transitions/index.ts b/packages/broadway/src/parsers/transitions/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..65aa11a8349c063eba48398c8e343b52a10af0e6 --- /dev/null +++ b/packages/broadway/src/parsers/transitions/index.ts @@ -0,0 +1,2 @@ +export { parseTransition } from "./parseTransition" +export { transitions } from "./transitions" \ No newline at end of file diff --git a/packages/broadway/src/parsers/transitions/parseTransition.ts b/packages/broadway/src/parsers/transitions/parseTransition.ts new file mode 100644 index 0000000000000000000000000000000000000000..10431b55fb3b877ba5c90b74e74c4f3d54fd716e --- /dev/null +++ b/packages/broadway/src/parsers/transitions/parseTransition.ts @@ -0,0 +1,19 @@ +import { transitions } from "./transitions" + +export function parseTransition(originalLine: string): string { + + const line = ` ${originalLine.trim()} ` + + // trimmed line is too short to be a transition + if (line.length < 3) { + return "" + } + + for (const transitionKeyword of Object.keys(transitions)) { + if (line.includes(transitionKeyword)) { + return transitionKeyword + } + } + + return "" +} diff --git a/packages/broadway/src/parsers/transitions/transitions.ts b/packages/broadway/src/parsers/transitions/transitions.ts new file mode 100644 index 0000000000000000000000000000000000000000..5089097cac631de7c9cc1bc0476f65ae141c40f6 --- /dev/null +++ b/packages/broadway/src/parsers/transitions/transitions.ts @@ -0,0 +1,67 @@ + + +// TODO use a transition type for the values, to avoid mistakes + +export const transitions: Record = { + "CUT TO BLACKNESS": "Cut to black", + "CUT TO BLACK": "Cut to black", + "SMASH CUT TO BLACK": "Cut to black", + "MATCH CUT TO BLACK": "Cut to black", + "MATCH CUT TO": "Cut to", + "MATCH CUT": "Cut to", + + // what are those? + "SMATCH CUT": "Cut to", + "SMASH CUT TO": "Cut to", + "SLAM CUT TO": "Cut to", + "JUMP CUT TO": "Cut to", + "TIME CUT TO": "Cut to", + "FLASH CUT TO": "Cut to", + "CUT TO REVERSE": "Cut to", + "FREEZE": "Freeze frame", + + "INTERCUT WITH": "Cut to", + "INTERCUT TO": "Cut to", + "INSERT CUT TO": "Cut to", + "INSERT CUT": "Cut to", + + "CUT TO": "Cut to", + "CUT BACK TO": "Cut to", + + "CLOSE ON TO": "Cut to", + + "FADE IN": "Fade in", + "FADES IN": "Fade in", + "DISSOLVE IN": "Fade in", + + "FADE OUT": "Fade out", + "FADES OUT": "Fade out", + "DISSOLVE OUT": "Fade in", + + "FADE TO BLACK": "Fade to black", + "FADES TO BLACK": "Fade to black", + + "FADE TO": "Fade to", + "FADES TO": "Fade to", + "FADE THROUGH TO": "Fade to", + "FADES THROUGH TO": "Fade to", + "DISSOLVE TO": "Fade to", + "FADE INTO": "Fade to", + "FADES INTO": "Fade to", + "FADE THROUGH INTO": "Fade to", + "FADES THROUGH INTO": "Fade to", + "DISSOLVE INTO": "Fade to", + + "QUICK FADE TO": "Quick fade to", + "QUICK FADES TO": "Quick fade to", + "QUICK FADE INTO": "Quick fade to", + "QUICK FADES INTO": "Quick fade to", + "QUICK FADE THROUGH TO": "Quick fade to", + "QUICK FADES THROUGH TO": "Quick fade to", + "QUICK DISSOLVE TO": "Quick fade to", + "QUICK DISSOLVE INTO": "Quick fade to", + + "FADE OUT AND CREDITS ROLL": "Fade to", + "FADES OUT AND CREDITS ROLL": "Fade to", + "CREDITS ROLL": "Fade to", +} diff --git a/packages/broadway/src/parsers/utils/createOccurrenceCounter.ts b/packages/broadway/src/parsers/utils/createOccurrenceCounter.ts new file mode 100644 index 0000000000000000000000000000000000000000..0eb02edd4299c049e8969eed8716b0774bca9781 --- /dev/null +++ b/packages/broadway/src/parsers/utils/createOccurrenceCounter.ts @@ -0,0 +1,34 @@ +import { SimpleNamedEntityParser, SimpleOccurrencesCounter } from "@/types" + +export const createOccurrenceCounter = (parser: SimpleNamedEntityParser): SimpleOccurrencesCounter => { + + return async (input: string, minimumOccurrences: number): Promise> => { + // console.log("input:", input) + const detected = await parser( + [ input ], + [], + false // <- important: we keep duplicates, so we can count! + ) + + const stats: Record = {} + + detected.forEach(value => { + stats[value] = (stats[value] || 0) + 1 + }) + // console.log("detected:", detected) + const finalStats: Record = {} + + Object.entries(stats) + .map(([key, value]) => { + return { key: key, value: Number(value) } + }) + .filter(a => a.value >= minimumOccurrences) + .sort((a, b) => b.value - a.value) + .forEach(s => { + finalStats[s.key] = s.value + }) + + //console.log("DEBUG:", stats) + return finalStats + } +} \ No newline at end of file diff --git a/packages/broadway/src/parsers/utils/createParser.ts b/packages/broadway/src/parsers/utils/createParser.ts new file mode 100644 index 0000000000000000000000000000000000000000..b1b256573307113804974378f7bf5ce6c10c9a68 --- /dev/null +++ b/packages/broadway/src/parsers/utils/createParser.ts @@ -0,0 +1,17 @@ +import ParseEntities from "@datagica/parse-entities" + +import { NamedEntity, NamedEntityParser, NamedEntityResult } from "@/types" + +export function createParser( + data: NamedEntity[] = [], + fields = ['label','aliases'] + ): NamedEntityParser { + class Parser extends ParseEntities { + constructor() { super({ fields, data }) } + } + const parser = new Parser() + + return (input: string): Promise => ( + (parser.parse(input) as Promise) + ) +} \ No newline at end of file diff --git a/packages/broadway/src/parsers/utils/createSimpleParser.ts b/packages/broadway/src/parsers/utils/createSimpleParser.ts new file mode 100644 index 0000000000000000000000000000000000000000..fb0a28cc45fde2ed5e189d1aa8e45a2997cc24dc --- /dev/null +++ b/packages/broadway/src/parsers/utils/createSimpleParser.ts @@ -0,0 +1,55 @@ +import ParseEntities from "@datagica/parse-entities" + +import { SimpleNamedEntityParser } from "@/types" + +export function createSimpleParser( + data: T[] = [], + fields = ['label','aliases'], + ): SimpleNamedEntityParser { + class Parser extends ParseEntities { + constructor() { super({ fields, data }) } + } + const parser = new Parser() + + async function parse(inputs: string[] = [], defaultValues: string[] = [], removeDuplicates = true): Promise { + const validInputs = inputs.map(input => `${input || ""}`).map(x => x) + if (!validInputs.length) { + return [] + } + + const singleText = validInputs.join(".\n") + + let results = (await parser.parse(singleText) || []) as T[] + + // as an extra security + if (!Array.isArray(results) || !results.length) { + results = [] + } + + // used for deduplication + const dedup = new Set() + + const finalResult = results.map(entity => { + const value = (entity as any).value?.label || "" + + // to identify duplicated, we normalize the keys + const key = value.trim().toLocaleLowerCase() + + // remove duplicates + if (removeDuplicates) { + if (dedup.has(key)) { return "" } + dedup.add(key) + } + + return value + }).filter(value => value) + + if (!finalResult.length) { + return defaultValues + } else { + return finalResult + } + } + + return parse +} \ No newline at end of file diff --git a/packages/broadway/src/parsers/utils/getParserItemFromLabel.ts b/packages/broadway/src/parsers/utils/getParserItemFromLabel.ts new file mode 100644 index 0000000000000000000000000000000000000000..710b53864f6bb9acdd9639f4a2985c5b84460bf5 --- /dev/null +++ b/packages/broadway/src/parsers/utils/getParserItemFromLabel.ts @@ -0,0 +1,58 @@ +// import { ClapSegmentCategory } from "@aitube/clap" + +import { NamedEntity } from "@/types" + +export const getParserItemFromLabel = (database: NamedEntity[]) => { + + return (label: string): NamedEntity => { + const defaultEmptyItem: NamedEntity = { + label: "", + aliases: { + en: [] + }, + prompts: { + CHARACTER: [], + TRANSITION: [], + LOCATION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + } + + const item = database.find(item => item.label === label) + + if (!item) { + return defaultEmptyItem + } + + const prompts: Partial> = + typeof item.prompts === "undefined" ? defaultEmptyItem.prompts! : item.prompts + + return { + ...defaultEmptyItem, + prompts: { + CHARACTER: Array.isArray(prompts?.CHARACTER) ? prompts.CHARACTER : [], + TRANSITION: Array.isArray(prompts?.TRANSITION) ? prompts.TRANSITION : [], + LOCATION: Array.isArray(prompts?.LOCATION) ? prompts.LOCATION : [], + TIME: Array.isArray(prompts?.TIME) ? prompts.TIME : [], + ERA: Array.isArray(prompts?.ERA) ? prompts.ERA : [], + LIGHTING: Array.isArray(prompts?.LIGHTING) ? prompts.LIGHTING : [], + WEATHER: Array.isArray(prompts?.WEATHER) ? prompts.WEATHER : [], + ACTION: Array.isArray(prompts?.ACTION) ? prompts.ACTION : [], + MUSIC: Array.isArray(prompts?.MUSIC) ? prompts.MUSIC : [], + SOUND: Array.isArray(prompts?.SOUND) ? prompts.SOUND : [], + DIALOGUE: Array.isArray(prompts?.DIALOGUE) ? prompts.DIALOGUE : [], + STYLE: Array.isArray(prompts?.STYLE) ? prompts.STYLE : [], + CAMERA: Array.isArray(prompts?.CAMERA) ? prompts.CAMERA : [], + } + } + } +} \ No newline at end of file diff --git a/packages/broadway/src/parsers/utils/index.ts b/packages/broadway/src/parsers/utils/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..c8ea574e73d08eae6c0fbaa9681f989874d2a308 --- /dev/null +++ b/packages/broadway/src/parsers/utils/index.ts @@ -0,0 +1,4 @@ +export { createOccurrenceCounter } from "./createOccurrenceCounter" +export { createParser } from "./createParser" +export { createSimpleParser } from "./createSimpleParser" +export { getParserItemFromLabel } from "./getParserItemFromLabel" \ No newline at end of file diff --git a/packages/broadway/src/parsers/weather/database.ts b/packages/broadway/src/parsers/weather/database.ts new file mode 100644 index 0000000000000000000000000000000000000000..35477022c264384a21698c4f6f564362228dd1cd --- /dev/null +++ b/packages/broadway/src/parsers/weather/database.ts @@ -0,0 +1,185 @@ +import { NamedEntity } from "@/types" + +export const data: NamedEntity[] = [ + { + "label": "tornado", + "aliases": { + "en": [ + "twister", + "tornado" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "stormy", + "aliases": { + "en": [ + "tempest", + "lightning", + "thunder", + "storm", + "stormy", + "storms" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "no rain", + "aliases": { + "en": [ + "no rain", + "not raining" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "raining", + "aliases": { + "en": [ + "heavy rain", + "raining", + "soft rain", + "rain" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "foggy", + "aliases": { + "en": [ + "fog", + "foggy", + "mist", + "misty", + "soft mist" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "sunny", + "aliases": { + "en": [ + "sun", + "clear sky", + "sunny", + "bright sun" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, + { + "label": "cloudy", + "aliases": { + "en": [ + "cloudy", + "clouds", + "covered sky", + "cloudy sky" + ] + }, + prompts: { + CHARACTER: [], + LOCATION: [], + TRANSITION: [], + TIME: [], + ERA: [], + LIGHTING: [], + WEATHER: [], + ACTION: [], + MUSIC: [], + SOUND: [], + DIALOGUE: [], + STYLE: [], + CAMERA: [], + } + }, +] \ No newline at end of file diff --git a/packages/broadway/src/parsers/weather/index.ts b/packages/broadway/src/parsers/weather/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..0437832c7ff4ca08133c60a8a6497c8629c9762d --- /dev/null +++ b/packages/broadway/src/parsers/weather/index.ts @@ -0,0 +1,8 @@ +import { NamedEntity } from "@/types" +import { createSimpleParser, getParserItemFromLabel } from "@/parsers/utils" + +import { data } from "./database" + +export const parseWeather = createSimpleParser(data, ["aliases"]) + +export const getWeather = getParserItemFromLabel(data) \ No newline at end of file diff --git a/packages/broadway/src/tests/main.test.ts b/packages/broadway/src/tests/main.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..272d5359fdeada80c38df073a2bbb86fceb799d2 --- /dev/null +++ b/packages/broadway/src/tests/main.test.ts @@ -0,0 +1,49 @@ +import { test, expect, describe } from "bun:test" + +import { ClapProject, serializeClap } from "@aitube/clap" +import { readPlainText } from "@aitube/io" + +import { parseScriptToClap } from ".." + +describe("main demo", async () => { + + test("parseScriptToClap", async () => { + const scriptName = "Afterglow v10 X Rewrite Bryan E. Harris 2023" + const inputScriptFilePath = `./samples/scripts/${scriptName}.txt` + const outputScriptFilePath = `./samples/claps/${scriptName}.clap` + + const script = await readPlainText(inputScriptFilePath) + + const clap: ClapProject = await parseScriptToClap(script) + + expect(clap.segments.length).toBe(2837) + + const blob = await serializeClap(clap) + + await Bun.write(outputScriptFilePath, blob) + }, + + // parsing a script will be slow the first time, as we need to download a dataset + // example: + // first time (need to download the dataset): [7.40s] + // second time (with the dataset cached): [839.00ms] + // + // UPDATE: + // we currently don't cache the result, + // because this was too much platform-specific (file system caching, so for Node only) + 30000) + + /* + test("julianDemo", async () => { + const inputScriptFilePath = `/Users/jbilcke/Documents/Clapper/scripts/The Office (US Pilot).txt` + const outputScriptFilePath = `/Users/jbilcke/Documents/Clapper/claps/The Office (US Pilot).clap` + + const script = await readPlainText(inputScriptFilePath) + const clap: ClapProject = await parseScriptToClap(script) + const blob = await serializeClap(clap) + await Bun.write(outputScriptFilePath, blob) + }, + 30000) + */ + +}) \ No newline at end of file diff --git a/packages/broadway/src/tests/setup.js b/packages/broadway/src/tests/setup.js new file mode 100644 index 0000000000000000000000000000000000000000..185831df017369fbc451b21da9e84d9c8f1fafe8 --- /dev/null +++ b/packages/broadway/src/tests/setup.js @@ -0,0 +1,45 @@ +// @bun + + +// --------- disable IndexedDB ------------ +global.indexedDB = false +globalThis.indexedDB = false + +// -------- mock other things ------------- + +// see https://github.com/oven-sh/bun/issues/1723 + +/*! MIT License. Jimmy Wärting */ +import zlib from 'node:zlib' + +// fyi, Byte streams aren't really implemented anywhere yet +// It only exist as a issue: https://github.com/WICG/compression/issues/31 + +const make = (ctx, handle) => Object.assign(ctx, { + writable: new WritableStream({ + write: chunk => handle.write(chunk), + close: () => handle.end() + }), + readable: new ReadableStream({ + type: 'bytes', + start (ctrl) { + handle.on('data', chunk => ctrl.enqueue(chunk)) + handle.once('end', () => ctrl.close()) + } + }) +}) + +globalThis.CompressionStream ??= class CompressionStream { + constructor(format) { + make(this, format === 'deflate' ? zlib.createDeflate() : + format === 'gzip' ? zlib.createGzip() : zlib.createDeflateRaw()) + } +} + +globalThis.DecompressionStream ??= class DecompressionStream { + constructor(format) { + make(this, format === 'deflate' ? zlib.createInflate() : + format === 'gzip' ? zlib.createGunzip() : + zlib.createInflateRaw()) + } +} diff --git a/packages/broadway/src/types.ts b/packages/broadway/src/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..574fcb4968b13e829023b93383c665ae6a5b4c58 --- /dev/null +++ b/packages/broadway/src/types.ts @@ -0,0 +1,118 @@ +import { ScreenplaySequenceType } from "@/constants/screenplaySequences" +// import { ClapSegmentCategory } from "@aitube/clap" + +export type NamedEntity = { + label: string + aliases: { + en: string[] + } + prompts: Omit< + Record, + "SPLAT" | "INTERFACE" | "EVENT" | "EFFECT" | "PHENOMENON" | "MESH" | "DEPTH" | "VIDEO" | "STORYBOARD" | "GENERIC" + > +} + +export type LocationEntity = NamedEntity | { + type: "INDOOR" | "OUTDOOR" +} + +export type NamedEntityPosition = { + sentence: number + word: number + begin: number + end: number +} + +export type NamedEntityResult = { + ngram: string + value: NamedEntity + score: number + position: NamedEntityPosition +} + +export type NamedEntityParser = (input: string) => Promise + +export type SimpleNamedEntityParser = (inputs?: string[], defaultValues?: string[], removeDuplicates?: boolean) => Promise + +export type SimpleOccurrencesCounter = (input: string, minimumOccurrences: number) => Promise> + +export type MovieScriptMeta = { + fileName: string + title: string +} +export type MovieScript = { + meta: MovieScriptMeta + content: string | Blob +} + +export type SceneEvent = { + id: string + type: "description" | "dialogue" | "action" + character?: string + description: string + behavior: string + startAtLine: number + endAtLine: number +} + +export type Scene = { + id: string + scene: string + line: string + rawLine: string + sequenceFullText: string + sequenceStartAtLine: number + sequenceEndAtLine: number + startAtLine: number + endAtLine: number + events: SceneEvent[] +} + +export type MergedLine = { + rawLine: string + trimmedLine: string + startAtLine: number + endAtLine: number +} + +export type ScreenplaySequence = { + id: string + location: string[] + type: ScreenplaySequenceType + time: string + transition: string + fullText: string + startAtLine: number + endAtLine: number + scenes: Scene[] +} + +export type Screenplay = { + fullText: string + sequences: ScreenplaySequence[] +} + +// --- what is below is only used during analysis, but I think we this is obsolete --- + +export type AssetType = + | "Direction" + | "Image" + | "Video" + | "Description" // eg. "H.M.S. Dauntless" -> "A pirate ship made of wod, with sails.." + +export type AssetCategory = + | "character" + | "location" + | "unknown" + + +export type TemporaryAssetData = { + id: string // unique identifier of the assets (UUID) + type: AssetType + category: AssetCategory + label: string // the asset name (eg. in the script) + content: string // url to the resource, or content string + occurrences: number // how many times we see this asset + sequences: ScreenplaySequence[] + predictedPrompt: string +} \ No newline at end of file diff --git a/packages/broadway/src/utils/cleanUTF8Characters.ts b/packages/broadway/src/utils/cleanUTF8Characters.ts new file mode 100644 index 0000000000000000000000000000000000000000..d349ba861c42d473d085e2fffbcc95a590e0d812 --- /dev/null +++ b/packages/broadway/src/utils/cleanUTF8Characters.ts @@ -0,0 +1,3 @@ +export function cleanUTF8Characters(input: string): string { + return input.replaceAll("–", "-").replaceAll(" ", "") +} \ No newline at end of file diff --git a/packages/broadway/src/utils/deduplicate.ts b/packages/broadway/src/utils/deduplicate.ts new file mode 100644 index 0000000000000000000000000000000000000000..93d21b852aa1f63970399606c555bc15bbd2723c --- /dev/null +++ b/packages/broadway/src/utils/deduplicate.ts @@ -0,0 +1,3 @@ +export function deduplicate(items: string[]): string[] { + return Object.keys(items.reduce((acc, item) => ({ ...acc, [item]: item }), {})) +} \ No newline at end of file diff --git a/packages/broadway/src/utils/getEntities.ts b/packages/broadway/src/utils/getEntities.ts new file mode 100644 index 0000000000000000000000000000000000000000..41977cfbb3ab470f33be7269acf94613f3611c29 --- /dev/null +++ b/packages/broadway/src/utils/getEntities.ts @@ -0,0 +1,117 @@ +import { deduplicate } from "@/utils/deduplicate" + +/** + * Return uppercase entities + * + * Note: + * entities might be things like "TED'S CAR" or "JOHN'S VOICE (V.O.)" + * + * @param input + * @returns + */ +export function getEntities(input?: string | string[]): string[] { + const text = Array.isArray(input) ? input.join(": ") : input + let result: string[] = []; + let sentences = `${text || ""}`.split(":").join(".") + // .split("'").join(".") + .split(","); + // console.log("sentences:", sentences) + for (let i = 0; i < sentences.length; i++) { + + // let's make sure we remove all those empty spaces + let sentence = sentences[i].replaceAll(/\r?\n/gi, " ").replaceAll(/\s+/gi, " ").trim(); + + if (sentence === sentence.toUpperCase()) { + result.push(sentence); + } + } + + result = result.filter(x => x) + + /* + console.log("getEntities: ", { + input, + text, + result, + sentences, + }) + */ + const rawEntities = result.map(entity => { + + // first of all, to make pattern patchign easier we add space + // also we normalize the entity to uppercase + let tmp = ` ${entity} `.toUpperCase() + + // first we need to eliminate everything which is in parenthesis + tmp = tmp.split("(").shift() || tmp + + // something seems wrong + if (tmp.endsWith(" OF ") || tmp.endsWith(" THE ")) { + return "" + } + + tmp = tmp + // common issue: the "MR" is is-typed" + .replaceAll(" MH. ", " MR. ") + .replaceAll(" MH ", " MR ") + + /* + voice over - let keep this enumeration for future use, but not here + + .replaceAll(" (CONT.D) ", "") + .replaceAll(" (O.S.) ", "") + .replaceAll(" ( O.S.) ", "") + .replaceAll(" (O.S. ) ", "") + .replaceAll(" (OS) ", "") + .replaceAll(" ( OS) ", "") + .replaceAll(" (OS ) ", "") + .replaceAll(" (V.O.) ", "") + .replaceAll(" ( V.O.) ", "") + .replaceAll(" (V. O.) ", "") + .replaceAll(" (V. O. ) ", "") + .replaceAll(" (V.O. ) ", "") + .replaceAll(" (VO) ", "") + .replaceAll(" ( VO) ", "") + .replaceAll(" (VO ) ", "") + .replaceAll("'S VOICE ", "") + .replaceAll(".S VOICE ", "") + .replaceAll(" VOICE ", "") + */ + + // do we still need those? + tmp = tmp + .replaceAll(" MOVING CLOSE SHOT ", "") + .replaceAll(" MED. CLOSE SHOT ", "") + .replaceAll(" MED. SHOT ", "") + .replaceAll(" MOVING SHOT ", "") + .replaceAll(" MEDIUM SHOT ", "") + .replaceAll(" CLOSE SHOT ", "") + .replaceAll(" FULL SHOT ", "") + .replaceAll(" LONG SHOT ", "") + + .replaceAll(" MOVING CLOSE VIEW ", "") + .replaceAll(" MED. CLOSE VIEW ", "") + .replaceAll(" MED. VIEW ", "") + .replaceAll(" MOVING VIEW ", "") + .replaceAll(" CLOSE VIEW ", "") + .replaceAll(" FULL VIEW ", "") + + tmp = tmp.trim() + + if (tmp.endsWith(" -")) { + tmp = tmp.slice(0, tmp.length - 2) + } + if (tmp.endsWith(".S")) { + tmp = tmp.slice(0, tmp.length - 2) + } + if (tmp.endsWith(".")) { + tmp = tmp.slice(0, tmp.length - 1) + } + tmp = tmp.trim() + return tmp + }).filter(entity => entity.length > 1) + + + // finally we need to deduplicate entities + return deduplicate(rawEntities) +} \ No newline at end of file diff --git a/packages/broadway/src/utils/index.ts b/packages/broadway/src/utils/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..09fda7141c4e7d70c3c4ac7ba2824e981cf5c25a --- /dev/null +++ b/packages/broadway/src/utils/index.ts @@ -0,0 +1,7 @@ +export { cleanUTF8Characters } from "./cleanUTF8Characters" +export { deduplicate } from "./deduplicate" +export { getEntities } from "./getEntities" +export { isAllCaps } from "./isAllCaps" +export { onlyContainsStrangeNumber } from "./onlyContainsStrangeNumber" +export { pick } from "./pick" +export { sleep } from "./sleep" diff --git a/packages/broadway/src/utils/isAllCaps.ts b/packages/broadway/src/utils/isAllCaps.ts new file mode 100644 index 0000000000000000000000000000000000000000..3ccdd5b28cb20c4f8b87f8e95c643e6eb313616d --- /dev/null +++ b/packages/broadway/src/utils/isAllCaps.ts @@ -0,0 +1,3 @@ +export function isAllCaps(line: string): boolean { + return line === line.toUpperCase() +} \ No newline at end of file diff --git a/packages/broadway/src/utils/onlyContainsStrangeNumber.ts b/packages/broadway/src/utils/onlyContainsStrangeNumber.ts new file mode 100644 index 0000000000000000000000000000000000000000..924366e2526fa08a5b4149844844da97b863e2bd --- /dev/null +++ b/packages/broadway/src/utils/onlyContainsStrangeNumber.ts @@ -0,0 +1,5 @@ +// used to detect anomalies such as lines with only "3." "42." in it, +// possibly indicating a chapter or something +export function onlyContainsStrangeNumber(text: string) { + return text.match(/\S*\d+\.\S*/gi) +} \ No newline at end of file diff --git a/packages/broadway/src/utils/pick.ts b/packages/broadway/src/utils/pick.ts new file mode 100644 index 0000000000000000000000000000000000000000..78a70f8b7575f5a922b26eaea2f479b73c93b67a --- /dev/null +++ b/packages/broadway/src/utils/pick.ts @@ -0,0 +1,3 @@ +export function pick(items: T[]) { + return items[Math.floor(Math.random()*items.length)] +} diff --git a/packages/broadway/src/utils/sleep.ts b/packages/broadway/src/utils/sleep.ts new file mode 100644 index 0000000000000000000000000000000000000000..2885c6e75c0dc415c9eaf71beabac7461eee5588 --- /dev/null +++ b/packages/broadway/src/utils/sleep.ts @@ -0,0 +1,6 @@ +export const sleep = async (durationInMs: number) => + new Promise((resolve) => { + setTimeout(() => { + resolve(true) + }, durationInMs) + }) \ No newline at end of file diff --git a/packages/broadway/tsconfig.json b/packages/broadway/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..ab7cc3ed096e5dc51a557fdee4e68c0e28076d0b --- /dev/null +++ b/packages/broadway/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "baseUrl": "./", + "paths": { + "@/*": ["src/*"] + }, + "lib": ["ESNext", "DOM"], + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": true, + "noEmit": true, + "composite": true, + "strict": true, + "downlevelIteration": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "types": [ + "bun-types" + ] + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/packages/broadway/tsconfig.types.json b/packages/broadway/tsconfig.types.json new file mode 100644 index 0000000000000000000000000000000000000000..75cb8c175c0e0a67df2ffa0f06da4aa5b272db59 --- /dev/null +++ b/packages/broadway/tsconfig.types.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "emitDeclarationOnly": true, + "declaration": true, + "outDir": "./dist", + "rootDir": "./src", + }, + "include": [ + "src/**/*.ts", + "src/tests/bun-shims.js" + ] +} diff --git a/packages/clap/.gitignore b/packages/clap/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ea8fe6a7905bd72f745584146daa9994bd211499 --- /dev/null +++ b/packages/clap/.gitignore @@ -0,0 +1,177 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +\*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +\*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +\*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +\*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.cache +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output +dist +.nuxt + +# Gatsby files + +.cache/ + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp +.cache + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.\* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store + +# TypeScript build information +*.tsbuildinfo \ No newline at end of file diff --git a/packages/clap/.npmignore b/packages/clap/.npmignore new file mode 100644 index 0000000000000000000000000000000000000000..78a661ea2d8f8cdaa94e4cc69d758a4b2d946feb --- /dev/null +++ b/packages/clap/.npmignore @@ -0,0 +1,4 @@ +# Ignore everything +* +# Except the dist directory +!dist/ diff --git a/packages/clap/.prettierrc.json b/packages/clap/.prettierrc.json new file mode 100644 index 0000000000000000000000000000000000000000..1dcadb7324877e15a4ffa4efa5723a519395f511 --- /dev/null +++ b/packages/clap/.prettierrc.json @@ -0,0 +1,9 @@ +{ + "semi": false, + "singleQuote": true, + "arrowParens": "avoid", + "printWidth": 140, + "tabWidth": 2, + "trailingComma": "es5", + "bracketSpacing": true +} diff --git a/packages/clap/LICENSE.md b/packages/clap/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..8b21ed7d57c2d217f49e10d0fb0b327961a4ea54 --- /dev/null +++ b/packages/clap/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2024 Julian Bilcke + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/clap/README.md b/packages/clap/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3b130f8c9e309268c56fab4e6641345b400aba1e --- /dev/null +++ b/packages/clap/README.md @@ -0,0 +1,158 @@ +# @aitube/clap + +*Types and helpers to manipulate .clap files* + +## Introduction + +This library is the reference implementation of [OpenClap](https://github.com/jbilcke-hf/OpenClap-Format) for NodeJS and browser environments. + +**OpenClap** is a prompt container file format that was initially created for my AiTube.at project. I am also using it in my other AI demos, and I think you should use it, too! + +## Installation + +To install the package, run the following command (`yaml` is a peer dependency): + +```bash +npm install @aitube/clap yaml +``` + +## Getting Started + +```typescript +import { + // types + ClapSegmentCategory, + ClapOutputType, + ClapSegmentStatus, + ClapAuthor, + ClapAssetSource, + ClapEntityGender, + ClapEntityAppearance, + ClapEntityRegion, + ClapEntityTimbre, + ClapEntityAudioEngine, + ClapSegmentFilteringMode, + ClapVoice, + ClapHeader, + ClapMeta, + ClapSceneEvent, + ClapScene, + ClapSegment, + ClapEntity, + ClapProject, + ClapMediaOrientation, + + ClapInputFieldNumber, + ClapInputFieldString, + ClapInputFieldBoolean, + ClapInputFieldAny, + ClapInputFields, + ClapInputValue, + ClapInputValues, + ClapWorkflowEngine, + ClapWorkflowCategory, + ClapWorkflowProvider, + ClapWorkflow, + +// defaults + defaultMediaOrientation, + + // factories + newClap, + newEntity, + newSegment, + newWorkflow, + + // main input/output handlers + parseClap, + serializeClap, + fetchClap, + updateClap, + + // utilities + filterSegments, + filterSegmentsWithinRange, + generateSeed, + getClapAssetSourceType, + getValidNumber, + isValidNumber, + parseMediaOrientation, + parseOutputType, + parseWorkflowEngine, + parseSegmentCategory, + parseSegmentStatus, + UUID, + + // converters + blobToDataUri, + dataUriToBlob, + clapToDataUri, + + // helpers + buildEntityIndex, + filterAssets, + filterSegmentsByCategory, + generateClapFromSimpleStory, + getEmptyClap, + removeGeneratedAssetUrls, + + // sanitizers + sanitizeEntities, + sanitizeEntity, + sanitizeMeta, + sanitizeSegment, + sanitizeSegments, + sanitizeWorkflow, + sanitizeWorkflows, +} from "@aitube/clap" + + +// fetch a Clap file +const res = await fetch("https://..../file.clap") +const file = await res.blob() + +// open the Clap file +const clap: ClapProject = await parseClap(file) + +// perform arbitrary changes in the project + +clap.segments.at(64).assetUrl = await generateVideoWithAI(....) + +const segment: ClapSegment = clap.segments.at(42) +segment.prompt = "a camel in the desert, medium-shot, award-winning, 4k, Canon EOS" + +const storyboards = clap.segment.filter(s => s.category === ClapSegmentCategory.STORYBOARD) + +// save the Clap file +const newFile: ClapProject = await serializeClap(clap) +``` + +## Build Instructions + +Install [Bun](https://bun.sh/) + +Run the following commands: + +```bash +bun install + +bun run build +``` + +To publish: + +```bash +bun run build + +bun run build:declaration + +bun run publish +``` + +## Contributing + +We welcome contributions! Please feel free to submit a pull request. + +## License + +This package is under the MIT License. See `LICENSE` file for more details. diff --git a/packages/clap/package.json b/packages/clap/package.json new file mode 100644 index 0000000000000000000000000000000000000000..9244736050e9210e53ac8d32933121a9ab16b97a --- /dev/null +++ b/packages/clap/package.json @@ -0,0 +1,47 @@ +{ + "name": "@aitube/clap", + "module": "index.ts", + "main": "dist/index.js", + "private": false, + "types": "dist/index.d.ts", + "type": "module", + "version": "0.2.4", + "description": "Types and helpers to manipulate .clap files", + "scripts": { + "build": "bun build ./src/index.ts --outfile=dist/index.js --external=yaml && bun run build:declaration", + "build:declaration": "tsc --emitDeclarationOnly --project tsconfig.types.json", + "postbuild": "rimraf tsconfig.types.tsbuildinfo && bun run build:declaration", + "publish": "npm publish --access public" + }, + "devDependencies": { + "bun-types": "latest", + "prettier": "^3.3.3", + "rimraf": "^6.0.1", + "typescript": "^5.5.4" + }, + "peerDependencies": { + "yaml": "^2.5.0" + }, + "dependencies": { + "pure-uuid": "^1.8.1" + }, + "repository": { + "type": "git", + "url": "https://github.com/jbilcke-hf/aitube-clap.git" + }, + "keywords": [ + "Clapper.app", + "OpenClap", + "AiTube.at", + "AI cinema", + "file format", + "specification" + ], + "author": "Julian Bilcke", + "license": "MIT", + "files": [ + "dist/*.js", + "dist/*.d.ts", + "dist/**/*.d.ts" + ] +} \ No newline at end of file diff --git a/packages/clap/src/constants/defaultValues.ts b/packages/clap/src/constants/defaultValues.ts new file mode 100644 index 0000000000000000000000000000000000000000..6153b5f84aeedcbf98c94f43f642f433bb92a479 --- /dev/null +++ b/packages/clap/src/constants/defaultValues.ts @@ -0,0 +1,3 @@ +import { ClapMediaOrientation } from "@/types" + +export const defaultMediaOrientation = ClapMediaOrientation.LANDSCAPE \ No newline at end of file diff --git a/packages/clap/src/constants/index.ts b/packages/clap/src/constants/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..428d841b3709fe928d6af16801d8f3853daee2db --- /dev/null +++ b/packages/clap/src/constants/index.ts @@ -0,0 +1 @@ +export { defaultMediaOrientation } from "@/constants/defaultValues" \ No newline at end of file diff --git a/packages/clap/src/converters/blobToDataUri.ts b/packages/clap/src/converters/blobToDataUri.ts new file mode 100644 index 0000000000000000000000000000000000000000..42d219bb06c2c638f2e8e9553e0d45d5a33036db --- /dev/null +++ b/packages/clap/src/converters/blobToDataUri.ts @@ -0,0 +1,21 @@ +export async function blobToDataUri(blob: Blob, defaultContentType = ""): Promise { + if (typeof window === "undefined") { + const arrayBuffer = await blob.arrayBuffer() + let buffer = Buffer.from(arrayBuffer) + return "data:" + (defaultContentType || blob.type) + ';base64,' + buffer.toString('base64'); + } else { + return new Promise((resolve, reject) => { + const reader = new FileReader() + reader.onload = _e => { + let dataUri = `${reader.result as string || ""}` + if (defaultContentType) { + dataUri = dataUri.replace("application/octet-stream", defaultContentType) + } + resolve(dataUri) + } + reader.onerror = _e => reject(reader.error) + reader.onabort = _e => reject(new Error("Read aborted")) + reader.readAsDataURL(blob) + }); + } +} \ No newline at end of file diff --git a/packages/clap/src/converters/clapToDataUri.ts b/packages/clap/src/converters/clapToDataUri.ts new file mode 100644 index 0000000000000000000000000000000000000000..dffe3cb8b2fa72950067661020790f7c33e51de9 --- /dev/null +++ b/packages/clap/src/converters/clapToDataUri.ts @@ -0,0 +1,10 @@ + +import { ClapProject } from "@/types" +import { serializeClap } from "@/io/serializeClap" +import { blobToDataUri } from "@/converters/blobToDataUri" + +export async function clapToDataUri(clap: ClapProject): Promise { + const archive = await serializeClap(clap) + const dataUri = await blobToDataUri(archive, "application/x-gzip") + return dataUri +} \ No newline at end of file diff --git a/packages/clap/src/converters/dataUriToBlob.ts b/packages/clap/src/converters/dataUriToBlob.ts new file mode 100644 index 0000000000000000000000000000000000000000..364f1dcdbbcb8500faef9e316a0fd1869e3b4e88 --- /dev/null +++ b/packages/clap/src/converters/dataUriToBlob.ts @@ -0,0 +1,22 @@ + +/** + * Convert a Data URI to a Blob + * + * @param dataURI + * @param defaultContentType (Optional) you can pass a default content + * @returns + */ +export function dataUriToBlob(dataURI = "", defaultContentType = ""): Blob { + dataURI = dataURI.replace(/^data:/, ''); + + const type = dataURI.match(/(?:image|application|video|audio|text)\/[^;]+/)?.[0] || defaultContentType; + const base64 = dataURI.replace(/^[^,]+,/, ''); + const arrayBuffer = new ArrayBuffer(base64.length); + const typedArray = new Uint8Array(arrayBuffer); + + for (let i = 0; i < base64.length; i++) { + typedArray[i] = base64.charCodeAt(i); + } + + return new Blob([arrayBuffer], { type }); +} \ No newline at end of file diff --git a/packages/clap/src/converters/index.ts b/packages/clap/src/converters/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..5bfbdbeb68c8a33d9af66694d6109baf2b64c332 --- /dev/null +++ b/packages/clap/src/converters/index.ts @@ -0,0 +1,3 @@ +export { blobToDataUri } from '@/converters/blobToDataUri' +export { clapToDataUri } from '@/converters/clapToDataUri' +export { dataUriToBlob } from '@/converters/dataUriToBlob' diff --git a/packages/clap/src/factories/index.ts b/packages/clap/src/factories/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..f324fa796e39ae7d7be0ea52d4e01921ca1d035e --- /dev/null +++ b/packages/clap/src/factories/index.ts @@ -0,0 +1,4 @@ +export { newClap } from '@/factories/newClap' +export { newEntity } from '@/factories/newEntity' +export { newSegment } from '@/factories/newSegment' +export { newWorkflow } from '@/factories/newWorkflow' diff --git a/packages/clap/src/factories/newClap.ts b/packages/clap/src/factories/newClap.ts new file mode 100644 index 0000000000000000000000000000000000000000..6336770811e37854bc3bc5377b003e228b28f820 --- /dev/null +++ b/packages/clap/src/factories/newClap.ts @@ -0,0 +1,26 @@ +import { ClapMeta, ClapEntity, ClapProject, ClapScene, ClapSegment, ClapWorkflow } from "@/types" +import { buildEntityIndex } from "@/helpers/buildEntityIndex" +import { sanitizeMeta } from "@/sanitizers/sanitizeMeta" +import { sanitizeWorkflows } from "@/sanitizers/sanitizeWorkflows" +import { sanitizeEntities } from "@/sanitizers/sanitizeEntities" +import { sanitizeSegments } from "@/sanitizers/sanitizeSegments" + +// generate an empty clap file, or copy one from a source +export function newClap(clap: { + meta?: Partial + workflows?: ClapWorkflow[] + entities?: ClapEntity[] + scenes?: ClapScene[] + segments?: ClapSegment[] + } = {}): ClapProject { + + const meta = sanitizeMeta(clap?.meta) + + const workflows: ClapWorkflow[] = clap?.workflows && Array.isArray(clap.workflows) ? sanitizeWorkflows(clap.workflows) : [] + const entities: ClapEntity[] = clap?.entities && Array.isArray(clap.entities) ? sanitizeEntities(clap.entities) : [] + const scenes: ClapScene[] = clap?.scenes && Array.isArray(clap.scenes) ? clap.scenes : [] + const segments: ClapSegment[] = clap?.segments && Array.isArray(clap.segments) ? sanitizeSegments(clap.segments) : [] + const entityIndex = buildEntityIndex(entities) + + return { meta, workflows, entities, entityIndex, scenes, segments } +} diff --git a/packages/clap/src/factories/newEntity.ts b/packages/clap/src/factories/newEntity.ts new file mode 100644 index 0000000000000000000000000000000000000000..b5a68987d01d9a92f7a2ec704096de15bfd73e35 --- /dev/null +++ b/packages/clap/src/factories/newEntity.ts @@ -0,0 +1,40 @@ +import { ClapAssetSource, ClapEntity, ClapEntityAppearance, ClapEntityAudioEngine, ClapEntityGender, ClapEntityRegion, ClapSegmentCategory } from "@/types" +import { generateSeed } from "@/utils/generateSeed" +import { isValidNumber } from "@/utils/isValidNumber" +import { parseSegmentCategory } from "@/utils/parseSegmentCategory" +import { UUID } from "@/utils/uuid" + +export function newEntity(maybeEntity?: Partial) { + + const entity: ClapEntity = { + id: typeof maybeEntity?.id === "string" ? maybeEntity.id : UUID(), + category: parseSegmentCategory(maybeEntity?.category, ClapSegmentCategory.CHARACTER), + triggerName: typeof maybeEntity?.triggerName === "string" ? maybeEntity.triggerName : "", + label: typeof maybeEntity?.label === "string" ? maybeEntity.label : "", + description: typeof maybeEntity?.description === "string" ? maybeEntity.description : "", + tags: Array.isArray(maybeEntity?.tags) ? maybeEntity?.tags : [], + author: typeof maybeEntity?.author === "string" ? maybeEntity.author : "", + thumbnailUrl: typeof maybeEntity?.thumbnailUrl === "string" ? maybeEntity.thumbnailUrl : "", + seed: isValidNumber(maybeEntity?.seed) ? (maybeEntity?.seed || 0) : generateSeed(), + + imagePrompt: typeof maybeEntity?.imagePrompt === "string" ? maybeEntity.imagePrompt : "", + imageSourceType: typeof maybeEntity?.imageSourceType === "string" ? (maybeEntity.imageSourceType as ClapAssetSource) : ClapAssetSource.EMPTY, + imageEngine: typeof maybeEntity?.imageEngine === "string" ? maybeEntity.imageEngine : "", + imageId: typeof maybeEntity?.imageId === "string" ? maybeEntity.imageId : "", + audioPrompt: typeof maybeEntity?.audioPrompt === "string" ? maybeEntity.audioPrompt : "", + audioSourceType: typeof maybeEntity?.audioSourceType === "string" ? (maybeEntity.audioSourceType as ClapAssetSource) : ClapAssetSource.EMPTY, + audioEngine: typeof maybeEntity?.audioEngine === "string" ? (maybeEntity.audioEngine as ClapEntityAudioEngine) : "Parler-TTS", + audioId: typeof maybeEntity?.audioId === "string" ? maybeEntity.audioId : "", + + // those are only used by certain types of entities + age: isValidNumber(maybeEntity?.age) ? (maybeEntity?.age || 0) : 25, + + // TODO find a way to validate those, using lists + // TODO: we are going to use `variant: ClapEntityVariant` instead, which is gonna be an arbitrary string + gender: typeof maybeEntity?.gender === "string" ? (maybeEntity.gender as ClapEntityGender) : "object", + region: typeof maybeEntity?.region === "string" ? (maybeEntity.region as ClapEntityRegion) : "global", + appearance: typeof maybeEntity?.appearance === "string" ? (maybeEntity.appearance as ClapEntityAppearance) : "neutral", + } + + return entity +} diff --git a/packages/clap/src/factories/newSegment.ts b/packages/clap/src/factories/newSegment.ts new file mode 100644 index 0000000000000000000000000000000000000000..9af3ca7da1d11679b8f8a19799211488815b35a3 --- /dev/null +++ b/packages/clap/src/factories/newSegment.ts @@ -0,0 +1,54 @@ +import { ClapAssetSource, ClapOutputType, ClapSegment, ClapSegmentStatus } from "@/types" +import { isValidNumber } from "@/utils/isValidNumber" +import { generateSeed } from "@/utils/generateSeed" +import { UUID } from "@/utils/uuid" +import { parseSegmentCategory } from "@/utils/parseSegmentCategory" +import { parseOutputType } from "@/index" + +export function newSegment(maybeSegment?: Partial) { + + const startTimeInMs = + isValidNumber(maybeSegment?.startTimeInMs) + ? (maybeSegment?.startTimeInMs || 0) + : 0 + + const assetDurationInMs = + isValidNumber(maybeSegment?.assetDurationInMs) + ? (maybeSegment?.assetDurationInMs || 0) + : 1000 + + const endTimeInMs = + isValidNumber(maybeSegment?.endTimeInMs) + ? (maybeSegment?.endTimeInMs || 0) + : (startTimeInMs + assetDurationInMs) + + const segment: ClapSegment = { + id: typeof maybeSegment?.id === "string" ? maybeSegment.id : UUID(), + track: isValidNumber(maybeSegment?.track) ? (maybeSegment?.track || 0) : 0, + startTimeInMs, + endTimeInMs, + category: parseSegmentCategory(maybeSegment?.category), + entityId: typeof maybeSegment?.entityId === "string" ? maybeSegment.entityId : "", + workflowId: typeof maybeSegment?.workflowId === "string" ? maybeSegment.workflowId : "", + sceneId: typeof maybeSegment?.sceneId === "string" ? maybeSegment.sceneId : "", + startTimeInLines: isValidNumber(maybeSegment?.startTimeInLines) ? (maybeSegment?.startTimeInLines || 0) : 0, + endTimeInLines: isValidNumber(maybeSegment?.endTimeInLines) ? (maybeSegment?.endTimeInLines || 0) : 0, + prompt: typeof maybeSegment?.prompt === "string" ? maybeSegment.prompt : "", + label: typeof maybeSegment?.label === "string" ? maybeSegment.label : "", + outputType: parseOutputType(maybeSegment?.outputType, ClapOutputType.TEXT), + renderId: typeof maybeSegment?.renderId === "string" ? maybeSegment.renderId : "", + status: typeof maybeSegment?.status === "string" ? maybeSegment.status : ClapSegmentStatus.TO_GENERATE, + assetUrl: typeof maybeSegment?.assetUrl === "string" ? maybeSegment.assetUrl : "", + assetDurationInMs: isValidNumber(assetDurationInMs) ? assetDurationInMs : 0, + assetSourceType: typeof maybeSegment?.assetSourceType === "string" ? maybeSegment.assetSourceType : ClapAssetSource.EMPTY, + assetFileFormat: typeof maybeSegment?.assetFileFormat === "string" ? maybeSegment.assetFileFormat : "", + revision: isValidNumber(maybeSegment?.revision) ? (maybeSegment?.revision || 0) : 0, + createdAt: typeof maybeSegment?.createdAt === "string" ? maybeSegment.createdAt : new Date().toISOString(), + createdBy: typeof maybeSegment?.createdBy === "string" ? maybeSegment.createdBy : "ai", + editedBy: typeof maybeSegment?.editedBy === "string" ? maybeSegment.editedBy : "ai", + outputGain: isValidNumber(maybeSegment?.outputGain) ? (maybeSegment?.outputGain || 0) : 0, + seed: isValidNumber(maybeSegment?.seed) ? (maybeSegment?.seed || 0) : generateSeed() + } + + return segment +} \ No newline at end of file diff --git a/packages/clap/src/factories/newWorkflow.ts b/packages/clap/src/factories/newWorkflow.ts new file mode 100644 index 0000000000000000000000000000000000000000..24cbbac4f4366c406ba60ef44c3508cfb4c5a0b6 --- /dev/null +++ b/packages/clap/src/factories/newWorkflow.ts @@ -0,0 +1,23 @@ +import { ClapWorkflow, ClapWorkflowCategory, ClapWorkflowEngine, ClapWorkflowProvider } from "@/types" +import { parseWorkflowCategory, parseWorkflowEngine, parseWorkflowProvider } from "@/utils" +import { UUID } from "@/utils/uuid" + +export function newWorkflow(maybeWorkflow?: Partial) { + + const workflow: ClapWorkflow = { + id: typeof maybeWorkflow?.id === "string" ? maybeWorkflow.id : UUID(), + label: typeof maybeWorkflow?.label === "string" ? maybeWorkflow.label : "", + description: typeof maybeWorkflow?.description === "string" ? maybeWorkflow.description : "", + tags: Array.isArray(maybeWorkflow?.tags) ? maybeWorkflow?.tags : [], + author: typeof maybeWorkflow?.author === "string" ? maybeWorkflow.author : "", + thumbnailUrl: typeof maybeWorkflow?.thumbnailUrl === "string" ? maybeWorkflow.thumbnailUrl : "", + engine: parseWorkflowEngine(maybeWorkflow?.engine, ClapWorkflowEngine.DEFAULT), + category: parseWorkflowCategory(maybeWorkflow?.category, ClapWorkflowCategory.IMAGE_GENERATION), + provider: parseWorkflowProvider(maybeWorkflow?.provider, ClapWorkflowProvider.NONE), + data: typeof maybeWorkflow?.data === "string" ? maybeWorkflow.data : "", + inputFields: Array.isArray(maybeWorkflow?.inputFields) ? maybeWorkflow.inputFields : [], + inputValues: typeof maybeWorkflow?.inputValues === "object" ? maybeWorkflow.inputValues : {}, + } + + return workflow +} diff --git a/packages/clap/src/helpers/README.md b/packages/clap/src/helpers/README.md new file mode 100644 index 0000000000000000000000000000000000000000..5a7df47deaaf29852e3e0cff3edc7362ed0846f6 --- /dev/null +++ b/packages/clap/src/helpers/README.md @@ -0,0 +1 @@ +Utilities to help developers getting quickly bootstrapped \ No newline at end of file diff --git a/packages/clap/src/helpers/buildEntityIndex.ts b/packages/clap/src/helpers/buildEntityIndex.ts new file mode 100644 index 0000000000000000000000000000000000000000..c0bee79245e3d3932174eea40b5665f26597cc9f --- /dev/null +++ b/packages/clap/src/helpers/buildEntityIndex.ts @@ -0,0 +1,9 @@ +import { ClapEntity } from "@/types" + +export function buildEntityIndex(entities: ClapEntity[] = []): Record { + const index: Record = {} + for (const entity of entities) { + index[entity.id] = entity + } + return index +} \ No newline at end of file diff --git a/packages/clap/src/helpers/filterAssets.ts b/packages/clap/src/helpers/filterAssets.ts new file mode 100644 index 0000000000000000000000000000000000000000..949994738027c133ed01ba2ef4d63d8bbefa69dc --- /dev/null +++ b/packages/clap/src/helpers/filterAssets.ts @@ -0,0 +1,73 @@ +import { parseClap } from "@/io/parseClap" +import { serializeClap } from "@/io/serializeClap" +import { ClapAssetSource, ClapProject, ClapSegmentCategory, ClapSegmentStatus } from "@/types" + +/** + * Keep or remove segment assets, by category + * + * You can choose a mode, to either INCLUDE or EXCLUDE + * + * The original is NOT modifed by default, unless you set: `modifyOriginal: true` + * which will clone the whole clap project + */ +export async function filterAssets({ + clap, + immutable = false, + mode = "INCLUDE", + categories = {}, + updateStatus = true +}: { + clap: ClapProject + immutable?: boolean + mode: "INCLUDE" | "EXCLUDE" + categories: Partial> + updateStatus?: boolean +}): Promise { + + if (immutable) { + const tmp = await serializeClap(clap) + const newClap = await parseClap(tmp) + return filterAssets({ + clap: newClap, + immutable: false, + mode, + categories, + updateStatus, + }) + } + + if (mode !== "INCLUDE" && mode !== "EXCLUDE") { + throw new Error(`unsupported mode "${mode}"`) + } + + clap.segments = clap.segments.map(segment => { + if (mode === "INCLUDE") { + if (typeof categories[segment.category] === "boolean" && categories[segment.category]) { + segment.assetUrl = segment.assetUrl + } else { + segment.assetUrl = "" + if (updateStatus) { + segment.status = ClapSegmentStatus.TO_GENERATE + segment.assetDurationInMs = 0 + segment.assetSourceType = ClapAssetSource.EMPTY + segment.assetFileFormat = "" + } + } + } else if (mode === "EXCLUDE") { + if (typeof categories[segment.category] === "boolean" && !categories[segment.category]) { + segment.assetUrl = "" + if (updateStatus) { + segment.status = ClapSegmentStatus.TO_GENERATE + segment.assetDurationInMs = 0 + segment.assetSourceType = ClapAssetSource.EMPTY + segment.assetFileFormat = "" + } + } else { + segment.assetUrl = segment.assetUrl + } + } + return segment + }) + + return clap +} \ No newline at end of file diff --git a/packages/clap/src/helpers/filterSegmentsByCategory.ts b/packages/clap/src/helpers/filterSegmentsByCategory.ts new file mode 100644 index 0000000000000000000000000000000000000000..b92555bd993838372109e3a9b175c6518f13b452 --- /dev/null +++ b/packages/clap/src/helpers/filterSegmentsByCategory.ts @@ -0,0 +1,53 @@ +import { parseClap } from "@/io/parseClap" +import { serializeClap } from "@/io/serializeClap" +import { ClapProject, ClapSegmentCategory } from "@/types" + +/** + * Filter segments by category + * + * You can choose a mode, to either INCLUDE or EXCLUDE + * + * The original is NOT modifed by default, unless you set: `modifyOriginal: true` + * which will clone the whole clap project + */ +export async function filterSegmentsByCategory({ + clap, + modifyOriginal, + mode, + categories +}: { + clap: ClapProject + modifyOriginal?: boolean + mode: "INCLUDE" | "EXCLUDE" + categories: Record +}): Promise { + + if (!modifyOriginal) { + const tmp = await serializeClap(clap) + const newClap = await parseClap(tmp) + return filterSegmentsByCategory({ + clap: newClap, + modifyOriginal: true, + mode, + categories, + }) + } + + if (mode === "INCLUDE") { + clap.segments = clap.segments.filter(segment => ( + typeof categories[segment.category] === "boolean" + ? categories[segment.category] + : false + )) + } else if (mode === "EXCLUDE") { + clap.segments = clap.segments.filter(segment => ( + typeof categories[segment.category] === "boolean" + ? !categories[segment.category] + : true + )) + } else { + throw new Error(`unsupported mode "${mode}"`) + } + + return clap +} diff --git a/packages/clap/src/helpers/generateClapFromSimpleStory.ts b/packages/clap/src/helpers/generateClapFromSimpleStory.ts new file mode 100644 index 0000000000000000000000000000000000000000..8dd9d4204b4b95a45af450a6cd25282e410769ce --- /dev/null +++ b/packages/clap/src/helpers/generateClapFromSimpleStory.ts @@ -0,0 +1,121 @@ +import { defaultSegmentDurationInMs, demoStory } from "@/samples/stories" + +import { newClap } from "@/factories/newClap" +import { newSegment } from "@/factories/newSegment" +import { ClapOutputType, ClapProject, ClapSegmentCategory } from "@/types" + +export function generateClapFromSimpleStory({ + story = demoStory, + showIntroPoweredByEngine = false, + showIntroDisclaimerAboutAI = false, +}: { + story?: string[] + showIntroPoweredByEngine?: boolean + showIntroDisclaimerAboutAI?: boolean +} = { + story: demoStory, + showIntroPoweredByEngine: false, + showIntroDisclaimerAboutAI: false, +}): ClapProject { + + const clap = newClap({ + meta: { + title: "Interactive Demo", + isInteractive: true, + isLoop: true, + } + }) + + let currentElapsedTimeInMs = 0 + let currentSegmentDurationInMs = defaultSegmentDurationInMs + + if (showIntroPoweredByEngine) { + clap.segments.push(newSegment({ + startTimeInMs: currentElapsedTimeInMs, + endTimeInMs: currentSegmentDurationInMs, + category: ClapSegmentCategory.INTERFACE, + prompt: "", + label: "disclaimer", + outputType: ClapOutputType.INTERFACE, + })) + currentElapsedTimeInMs += currentSegmentDurationInMs + } + + if (showIntroDisclaimerAboutAI) { + clap.segments.push(newSegment({ + startTimeInMs: currentElapsedTimeInMs, + endTimeInMs: currentSegmentDurationInMs, + category:ClapSegmentCategory.INTERFACE, + prompt: "", + label: "disclaimer", + outputType: ClapOutputType.INTERFACE, + })) + currentElapsedTimeInMs += currentSegmentDurationInMs + } + + /* + clap.segments.push( + newSegment({ + // id: string + // track: number + startTimeInMs: currentElapsedTimeInMs, + endTimeInMs: currentSegmentDurationInMs, + category: ClapSegmentCategory.INTERFACE, + // entityId: string + // sceneId: string + prompt: "a hello world", + label: "hello world", + outputType: ClapOutputType.INTERFACE, + // renderId: string + // status: ClapSegmentStatus + // assetUrl: string + // assetDurationInMs: number + // createdBy: ClapAuthor + // editedBy: ClapAuthor + // outputGain: number + // seed: number + }) + ) + + currentElapsedTimeInMs += currentSegmentDurationInMs + */ + + + + for (let prompt of story) { + + clap.segments.push(newSegment({ + track: 0, + startTimeInMs: currentElapsedTimeInMs, + endTimeInMs: currentSegmentDurationInMs, + category: ClapSegmentCategory.VIDEO, + prompt: "", + label: "video", + outputType: ClapOutputType.VIDEO, + })) + clap.segments.push(newSegment({ + track: 1, + startTimeInMs: currentElapsedTimeInMs, + endTimeInMs: currentSegmentDurationInMs, + category: ClapSegmentCategory.GENERIC, + prompt, + label: prompt, + outputType: ClapOutputType.TEXT, + })) + clap.segments.push(newSegment({ + track: 2, + startTimeInMs: currentElapsedTimeInMs, + endTimeInMs: currentSegmentDurationInMs, + category: ClapSegmentCategory.CAMERA, + prompt: "medium-shot", + label: "medium-shot", + outputType: ClapOutputType.TEXT, + })) + + currentElapsedTimeInMs += currentSegmentDurationInMs + } + + clap.meta.durationInMs = currentElapsedTimeInMs + + return clap +} \ No newline at end of file diff --git a/packages/clap/src/helpers/getEmptyClap.ts b/packages/clap/src/helpers/getEmptyClap.ts new file mode 100644 index 0000000000000000000000000000000000000000..86a075c23db2df405b7070af9844d84bdc894465 --- /dev/null +++ b/packages/clap/src/helpers/getEmptyClap.ts @@ -0,0 +1,18 @@ +import { newClap } from "@/factories/newClap" +import { serializeClap } from "@/io/serializeClap" + +let globalState: { + blob?: Blob +} = { + blob: undefined +} + +export async function getEmptyClap(): Promise { + if (globalState.blob) { return globalState.blob } + + const clap = newClap() + + globalState.blob = await serializeClap(clap) + + return globalState.blob +} \ No newline at end of file diff --git a/packages/clap/src/helpers/index.ts b/packages/clap/src/helpers/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..ea7659caf9026e8b2f5d267d1b5bb01786bfc282 --- /dev/null +++ b/packages/clap/src/helpers/index.ts @@ -0,0 +1,6 @@ +export { buildEntityIndex } from '@/helpers/buildEntityIndex' +export { filterAssets } from '@/helpers/filterAssets' +export { filterSegmentsByCategory } from '@/helpers/filterSegmentsByCategory' +export { getEmptyClap } from '@/helpers/getEmptyClap' +export { generateClapFromSimpleStory } from '@/helpers/generateClapFromSimpleStory' +export { removeGeneratedAssetUrls } from '@/helpers/removeGeneratedAssetUrls' \ No newline at end of file diff --git a/packages/clap/src/helpers/removeGeneratedAssetUrls.ts b/packages/clap/src/helpers/removeGeneratedAssetUrls.ts new file mode 100644 index 0000000000000000000000000000000000000000..00079e9f6f6cc40dcb012c29fcdc6fede2cc59fe --- /dev/null +++ b/packages/clap/src/helpers/removeGeneratedAssetUrls.ts @@ -0,0 +1,30 @@ +import { ClapProject, ClapSegmentCategory, ClapSegmentStatus, ClapSegment } from "@/types" + +// return a new clap (but in a memory efficient way: it will hold references to the original) +// with all the generated, partially generated or in-erorr segments stripped of their assetUrl +// +// this will has the effect or drastically reducing the size of the payload +// +// note: please make sure you don't accidentally have segments +// with status TO_GENERATE and something in assetUrl +export function removeGeneratedAssetUrls( + clap: ClapProject, + + // those segments will be preserved no matter what + idsOfSegmentsToKeep: string[] = [] +): ClapProject { + return { + ...clap, + segments: (Array.isArray(clap.segments) ? clap.segments : []) + .map((segment: ClapSegment) => + // if a segment is not "TO_GENERATE" then we assume it contains an URL, + // which is information we can strip out + // also if it's in idsOfSegmentsToKeep we keep it without asking questions + ( + idsOfSegmentsToKeep.includes(segment.id) || + segment?.status === ClapSegmentStatus.TO_GENERATE) + ? segment + : { ...segment, assetUrl: '' } + ) + } +} diff --git a/packages/clap/src/index.ts b/packages/clap/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..46e8d8b198511c3f7b3053fcb4174a9397db45c3 --- /dev/null +++ b/packages/clap/src/index.ts @@ -0,0 +1,93 @@ +export { + ClapAssetSource, + ClapAuthor, + ClapEntity, + ClapEntityAppearance, + ClapEntityAudioEngine, + ClapEntityVariant, + ClapEntityGender, + ClapEntityRegion, + ClapEntityTimbre, + ClapFormat, + ClapHeader, + ClapMediaOrientation, + ClapMeta, + ClapOutputType, + ClapProject, + ClapScene, + ClapSceneEvent, + ClapSegment, + ClapSegmentCategory, + ClapSegmentFilteringMode, + ClapSegmentStatus, + ClapTrack, + ClapTracks, + ClapVoice, + ClapCompletionMode, + ClapInputField, + ClapInputFieldNumber, + ClapInputFieldInteger, + ClapInputFieldString, + ClapInputFieldBoolean, + ClapInputFieldAny, + ClapInputFields, + ClapInputValue, + ClapInputValues, + ClapWorkflowEngine, + ClapWorkflowCategory, + ClapWorkflowProvider, + ClapWorkflow +} from '@/types' +export { + defaultMediaOrientation +} from '@/constants' +export { + newClap, + newEntity, + newSegment, + newWorkflow +} from '@/factories' +export { + parseClap, + serializeClap, + fetchClap, + updateClap +} from '@/io' +export { + filterSegments, + filterSegmentsWithinRange, + generateSeed, + getClapAssetSourceType, + getValidNumber, + isValidNumber, + parseMediaOrientation, + parseOutputType, + parseWorkflowEngine, + parseWorkflowCategory, + parseWorkflowProvider, + parseSegmentCategory, + parseSegmentStatus, + UUID +} from '@/utils' +export { + blobToDataUri, + dataUriToBlob, + clapToDataUri +} from '@/converters' +export { + buildEntityIndex, + filterAssets, + filterSegmentsByCategory, + generateClapFromSimpleStory, + getEmptyClap, + removeGeneratedAssetUrls, +} from '@/helpers' +export { + sanitizeEntities, + sanitizeEntity, + sanitizeMeta, + sanitizeSegment, + sanitizeSegments, + sanitizeWorkflow, + sanitizeWorkflows, +} from '@/sanitizers' \ No newline at end of file diff --git a/packages/clap/src/io/fetchClap.ts b/packages/clap/src/io/fetchClap.ts new file mode 100644 index 0000000000000000000000000000000000000000..1a8bdea49e97eef52a9196b38f0ef4da434de59e --- /dev/null +++ b/packages/clap/src/io/fetchClap.ts @@ -0,0 +1,30 @@ +import { ClapProject } from "@/types" +import { parseClap } from "@/io/parseClap" + +export async function fetchClap(url: string, { + method = "GET", + body, + headers, + cache, +}: { + method?: string + body?: BodyInit | null + headers?: HeadersInit + cache?: RequestCache +} = { + method: "GET" +}): Promise { + + const res = await fetch(url, { + method, + headers, + body, + cache, + }) + + const blob = await res.blob() + + const clap = await parseClap(blob) + + return clap +} \ No newline at end of file diff --git a/packages/clap/src/io/index.ts b/packages/clap/src/io/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..5a46c8124d14bfadb29a98210cdbbeb1f497759f --- /dev/null +++ b/packages/clap/src/io/index.ts @@ -0,0 +1,4 @@ +export { parseClap } from '@/io/parseClap' +export { serializeClap } from '@/io/serializeClap' +export { fetchClap } from '@/io/fetchClap' +export { updateClap } from '@/io/updateClap' diff --git a/packages/clap/src/io/parseClap.ts b/packages/clap/src/io/parseClap.ts new file mode 100644 index 0000000000000000000000000000000000000000..d3cdecc1a2a7591a590051fa5e29bb9314dd686e --- /dev/null +++ b/packages/clap/src/io/parseClap.ts @@ -0,0 +1,278 @@ +import YAML from "yaml" + +import { ClapHeader, ClapMeta, ClapEntity, ClapProject, ClapScene, ClapSegment, ClapFormat, ParseClapProgressUpdate, ClapWorkflow } from "@/types" +import { dataUriToBlob } from "@/converters/dataUriToBlob" +import { buildEntityIndex } from "@/helpers/buildEntityIndex" +import { sanitizeWorkflows } from "@/sanitizers/sanitizeWorkflows" +import { sanitizeEntities } from "@/sanitizers/sanitizeEntities" +import { sanitizeSegment } from "@/sanitizers/sanitizeSegment" +import { sanitizeMeta } from "@/sanitizers/sanitizeMeta" + +type StringOrBlob = string | Blob + +const defaultParseClapProgressUpdate: ParseClapProgressUpdate = async () => {} + +/** + * Import a clap file from various data sources into an ClapProject + * + * Inputs can be: + * - a Clap project (which is an object) + * - an URL to a remote .clap file + * - a string containing a YAML array + * - a data uri containing a gzipped YAML array + * - a Blob containing a gzipped YAML array + * + * note: it is not really async, because for some reason YAML.parse is a blocking call like for JSON, + * there is no async version although we are now in the 20s not 90s + */ +export async function parseClap( + src?: ClapProject | string | Blob, + debug = false, + onProgressUpdate: ParseClapProgressUpdate = defaultParseClapProgressUpdate +): Promise { + + await onProgressUpdate({ value: 0, message: "Opening .clap file.." }) + + try { + if ( + typeof src === "object" && + Array.isArray( (src as any)?.scenes) && + Array.isArray((src as any)?.entities) + ) { + if (debug) { + console.log("parseClap: input is already a Clap file, nothing to do:", src) + } + // we can skip verification + return src as ClapProject + } + } catch (err) { + // well, this is not a clap project + } + + let stringOrBlob = (src || "") as StringOrBlob + + // both should work + const dataUriHeader1 = "data:application/x-gzip;base64," + const dataUriHeader2 = "data:application/octet-stream;base64," + + const inputIsString = typeof stringOrBlob === "string" + const inputIsDataUri = typeof stringOrBlob === "string" ? stringOrBlob.startsWith(dataUriHeader1) || stringOrBlob.startsWith(dataUriHeader2) : false + const inputIsRemoteFile = typeof stringOrBlob === "string" ? (stringOrBlob.startsWith("http://") || stringOrBlob.startsWith("https://")) : false + + let inputIsBlob = typeof stringOrBlob !== "string" + + let inputYamlArrayString = "" + + if (debug) { + console.log(`parseClap: pre-analysis: ${JSON.stringify({ + inputIsString, + inputIsBlob, + inputIsDataUri, + inputIsRemoteFile + }, null, 2)}`) + } + + await onProgressUpdate({ value: 10, message: "Analyzing .clap file.." }) + + if (typeof stringOrBlob === "string") { + if (debug) { + console.log("parseClap: input is a string ", stringOrBlob.slice(0, 120)) + } + if (inputIsDataUri) { + if (debug) { + console.log(`parseClap: input is a data uri archive`) + } + stringOrBlob = dataUriToBlob(stringOrBlob, "application/x-gzip") + if (debug) { + console.log(`parseClap: inputBlob = `, stringOrBlob) + } + inputIsBlob = true + } else if (inputIsRemoteFile) { + try { + if (debug) { + console.log(`parseClap: input is a remote .clap file`) + } + await onProgressUpdate({ value: 20, message: "Downloading .clap file.." }) + const res = await fetch(stringOrBlob) + stringOrBlob = await res.blob() + if (!stringOrBlob) { throw new Error("blob is empty") } + inputIsBlob = true + } catch (err) { + // url seems invalid + throw new Error(`failed to download the .clap file (${err})`) + } + } else { + if (debug) { + console.log("parseClap: input is a text string containing a YAML array") + } + inputYamlArrayString = stringOrBlob + inputIsBlob = false + } + } + + if (typeof stringOrBlob !== "string" && stringOrBlob) { + if (debug) { + console.log("parseClap: decompressing the blob..") + } + // Decompress the input blob using gzip + const decompressedStream = stringOrBlob.stream().pipeThrough(new DecompressionStream('gzip')) + + try { + // Convert the stream to text using a Response object + const decompressedOutput = new Response(decompressedStream) + // decompressedOutput.headers.set("Content-Type", "application/x-gzip") + if (debug) { + console.log("parseClap: decompressedOutput: ", decompressedOutput) + } + + await onProgressUpdate({ value: 30, message: "Decompressing .clap file.." }) + + // const blobAgain = await decompressedOutput.blob() + inputYamlArrayString = await decompressedOutput.text() + + if (debug && inputYamlArrayString) { + console.log("parseClap: successfully decompressed the blob!") + } + } catch (err) { + const message = `parseClap: failed to decompress (${err})` + console.error(message) + throw new Error(message) + } + } + + await onProgressUpdate({ value: 40, message: "Parsing .clap file.." }) + + // we don't need this anymore I think + // new Blob([inputStringOrBlob], { type: "application/x-yaml" }) + + let maybeArray: any = {} + try { + if (debug) { + console.log("parseClap: parsing the YAML array..") + } + // Parse YAML string to raw data + maybeArray = YAML.parse(inputYamlArrayString) + } catch (err) { + throw new Error("invalid clap file (input string is not YAML)") + } + + if (!Array.isArray(maybeArray) || maybeArray.length < 2) { + throw new Error("invalid clap file (need a clap format header block and project metadata block)") + } + + if (debug) { + console.log("parseClap: the YAML seems okay, continuing decoding..") + } + + + await onProgressUpdate({ value: 50, message: "Importing data from .clap file.." }) + + const maybeClapHeader = maybeArray[0] as ClapHeader + + if (maybeClapHeader.format !== ClapFormat.CLAP_0) { + throw new Error("invalid clap file (sorry, but you can't make up version numbers like that)") + } + + + const maybeClapMeta = maybeArray[1] as ClapMeta + + const clapMeta = sanitizeMeta(maybeClapMeta) + + /* + in case we want to support streaming (mix of entities and segments etc), we could do it this way: + + const maybeEntitiesOrSegments = rawData.slice(2) + maybeEntitiesOrSegments.forEach((unknownElement: any) => { + if (isValidNumber(unknownElement?.track)) { + maybeSegments.push(unknownElement as ClapSegment) + } else { + maybeEntities.push(unknownElement as ClapEntity) + } + }) + */ + + const expectedNumberOfWorkflows = maybeClapHeader.numberOfWorkflows || 0 + const expectedNumberOfEntities = maybeClapHeader.numberOfEntities || 0 + const expectedNumberOfScenes = maybeClapHeader.numberOfScenes || 0 + + // unused for now, but this can of information can be used by lower-level languages eg. C + const expectedNumberOfSegments = maybeClapHeader.numberOfSegments || 0 + + // note: we assume the order is strictly enforced! + // if you implement streaming (mix of entities and segments) you will have to rewrite this! + + const afterTheHeaders = 2 + + const afterTheWorkflows = afterTheHeaders + expectedNumberOfWorkflows + + const afterTheEntities = afterTheWorkflows + expectedNumberOfEntities + + const afterTheScenes = afterTheEntities + expectedNumberOfScenes + + // note: if there are no expected workflows, maybeWorkflows will be empty + const maybeWorkflows = maybeArray.slice(afterTheHeaders, afterTheWorkflows) as ClapWorkflow[] + + // note: if there are no expected entities, maybeEntities will be empty + const maybeEntities = maybeArray.slice(afterTheWorkflows, afterTheEntities) as ClapEntity[] + + // note: if there are no expected scenes, maybeScenes will be empty + const maybeScenes = maybeArray.slice(afterTheEntities, afterTheScenes) as ClapScene[] + + const maybeSegments = maybeArray.slice(afterTheScenes) as ClapSegment[] + + await onProgressUpdate({ value: 60, message: "Importing workflows from .clap file.." }) + const clapWorkflows = sanitizeWorkflows(maybeWorkflows) + + await onProgressUpdate({ value: 70, message: "Importing entities from .clap file.." }) + const clapEntities = sanitizeEntities(maybeEntities) + + await onProgressUpdate({ value: 80, message: "Importing scenes from .clap file.." }) + + const clapScenes: ClapScene[] = maybeScenes.map(({ + id, + scene, + line, + rawLine, + sequenceFullText, + sequenceStartAtLine, + sequenceEndAtLine, + startAtLine, + endAtLine, + events, + }) => ({ + id, + scene, + line, + rawLine, + sequenceFullText, + sequenceStartAtLine, + sequenceEndAtLine, + startAtLine, + endAtLine, + events: events.map(e => e) + })) + await onProgressUpdate({ value: 90, message: "Importing segments from .clap file.." }) + + const clapSegments: ClapSegment[] = maybeSegments.map(maybeSegment => { + const segment = sanitizeSegment(maybeSegment) + if (segment.endTimeInMs > clapMeta.durationInMs) { + clapMeta.durationInMs = segment.endTimeInMs + } + return segment + }) + + if (debug) { + console.log(`parseClap: successfully parsed ${clapWorkflows.length} workflows, ${clapEntities.length} entities, ${clapScenes.length} scenes and ${clapSegments.length} segments`) + } + + await onProgressUpdate({ value: 100, message: "Buiding entity index.." }) + + return { + meta: clapMeta, + workflows: clapWorkflows, + entities: clapEntities, + entityIndex: buildEntityIndex(clapEntities), + scenes: clapScenes, + segments: clapSegments + } +} diff --git a/packages/clap/src/io/serializeClap.ts b/packages/clap/src/io/serializeClap.ts new file mode 100644 index 0000000000000000000000000000000000000000..44378c4371a628acd611074f1db64e41e73205b6 --- /dev/null +++ b/packages/clap/src/io/serializeClap.ts @@ -0,0 +1,90 @@ +import YAML from "yaml" + +import { getValidNumber } from "@/utils/getValidNumber" + +import { ClapHeader, ClapMeta, ClapEntity, ClapProject, ClapScene, ClapSegment, ClapFormat, ClapWorkflow, ClapWorkflowEngine } from "@/types" +import { UUID } from "@/utils/uuid" +import { parseMediaOrientation } from "@/utils/parseMediaOrientation" +import { isValidNumber, parseWorkflowEngine } from "@/utils" +import { sanitizeWorkflows } from "@/sanitizers/sanitizeWorkflows" +import { sanitizeEntities } from "@/sanitizers/sanitizeEntities" +import { sanitizeSegments } from "@/sanitizers/sanitizeSegments" +import { sanitizeMeta } from "@/sanitizers/sanitizeMeta" + +export async function serializeClap({ + meta, // ClapMeta + workflows, // ClapWorkflow[] + entities, // ClapEntity[] + scenes, // ClapScene[] + segments, // ClapSegment[] +}: ClapProject): Promise { + + const clapWorkflows = sanitizeWorkflows(workflows) + const clapEntities = sanitizeEntities(entities) + + const clapScenes: ClapScene[] = scenes.map(({ + id, + scene, + line, + rawLine, + sequenceFullText, + sequenceStartAtLine, + sequenceEndAtLine, + startAtLine, + endAtLine, + events, + }) => ({ + id, + scene, + line, + rawLine, + sequenceFullText, + sequenceStartAtLine, + sequenceEndAtLine, + startAtLine, + endAtLine, + events: events.map(e => e) + })) + + const clapSegments = sanitizeSegments(segments) + + const clapHeader: ClapHeader = { + format: ClapFormat.CLAP_0, + numberOfWorkflows: isValidNumber(clapWorkflows?.length) ? clapWorkflows.length : 0, + numberOfEntities: isValidNumber(clapEntities.length) ? clapEntities.length : 0, + numberOfScenes: isValidNumber(clapScenes.length) ? clapScenes.length : 0, + numberOfSegments: isValidNumber(clapSegments.length) ? clapSegments.length : 0, + } + + const clapMeta = sanitizeMeta(meta) + + const entries = [ + clapHeader, + clapMeta, + ...clapWorkflows, + ...clapEntities, + ...clapScenes, + ...clapSegments + ] + + const strigifiedResult = YAML.stringify(entries) + + // Convert the string to a Blob + const blobResult = new Blob([strigifiedResult], { type: "application/x-yaml" }) + + // Create a stream for the blob + const readableStream = blobResult.stream() + + // Compress the stream using gzip + const compressionStream = new CompressionStream('gzip') + const compressedStream = readableStream.pipeThrough(compressionStream) + + // Create a new blob from the compressed stream + const response = new Response(compressedStream) + + response.headers.set("Content-Type", "application/x-gzip") + + const compressedBlob = await response.blob() + + return compressedBlob +} \ No newline at end of file diff --git a/packages/clap/src/io/updateClap.ts b/packages/clap/src/io/updateClap.ts new file mode 100644 index 0000000000000000000000000000000000000000..78fd61d7d1a061bcab1c9e9a746805799bcfaf1c --- /dev/null +++ b/packages/clap/src/io/updateClap.ts @@ -0,0 +1,138 @@ +import { ClapEntity, ClapProject, ClapScene, ClapSegment, ClapSegmentStatus } from "@/types" +import { newClap } from "@/factories/newClap" + +function clone(input: T): T { + try { + return JSON.parse(JSON.stringify(input)) + } catch (err) { + return input + } +} +/** + * This function takes two clap projects (an old and a newer one) and merge them. + * + * The most common use case is when we generate a Clap project in multiple steps, + * sending only partial results over the wire to preserve bandwidth and compute time. + * + * The new clap can either be partial (should be the preferred use case), or full. + * If the new clap is a full one, then you will get ID collions (overlapping). + + * A simple rule is used when that happen: newer content will overwrite older content. + * + * @param existingClap + * @param newerClap + */ +export async function updateClap(existingClap: ClapProject, newerClap: ClapProject, { + overwriteMeta = false, + inlineReplace = false +}: { + // Whether to overwrite the meta or not. Defaults to false. + overwriteMeta?: boolean + + // Whether to replace the existing clap "inline" or not. Defaults to false. + // + // true: the function will have side effects as the existing clap will be modified and returned + // false: the function will have no side effects, the existing clap will be untouched and instead a new object will be created. + // + // Depending on your code architecture or use case, + // you will either want the version with or without the side effects + // but keep in mind that Clap files can get large (in megabytes or even gigabytes) + // and you may have to switch to the inline mode for performance reasons + inlineReplace?: boolean +} = { + inlineReplace: false +}): Promise { + + const clap: ClapProject = inlineReplace ? existingClap : newClap() + + + // create some temporary indexes for faster checking + const existingEntityIndex: Record = {} + for (const entity of existingClap.entities) { + if (inlineReplace) { + existingEntityIndex[entity.id] = entity + } else { + clap.entities.push(existingEntityIndex[entity.id] = entity) + } + } + + const existingSceneIndex: Record = {} + for (const scene of existingClap.scenes) { + if (inlineReplace) { + existingSceneIndex[scene.id] = scene + } else { + clap.scenes.push(existingSceneIndex[scene.id] = scene) + } + } + + const existingSegmentIndex: Record = {} + for (const segment of existingClap.segments) { + if (inlineReplace) { + + existingSegmentIndex[segment.id] = segment + } else { + clap.segments.push(existingSegmentIndex[segment.id] = segment) + } + } + + // we replace all the data that is not "completed" + for (const entity of newerClap.entities) { + if (existingEntityIndex[entity.id]) { + // we only overwrite entities without a valid imageId or audioId + // otherwise during parallel execution, we would overwrite entities with old data + if (!existingEntityIndex[entity.id].imageId || !existingEntityIndex[entity.id].audioId) { + Object.assign(existingEntityIndex[entity.id], entity) + } + } else { + clap.entities.push(existingEntityIndex[entity.id] = entity) + } + } + + for (const scene of newerClap.scenes) { + if (existingSceneIndex[scene.id]) { + Object.assign(existingSceneIndex[scene.id], scene) + } else { + clap.scenes.push(existingSceneIndex[scene.id] = scene) + } + } + + for (const segment of newerClap.segments) { + if (existingSegmentIndex[segment.id]) { + // we only overwrite segments that are not completed + // otherwise we would have issue during parallel execution, + // older empty data would be used to update the segments + if (existingSegmentIndex[segment.id].status !== ClapSegmentStatus.COMPLETED) { + Object.assign(existingSegmentIndex[segment.id], segment) + } + + // note: sometimes a segment is marked as "completed" but is actually + // empty when it comes to the assetUrl.. that is perfectly fine! + // it just means that its value is held somewhere else, and that we shouldn't touch it + } else { + clap.segments.push(existingSegmentIndex[segment.id] = segment) + } + } + + // sort by ascending line + clap.scenes = clap.scenes.sort((a, b) => a.startAtLine - b.startAtLine) + + // sort by ascending start time + // in case of equivalent time (which happens a lot) we sort by ascending track number + clap.segments = clap.segments.sort((a, b) => { + if (a.startTimeInMs === b.startTimeInMs) { + return a.track - b.track + } else { + return a.startTimeInMs - b.startTimeInMs + } + }) + + // we re-create the entity index + // create some temporary indexes for faster checking + for (const entity of clap.entities) { + clap.entityIndex[entity.id] = entity + } + + clap.meta = overwriteMeta ? clone(newerClap.meta) : clone(existingClap.meta) + + return clap +} \ No newline at end of file diff --git a/packages/clap/src/samples/stories.ts b/packages/clap/src/samples/stories.ts new file mode 100644 index 0000000000000000000000000000000000000000..d1ebafc6e480a50e416ede5688a78f62628f3d30 --- /dev/null +++ b/packages/clap/src/samples/stories.ts @@ -0,0 +1,28 @@ +export const defaultSegmentDurationInMs = 2500 // 2584 + +export const fishDemoStory = [ + "Siamese fighting fish, bokeh, underwater, coral, lively, bubbles, translucency, perfect", + + // this one is magnificient! + "princess parrot fish, bokeh, underwater, coral, lively, bubbles, translucency, perfect", + + "pacific ocean perch, bokeh, underwater, coral, lively, bubbles, translucency, perfect", + + "Queen angelfish, bokeh, underwater, coral, lively, bubbles, translucency, perfect", + + "sea turtle, bokeh, underwater, coral, lively, bubbles, translucency, perfect", + + "hippocampus, bokeh, underwater, coral, lively, bubbles, translucency, perfect", +] + +export const demoStory = [ + ...fishDemoStory, + + // "portrait of one man news anchor, 60yo, thin, fit, american, mustache, beard, wearing a suit, medium-shot, central park, outside, serious, bokeh, perfect", + + // "screenshot from Call of Duty, FPS game, nextgen, videogame screenshot, unreal engine, raytracing, perfect", + + // "screenshot from a flight simulator, nextgen, videogame screenshot, unreal engine, raytracing, perfect", + // "screenshot from fallout3, fallout4, western, wasteland, 3rd person RPG, nextgen, videogame screenshot, unreal engine, raytracing, perfect", + // "portrait of single influencer woman, 30yo, thin, fit, american, wearing a red tshirt, medium-shot, central park, outside, serious, bokeh, perfect", +] diff --git a/packages/clap/src/sanitizers/index.ts b/packages/clap/src/sanitizers/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..df6b6bca330d100eac6964bb5b871820df32bd6d --- /dev/null +++ b/packages/clap/src/sanitizers/index.ts @@ -0,0 +1,7 @@ +export { sanitizeEntities } from "@/sanitizers/sanitizeEntities" +export { sanitizeEntity } from "@/sanitizers/sanitizeEntity" +export { sanitizeMeta } from "@/sanitizers/sanitizeMeta" +export { sanitizeSegment } from "@/sanitizers/sanitizeSegment" +export { sanitizeSegments } from "@/sanitizers/sanitizeSegments" +export { sanitizeWorkflow } from "@/sanitizers/sanitizeWorkflow" +export { sanitizeWorkflows } from "@/sanitizers/sanitizeWorkflows" \ No newline at end of file diff --git a/packages/clap/src/sanitizers/sanitizeEntities.ts b/packages/clap/src/sanitizers/sanitizeEntities.ts new file mode 100644 index 0000000000000000000000000000000000000000..ad84dfdabc89efd3ab90f13ec05a9319e201f708 --- /dev/null +++ b/packages/clap/src/sanitizers/sanitizeEntities.ts @@ -0,0 +1,6 @@ +import { ClapEntity } from "@/types"; +import { sanitizeEntity } from "@/sanitizers/sanitizeEntity"; + +export function sanitizeEntities(maybeEntities: ClapEntity[] = []): ClapEntity[] { + return maybeEntities.map(entity => sanitizeEntity(entity)) +} \ No newline at end of file diff --git a/packages/clap/src/sanitizers/sanitizeEntity.ts b/packages/clap/src/sanitizers/sanitizeEntity.ts new file mode 100644 index 0000000000000000000000000000000000000000..1b2734e5ddfc4330d6513645e382fd7e9589e9c6 --- /dev/null +++ b/packages/clap/src/sanitizers/sanitizeEntity.ts @@ -0,0 +1,54 @@ +import { ClapAssetSource, ClapEntity, ClapEntityAppearance, ClapEntityAudioEngine, ClapEntityGender, ClapEntityRegion } from "@/types"; +import { generateSeed, isValidNumber, parseSegmentCategory, UUID } from "@/utils"; + +export function sanitizeEntity({ + id, + category, + triggerName, + label, + description, + tags, + author, + thumbnailUrl, + seed, + imagePrompt, + imageSourceType, + imageEngine, + imageId, + audioPrompt, + audioSourceType, + audioEngine, + audioId, + age, + gender, + region, + appearance, + }: Partial = {}): ClapEntity { + return { + id: typeof id === "string" ? id : UUID(), + category: parseSegmentCategory(category), + triggerName: typeof triggerName === "string" ? triggerName : "", + label: typeof label === "string" ? label : "", + description: typeof description === "string" ? description : "", + tags: Array.isArray(tags) ? tags : [], + author: typeof author === "string" ? author : "", + thumbnailUrl: typeof thumbnailUrl === "string" ? thumbnailUrl : "", + seed: isValidNumber(seed) ? (seed || 0) : generateSeed(), + imagePrompt: typeof imagePrompt === "string" ? imagePrompt : "", + imageSourceType: typeof imageSourceType === "string" ? (imageSourceType as ClapAssetSource) : ClapAssetSource.EMPTY, + imageEngine: typeof imageEngine === "string" ? imageEngine : "", + imageId: typeof imageId === "string" ? imageId : "", + audioPrompt: typeof audioPrompt === "string" ? audioPrompt : "", + audioSourceType: typeof audioSourceType === "string" ? (audioSourceType as ClapAssetSource) : ClapAssetSource.EMPTY, + audioEngine: typeof audioEngine === "string" ? (audioEngine as ClapEntityAudioEngine) : "Parler-TTS", + audioId: typeof audioId === "string" ? audioId : "", + // those are only used by certain types of entities + age: isValidNumber(age) ? (age || 0) : 25, + + // TODO find a way to validate those, using lists + // TODO: we are going to use `variant: ClapEntityVariant` instead, which is gonna be an arbitrary string + gender: typeof gender === "string" ? (gender as ClapEntityGender) : "object", + region: typeof region === "string" ? (region as ClapEntityRegion) : "global", + appearance: typeof appearance === "string" ? (appearance as ClapEntityAppearance) : "neutral", + } +} \ No newline at end of file diff --git a/packages/clap/src/sanitizers/sanitizeMeta.ts b/packages/clap/src/sanitizers/sanitizeMeta.ts new file mode 100644 index 0000000000000000000000000000000000000000..59bc58d5ccb0fdfee2bf9b3583dd26dce2ac123d --- /dev/null +++ b/packages/clap/src/sanitizers/sanitizeMeta.ts @@ -0,0 +1,40 @@ +import { ClapMeta } from "@/types"; +import { getValidNumber, parseMediaOrientation, UUID } from "@/utils"; + +export function sanitizeMeta({ + id, + title, + description, + synopsis, + licence, + tags, + thumbnailUrl, + orientation, + durationInMs, + width, + height, + defaultVideoModel, + extraPositivePrompt, + screenplay, + isLoop, + isInteractive, +}: Partial = {}): ClapMeta { + return { + id: typeof id === "string" ? id : UUID(), + title: typeof title === "string" ? title : "", + description: typeof description === "string" ? description : "", + synopsis: typeof synopsis === "string" ? synopsis : "", + licence: typeof licence === "string" ? licence : "", + tags: Array.isArray(tags) ? tags : [], + thumbnailUrl: typeof thumbnailUrl === "string" ? thumbnailUrl : "", + orientation: parseMediaOrientation(orientation), + durationInMs: getValidNumber(durationInMs, 1000, Number.MAX_SAFE_INTEGER, 4000), + width: getValidNumber(width, 128, 8192, 1024), + height: getValidNumber(height, 128, 8192, 576), + defaultVideoModel: typeof defaultVideoModel === "string" ? defaultVideoModel : "SVD", + extraPositivePrompt: Array.isArray(extraPositivePrompt) ? extraPositivePrompt : [], + screenplay: typeof screenplay === "string" ? screenplay : "", + isLoop: typeof isLoop === "boolean" ? isLoop : false, + isInteractive: typeof isInteractive === "boolean" ? isInteractive : false, + } +} \ No newline at end of file diff --git a/packages/clap/src/sanitizers/sanitizeSegment.ts b/packages/clap/src/sanitizers/sanitizeSegment.ts new file mode 100644 index 0000000000000000000000000000000000000000..852d7a65fbf755303bc78c314e07e174872397a7 --- /dev/null +++ b/packages/clap/src/sanitizers/sanitizeSegment.ts @@ -0,0 +1,58 @@ +import { ClapAssetSource, ClapOutputType, ClapSegment, ClapSegmentStatus } from "@/types" +import { generateSeed, isValidNumber, parseOutputType, parseSegmentCategory, UUID } from "@/utils" + +export function sanitizeSegment({ + id, + track, + startTimeInMs, + endTimeInMs, + category, + entityId, + workflowId, + sceneId, + startTimeInLines, + endTimeInLines, + prompt, + label, + outputType, + renderId, + status, + assetUrl, + assetDurationInMs, + assetSourceType, + assetFileFormat, + revision, + createdAt, + createdBy, + editedBy, + outputGain, + seed, + }: Partial = {}): ClapSegment { + return { + id: typeof id === "string" ? id : UUID(), + track: isValidNumber(track) ? (track || 0) : 0, + startTimeInMs: isValidNumber(startTimeInMs) ? (startTimeInMs || 0) : 0, + endTimeInMs: isValidNumber(assetDurationInMs) ? (endTimeInMs || 0) : 0, + category: parseSegmentCategory(category), + entityId: typeof entityId === "string" ? entityId : "", + workflowId: typeof workflowId === "string" ? workflowId : "", + sceneId: typeof sceneId === "string" ? sceneId : "", + startTimeInLines: isValidNumber(startTimeInLines) ? (startTimeInLines || 0) : 0, + endTimeInLines: isValidNumber(endTimeInLines) ? (endTimeInLines || 0) : 0, + prompt: typeof prompt === "string" ? prompt : "", + label: typeof label === "string" ? label : "", + outputType: parseOutputType(outputType, ClapOutputType.TEXT), + renderId: typeof renderId === "string" ? renderId : "", + status: typeof status === "string" ? status : ClapSegmentStatus.TO_GENERATE, + assetUrl: typeof assetUrl === "string" ? assetUrl : "", + assetDurationInMs: isValidNumber(assetDurationInMs) ? (assetDurationInMs || 0) : 0, + assetSourceType: typeof assetSourceType === "string" ? assetSourceType : ClapAssetSource.EMPTY, + assetFileFormat: typeof assetFileFormat === "string" ? assetFileFormat : "", + revision: isValidNumber(revision) ? (revision || 0) : 0, + createdAt: typeof createdAt === "string" ? createdAt : new Date().toISOString(), + createdBy: typeof createdBy === "string" ? createdBy : "ai", + editedBy: typeof editedBy === "string" ? editedBy : "ai", + outputGain: isValidNumber(outputGain) ? (outputGain || 0) : 0, + seed: isValidNumber(seed) ? (seed || 0) : generateSeed() + } +} \ No newline at end of file diff --git a/packages/clap/src/sanitizers/sanitizeSegments.ts b/packages/clap/src/sanitizers/sanitizeSegments.ts new file mode 100644 index 0000000000000000000000000000000000000000..e9bafcc4390676ca8b3ae590f602ad2841d98d92 --- /dev/null +++ b/packages/clap/src/sanitizers/sanitizeSegments.ts @@ -0,0 +1,6 @@ +import { ClapSegment } from "@/types"; +import { sanitizeSegment } from "@/sanitizers/sanitizeSegment"; + +export function sanitizeSegments(maybeSegments: ClapSegment[] = []): ClapSegment[] { + return maybeSegments.map(segment => sanitizeSegment(segment)) +} \ No newline at end of file diff --git a/packages/clap/src/sanitizers/sanitizeWorkflow.ts b/packages/clap/src/sanitizers/sanitizeWorkflow.ts new file mode 100644 index 0000000000000000000000000000000000000000..6bdc8355f2cdb289c6f780a7fe5a61273188f7a9 --- /dev/null +++ b/packages/clap/src/sanitizers/sanitizeWorkflow.ts @@ -0,0 +1,32 @@ +import { ClapWorkflow, ClapWorkflowCategory, ClapWorkflowEngine, ClapWorkflowProvider } from "@/types"; +import { parseWorkflowCategory, parseWorkflowEngine, parseWorkflowProvider, UUID } from "@/utils"; + +export function sanitizeWorkflow({ + id, + label, + description, + tags, + author, + thumbnailUrl, + engine, + category, + provider, + data, + inputFields, + inputValues, + }: Partial = {}): ClapWorkflow { + return { + id: typeof id === "string" ? id : UUID(), + label: typeof label === "string" ? label : "", + description: typeof description === "string" ? description : "", + tags: Array.isArray(tags) ? tags : [], + author: typeof author === "string" ? author : "", + thumbnailUrl: typeof thumbnailUrl === "string" ? thumbnailUrl : "", + engine: parseWorkflowEngine(engine, ClapWorkflowEngine.DEFAULT), + category: parseWorkflowCategory(category, ClapWorkflowCategory.IMAGE_GENERATION), + provider: parseWorkflowProvider(provider, ClapWorkflowProvider.NONE), + data: typeof data === "string" ? data : "", + inputFields: Array.isArray(inputFields) ? inputFields : [], + inputValues: typeof inputValues === "object" ? inputValues : {}, + } +} \ No newline at end of file diff --git a/packages/clap/src/sanitizers/sanitizeWorkflows.ts b/packages/clap/src/sanitizers/sanitizeWorkflows.ts new file mode 100644 index 0000000000000000000000000000000000000000..ee70c018cfaafe21415e8bacc5c075495c64316c --- /dev/null +++ b/packages/clap/src/sanitizers/sanitizeWorkflows.ts @@ -0,0 +1,6 @@ +import { ClapWorkflow } from "@/types"; +import { sanitizeWorkflow } from "@/sanitizers/sanitizeWorkflow"; + +export function sanitizeWorkflows(maybeWorkflows: ClapWorkflow[] = []): ClapWorkflow[] { + return maybeWorkflows.map(workflow => sanitizeWorkflow(workflow)) +} \ No newline at end of file diff --git a/packages/clap/src/types.ts b/packages/clap/src/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..079e207755b47ef2f14938f60962fdcabf94b807 --- /dev/null +++ b/packages/clap/src/types.ts @@ -0,0 +1,829 @@ +export enum ClapFormat { + CLAP_0 = "clap-0", + + // current active version, where some enums have uppercased, + // and some extract things added + CLAP_0b = "clap-0b", +} + +export enum ClapSegmentCategory { + // a 3D Gaussian Splatting object (eg. a .splatv) + SPLAT = "SPLAT", + + // a 3D mesh object + MESH = "MESH", + + // a depth map + DEPTH = "DEPTH", + + // a transformative effect and/or filter to apply to an input + // eg. upscaling, face swap.. + EFFECT = "EFFECT", + + // a event happening in the scene + EVENT = "EVENT", + + // a user interface element, such as an overlay or caption, or HTML content + INTERFACE = "INTERFACE", + + // a phenomenom triggering changes in the scene + PHENOMENON = "PHENOMENON", + + // a video clip, eg. mp4 or webm + // it is strongly recommended to use an open and royalty-free codec such as VP9, + // otherwise some web browsers might not be able to display it + VIDEO = "VIDEO", + + // a storyboard image, eg. jpg, png, webp, heic (note: most of the apps compatible with .clap prefer to work with jpg and png) + STORYBOARD = "STORYBOARD", + + // a transition between two shots (eg. a cross-fade) + TRANSITION = "TRANSITION", + + // a character (person, animal, alien, robot, walking skeleton..) + CHARACTER = "CHARACTER", + + // a location (indoor or outdoor eg. a house, castle, garden..) + LOCATION = "LOCATION", + + // the absolute time where the action takes place + // + // this can be anything that a language model or stable diffusion model can interpret, eg: + // eg. "today at 12am", "2024-01-01", "contemporary times, in the morning", "14th century, in the afternoon", 1960, "AB 31, 11pm", "20 BC" + // + // ideally you should use a date formatting indicating the hour and timezone (if your LLM can understand those) + // that way it will be possible to automatically determine if it's day or night! + TIME = "TIME", + + // @deprecated - we should use TIME instead + ERA = "ERA", + + // how to lit the scene, colors, angles etc + LIGHTING = "LIGHTING", + + // weather conditions in the scene (raining, sunny, cloudy, morning mist..) + WEATHER = "WEATHER", + + // direct description of what is happening in the scene ("people talking", "bus passing by", "putting down the glass") + ACTION = "ACTION", + + // some music + // like for all segments you can either give a prompt and/or work with an actual file (in the case mp3 or wav) + MUSIC = "MUSIC", + + // some sound + // eg. "dog barking", "foot steps", "crowded bar" + SOUND = "SOUND", + + // a dialogue line + // either the transcript and/or the generated TTS line + DIALOGUE = "DIALOGUE", + + // a specific style to apply + // "cinematic", "1950s comic book", "Panavision 70 mm" + STYLE = "STYLE", + + // type of shot eg "medium-shot", aperture, ISO.. + CAMERA = "CAMERA", + + // ..anything else, from prompt to arbitrary/custom/obscure file format + // + // however if you have a special demand, something that could be popular and not too niche, + // we can turn it into its own category + GENERIC = "GENERIC" +} + +export enum ClapMediaOrientation { + LANDSCAPE = "LANDSCAPE", + PORTRAIT = "PORTRAIT", + SQUARE = "SQUARE" +} + +export enum ClapOutputType { + // a plain text + TEXT = "TEXT", + + // an animation + ANIMATION = "ANIMATION", + + // UI element + INTERFACE = "INTERFACE", + + // event + EVENT = "EVENT", + + PHENOMENON = "PHENOMENON", + + TRANSITION = "TRANSITION", + + // image asset + IMAGE = "IMAGE", + + // image segmentation layer + IMAGE_SEGMENTATION = "IMAGE_SEGMENTATION", + + // image depthmap layer + IMAGE_DEPTH = "IMAGE_DEPTH", + + // video asset + VIDEO = "VIDEO", + + // video segmentation layer + VIDEO_SEGMENTATION = "VIDEO_SEGMENTATION", + + // image depthmap layer + VIDEO_DEPTH = "VIDEO_DEPTH", + + // audio asset + AUDIO = "AUDIO" +} + +export enum ClapSegmentStatus { + TO_GENERATE = "TO_GENERATE", + IN_PROGRESS = "IN_PROGRESS", + TO_INTERPOLATE = "TO_INTERPOLATE", + TO_UPSCALE = "TO_UPSCALE", + COMPLETED = "COMPLETED", + ERROR = "ERROR", +} + +export type ClapAuthor = + | "auto" // the element was edited automatically using basic if/else logical rules + | "ai" // the element was edited using a large language entity + | "human" // the element was edited by a human + | string + +export enum ClapAssetSource { + REMOTE = "REMOTE", // http:// or https:// + + // note that "path" assets are potentially a security risk, they need to be treated with care + PATH = "PATH", // a file path eg. /path or ./path/to/ or ../path/to/ + + DATA = "DATA", // a data URI, starting with data: + + PROMPT = "PROMPT", // by default, a plain text prompt + + EMPTY = "EMPTY" +} + +// @deprecated we are going to use ClapEntityVariant (see below) +export type ClapEntityGender = + | "male" + | "female" + | "person" + | "object" + | string + +// an arbitrary physical description +export type ClapEntityVariant = string + +// @deprecated - we are going to use the ClapEntityVariant instead +export type ClapEntityAppearance = + | "serious" + | "neutral" + | "friendly" + | "chill" + | string + +// this is used for accent, style.. +export type ClapEntityRegion = + | "global" + | "american" + | "european" + | "british" + | "australian" + | "canadian" + | "indian" + | "french" + | "italian" + | "german" + | "chinese" + | string + +// note: this is all very subjective, so please use good judgment +// +// "deep" might indicate a deeper voice tone, thicker, rich in harmonics +// in this context, it is used to indicate voices that could +// be associated with African American (AADOS) characters +// +// "high" could be used for some other countries, eg. asia +export type ClapEntityTimbre = "high" | "neutral" | "deep" + +export type ClapEntityAudioEngine = + | "ElevenLabs" + | "XTTS" + | "Parler-TTS" + | "OpenVoice" + | string + +export enum ClapSegmentFilteringMode { + // the start of a segment must be within the range + START, + + // the end of a segment must be within the range + END, + + // any end of a segment must be within the range + ANY, + + // both ends of a segment must be within the range + BOTH, +} + +export type ClapVoice = { + name: string + gender: ClapEntityGender + age: number + region: ClapEntityRegion + timbre: ClapEntityTimbre + appearance: ClapEntityAppearance + audioEngine: ClapEntityAudioEngine + audioId: string +} + +export type ClapHeader = { + format: ClapFormat + numberOfWorkflows: number + numberOfEntities: number + numberOfScenes: number + numberOfSegments: number +} + +export type ClapMeta = { + id: string + title: string + description: string + synopsis: string + licence: string + + /** + * List of keywords used to describe the project. + * + * Examples: action, sci-fi, romance, advert, music video, + */ + tags: string[] + + /** + * A thumbnail representing the project. + * + * Can be hosted on a remote server or in base64 + */ + thumbnailUrl: string + + orientation: ClapMediaOrientation + + // the default duration of the experience + // the real one might last longer if made interactive + durationInMs: number + + width: number + height: number + defaultVideoModel: string + extraPositivePrompt: string[] + screenplay: string + isLoop: boolean + isInteractive: boolean +} + +export type ClapSceneEvent = { + id: string + type: "description" | "dialogue" | "action" + character?: string + description: string + behavior: string + startAtLine: number + endAtLine: number +} + +export type ClapScene = { + id: string + scene: string + line: string + rawLine: string + sequenceFullText: string + sequenceStartAtLine: number + sequenceEndAtLine: number + startAtLine: number + endAtLine: number + events: ClapSceneEvent[] +} + +export type ClapSegment = { + id: string + track: number // usually track 0 is the video, track 1 is the storyboard, track 2 is the camera + startTimeInMs: number + endTimeInMs: number + category: ClapSegmentCategory + + /** + * ID of the entity attached to the segment + * + * This allows segments of different nature (image, voice) to be attached to the same or different entities. + * + * Eg. video of character A but voice of character B + * + * If you want multiple entities, you can add multiple segments. + */ + entityId: string + + /** + * ID of the workflow to use for the segment + * + * This is optional (empty string by default) + * + * If unspecified, a default workflow will be used + */ + workflowId: string + + /** + * Id of the scene to which the segment is attached + * + * This is optional (empty string by default) + */ + sceneId: string + + /** + * Statring line number to which the segment is attached + * + * This is optional (empty string by default) + */ + startTimeInLines: number + + /** + * Ending line number to which the segment is attached + * + * This is optional (empty string by default) + */ + endTimeInLines: number + + /** + * + */ + prompt: string + + /** + * Human-readable label to showfor this segment. + * + * Should be kept short. + */ + label: string + + outputType: ClapOutputType + + /** + * Id of an external rendering job to which this segment could be attached. + * + * This is optional (empty string by default) + * + * It is possible that this field gets removed in the future, + * and instead moved to TimelineSegment + */ + renderId: string + + /** + * Status of the segment (is it generated, to generate etc) + */ + status: ClapSegmentStatus + + /** + * The value of the segment, ie. the data + * + * It can come from the output of a workflow. + * + * This can be either a link to a remotely hosted resource, + * a file path or a data URI (base64) + * + * I recommend the data URI for small projects, + * as the other modes create additional complexity + * (manage a cloud, access rights, deletes, downloads etc) + */ + assetUrl: string + + /** + * The duration of the asset itself. + * + * This might be different from the segment itself, + * for instance if the asset has a zero length (a storyboard), + * or if the asset is longer (eg. a cropped audio file) + */ + assetDurationInMs: number + assetSourceType: ClapAssetSource + assetFileFormat: string + + // when was the segment created + createdAt: string + + createdBy: ClapAuthor + + // clap segment default: 0) + revision: number + + editedBy: ClapAuthor + + /** + * The volume of the segment + */ + outputGain: number + + /** + * The seed used to generate the asset data/value. + * + * This is mostly used fo tracking changes, + * and reproduce result + */ + seed: number +} + +export type ClapInputFieldNumber = { + type: 'number' + minValue: number + maxValue: number + defaultValue: number +} + +export type ClapInputFieldInteger = { + type: 'integer' + minValue: number + maxValue: number + defaultValue: number +} + +export type ClapInputFieldString = { + type: 'string' + allowedValues: string[] + defaultValue: string +} + +export type ClapInputFieldBoolean = { + type: 'boolean' + defaultValue: boolean +} + +export type ClapInputFieldAny = { + type: 'any' + defaultValue: any +} + +export type ClapInputField = { + /** + * Machine readable input field name or identifier + */ + id: string + + /** + * Human-readable input field name + */ + label: string + + /** + * Description of what the input field does + */ + description: string +} & ( + | ClapInputFieldNumber + | ClapInputFieldInteger + | ClapInputFieldString + | ClapInputFieldBoolean + | ClapInputFieldAny +) + +export type ClapInputFields = ClapInputField[] + +export type ClapInputValue = + number | string | boolean | string[] | number[] | null | undefined + +export type ClapInputValues = + Record + + +export enum ClapWorkflowProvider { + NONE = "NONE", + BUILTIN = "BUILTIN", + CUSTOM = "CUSTOM", + COMFYUI = "COMFUI", // any ComfyUI server (local or remote) + AITUBE = "AITUBE", // https://aitube.at + HUGGINGFACE = "HUGGINGFACE", // https://huggingface.co + REPLICATE = "REPLICATE", // https://replicate.com + COMFYDEPLOY = "COMFYDEPLOY", // https://comfydeploy.com + COMFYICU = "COMFYICU", // https://comfy.icu + ELEVENLABS = "ELEVENLABS", // https://elevenlabs.io + KITSAI = "KITSAI", // https://kits.ai + OPENAI = "OPENAI", // https://openai.com + STABILITYAI = "STABILITYAI", // https://stability.ai + FIREWORKSAI = "FIREWORKSAI", // https://fireworks.ai + GROQ = "GROQ", // https://groq.com + ANTHROPIC = "ANTHROPIC", // https://anthropic.com + GOOGLE = "GOOGLE", // https://google.com (in case you didn't know) + MISTRALAI = "MISTRALAI", // https://mistral.ai + COHERE = "COHERE", // https://cohere.com + FALAI = "FALAI", // https://fal.ai + MODELSLAB = "MODELSLAB", // https://modelslab.com + MIDJOURNEY = "MIDJOURNEY", + SUNO = "SUNO", + UDIO = "UDIO", + LUMALABS = "LUMALABS", + KUAISHOU = "KUAISHOU", + RUNWAYML = "RUNWAYML", + HEDRA = "HEDRA", + LEONARDOAI = "LEONARDOAI", + EVERARTAI = "EVERARTAI", +} + + +// note: it could be argued that image filtering and upscaling +// are both subsets of the same general concept of "image to image" +// and.. yes, that's true! +// there are only separated for convenient, to add some semantic +// to those abstract image-to-image models. +export enum ClapWorkflowCategory { + ASSISTANT = "ASSISTANT", + IMAGE_GENERATION = "IMAGE_GENERATION", + IMAGE_FILTERING = "IMAGE_FILTERING", + IMAGE_UPSCALING = "IMAGE_UPSCALING", + IMAGE_DEPTH_MAPPING = "IMAGE_DEPTH_MAPPING", + IMAGE_SEGMENTATION = "IMAGE_SEGMENTATION", + MUSIC_GENERATION = "MUSIC_GENERATION", + SOUND_GENERATION = "SOUND_GENERATION", + VOICE_GENERATION = "VOICE_GENERATION", + VIDEO_GENERATION = "VIDEO_GENERATION", + VIDEO_FILTERING = "VIDEO_FILTERING", + VIDEO_UPSCALING = "VIDEO_UPSCALING", + VIDEO_DEPTH_MAPPING = "VIDEO_DEPTH_MAPPING", + VIDEO_SEGMENTATION = "VIDEO_SEGMENTATION", +} + +export enum ClapWorkflowEngine { + // the default pipeline (can be anything, this is left to the app developer) + DEFAULT = "DEFAULT", + + REST_API = "REST_API", + + GRADIO_API = "GRADIO_API", + + // for any API that natively accepts OpenClap + OPENCLAP = "OPENCLAP", + + // the JSON format used by ComfyUI + COMFYUI_WORKFLOW = "COMFYUI_WORKFLOW", + + // the proprietary format used by Fal.ai + // Fal.ai also supports ComfyUI workflows, but this is separate + FALAI_WORKFLOW = "FALAI_WORKFLOW", + + // the proprietary format used by Glif + // Glif also supports ComfyUI workflows, but as part of a Glif workflow + GLIF_WORKFLOW = "GLIF_WORKFLOW", + + // the format used by Google Visual Blocks + // this is a new and experimental tool, usage is limited for now, + // I think it can be used in a Colab only and there are now API + VISUALBLOCKS_WORKFLOW = "VISUALBLOCKS_WORKFLOW" +} + +export type ClapWorkflow = { + id: string + + /** + * Human-readable label (this is the name or title of the workflow) + */ + label: string + + /** + * Long description of what the workflow is about. + */ + description: string + + /** + * List of keywords used to describe the workflow. + * + * Examples: upscaling, lip-sync, body animation, text-to-video.. + */ + tags: string[] + + /** + * The original author of the workflow + * + * Can be a name, email, social media handle.. + */ + author: string + + /** + * A thumbnail representing the workflow. + * + * Can be hosted on a remote server or in base64 + * (we could use a "ClapAssetSource" here too, but the thumbnail is not + * used within a workflow so there is no need to do any kind of precise optimization or verification here) + */ + thumbnailUrl: string + + engine: ClapWorkflowEngine + + category: ClapWorkflowCategory + + provider: ClapWorkflowProvider + + /** + * The workflow data itself + * + * This is typically a serialized JSON, although this can be other things + * depending on which engine is used (YAML, base64, or even an ID to a proprietary commercial platform) + */ + data: string + + /** + * Inputs of the workflow (this is used to build an UI for the automatically) + */ + inputFields: ClapInputFields + + /** + * Default values (this is used to initialize the workflow automatically) + */ + inputValues: ClapInputValues +} + +export type ClapEntity = { + id: string + category: ClapSegmentCategory + + /** + * keyword referencing the entity within a screenplay + * + * Typically in UPPERCASE + */ + triggerName: string + + /** + * Human-readable label (this is the name or title of the entity) + */ + label: string + + /** + * Long description of what the entity is about. + * + * This can be for instance a short history or biography of the entity. + */ + description: string + + /** + * List of keywords used to describe the entity. + * + * Examples: location, character, male, female, car.. + */ + tags: string[] + + /** + * The original author of the entity + * + * Can be a name, email, social media handle.. + */ + author: string + + /** + * A thumbnail representing the entity. + * + * Can be hosted on a remote server or in base64 + * (we could use a "ClapAssetSource" here too, but the thumbnail is not + * used within a workflow so there is no need to do any kind of precise optimization or verification here) + */ + thumbnailUrl: string + + /** + * The seed associated with the entity. + * + * This can be used to reproduce the settings (eg. reproduce the image + * from the image prompt, by re-using the same seed) + */ + seed: number + + /** + * Text prompt describing the appearance of the entity + */ + imagePrompt: string + + /** + * Where the image is hosted (remote, local file etc) + */ + imageSourceType: ClapAssetSource + + /** + * Can be used to tell the model used to generate the engine (eg. SDXL, Dalle-3) + */ + imageEngine: string + + /** + * The "identity picture" of the entity + * + * if this is too confusing to people, we can rename it + * + * this is a regular URI so, it can be a file path, a remote url, a base64.. + */ + imageId: string + + + /** + * Text prompt describing the voice + * + * Eg. "low quality phone recording of an old man" + */ + audioPrompt: string + + /** + * Where the audio is hosted (remote, local file etc) + */ + audioSourceType: ClapAssetSource + + /** + * The engine used to generate the audio + * + * This is important as this impacts what is the vendor and type audioId + */ + audioEngine: ClapEntityAudioEngine + + /** + * The voice identity (the "identity picture" equivalent of the voice) + * + * Depending on the engine, this can be a voice sample or an ID to a 3rd party proprietary platform + */ + audioId: string + + // could be replaced by an inceptionDate, so it can be used to compute the absolute "age" of anything: + // a pyramid, a person, a spaceship.. + // maybe also with a destructionDate + age: number + + // @deprecated TODO: we are going to use `variant: ClapEntityVariant` instead, which is gonna be an arbitrary string + // + // thay way clap entities could be used for inanimate or fantastic entities like: + // buildings, vehicles, robots, animals, people, aliens.. + // (anything that needs visual and audio consistency) + // @deprecated + gender: ClapEntityGender + + // we can keep this, this is generic enough + // ClapEntityRegion should be renamed to ClapEntityRegion + region: ClapEntityRegion + + // @deprecated TODO: we are going to use `variant: ClapEntityVariant` instead, which is gonna be an arbitrary string + appearance: ClapEntityAppearance +} + +export type ClapTrack = { + id: number + name: string + isPreview: boolean + height: number + hue: number + occupied: boolean + visible: boolean +} + +export type ClapTracks = ClapTrack[] + +export type ClapProject = { + meta: ClapMeta + workflows: ClapWorkflow[] + entities: ClapEntity[] + entityIndex: Record + scenes: ClapScene[] + segments: ClapSegment[] + // let's keep room for other stuff (screenplay etc) +} + +export enum ClapCompletionMode { + /** + * the API and the client will return a full clap file. + * This is a very convenient and simple mode, but it is also very ineficient, + * so it should not be used for intensive applications. + */ + FULL = "FULL", + + /** + * the API and the client will return a partial clap file containing only the changes, + * containing only the new values and changes. + * This is useful for real-time applications and streaming. + */ + PARTIAL = "PARTIAL", + + /** + * the API will return a partial clap file containing only the changes, + * and the client will return a merge of the original with the new values. + * This is safe to run, there are no side-effects. + */ + MERGE = "MERGE", + + /** + * the API will return a partial clap file, and the client will replace the original. + * This is the most efficient mode, but it relies on side-effects and inline object updates. + */ + REPLACE = "REPLACE" +} + +export type ParseClapProgressUpdate = ({ + value, + sleepDelay, + message +}: { + value: number + sleepDelay?: number + message?: string +}) => Promise diff --git a/packages/clap/src/utils/filterSegments.ts b/packages/clap/src/utils/filterSegments.ts new file mode 100644 index 0000000000000000000000000000000000000000..336dd29164d153815e37566484c66b4cb39fff15 --- /dev/null +++ b/packages/clap/src/utils/filterSegments.ts @@ -0,0 +1,39 @@ +import { ClapSegment, ClapSegmentCategory, ClapSegmentFilteringMode } from "@/types" +import { filterSegmentsWithinRange } from "@/utils/filterSegmentsWithinRange" + +/** + * Return all the segments within the provided reference segment, for the given mode: + * + * - START: the start of a segment must be within the provided segment's range + * - END: the end of a segment must be within the provided segment's range + * - ANY: any end of a segment must be within the provided segment's range + * - BOTH: both ends of a segment must be within the provided segment's range + * + * Note: we use a loose definition for the input segment, + * to get a bit more flexibility + * + * @param mode + * @param segment + * @param segments + * @param category optional, to also filter by category + * @returns + */ +export function filterSegments( + mode: ClapSegmentFilteringMode, + segment?: { + startTimeInMs: number + endTimeInMs: number + category?: ClapSegmentCategory + }, + segments?: ClapSegment[], + category?: ClapSegmentCategory +): ClapSegment[] { + + const array = Array.isArray(segments) ? segments : [] + + if (!segment || !array.length) { return [] } + + const { startTimeInMs, endTimeInMs } = segment + + return filterSegmentsWithinRange(mode, startTimeInMs, endTimeInMs, segments, category) +} \ No newline at end of file diff --git a/packages/clap/src/utils/filterSegmentsWithinRange.ts b/packages/clap/src/utils/filterSegmentsWithinRange.ts new file mode 100644 index 0000000000000000000000000000000000000000..f1f319ef21a7331995a6b1dd2f4e99ff911451c5 --- /dev/null +++ b/packages/clap/src/utils/filterSegmentsWithinRange.ts @@ -0,0 +1,49 @@ +import { ClapSegment, ClapSegmentCategory, ClapSegmentFilteringMode } from "@/types" + +/** + * Return all the segments within the provided range, for the given mode: + * + * - START: the start of a segment must be within the range + * - END: the end of a segment must be within the range + * - ANY: any *PART* of a segment must be within the range + * - BOTH: both ends of a segment must be within the range + * + * Note: this is a strict inclusion + * + * @param mode + * @param startTimeInMs + * @param endTimeInMs + * @param segments + * @param category optional, to also filter by category + * @returns + */ +export function filterSegmentsWithinRange( + mode: ClapSegmentFilteringMode, + startTimeInMs: number, + endTimeInMs: number, + segments?: ClapSegment[], + category?: ClapSegmentCategory +): ClapSegment[] { + + const array = Array.isArray(segments) ? segments : [] + + if (!array.length) { return [] } + + switch (mode) { + case ClapSegmentFilteringMode.START: + return array.filter(s => (startTimeInMs <= s.startTimeInMs && s.startTimeInMs < endTimeInMs) && ((category && s?.category) ? s.category === category : true)) + case ClapSegmentFilteringMode.END: + return array.filter(s => (startTimeInMs < s.endTimeInMs && s.endTimeInMs <= endTimeInMs) && ((category && s?.category) ? s.category === category : true)) + case ClapSegmentFilteringMode.BOTH: + return array.filter(s => (startTimeInMs <= s.startTimeInMs && s.endTimeInMs <= endTimeInMs) && ((category && s?.category) ? s.category === category : true)) + case ClapSegmentFilteringMode.ANY: + return array.filter(s => ( + // we keep if we ARE NOT out of bound + !(s.endTimeInMs <= startTimeInMs || s.startTimeInMs >= endTimeInMs) + + && ((category && s?.category) ? s.category === category : true) + )) + default: + throw new Error(`unknown ClapSegmentFilteringMode "${mode}"`) + } +} \ No newline at end of file diff --git a/packages/clap/src/utils/generateSeed.ts b/packages/clap/src/utils/generateSeed.ts new file mode 100644 index 0000000000000000000000000000000000000000..563e25ec894ab5af54c5025a15a9b7a5918325de --- /dev/null +++ b/packages/clap/src/utils/generateSeed.ts @@ -0,0 +1,3 @@ +export function generateSeed() { + return Math.floor(Math.random() * Math.pow(2, 31)); +} \ No newline at end of file diff --git a/packages/clap/src/utils/getClapAssetSourceType.ts b/packages/clap/src/utils/getClapAssetSourceType.ts new file mode 100644 index 0000000000000000000000000000000000000000..ff5f146a31256a31decfa3f12ca084ebdc69edaa --- /dev/null +++ b/packages/clap/src/utils/getClapAssetSourceType.ts @@ -0,0 +1,25 @@ +import { ClapAssetSource } from "@/types" + +export function getClapAssetSourceType(input: string = ""): ClapAssetSource { + + const str = `${input || ""}`.trim() + + if (!str || !str.length) { + return ClapAssetSource.EMPTY + } + + if (str.startsWith("https://") || str.startsWith("http://")) { + return ClapAssetSource.REMOTE + } + + // note that "path" assets are potentially a security risk, they need to be treated with care + if (str.startsWith("/") || str.startsWith("../") || str.startsWith("./")) { + return ClapAssetSource.PATH + } + + if (str.startsWith("data:")) { + return ClapAssetSource.DATA + } + + return ClapAssetSource.PROMPT +} \ No newline at end of file diff --git a/packages/clap/src/utils/getValidNumber.ts b/packages/clap/src/utils/getValidNumber.ts new file mode 100644 index 0000000000000000000000000000000000000000..841fc4afab03b33fbc6e6349b41d9099a3073cb3 --- /dev/null +++ b/packages/clap/src/utils/getValidNumber.ts @@ -0,0 +1,10 @@ +export const getValidNumber = (something: any, minValue: number, maxValue: number, defaultValue: number) => { + const strValue = `${something || defaultValue}` + const numValue = Number(strValue) + const isValid = !isNaN(numValue) && isFinite(numValue) + if (!isValid) { + return defaultValue + } + return Math.max(minValue, Math.min(maxValue, numValue)) + +} \ No newline at end of file diff --git a/packages/clap/src/utils/index.ts b/packages/clap/src/utils/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..0136dbf236bfe7e001f01284baaece072399774b --- /dev/null +++ b/packages/clap/src/utils/index.ts @@ -0,0 +1,14 @@ +export { filterSegments } from '@/utils/filterSegments' +export { filterSegmentsWithinRange } from '@/utils/filterSegmentsWithinRange' +export { generateSeed } from '@/utils/generateSeed' +export { getClapAssetSourceType } from '@/utils/getClapAssetSourceType' +export { getValidNumber } from '@/utils/getValidNumber' +export { isValidNumber } from '@/utils/isValidNumber' +export { parseMediaOrientation } from '@/utils/parseMediaOrientation' +export { parseOutputType } from '@/utils/parseOutputType' +export { parseSegmentCategory } from '@/utils/parseSegmentCategory' +export { parseSegmentStatus } from '@/utils/parseSegmentStatus' +export { parseWorkflowEngine } from '@/utils/parseWorkflowEngine' +export { parseWorkflowCategory } from '@/utils/parseWorkflowCategory' +export { parseWorkflowProvider } from '@/utils/parseWorkflowProvider' +export { UUID } from '@/utils/uuid' \ No newline at end of file diff --git a/packages/clap/src/utils/isValidNumber.ts b/packages/clap/src/utils/isValidNumber.ts new file mode 100644 index 0000000000000000000000000000000000000000..21ab9f7212d471224dc81f9bf89773e73c68a067 --- /dev/null +++ b/packages/clap/src/utils/isValidNumber.ts @@ -0,0 +1,3 @@ +export function isValidNumber(input?: any) { + return typeof input === "number" && !isNaN(input) && isFinite(input) +} \ No newline at end of file diff --git a/packages/clap/src/utils/parseMediaOrientation.ts b/packages/clap/src/utils/parseMediaOrientation.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae000ebbcb599edfba4d1f4747b13948d88b7d4a --- /dev/null +++ b/packages/clap/src/utils/parseMediaOrientation.ts @@ -0,0 +1,39 @@ +import { defaultMediaOrientation } from "@/constants/defaultValues" +import { ClapMediaOrientation } from "@/types" + +export function parseMediaOrientation(input: any, defaultToUse?: ClapMediaOrientation): ClapMediaOrientation { + + let unknownString = `${input || ""}`.trim() + + // the "normal" case + if (Object.values(ClapMediaOrientation).includes(unknownString as ClapMediaOrientation)) { + return unknownString as ClapMediaOrientation + } + + let orientation: ClapMediaOrientation = defaultToUse || defaultMediaOrientation + + unknownString = unknownString.toUpperCase() + + if ( + unknownString === "LANDSCAPE" || + unknownString === "HORIZONTAL" + ) { + orientation = ClapMediaOrientation.LANDSCAPE + } + + if ( + unknownString === "PORTRAIT" || + unknownString === "VERTICAL" || + unknownString === "MOBILE" + ) { + orientation = ClapMediaOrientation.PORTRAIT + } + + if ( + unknownString === "SQUARE" + ) { + orientation = ClapMediaOrientation.PORTRAIT + } + + return orientation +} \ No newline at end of file diff --git a/packages/clap/src/utils/parseOutputType.ts b/packages/clap/src/utils/parseOutputType.ts new file mode 100644 index 0000000000000000000000000000000000000000..a9a7d8ac0ef801db0d2fde18b2290d6b2ff12559 --- /dev/null +++ b/packages/clap/src/utils/parseOutputType.ts @@ -0,0 +1,61 @@ +import { ClapOutputType } from "@/types" + +export function parseOutputType(input: any, defaultToUse?: ClapOutputType): ClapOutputType { + + let unknownString = `${input || ""}`.trim() + + // the "normal" case + if (Object.values(ClapOutputType).includes(unknownString as ClapOutputType)) { + return unknownString as ClapOutputType + } + + let output: ClapOutputType = defaultToUse || ClapOutputType.TEXT + + // sometimes we want to use a LLM to generate the categories, + // but those aren't very precise and can hallucinate + // for instance they like to use plural + // so we need to be a bit flexible in how we detect those + + unknownString = unknownString.toUpperCase() + + if (unknownString === "TEXT") { + output = ClapOutputType.TEXT + } + else if (unknownString === "ANIMATION") { + output = ClapOutputType.ANIMATION + } + else if (unknownString === "INTERFACE") { + output = ClapOutputType.INTERFACE + } + else if (unknownString === "EVENT") { + output = ClapOutputType.EVENT + } + else if (unknownString === "PHENOMENON") { + output = ClapOutputType.PHENOMENON + } + else if (unknownString === "TRANSITION") { + output = ClapOutputType.TRANSITION + } + else if (unknownString === "IMAGE") { + output = ClapOutputType.IMAGE + } + else if (unknownString === "IMAGE_SEGMENTATION") { + output = ClapOutputType.IMAGE_SEGMENTATION + } + else if (unknownString === "IMAGE_DEPTH") { + output = ClapOutputType.IMAGE_DEPTH + } + else if (unknownString === "VIDEO") { + output = ClapOutputType.VIDEO + } + else if (unknownString === "VIDEO_SEGMENTATION") { + output = ClapOutputType.VIDEO_SEGMENTATION + } + else if (unknownString === "VIDEO_DEPTH") { + output = ClapOutputType.VIDEO_DEPTH + } + else if (unknownString === "AUDIO") { + output = ClapOutputType.AUDIO + } + return output +} \ No newline at end of file diff --git a/packages/clap/src/utils/parseSegmentCategory.ts b/packages/clap/src/utils/parseSegmentCategory.ts new file mode 100644 index 0000000000000000000000000000000000000000..4dc78c230d322f43e4a1b0d55d832577e942648e --- /dev/null +++ b/packages/clap/src/utils/parseSegmentCategory.ts @@ -0,0 +1,92 @@ +import { ClapSegmentCategory } from "../types" + +export function parseSegmentCategory(input: any, defaultCategory?: ClapSegmentCategory): ClapSegmentCategory { + + let unknownString = `${input || ""}`.trim() + + // the "normal" case + if (Object.values(ClapSegmentCategory).includes(unknownString as ClapSegmentCategory)) { + return unknownString as ClapSegmentCategory + } + + let category: ClapSegmentCategory = defaultCategory || ClapSegmentCategory.GENERIC + + // sometimes we want to use a LLM to generate the categories, + // but those aren't very precise and can hallucinate + // for instance they like to use plural + // so we need to be a bit flexible in how we detect those + + unknownString = unknownString.toLowerCase() + + if (unknownString === "splat" || unknownString === "splats" || unknownString === "splatting" || unknownString === "gaussian splat" || unknownString === "splatv") { + category = ClapSegmentCategory.SPLAT + } + else if (unknownString === "mesh" || unknownString === "meshes" || unknownString === "3d mesh") { + category = ClapSegmentCategory.MESH + } + else if (unknownString === "depth" || unknownString === "depthmap" || unknownString === "depth map") { + category = ClapSegmentCategory.DEPTH + } + else if (unknownString === "effect") { + category = ClapSegmentCategory.EFFECT + } + else if (unknownString === "event" || unknownString === "events") { + category = ClapSegmentCategory.EVENT + } + else if (unknownString === "interface" || unknownString === "ui" || unknownString === "caption" || unknownString === "html") { + category = ClapSegmentCategory.INTERFACE + } + else if (unknownString === "phenomenon" || unknownString === "phenomenons" || unknownString === "effect" || unknownString === "effects" || unknownString === "mutation" || unknownString === "reaction" || unknownString === "transformation") { + category = ClapSegmentCategory.PHENOMENON + } + else if (unknownString === "video" || unknownString === "videos") { + category = ClapSegmentCategory.VIDEO + } + else if (unknownString === "storyboard" || unknownString === "storyboards") { + category = ClapSegmentCategory.STORYBOARD + } + else if (unknownString === "transition" || unknownString === "transitions" || unknownString === "cut" || unknownString === "cuts") { + category = ClapSegmentCategory.TRANSITION + } + else if (unknownString === "character" || unknownString === "characters" || unknownString === "actor" || unknownString === "person") { + category = ClapSegmentCategory.CHARACTER + } + else if (unknownString === "location" || unknownString === "locations" || unknownString === "place" || unknownString === "places") { + category = ClapSegmentCategory.LOCATION + } + else if (unknownString === "time" || unknownString === "timestamp") { + category = ClapSegmentCategory.TIME + } + else if (unknownString === "era") { + category = ClapSegmentCategory.ERA + } + else if (unknownString === "lighting" || unknownString === "light" || unknownString === "lighting") { + category = ClapSegmentCategory.LIGHTING + } + else if (unknownString === "weather" || unknownString === "sky" || unknownString === "meteo") { + category = ClapSegmentCategory.WEATHER + } + else if (unknownString === "action") { + category = ClapSegmentCategory.ACTION + } + else if (unknownString === "music") { + category = ClapSegmentCategory.MUSIC + } + else if (unknownString === "sound" || unknownString === "sounds") { + category = ClapSegmentCategory.SOUND + } + else if (unknownString === "dialogue" || unknownString === "dialogues" || unknownString === "speech" || unknownString === "voice" || unknownString === "voices") { + category = ClapSegmentCategory.DIALOGUE + } + else if (unknownString === "style") { + category = ClapSegmentCategory.STYLE + } + else if (unknownString === "camera") { + category = ClapSegmentCategory.CAMERA + } + else if (unknownString === "generic") { + category = ClapSegmentCategory.GENERIC + } + + return category +} \ No newline at end of file diff --git a/packages/clap/src/utils/parseSegmentStatus.ts b/packages/clap/src/utils/parseSegmentStatus.ts new file mode 100644 index 0000000000000000000000000000000000000000..6941f3f38ee40041f6c6ac20813df4fbb60724d4 --- /dev/null +++ b/packages/clap/src/utils/parseSegmentStatus.ts @@ -0,0 +1,31 @@ +import { ClapSegmentStatus } from "@/types" + +export function parseSegmentStatus(input: any, defaultStatus?: ClapSegmentStatus): ClapSegmentStatus { + + let unknownString = `${input || ""}`.trim() + + // the "normal" case + if (Object.values(ClapSegmentStatus).includes(unknownString as ClapSegmentStatus)) { + return unknownString as ClapSegmentStatus + } + + let status: ClapSegmentStatus = defaultStatus || ClapSegmentStatus.TO_GENERATE + + unknownString = unknownString.toLowerCase() + + if (unknownString === "to_generate") { + status = ClapSegmentStatus.TO_GENERATE + } + else if (unknownString === "to_interpolate") { + status = ClapSegmentStatus.TO_INTERPOLATE + } + else if (unknownString === "to_upscale") { + status = ClapSegmentStatus.TO_UPSCALE + } + else if (unknownString === "completed") { + status = ClapSegmentStatus.COMPLETED + } else { + status = ClapSegmentStatus.ERROR + } + return status +} \ No newline at end of file diff --git a/packages/clap/src/utils/parseWorkflowCategory.ts b/packages/clap/src/utils/parseWorkflowCategory.ts new file mode 100644 index 0000000000000000000000000000000000000000..62ec9e87553f7fff510182be8c36420c224fde4d --- /dev/null +++ b/packages/clap/src/utils/parseWorkflowCategory.ts @@ -0,0 +1,15 @@ +import { ClapWorkflowCategory } from "@/types" + +export function parseWorkflowCategory(input: any, defaultToUse?: ClapWorkflowCategory): ClapWorkflowCategory { + + let unknownString = `${input || ""}`.trim() + + // the "normal" case + if (Object.values(ClapWorkflowCategory).includes(unknownString as ClapWorkflowCategory)) { + return unknownString as ClapWorkflowCategory + } + + let category: ClapWorkflowCategory = defaultToUse || ClapWorkflowCategory.IMAGE_GENERATION + + return category +} \ No newline at end of file diff --git a/packages/clap/src/utils/parseWorkflowEngine.ts b/packages/clap/src/utils/parseWorkflowEngine.ts new file mode 100644 index 0000000000000000000000000000000000000000..7c2feb0408ba2d19edf519c8c3c209454cf145b9 --- /dev/null +++ b/packages/clap/src/utils/parseWorkflowEngine.ts @@ -0,0 +1,37 @@ +import { ClapWorkflowEngine } from "@/types" + +export function parseWorkflowEngine(input: any, defaultToUse?: ClapWorkflowEngine): ClapWorkflowEngine { + + let unknownString = `${input || ""}`.trim() + + // the "normal" case + if (Object.values(ClapWorkflowEngine).includes(unknownString as ClapWorkflowEngine)) { + return unknownString as ClapWorkflowEngine + } + + let engine: ClapWorkflowEngine = defaultToUse || ClapWorkflowEngine.DEFAULT + + // sometimes we want to use a LLM to generate the categories, + // but those aren't very precise and can hallucinate + // for instance they like to use plural + // so we need to be a bit flexible in how we detect those + + unknownString = unknownString.toUpperCase() + + if (unknownString === "DEFAULT") { + engine = ClapWorkflowEngine.DEFAULT + } + else if (unknownString === "COMFYUI_WORKFLOW") { + engine = ClapWorkflowEngine.COMFYUI_WORKFLOW + } + else if (unknownString === "FALAI_WORKFLOW") { + engine = ClapWorkflowEngine.FALAI_WORKFLOW + } + else if (unknownString === "GLIF_WORKFLOW") { + engine = ClapWorkflowEngine.GLIF_WORKFLOW + } + else if (unknownString === "VISUALBLOCKS_WORKFLOW") { + engine = ClapWorkflowEngine.VISUALBLOCKS_WORKFLOW + } + return engine +} \ No newline at end of file diff --git a/packages/clap/src/utils/parseWorkflowProvider.ts b/packages/clap/src/utils/parseWorkflowProvider.ts new file mode 100644 index 0000000000000000000000000000000000000000..4603777b47d1161169259a359156a19aff2e8bb3 --- /dev/null +++ b/packages/clap/src/utils/parseWorkflowProvider.ts @@ -0,0 +1,15 @@ +import { ClapWorkflowProvider } from "@/types" + +export function parseWorkflowProvider(input: any, defaultToUse?: ClapWorkflowProvider): ClapWorkflowProvider { + + let unknownString = `${input || ""}`.trim() + + // the "normal" case + if (Object.values(ClapWorkflowProvider).includes(unknownString as ClapWorkflowProvider)) { + return unknownString as ClapWorkflowProvider + } + + let provider: ClapWorkflowProvider = defaultToUse || ClapWorkflowProvider.NONE + + return provider +} \ No newline at end of file diff --git a/packages/clap/src/utils/uuid.ts b/packages/clap/src/utils/uuid.ts new file mode 100644 index 0000000000000000000000000000000000000000..b2452e0e78fd97ad163a4b6e2702a89ec5451bd0 --- /dev/null +++ b/packages/clap/src/utils/uuid.ts @@ -0,0 +1,5 @@ +import PureUUID from "pure-uuid" + +export function UUID() { + return new PureUUID(4).format() +} \ No newline at end of file diff --git a/packages/clap/tsconfig.json b/packages/clap/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..ab7cc3ed096e5dc51a557fdee4e68c0e28076d0b --- /dev/null +++ b/packages/clap/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "baseUrl": "./", + "paths": { + "@/*": ["src/*"] + }, + "lib": ["ESNext", "DOM"], + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": true, + "noEmit": true, + "composite": true, + "strict": true, + "downlevelIteration": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "types": [ + "bun-types" + ] + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/packages/clap/tsconfig.types.json b/packages/clap/tsconfig.types.json new file mode 100644 index 0000000000000000000000000000000000000000..a6a3f21154bb178f1850c9b70714fb66ef5bf750 --- /dev/null +++ b/packages/clap/tsconfig.types.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "emitDeclarationOnly": true, + "declaration": true, + "outDir": "./dist", + "rootDir": "./src", + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/packages/clapper-services/.gitignore b/packages/clapper-services/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ea8fe6a7905bd72f745584146daa9994bd211499 --- /dev/null +++ b/packages/clapper-services/.gitignore @@ -0,0 +1,177 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +\*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +\*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +\*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +\*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.cache +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output +dist +.nuxt + +# Gatsby files + +.cache/ + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp +.cache + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.\* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store + +# TypeScript build information +*.tsbuildinfo \ No newline at end of file diff --git a/packages/clapper-services/.npmignore b/packages/clapper-services/.npmignore new file mode 100644 index 0000000000000000000000000000000000000000..78a661ea2d8f8cdaa94e4cc69d758a4b2d946feb --- /dev/null +++ b/packages/clapper-services/.npmignore @@ -0,0 +1,4 @@ +# Ignore everything +* +# Except the dist directory +!dist/ diff --git a/packages/clapper-services/.prettierrc.json b/packages/clapper-services/.prettierrc.json new file mode 100644 index 0000000000000000000000000000000000000000..1dcadb7324877e15a4ffa4efa5723a519395f511 --- /dev/null +++ b/packages/clapper-services/.prettierrc.json @@ -0,0 +1,9 @@ +{ + "semi": false, + "singleQuote": true, + "arrowParens": "avoid", + "printWidth": 140, + "tabWidth": 2, + "trailingComma": "es5", + "bracketSpacing": true +} diff --git a/packages/clapper-services/LICENSE.md b/packages/clapper-services/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..8b21ed7d57c2d217f49e10d0fb0b327961a4ea54 --- /dev/null +++ b/packages/clapper-services/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2024 Julian Bilcke + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/clapper-services/README.md b/packages/clapper-services/README.md new file mode 100644 index 0000000000000000000000000000000000000000..90c2ef607d204b4e03503ea5dcacc65b74c0da9d --- /dev/null +++ b/packages/clapper-services/README.md @@ -0,0 +1,6 @@ +# @aitube/clapper-services + +*Base types for Clapper services* + +This module is used by Clapper and by Clapper plugins + diff --git a/packages/clapper-services/package.json b/packages/clapper-services/package.json new file mode 100644 index 0000000000000000000000000000000000000000..465c9ea253e289f3f6e6d751c330c9d63b98e0c3 --- /dev/null +++ b/packages/clapper-services/package.json @@ -0,0 +1,48 @@ +{ + "name": "@aitube/clapper-services", + "module": "index.ts", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "type": "module", + "version": "0.2.4", + "description": "Base types for Clapper services", + "scripts": { + "build": "bun build ./src/index.ts --outfile=dist/index.js --external=@aitube/clap --external=@aitube/timeline --external=@monaco-editor/react --external=monaco-editor --external=zustand --external=react --external=react-dom && bun run build:declaration", + "build:declaration": "tsc --emitDeclarationOnly --project tsconfig.types.json", + "postbuild": "rimraf tsconfig.types.tsbuildinfo && bun run build:declaration", + "publish": "bun run build && npm publish --access public", + "update": "rm -Rf node_modules && rm bun.lockb && bun i && bun run build" + }, + "devDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "bun-types": "latest", + "prettier": "^3.3.3", + "rimraf": "^6.0.1", + "typescript": "^5.5.4" + }, + "peerDependencies": { + "@aitube/clap": "workspace:*", + "@aitube/timeline": "workspace:*", + "@monaco-editor/react": "4.6.0", + "monaco-editor": "0.50.0", + "react": "*", + "react-dom": "*", + "zustand": "4.5.2" + }, + "repository": { + "type": "git", + "url": "https://github.com/jbilcke-hf/services.git" + }, + "keywords": [ + "Clapper", + "Clapper.app" + ], + "author": "Julian Bilcke", + "license": "MIT", + "files": [ + "dist/*.js", + "dist/*.d.ts", + "dist/**/*.d.ts" + ] +} diff --git a/packages/clapper-services/src/assistant.ts b/packages/clapper-services/src/assistant.ts new file mode 100644 index 0000000000000000000000000000000000000000..8ce3348dc9c9ed4e53984e1f05d69de11c8ac501 --- /dev/null +++ b/packages/clapper-services/src/assistant.ts @@ -0,0 +1,42 @@ +import { + ChatEvent, + ChatHistory, + AssistantMessage, + AssistantAction, +} from "./base-types" + +/** + * Assistant + */ +export type AssistantState = { + /** + * the chat history + */ + history: ChatHistory +} +export type AssistantControls = { + + processUserMessage: (userMessage: string) => void + + /** + * Process an action or a message + * + * @param actionOrAssistantMessage + * @returns + */ + processActionOrMessage: (actionOrAssistantMessage: AssistantAction | AssistantMessage) => Promise + + /** + * Add a chat event to the history + * + * @param event + * @returns + */ + addEventToHistory: (event: Partial) => ChatEvent + + clearHistory: () => void +} + +export type AssistantStore = + AssistantState & + AssistantControls diff --git a/packages/clapper-services/src/audio.ts b/packages/clapper-services/src/audio.ts new file mode 100644 index 0000000000000000000000000000000000000000..14d1947c1a7b5926a0093b6231fa7f40ad8d0f64 --- /dev/null +++ b/packages/clapper-services/src/audio.ts @@ -0,0 +1,64 @@ +import { TimelineSegment } from "@aitube/timeline" + +export type AudioAnalysis = { + audioBuffer: AudioBuffer + bpm: number + durationInMs: number + durationInSteps: number +} + +export type AudioState = { + isPlaying: boolean + isMuted: boolean + userDefinedGain: number + currentGain: number + audioContext: AudioContext // we keep a single audio context + currentlyPlaying: CurrentlyPlayingAudioSource[] +} + +export type AudioControls = { + play: () => void + stop: () => void + setUserDefinedGain: (userDefinedGain: number) => void + setCurrentGain: (currentGain: number) => void + mute: () => void + unmute: () => void + syncAudioToCurrentCursorPosition: (activeAudioSegments: TimelineSegment[]) => void +} + +export type AudioStore = AudioState & AudioControls +/** + * This is the data structure used to keep track of currently played audio nodes + */ +export type CurrentlyPlayingAudioSource = { + /** + * The unique ID associated with this audio source + * + * This exists because the same segment might can be present multiple times + * + * Eg. the same "cymbal crash" sound might be triggered multiple times + */ + sourceId: string + + /** + * The segment being played (this is for identification so we only need the ID) + */ + segmentId: string + + /** + * The actual source node (this allows us to call .stop() on it) + */ + sourceNode: AudioScheduledSourceNode + + // the original value that was set to the segment + originalGain: number + + /** + * The gain node, to control the volume + * + * Note that for the moment, we do not persist the changes to the gain, + * but this is something we should do since it is part of the project data + */ + + gainNode: GainNode +} \ No newline at end of file diff --git a/packages/clapper-services/src/base-types.ts b/packages/clapper-services/src/base-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..57929cec317a55c395a5e527d6257b1410d38149 --- /dev/null +++ b/packages/clapper-services/src/base-types.ts @@ -0,0 +1,204 @@ +import { ClapWorkflow } from "@aitube/clap" + +export enum ChatEventVisibility { + TO_ASSISTANT_ONLY = 'TO_ASSISTANT_ONLY', + TO_USER_ONLY = 'TO_USER_ONLY', + TO_BOTH = 'TO_BOTH', +} + +export type ChatEvent = { + eventId: string + senderId: string + senderName: string + roomId: string + roomName: string + sentAt: string + message: string + isCurrentUser: boolean + + /** + * Some message are only used for purely technical reasons, + * and should be hidden (eg. JSON responses) + */ + visibility: ChatEventVisibility +} + +export type ChatHistory = ChatEvent[] + + +export enum SettingsCategory { + NONE = "NONE", + PROVIDER = "PROVIDER", + ASSISTANT = "ASSISTANT", + EDITORS = "EDITORS", + IMAGE = "IMAGE", + VIDEO = "VIDEO", + VOICE = "VOICE", + MUSIC = "MUSIC", + SOUND = "SOUND" +} + +export enum ComfyIcuAccelerator { + T4 = "T4", + L4 = "L4", + A10 = "A10", + A100_40GB = "A100_40GB", + A100_80GB = "A100_80GB", + H100 = "H100" +} + +export type ResolveRequestPrompts = { + image: { + // the positive prompt - elements we want in the scene + positive: string + + // the positive prompt - elements we don't want in the scene + negative: string + + + // the "identification picture" of the character, if available + identity: string + + // TODO: add LoRAs etc.. for location consistency + } + video: { + // input image to use for the video generation + image: string + + // input voice sample to use for the video generation + voice: string + } + voice: { + // the "identification voiceprint" of the character, if available + identity: string + + // the positive prompt - elements we want in the voice + positive: string + + // the positive prompt - elements we don't want in the voice + negative: string + } + audio: { + // the positive prompt - elements we want in the audio + positive: string + + // the positive prompt - elements we don't want in the audio + negative: string + } + music: { + // the positive prompt - elements we want in the music + positive: string + + // the positive prompt - elements we don't want in the music + negative: string + } +} + +export type ComfyParameter = + | string + | number + | boolean + | Array< string | number | boolean> + +export type ComfyNode = { + inputs: Record + /* + inputs: { + "seed": number + "steps": number + "cfg": number + "sampler_name":string + "scheduler": string + "denoise": number + "model": any[] + "positive": any[] + "negative": any[] + "latent_image": any[] + } + */ + class_type: string + _meta: { + title: string + } +} + +// note: they keep the high digit first in all cases +export enum FalAiImageSize { + SQUARE_HD = "square_hd", + SQUARE = "square", + PORTRAIT_4_3 = "portrait_4_3", + PORTRAIT_16_9 = "portrait_16_9", + LANDSCAPE_4_3 = "landscape_4_3", + LANDSCAPE_16_9 = "landscape_16_9" +} + +export enum StabilityAiImageSize { + SQUARE = "1:1", + PORTRAIT_2_3 = "2:3", + PORTRAIT_4_5 = "4:5", + PORTRAIT_9_16 = "9:16", + PORTRAIT_9_21 = "9:21", + LANDSCAPE_3_2 = "3:2", + LANDSCAPE_5_4 = "5:4", + LANDSCAPE_16_9 = "16:9", + LANDSCAPE_21_9 = "21:9" +} + +export enum StabilityAiGenerationMode { + "TEXT_TO_IMAGE" = "text-to-image", + "IMAGE_TO_IMAGE" = "image-to-image" +} + +export interface ImageSegment { + id: number; + box: number[]; + color: number[]; + label: string; + score: number; +} + +export type AssistantSceneSegment = { + segmentId: number + prompt: string + startTimeInMs: number + endTimeInMs: number + category: string +} + +export type AssistantStoryBlock = { + blockId: number + block: string +} + +export type AssistantInput = { + directorRequest: string + storyBlocks: AssistantStoryBlock[] + sceneSegments: AssistantSceneSegment[] +} + +export enum AssistantAction { + NONE = 'NONE', + UPDATE_STORY_AND_SCENE = 'UPDATE_STORY_AND_SCENE', + PLAY_VIDEO = 'PLAY_VIDEO', + PAUSE_VIDEO = 'PAUSE_VIDEO', + MUTE_AUDIO = 'MUTE_AUDIO', + UNMUTE_AUDIO = 'UNMUTE_AUDIO', + GO_BACK = 'GO_BACK', + GO_FORWARD = 'GO_FORWARD', + UNDO = 'UNDO', + REDO = 'REDO', +} + +export type AssistantMessage = { + comment: string; + action: AssistantAction; + updatedStoryBlocks: AssistantStoryBlock[]; + updatedSceneSegments: AssistantSceneSegment[]; +}; + + +export enum ProjectCreationWizardStep { + NONE = "NONE", + CHOOSE_CATEGORY = "CHOOSE_CATEGORY", + CREATE_FROM_PROMPT = "CREATE_FROM_PROMPT", +} diff --git a/packages/clapper-services/src/broadcast.ts b/packages/clapper-services/src/broadcast.ts new file mode 100644 index 0000000000000000000000000000000000000000..fca28b931ada8c33148e89778c48fd04b2e9cd11 --- /dev/null +++ b/packages/clapper-services/src/broadcast.ts @@ -0,0 +1,15 @@ + +export type BroadcastState = { + isBroadcasting: boolean +} + +export type BroadcastControls = { + /** + * Toggles the broadcast on or off + * @param forceValue + * @returns + */ + toggleBroadcast: (forceValue?: boolean) => boolean +} + +export type BroadcastStore = BroadcastState & BroadcastControls \ No newline at end of file diff --git a/packages/clapper-services/src/editors.ts b/packages/clapper-services/src/editors.ts new file mode 100644 index 0000000000000000000000000000000000000000..64b26b036ae4fbea7bac6b0c17c3fbe1289982e3 --- /dev/null +++ b/packages/clapper-services/src/editors.ts @@ -0,0 +1,18 @@ +export enum EditorView { + PROJECT = "PROJECT", + SCRIPT = "SCRIPT", + ENTITY = "ENTITY", + SEGMENT = "SEGMENT", + HISTORY = "HISTORY", + WORKFLOW = "WORKFLOW", +} + +export type EditorsState = { + view: EditorView +} + +export type EditorsControls = { + setView: (editorView: EditorView) => void +} + +export type EditorsStore = EditorsState & EditorsControls diff --git a/packages/clapper-services/src/entity-editor.ts b/packages/clapper-services/src/entity-editor.ts new file mode 100644 index 0000000000000000000000000000000000000000..63bd1070eee12ecd7c6ce21f61df9d70b433ad01 --- /dev/null +++ b/packages/clapper-services/src/entity-editor.ts @@ -0,0 +1,18 @@ +import { ClapEntity } from "@aitube/clap" + +import { VersionControls, VersionState } from "./version-control" + +export type EntityEditorState = { + draft?: ClapEntity + showEntityList: boolean +} & VersionState + +export type EntityEditorControls = { + setDraft: (draft?: ClapEntity) => void + selectEntity: (id: string) => void + addEntity: (entity: ClapEntity) => void + removeEntity: (id: string) => void + setShowEntityList: (showEntityList: boolean) => void +} & VersionControls + +export type EntityEditorStore = EntityEditorState & EntityEditorControls diff --git a/packages/clapper-services/src/filter-editor.ts b/packages/clapper-services/src/filter-editor.ts new file mode 100644 index 0000000000000000000000000000000000000000..3513528b37b4e129930455c4a8c8f8c0a2ded242 --- /dev/null +++ b/packages/clapper-services/src/filter-editor.ts @@ -0,0 +1,34 @@ +import { ClapInputField } from "@aitube/clap/dist/types" + +import { VersionControls, VersionState } from "./version-control" + +export type Filter = { + id: string + label: string + parameters: Array + shader: string // WGSL shader code for the filter +} + +export type FilterParams = Record + +export type FilterWithParams = { + filter: Filter + parameters: FilterParams +} + +export type FilterEditorState = { + isEnabled: boolean + availableFilters: Filter[] + activeFilters: FilterWithParams[] +}& VersionState + +export type FilterEditorControls = { + runFilterPipeline: (input: string) => Promise + + setEnabled: (isEnabled: boolean) => void + + // later we can have functions like addFilter() + // which could be used by the plugin engine to add filters +} & VersionControls + +export type FilterEditorStore = FilterEditorState & FilterEditorControls \ No newline at end of file diff --git a/packages/clapper-services/src/index.ts b/packages/clapper-services/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..9dd88083b3b0a90f72d87a9f17c701639df4d880 --- /dev/null +++ b/packages/clapper-services/src/index.ts @@ -0,0 +1,226 @@ +export { + AssistantStore, + AssistantState, + AssistantControls, +} from "./assistant" + +export { + MicStore, + MicState, + MicControls, +} from "./mic" + +export { + AudioAnalysis, + AudioState, + AudioControls, + AudioStore, + CurrentlyPlayingAudioSource +} from "./audio" + +export { + AssistantInput, + AssistantSceneSegment, + AssistantStoryBlock, + AssistantAction, + AssistantMessage, + ChatEvent, + ChatEventVisibility, + ChatHistory, + SettingsCategory, + ComfyIcuAccelerator, + ResolveRequestPrompts, + ComfyParameter, + ComfyNode, + FalAiImageSize, + StabilityAiImageSize, + StabilityAiGenerationMode, + ImageSegment, + ProjectCreationWizardStep, +} from "./base-types" + +export { + BroadcastState, + BroadcastControls, + BroadcastStore +} from "./broadcast" + +export { + AudioService, + AssistantService, + MicService, + TasksService, + BroadcastService, + ProjectEditorService, + SegmentEditorService, + EntityEditorService, + FilterEditorService, + ScriptEditorService, + WorkflowEditorService, + EditorsService, + MonitorService, + RendererService, + ResolverService, + SettingsService, + SimulatorService, + TimelineService, + UIService, + IOService, + PrivateServices, + PublicServices, + Services, +} from "./services" + +export { + ScrollData, + ScriptEditorState, + ScriptEditorControls, + ScriptEditorStore +} from "./script-editor" + + +export { + ProjectEditorState, + ProjectEditorControls, + ProjectEditorStore +} from "./project-editor" + + +export { + EntityEditorState, + EntityEditorControls, + EntityEditorStore +} from "./entity-editor" + +export { + Filter, + FilterParams, + FilterWithParams, + FilterEditorState, + FilterEditorControls, + FilterEditorStore, +} from "./filter-editor" + +export { + SegmentEditorState, + SegmentEditorControls, + SegmentEditorStore +} from "./segment-editor" + +export { + WorkflowEditorState, + WorkflowEditorControls, + WorkflowEditorStore, + WorkflowEditorTheme +} from "./workflow-editor" + +export { + EditorView, + EditorsState, + EditorsControls, + EditorsStore +} from "./editors" + +export { + MonitorState, + MonitorControls, + MonitorStore +} from "./monitor" + +export { + ClapperPluginCategory, + ClapperPluginSettingType, + ClapperPluginSettingBase, + ClapperPluginSettingString, + ClapperPluginSettingNumber, + ClapperPluginSettingBoolean, + ClapperPluginSetting, + ClapperPluginSettings, + ClapperPluginMeta, + BaseClapperPluginStore, + ClapperPluginService, + ClapperPlugin, +} from "./plugin" + +export { + ClapperPluginApi, + PluginsState, + PluginsControls, + PluginsStore, +} from "./plugins" + +export { + ActiveSegments, + UpcomingSegments, + BufferedSegments, + RendererState, + RendererControls, + RendererStore, +} from "./renderer" + + +export { + ResolverState, + ResolverControls, + ResolverStore, +} from "./resolver" + +export { + TaskVisibility, + TaskProgressType, + TaskCategory, + TaskStatus, + StatusGetter, + TaskRunner, + NewTask, + Task, + TaskRemoteControl, + TasksState, + TasksControls, + TasksStore, +} from "./tasks" + +export { + BaseSettings, + RequestSettings, + SettingsState, + SettingsControls, + SettingsStore +} from "./settings" + +export { + SimulatorState, + SimulatorControls, + SimulatorStore +} from "./simulator" + +export { + ResolveRequest, + AssistantRequest, +} from "./types" + +export { + UIThemeColorMode, + UIThemeName, + UITheme, + UIStore, + UIState, + UIControls, + UIWindowLayout +} from "./ui" + +export { + ResourceType, + ResourceCategory, + IOState, + IOControls, + IOStore +} from "./io" + +export { + VersionHistory, + VersionState, + VersionControls, + undo, + redo, +} from "./version-control" \ No newline at end of file diff --git a/packages/clapper-services/src/io.ts b/packages/clapper-services/src/io.ts new file mode 100644 index 0000000000000000000000000000000000000000..5babcd7c6252981bd178a1a49ac0c4274e3b0355 --- /dev/null +++ b/packages/clapper-services/src/io.ts @@ -0,0 +1,63 @@ +import { ClapEntity } from "@aitube/clap" + +/** + * Describe a resource file type that has been uploaded and attached to a project + * + */ +export type ResourceType = +| "audio" +| "video" +| "image" +| "text" +| "misc" + +/** + * Describe a resource file category that has been uploaded and attached to a project + */ +export type ResourceCategory = + | "control_image" + | "control_mask" + | "character_face" + | "character_voice" + | "background_music" + | "character_dialogue" + | "text_prompt" + | "sound" + | "misc" + + +export type IOState = { + +} + +export type IOControls = { + + clear: () => void + + openFiles: (files: File[]) => Promise + + openScreenplay: (projectName: string, fileName: string, fileContent: string | Blob) => Promise + openScreenplayUrl: (url: string) => Promise + saveAnyFile: (blob: Blob, fileName: string) => void + openClapUrl: (url: string) => Promise + openClapBlob: (projectName: string, fileName: string, blob: Blob) => Promise + openVideo: (projectName: string, fileName: string, fileContent: string | Blob) => Promise + saveClap: () => Promise + saveVideoFile: () => Promise + saveZipFile: () => Promise + + openMLT: (file: File) => Promise + saveMLT: () => Promise + generateMLT: () => Promise + + openKdenline: (file: File) => Promise + saveKdenline: () => Promise + + openOpenTimelineIO: (file: File) => Promise + saveOpenTimelineIO: () => Promise + + saveEntitiesToClap: (entities: ClapEntity[]) => Promise + openEntitiesFromClap: (file: File) => Promise +} + +export type IOStore = IOState & IOControls \ No newline at end of file diff --git a/packages/clapper-services/src/mic.ts b/packages/clapper-services/src/mic.ts new file mode 100644 index 0000000000000000000000000000000000000000..6095276b6de4ed9c87bad0b81c38a314c443a651 --- /dev/null +++ b/packages/clapper-services/src/mic.ts @@ -0,0 +1,25 @@ +/** + * Mic + */ +export type MicState = { + isSupported: boolean + isListening: boolean + transcript: string + interimResults: boolean + error: string + lang: string + grammar: string + grammarWeight: number + continuous: boolean + recognition?: SpeechRecognition +} +export type MicControls = { + init: () => void + start: () => void + stop: () => void + clear: () => void +} + +export type MicStore = + MicState & + MicControls diff --git a/packages/clapper-services/src/monitor.ts b/packages/clapper-services/src/monitor.ts new file mode 100644 index 0000000000000000000000000000000000000000..15945c33b4547c8b6be99e9a59db37de919e4c0b --- /dev/null +++ b/packages/clapper-services/src/monitor.ts @@ -0,0 +1,35 @@ +export type MonitorState = { + shortcutsAreBound: boolean + lastTimelineUpdateAtInMs: number + isPlaying: boolean + staticVideoRef?: HTMLVideoElement +} + +export type MonitorControls = { + bindShortcuts: () => void + + setStaticVideoRef: (staticVideoRef: HTMLVideoElement) => void + + checkIfPlaying: () => boolean + /** + * Play/pause the project timeline (video and audio) + * + * @param forcePlaying + * @returns + */ + togglePlayback: (forcePlaying?: boolean) => { + wasPlaying: boolean + isPlaying: boolean + } + + /** + * Seek to a specific timestamp + * + * @param timeInMs + * @returns + */ + jumpAt: (timeInMs?: number) => void + + setLastTimelineUpdateAtInMs: (lastTimelineUpdateAtInMs: number) => void +} +export type MonitorStore = MonitorState & MonitorControls \ No newline at end of file diff --git a/packages/clapper-services/src/plugin.ts b/packages/clapper-services/src/plugin.ts new file mode 100644 index 0000000000000000000000000000000000000000..919f4b038086926c7462b91e5dd2e894db2f10e4 --- /dev/null +++ b/packages/clapper-services/src/plugin.ts @@ -0,0 +1,82 @@ +import { StoreApi, UseBoundStore } from "zustand" + +export enum ClapperPluginCategory { + THEME = "THEME", + IMPORTER = "IMPORTER", + EXPORTER = "EXPORTER", + RESOLVER = "RESOLVER" +} + +export enum ClapperPluginSettingType { + STRING = "STRING", + NUMBER = "NUMBER", + BOOLEAN = "BOOLEAN" +} + +export type ClapperPluginSettingBase = { + key: string + label: string +} +export type ClapperPluginSettingString = { + value: string + defaultValue: string + type: ClapperPluginSettingType.STRING +} +export type ClapperPluginSettingNumber = { + value: number + defaultValue: number + type: ClapperPluginSettingType.NUMBER +} +export type ClapperPluginSettingBoolean = { + value: boolean + defaultValue: boolean + type: ClapperPluginSettingType.BOOLEAN +} +export type ClapperPluginSetting = +ClapperPluginSettingBase & + ( + ClapperPluginSettingString | + ClapperPluginSettingNumber | + ClapperPluginSettingBoolean + ) + +export type ClapperPluginSettings = ClapperPluginSetting[] + +export type ClapperPluginMeta = { + // a lowercase alphabetical name (letters and digits only) + // used to uniquely identify the plugin + id: string + + // a human-readable name + label: string + + // a list of categories + categories: ClapperPluginCategory[] + + // a list of settings for this plugin + settings: ClapperPluginSetting[] + + // the purpose of the plugin + description: string + + // semver of the plugin + version: string + + licence: string + author: string + + // project or company website + website: string + + // direct URL to the .js file for fetch and injection + assetUrl: string +} + +export type BaseClapperPluginStore = {} + +export type ClapperPluginService = UseBoundStore> + +export type ClapperPlugin = { + meta: ClapperPluginMeta + service: ClapperPluginService +} diff --git a/packages/clapper-services/src/plugins.ts b/packages/clapper-services/src/plugins.ts new file mode 100644 index 0000000000000000000000000000000000000000..f0d9a587f0c71702d630c238117234cc5aef8c5c --- /dev/null +++ b/packages/clapper-services/src/plugins.ts @@ -0,0 +1,45 @@ + +import { PublicServices } from "./services" +import { + ClapperPlugin, + ClapperPluginMeta, + ClapperPluginSettings, +} from "./plugin" + +export type ClapperPluginApi = { + /** + * Provide some public controllers + * + * @returns + */ + getServices: () => Promise + + /** + * Load the plugin settings saved by the user + * + * (to the local storage usually) + * @returns + */ + getSettings: () => Promise +} + +export type PluginsState = { + // list of plugins available for install + availablePlugins: ClapperPluginMeta[] + + installedPlugins: Record +} + +export type PluginsControls = { + refreshAvailablePlugins: () => Promise + + install: (id: string) => Promise + uninstall: (id: string) => Promise + + pluginApiGetServices: (id: string) => Promise + pluginApiGetSettings: (id: string) => Promise + + connect: (plugin: ClapperPlugin) => Promise +} + +export type PluginsStore = PluginsState & PluginsControls \ No newline at end of file diff --git a/packages/clapper-services/src/project-editor.ts b/packages/clapper-services/src/project-editor.ts new file mode 100644 index 0000000000000000000000000000000000000000..c3d83c6d9089b47b6572994d920a36957606ec48 --- /dev/null +++ b/packages/clapper-services/src/project-editor.ts @@ -0,0 +1,14 @@ +import { ClapMeta } from "@aitube/clap" + +import { VersionControls, VersionState } from "./version-control" + +export type ProjectEditorState = { + +} & VersionState + + +export type ProjectEditorControls = { + +} & VersionControls + +export type ProjectEditorStore = ProjectEditorState & ProjectEditorControls diff --git a/packages/clapper-services/src/renderer.ts b/packages/clapper-services/src/renderer.ts new file mode 100644 index 0000000000000000000000000000000000000000..3ffe797beb0af6cf1111dd75f29b40e22a3acef9 --- /dev/null +++ b/packages/clapper-services/src/renderer.ts @@ -0,0 +1,67 @@ +import { TimelineSegment } from "@aitube/timeline" + +export type ActiveSegments = { + activeSegmentsCacheKey: string + activeSegments: TimelineSegment[] + activeVideoSegment?: TimelineSegment + activeStoryboardSegment?: TimelineSegment + activeAudioSegments: TimelineSegment[] +} + +export type UpcomingSegments = { + upcomingSegmentsCacheKey: string + upcomingSegments: TimelineSegment[] + upcomingVideoSegment?: TimelineSegment + upcomingStoryboardSegment?: TimelineSegment +} + +export type BufferedSegments = ActiveSegments & UpcomingSegments + +export type RendererState = { + bufferedSegments: BufferedSegments + + // various helpers to manage buffering, + // cache, cache invalidation.. + dataUriBuffer1?: TimelineSegment + dataUriBuffer2?: TimelineSegment + activeBufferNumber: number + currentSegment?: TimelineSegment + preloadSegment?: TimelineSegment + currentSegmentKey: string + preloadSegmentKey: string + dataUriBuffer1Key: string + dataUriBuffer2Key: string +} + +export type RendererControls = { + + // used to clear the renderer eg. when we load a new project + clear: () => void + + // this will be called at 60 FPS - and yes, it is expensive + // we could probably improve things by using a temporal tree index + + /** + * Cycle through the segments to see which ones are crossing the current cursor, + * then this updates the internal buffer of segments + * (this has side effects as it modifies the internal state) + * + * @returns + */ + renderLoop: (jumpedSomewhere?: boolean) => BufferedSegments + + /** + * Cycle through the segments to see which ones are crossing the current cursor, + * and return it (this doesn't change any state, but it reads the state from various stores) + * @returns + */ + computeBufferedSegments: () => BufferedSegments + + setDataUriBuffer1: (dataUriBuffer1?: TimelineSegment) => void + setDataUriBuffer2: (dataUriBuffer2?: TimelineSegment) => void + setActiveBufferNumber: (activeBufferNumber: number) => void + + syncVideoToCurrentCursorPosition: () => void +} + +export type RendererStore = RendererState & RendererControls diff --git a/packages/clapper-services/src/resolver.ts b/packages/clapper-services/src/resolver.ts new file mode 100644 index 0000000000000000000000000000000000000000..a0849d44de46e649488febe92eb310cb8aa36e41 --- /dev/null +++ b/packages/clapper-services/src/resolver.ts @@ -0,0 +1,70 @@ +import { ClapEntity } from "@aitube/clap" +import { TimelineSegment } from "@aitube/timeline" + +export type ResolverState = { + // this indicate the status of the loop + // normally once it is running it is never stopped, + // since this is used to check if we have pending tasks + isRunning: boolean + + // used to "pause" the resolution + // request have have already be sent to the API providers + // will still be honored, which is why the number of pending + // requests won't drop to 0 immediately + isPaused: boolean + + defaultParallelismQuotas: { + video: number + image: number + voice: number + sound: number + music: number + } + + // used for UI display, show some metrics + currentParallelismQuotaForVideo: number + currentParallelismQuotaForImage: number + currentParallelismQuotaForVoice: number + currentParallelismQuotaForSound: number + currentParallelismQuotaForMusic: number + + // just some aliases for convenience, + // used for UI display, show some metrics + nbPendingRequestsForVideo: number + nbPendingRequestsForImage: number + nbPendingRequestsForVoice: number + nbPendingRequestsForSound: number + nbPendingRequestsForMusic: number + nbRequestsRunningInParallel: number + isBusyResolving: boolean +} + +export type ResolverControls = { + startLoop: () => void + runLoop: () => Promise + + togglePause: (isPaused?: boolean) => boolean + + /** + * This resolve an entity (eg. a character or a location) + * + * This will generate for instance an image and a voice + * for the entity, based on the entity description. + * + * @param segment + * @returns + */ + resolveEntity: (entity: ClapEntity) => Promise + + /** + * This resolve a segment + * + * Note: while we return a clap segment, the original will be replaced, too + * + * @param segment + * @returns + */ + resolveSegment: (segment: TimelineSegment) => Promise +} + +export type ResolverStore = ResolverState & ResolverControls \ No newline at end of file diff --git a/packages/clapper-services/src/script-editor.ts b/packages/clapper-services/src/script-editor.ts new file mode 100644 index 0000000000000000000000000000000000000000..025fb0085ab7825b11f57ac49caa70bac207b7b8 --- /dev/null +++ b/packages/clapper-services/src/script-editor.ts @@ -0,0 +1,55 @@ +import { ClapProject } from "@aitube/clap" +import { TimelineSegment } from "@aitube/timeline" +import { Monaco } from "@monaco-editor/react" +import MonacoEditor from "monaco-editor" + +import { VersionControls, VersionState } from "./version-control" + +export type ScrollData = { + scrollHeight: number + scrollLeft: number + scrollTop: number + scrollWidth: number +} + +export type ScriptEditorState = { + monaco?: Monaco + + textModel?: MonacoEditor.editor.ITextModel + + // reference to the React component + standaloneCodeEditor?: MonacoEditor.editor.IStandaloneCodeEditor + + // used to know if the user is actually inside the editor or not + mouseIsInside: boolean + + // the last version of the prompt that was published + lastPublished: string + + // map prompt lines to dialogue segments + // (note: some lines point to nothing, eg. when we have empty spaces) + lineNumberToMentionedSegments: Record + + + /** + * the index of the first step visible in the current prompt + * + * (the topmost visible timeline step in the current timeline) + */ + scrollTopInMs: number +} & ScrollData & VersionState + +export type ScriptEditorControls = { + setMonaco: (monaco?: Monaco) => void + setTextModel: (textModel?: MonacoEditor.editor.ITextModel) => void + setStandaloneCodeEditor: (standaloneCodeEditor?: MonacoEditor.editor.IStandaloneCodeEditor) => void + setMouseIsInside: (mouseIsInside: boolean) => void + loadDraftFromClap: (clap: ClapProject) => void + publish: () => Promise + onDidScrollChange: (scrollData: ScrollData) => void + jumpCursorOnLineClick: (line?: number) => void + highlightElements: () => void + applyClassNameToKeywords: (className?: string, keywords?: string[], caseSensitive?: boolean) => void +} & VersionControls + +export type ScriptEditorStore = ScriptEditorState & ScriptEditorControls diff --git a/packages/clapper-services/src/segment-editor.ts b/packages/clapper-services/src/segment-editor.ts new file mode 100644 index 0000000000000000000000000000000000000000..aebef6e12f85968fb08c795da861a8eebc43a303 --- /dev/null +++ b/packages/clapper-services/src/segment-editor.ts @@ -0,0 +1,13 @@ +import { TimelineSegment } from "@aitube/timeline" + +import { VersionControls, VersionState } from "./version-control" + +export type SegmentEditorState = { + +} & VersionState + +export type SegmentEditorControls = { + +} & VersionControls + +export type SegmentEditorStore = SegmentEditorState & SegmentEditorControls diff --git a/packages/clapper-services/src/services.ts b/packages/clapper-services/src/services.ts new file mode 100644 index 0000000000000000000000000000000000000000..35bdf7154d442b184709976795d4a9bcc8f888c0 --- /dev/null +++ b/packages/clapper-services/src/services.ts @@ -0,0 +1,76 @@ +import { StoreApi, UseBoundStore } from "zustand" +import { TimelineStore } from "@aitube/timeline" + +import { AssistantStore } from "./assistant" +import { MicStore } from "./mic" +import { BroadcastStore } from "./broadcast" +import { SegmentEditorStore } from "./segment-editor" +import { EntityEditorStore } from "./entity-editor" +import { FilterEditorStore } from "./filter-editor" +import { ProjectEditorStore } from "./project-editor" +import { ScriptEditorStore } from "./script-editor" +import { WorkflowEditorStore } from "./workflow-editor" +import { EditorsStore } from "./editors" +import { MonitorStore } from "./monitor" +import { RendererStore } from "./renderer" +import { ResolverStore } from "./resolver" +import { PluginsStore } from "./plugins" +import { AudioStore } from "./audio" +import { SettingsStore } from "./settings" +import { SimulatorStore } from "./simulator" +import { TasksStore } from "./tasks" +import { UIStore } from "./ui" +import { IOStore } from "./io" + +export type AssistantService = UseBoundStore> +export type MicService = UseBoundStore> +export type AudioService = UseBoundStore> +export type BroadcastService = UseBoundStore> +export type SegmentEditorService = UseBoundStore> +export type EntityEditorService = UseBoundStore> +export type FilterEditorService = UseBoundStore> +export type ProjectEditorService = UseBoundStore> +export type ScriptEditorService = UseBoundStore> +export type WorkflowEditorService = UseBoundStore> +export type EditorsService = UseBoundStore> +export type MonitorService = UseBoundStore> +export type RendererService = UseBoundStore> +export type ResolverService = UseBoundStore> +export type SettingsService = UseBoundStore> +export type SimulatorService = UseBoundStore> +export type TasksService = UseBoundStore> +export type TimelineService = UseBoundStore> +export type PluginsService = UseBoundStore> +export type UIService = UseBoundStore> +export type IOService = UseBoundStore> + +export type PrivateServices = { + plugins: PluginsService + settings: SettingsService +} + +// the controllers publicly available +// missing from this list are the settings and the plugins store itself +export type PublicServices = { + assistant: AssistantService + mic: MicService + audio: AudioService + tasks: TasksService + segmentEditor: SegmentEditorService + entityEditor: EntityEditorService + filterEditor: FilterEditorService + projectEditor: ProjectEditorService + scriptEditor: ScriptEditorService + workflowEditor: WorkflowEditorService + editors: EditorsService + monitor: MonitorService + timeline: TimelineService + renderer: RendererService + resolver: ResolverService + broadcast: BroadcastService + simulator: SimulatorService + ui: UIService + io: IOService +} + +export type Services = PrivateServices & PublicServices \ No newline at end of file diff --git a/packages/clapper-services/src/settings.ts b/packages/clapper-services/src/settings.ts new file mode 100644 index 0000000000000000000000000000000000000000..ce6fae5ae2ea8347ea71e413fe72e2522634c07c --- /dev/null +++ b/packages/clapper-services/src/settings.ts @@ -0,0 +1,211 @@ +import { ClapWorkflow, ClapWorkflowProvider } from "@aitube/clap" +import { RenderingStrategy } from "@aitube/timeline" + +import { ComfyIcuAccelerator } from "./base-types" + +export type BaseSettings = { + comfyUiClientId: string + comfyUiHttpAuthLogin: string + comfyUiHttpAuthPassword: string + replicateApiKey: string + comfyIcuApiKey: string + comfyIcuAccelerator: ComfyIcuAccelerator + comfyDeployApiKey: string + aiTubeApiKey: string + falAiApiKey: string + modelsLabApiKey: string + huggingFaceApiKey: string + openaiApiKey: string + googleApiKey: string + groqApiKey: string + anthropicApiKey: string + elevenLabsApiKey: string + kitsAiApiKey: string + cohereApiKey: string + mistralAiApiKey: string + stabilityAiApiKey: string + fireworksAiApiKey: string + + broadcastObsServerHost: string + broadcastObsServerPort: number + broadcastObsServerPass: string + + // -------------- SAFETY CHECKER ------------------ + + censorNotForAllAudiencesContent: boolean + + // -------------- MISC SETTINGS ------------------- + + imagePromptPrefix: string + imagePromptSuffix: string + imageNegativePrompt: string + videoPromptPrefix: string + videoPromptSuffix: string + videoNegativePrompt: string + + imageRenderingStrategy: RenderingStrategy + imageUpscalingRenderingStrategy: RenderingStrategy + imageDepthRenderingStrategy: RenderingStrategy + imageSegmentationRenderingStrategy: RenderingStrategy + videoRenderingStrategy: RenderingStrategy + videoUpscalingRenderingStrategy: RenderingStrategy + videoDepthRenderingStrategy: RenderingStrategy + videoSegmentationRenderingStrategy: RenderingStrategy + voiceRenderingStrategy: RenderingStrategy + soundRenderingStrategy: RenderingStrategy + musicRenderingStrategy: RenderingStrategy + + maxImagesToGenerateInParallel: number + maxVideosToGenerateInParallel: number + + // ------------ COMFY UI WORKFLOWS ----------------- + comfyWorkflowForImage: string + comfyWorkflowForVideo: string + comfyWorkflowForVoice: string + comfyWorkflowForSound: string + comfyWorkflowForMusic: string + + // ------------ OTHER SETTINGS ----------- + + comfyUiApiUrl: string + + gradioApiUrlForAssistant: string + gradioApiUrlForImage: string + gradioApiUrlForVideo: string + gradioApiUrlForVoice: string + gradioApiUrlForSound: string + gradioApiUrlForMusic: string + + scriptEditorShowLineNumbers: boolean + scriptEditorShowMinimap: boolean +} + +// Settings are serialized to the local storage, +// and we want to keep them lightweight +export type SettingsState = BaseSettings & { + assistantWorkflow: string + assistantTurboWorkflow: string + imageGenerationWorkflow: string + imageGenerationTurboWorkflow: string + imageUpscalingWorkflow: string + imageDepthWorkflow: string + imageSegmentationWorkflow: string + videoGenerationWorkflow: string + videoUpscalingWorkflow: string + videoDepthWorkflow: string + videoSegmentationWorkflow: string + soundGenerationWorkflow: string + voiceGenerationWorkflow: string + musicGenerationWorkflow: string +} + +// those settings are used for requests to the AI Assistant, +// or to resolve segments +export type RequestSettings = BaseSettings & { + assistantWorkflow: ClapWorkflow + assistantTurboWorkflow: ClapWorkflow + imageGenerationWorkflow: ClapWorkflow + imageGenerationTurboWorkflow: ClapWorkflow + imageUpscalingWorkflow: ClapWorkflow + imageDepthWorkflow: ClapWorkflow + imageSegmentationWorkflow: ClapWorkflow + videoGenerationWorkflow: ClapWorkflow + videoUpscalingWorkflow: ClapWorkflow + videoDepthWorkflow: ClapWorkflow + videoSegmentationWorkflow: ClapWorkflow + soundGenerationWorkflow: ClapWorkflow + voiceGenerationWorkflow: ClapWorkflow + musicGenerationWorkflow: ClapWorkflow +} + +export type SettingsControls = { + setComfyUiClientId: (comfyUiClientId?: string) => void + setComfyUiHttpAuthLogin: (comfyUiHttpAuthLogin?: string) => void + setComfyUiHttpAuthPassword: (comfyUiHttpAuthPassword?: string) => void + setReplicateApiKey: (replicateApiKey?: string) => void + setComfyIcuApiKey: (comfyIcuApiKey?: string) => void + setComfyIcuAccelerator: (comfyIcuAccelerator?: ComfyIcuAccelerator) => void + setComfyDeployApiKey: (comfyDeployApiKey?: string) => void + setHuggingFaceApiKey: (huggingFaceApiKey?: string) => void + setModelsLabApiKey: (modelsLabApiKey?: string) => void + setAiTubeApiKey: (aiTubeApiKey?: string) => void + setFalAiApiKey: (falAiApiKey?: string) => void + setOpenaiApiKey: (openaiApiKey?: string) => void + setGoogleApiKey: (googleApiKey?: string) => void + setGroqApiKey: (groqApiKey?: string) => void + setFireworksAiApiKey: (fireworksAiApiKey?: string) => void + setAnthropicApiKey: (anthropicApiKey?: string) => void + setElevenLabsApiKey: (elevenLabsApiKey?: string) => void + setCohereApiKey: (cohereApiKey?: string) => void + setMistralAiApiKey: (mistralAiApiKey?: string) => void + setKitsAiApiKey: (kitsAiApiKey?: string) => void + setStabilityAiApiKey: (stabilityAiApiKey?: string) => void + + setCensorNotForAllAudiencesContent: (censorNotForAllAudiencesContent?: boolean) => void + setImagePromptPrefix: (imagePromptPrefix?: string) => void + setImagePromptSuffix: (imagePromptSuffix?: string) => void + setImageNegativePrompt: (imageNegativePrompt?: string) => void + setVideoPromptPrefix: (videoPromptPrefix?: string) => void + setVideoPromptSuffix: (videoPromptSuffix?: string) => void + setVideoNegativePrompt: (videoNegativePrompt?: string) => void + + setAssistantWorkflow: (assistantWorkflow?: string) => void + setAssistantTurboWorkflow: (assistantTurboWorkflow?: string) => void + setImageGenerationWorkflow: (imageGenerationWorkflow?: string) => void + setImageGenerationTurboWorkflow: (imageGenerationTurboWorkflow?: string) => void + setImageUpscalingWorkflow: (imageUpscalingWorkflow?: string) => void + setImageDepthWorkflow: (imageDepthWorkflow?: string) => void + setImageSegmentationWorkflow: (imageSegmentationWorkflow?: string) => void + setVideoGenerationWorkflow: (videoGenerationWorkflow?: string) => void + setVideoDepthWorkflow: (videoDepthWorkflow?: string) => void + setVideoSegmentationWorkflow: (videoSegmentationWorkflow?: string) => void + setVideoUpscalingWorkflow: (videoUpscalingWorkflow?: string) => void + setSoundGenerationWorkflow: (soundGenerationWorkflow?: string) => void + setVoiceGenerationWorkflow: (voiceGenerationWorkflow?: string) => void + setMusicGenerationWorkflow: (musicGenerationWorkflow?: string) => void + + setImageRenderingStrategy: (imageRenderingStrategy?: RenderingStrategy) => void + setImageUpscalingRenderingStrategy: (imageUpscalingRenderingStrategy?: RenderingStrategy) => void + setImageDepthRenderingStrategy: (imageDepthRenderingStrategy?: RenderingStrategy) => void + setImageSegmentationRenderingStrategy: (imageSegmentationRenderingStrategy?: RenderingStrategy) => void + setVideoRenderingStrategy: (videoRenderingStrategy?: RenderingStrategy) => void + setVideoDepthRenderingStrategy: (videoDepthRenderingStrategy?: RenderingStrategy) => void + setVideoSegmentationRenderingStrategy: (videoSegmentationRenderingStrategy?: RenderingStrategy) => void + setVideoUpscalingRenderingStrategy: (videoUpscalingRenderingStrategy?: RenderingStrategy) => void + setVoiceRenderingStrategy: (voiceRenderingStrategy?: RenderingStrategy) => void + setSoundRenderingStrategy: (soundRenderingStrategy?: RenderingStrategy) => void + setMusicRenderingStrategy: (musicRenderingStrategy?: RenderingStrategy) => void + + + setMaxImagesToGenerateInParallel: (maxImagesToGenerateInParallel?: number) => void + setMaxVideosToGenerateInParallel: (maxVideosToGenerateInParallel?: number) => void + + setComfyWorkflowForImage: (comfyWorkflowForImage?: string) => void + setComfyWorkflowForVideo: (comfyWorkflowForVideo?: string) => void + setComfyWorkflowForVoice: (comfyWorkflowForVoice?: string) => void + setComfyWorkflowForSound: (comfyWorkflowForSound?: string) => void + setComfyWorkflowForMusic: (comfyWorkflowForMusic?: string) => void + + setComfyUiApiUrl: (comfyUiApiUrl?: string) => void + + setGradioApiUrlForAssistant: (gradioApiUrlForAssistant?: string) => void + setGradioApiUrlForImage: (gradioApiUrlForImage?: string) => void + setGradioApiUrlForVideo: (gradioApiUrlForVideo?: string) => void + setGradioApiUrlForVoice: (gradioApiUrlForVoice?: string) => void + setGradioApiUrlForSound: (gradioApiUrlForSound?: string) => void + setGradioApiUrlForMusic: (gradioApiUrlForMusic?: string) => void + + setScriptEditorShowLineNumbers: (scriptEditorShowLineNumbers: boolean) => void + setScriptEditorShowMinimap: (scriptEditorShowMinimap: boolean) => void + + /** + * Return settings that can be used for a request + * + * @returns + */ + getRequestSettings: () => RequestSettings +} + +export type SettingsStore = + SettingsState & + SettingsControls \ No newline at end of file diff --git a/packages/clapper-services/src/simulator.ts b/packages/clapper-services/src/simulator.ts new file mode 100644 index 0000000000000000000000000000000000000000..e31d21af188ae55b799e5c3d17b8c5a686c85bcf --- /dev/null +++ b/packages/clapper-services/src/simulator.ts @@ -0,0 +1,12 @@ +export type SimulatorState = { + isRunning: boolean +} + +export type SimulatorControls = { + startLoop: () => void + runLoop: () => Promise + + togglePause: (isPaused?: boolean) => boolean +} + +export type SimulatorStore = SimulatorState & SimulatorControls \ No newline at end of file diff --git a/packages/clapper-services/src/speech.d.ts b/packages/clapper-services/src/speech.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..427b4065a1fd15c69d08e5de20de780a25e50ce9 --- /dev/null +++ b/packages/clapper-services/src/speech.d.ts @@ -0,0 +1,135 @@ +// https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition#events +interface SpeechRecognitionEventMap { + audioend: Event; + audiostart: Event; + end: Event; + error: SpeechRecognitionErrorEvent; + nomatch: SpeechRecognitionEvent; + result: SpeechRecognitionEvent; + soundend: Event; + soundstart: Event; + speechend: Event; + speechstart: Event; + start: Event; +} + +// https://wicg.github.io/speech-api/#speechreco-section +interface SpeechRecognition extends EventTarget { + continuous: boolean; + grammars: SpeechGrammarList; + interimResults: boolean; + lang: string; + maxAlternatives: number; + onaudioend: ((this: SpeechRecognition, ev: Event) => any) | null; + onaudiostart: ((this: SpeechRecognition, ev: Event) => any) | null; + onend: ((this: SpeechRecognition, ev: Event) => any) | null; + onerror: ((this: SpeechRecognition, ev: SpeechRecognitionErrorEvent) => any) | null; + onnomatch: ((this: SpeechRecognition, ev: SpeechRecognitionEvent) => any) | null; + onresult: ((this: SpeechRecognition, ev: SpeechRecognitionEvent) => any) | null; + onsoundend: ((this: SpeechRecognition, ev: Event) => any) | null; + onsoundstart: ((this: SpeechRecognition, ev: Event) => any) | null; + onspeechend: ((this: SpeechRecognition, ev: Event) => any) | null; + onspeechstart: ((this: SpeechRecognition, ev: Event) => any) | null; + onstart: ((this: SpeechRecognition, ev: Event) => any) | null; + abort(): void; + start(): void; + stop(): void; + addEventListener( + type: K, + listener: (this: SpeechRecognition, ev: SpeechRecognitionEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: (this: SpeechRecognition, ev: SpeechRecognitionEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var SpeechRecognition: { prototype: SpeechRecognition; new(): SpeechRecognition }; + +// https://wicg.github.io/speech-api/#speechrecognitionevent +interface SpeechRecognitionEventInit extends EventInit { + resultIndex?: number; + results: SpeechRecognitionResultList; +} + +// https://wicg.github.io/speech-api/#dictdef-speechrecognitioneventinit +interface SpeechRecognitionEvent extends Event { + readonly resultIndex: number; + readonly results: SpeechRecognitionResultList; +} + +declare var SpeechRecognitionEvent: { + prototype: SpeechRecognitionEvent; + new(type: string, eventInitDict: SpeechRecognitionEventInit): SpeechRecognitionEvent; +}; + +// https://wicg.github.io/speech-api/#enumdef-speechrecognitionerrorcode +type SpeechRecognitionErrorCode = + | "aborted" + | "audio-capture" + | "bad-grammar" + | "language-not-supported" + | "network" + | "no-speech" + | "not-allowed" + | "service-not-allowed"; + +// https://wicg.github.io/speech-api/#dictdef-speechrecognitionerroreventinit +interface SpeechRecognitionErrorEventInit extends EventInit { + error: SpeechRecognitionErrorCode; + message?: string; +} + +// https://wicg.github.io/speech-api/#speechrecognitionerrorevent +interface SpeechRecognitionErrorEvent extends Event { + readonly error: SpeechRecognitionErrorCode; + readonly message: string; +} + +declare var SpeechRecognitionErrorEvent: { + prototype: SpeechRecognitionErrorEvent; + new(type: string, eventInitDict: SpeechRecognitionErrorEventInit): SpeechRecognitionErrorEvent; +}; + +// https://wicg.github.io/speech-api/#speechgrammar +interface SpeechGrammar { + src: string; + weight: number; +} + +declare var SpeechGrammar: { + prototype: SpeechGrammar; + new(): SpeechGrammar; +}; + +// https://wicg.github.io/speech-api/#speechgrammarlist +interface SpeechGrammarList { + readonly length: number; + addFromString(string: string, weight?: number): void; + addFromURI(src: string, weight?: number): void; + item(index: number): SpeechGrammar; + [index: number]: SpeechGrammar; +} + +declare var SpeechGrammarList: { prototype: SpeechGrammarList; new(): SpeechGrammarList }; + +// prefixed global variables in Chrome; should match the equivalents above +// https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API/Using_the_Web_Speech_API#chrome_support +declare var webkitSpeechRecognition: { prototype: SpeechRecognition; new(): SpeechRecognition }; +declare var webkitSpeechGrammarList: { prototype: SpeechGrammarList; new(): SpeechGrammarList }; +declare var webkitSpeechRecognitionEvent: { + prototype: SpeechRecognitionEvent; + new(type: string, eventInitDict: SpeechRecognitionEventInit): SpeechRecognitionEvent; +}; diff --git a/packages/clapper-services/src/tasks.ts b/packages/clapper-services/src/tasks.ts new file mode 100644 index 0000000000000000000000000000000000000000..3a0ed5703d75f4a4e8be0a395d3cbbc8116569aa --- /dev/null +++ b/packages/clapper-services/src/tasks.ts @@ -0,0 +1,119 @@ +import { ReactNode } from "react" + +export enum TaskVisibility { + BLOCKER = "BLOCKER", + BACKGROUND = "BACKGROUND", + INVISIBLE = "INVISIBLE" +} + +export enum TaskProgressType { + RATIO = "RATIO", // number between 0 and 1 + PERCENTAGE = "PERCENTAGE", // number between 0 and 100 + COUNTER = "COUNTER" // number between min and max +} + +export enum TaskCategory { + DOWNLOAD = "DOWNLOAD", + EXPORT = "EXPORT", + IMPORT = "IMPORT", + ANALYSIS = "ANALYSIS", + STORYBOARD = "STORYBOARD", + VIDEO = "VIDEO", + GENERIC = "GENERIC" +} + +export enum TaskStatus { + UPCOMING = "UPCOMING", + RUNNING = "RUNNING", + PAUSED = "PAUSED", + CANCELLED = "CANCELLED", + ERROR = "ERROR", + SUCCESS = "SUCCESS", + DELETED = "DELETED" +} + +export type StatusGetter = () => TaskStatus +export type TaskRunner = (getStatus: StatusGetter) => Promise + +export type NewTask = { + id: string + category: TaskCategory + visibility: TaskVisibility + initialMessage: ReactNode + successMessage: ReactNode + priority: number // 0 = lowest, 1 or more = more and more important + value: number + progress: number + status: TaskStatus + min: number + max: number + mode: TaskProgressType + run?: TaskRunner +} + +export type Task = NewTask & { + currentMessage: ReactNode + startedAt: string + endedAt: string + value: number + promise: Promise +} + +/** + * A nice helper to do various operations with tasks + */ +export type TaskRemoteControl = { + task: Task + + // a promise tracking the current status of the task + promise: Promise + pause: () => void + continue: () => void + setStatus: (status: TaskStatus) => void + setProgress: (options?: { + value?: number + sleepDelay?: number + message?: string + isFinished?: boolean + }) => Promise + + success: () => void + fail: (reason?: string) => void + cancel: () => void +} + +export type TasksState = { + tasks: Record, + expandTasks: boolean +} + +export type TasksControls = { + setExpandTasks: (expandTasks: boolean) => void, + get: (taskId?: string) => TaskRemoteControl | undefined + find: (params?: { + status?: TaskStatus + category?: TaskCategory + visibility?: TaskVisibility + }) => Task[] + add: (partialTask: Partial, status?: TaskStatus) => TaskRemoteControl + pause: (taskId?: string) => void + continue: (taskId?: string) => void + setStatus: (status: TaskStatus, taskId?: string) => void + setProgress: (taskId: string, options?: { + value?: number + sleepDelay?: number + message?: string + isFinished?: boolean + hasFailed?: boolean + }) => Promise + + // cancel and clear all tasks (used when switching project) + clear: () => void + + // mark a task as completed + success: (taskId: string) => void + fail: (taskId: string, reason?: string) => void + cancel: (taskId?: string) => void +} + +export type TasksStore = TasksState & TasksControls \ No newline at end of file diff --git a/packages/clapper-services/src/types.ts b/packages/clapper-services/src/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..731e5dde181afbec4027922e3b82dfd3e99d5208 --- /dev/null +++ b/packages/clapper-services/src/types.ts @@ -0,0 +1,50 @@ +// import { ClapEntity, ClapMeta } from "@aitube/clap" + +import { TimelineSegment } from "@aitube/timeline" + +import { RequestSettings, SettingsState } from "./settings" +import { ChatEvent, ResolveRequestPrompts } from "./base-types" + +export type ResolveRequest = { + settings: RequestSettings + + // the reference segment to render (eg. storyboard or video) + segment: TimelineSegment + + // the slice to use for rendering + segments: TimelineSegment[] + + entities: Record // ClapEntity + + speakingCharactersIds: string[] + generalCharactersIds: string[] + mainCharacterId?: string + mainCharacterEntity?: any // ClapEntity + + meta: any // ClapMeta + + prompts: ResolveRequestPrompts +} + +export type AssistantRequest = { + settings: RequestSettings + + prompt: string + + // the slice to edit + segments: TimelineSegment[] + + // the full text of the current scene + fullScene: string + + // the full text of the current action line + actionLine: string + + // used to provide more context + entities: Record // ClapEntity + + // used to provide more context + projectInfo: string + + history: ChatEvent[] +} diff --git a/packages/clapper-services/src/ui.ts b/packages/clapper-services/src/ui.ts new file mode 100644 index 0000000000000000000000000000000000000000..8b5b9fce8c7c2b99abb1c3f410cf984f1d7b7e77 --- /dev/null +++ b/packages/clapper-services/src/ui.ts @@ -0,0 +1,132 @@ +import { ClapTimelineTheme } from "@aitube/timeline" +import { ProjectCreationWizardStep, SettingsCategory } from "./base-types" +import { WorkflowEditorTheme } from "./workflow-editor" + +export type UIThemeName = + | 'backstage' + | 'midnight' + | 'lavender' + | 'flix' + | 'lore' + | 'gordon' + | 'ripley' + | 'silent' + | string + +// Tailwind and React Flow expect a color mode in lowercase, +// so we just leave it that way +export enum UIThemeColorMode { + DARK = "dark", + LIGHT = "light" +} + +/** + * TODO: + * + * - more colors for Monaco editor + * + * - change shadcn/ui colors + * + * - timeline CSS filter is a quick hack to get a hue, + * instead (or in addition to it) we could pass color parameters + * + * - handle light and dark themes + * + */ +export type UITheme = { + id: UIThemeName + colorMode: UIThemeColorMode + label: string + author: string + description: string + + wallpaperBgImage?: string + + defaultBgColor?: string + defaultTextColor?: string + defaultPrimaryColor?: string + defaultBorderColor?: string + logoColor?: string + editorBgColor?: string + editorCursorColor?: string + editorTextColor?: string + editorMenuBgColor?: string + editorMenuTextColor?: string + editorBorderColor?: string + + // background color of the video preview monitor + monitorBgColor?: string + + // text of the elapsed/total duration counter in the video preview monitor + monitorSecondaryTextColor?: string + monitorPrimaryTextColor?: string + + assistantBgColor?: string + assistantUserBgColor?: string + assistantRobotBgColor?: string + assistantUserTextColor?: string + assistantRobotTextColor?: string + + formInputRadius?: string + + windowHeaderBgColor?: string + windowBodyBgColor?: string + windowBorderColor?: string + windowBorderRadius?: string + + timeline: ClapTimelineTheme + + workflow: WorkflowEditorTheme +} + +export enum UIWindowLayout { + GRID = "GRID", + FLYING = "FLYING" +} + +export type UIState = { + isTopMenuOpen: boolean + showWelcomeScreen: boolean + hasBetaAccess: boolean + themeName: UIThemeName + showApiKeys: boolean + showSettings: SettingsCategory + showImporter: boolean + showTimeline: boolean + showExplorer: boolean + showVideoPlayer: boolean + showAssistant: boolean + showFPS: boolean + followCursor: boolean + editorFontSize: number + + windowLayout: UIWindowLayout + projectCreationWizardStep: ProjectCreationWizardStep +} + +export type UIControls = { + setIsTopMenuOpen: (isTopMenuOpen: boolean) => void + setShowWelcomeScreen: (showWelcomeScreen: boolean) => void + // TODO @Julian: can be used to control the onboarding process + // setOnboardingStep: (onboardingStep?: OnboardingStep) => void + setHasBetaAccess: (hasBetaAccess: boolean) => void + setThemeName: (themeName: UIThemeName) => void + applyThemeToComponents: () => void + getTheme: () => UITheme + setShowApiKeys: (showApiKeys: boolean) => void + setShowSettings: (showSettings: SettingsCategory) => void + setShowImporter: (showImporter: boolean) => void + setShowTimeline: (showTimeline: boolean) => void + setShowExplorer: (showExplorer: boolean) => void + setShowVideoPlayer: (showVideoPlayer: boolean) => void + setShowAssistant: (showAssistant: boolean) => void + setShowFPS: (showFPS: boolean) => void + setFollowCursor: (followCursor: boolean) => void + setEditorFontSize: (editorFontSize: number) => void + setWindowLayout: (windowLayout: UIWindowLayout) => void + setProjectCreationWizardStep: (projectCreationWizardStep: ProjectCreationWizardStep) => void +} + +export type UIStore = + UIState & + UIControls \ No newline at end of file diff --git a/packages/clapper-services/src/version-control.ts b/packages/clapper-services/src/version-control.ts new file mode 100644 index 0000000000000000000000000000000000000000..4205f9aba7a328dc00fe41369256d1416b766fbf --- /dev/null +++ b/packages/clapper-services/src/version-control.ts @@ -0,0 +1,59 @@ +export type VersionHistory = { + before: T[] + current?: T + after: T[] +} + +export type VersionState = VersionHistory & { + version: number +} + +export type VersionControls = { + setCurrent: (current?: T) => void + undo: () => void + redo: () => void +} + +export function undo(state: VersionState) { + let before: T[] = state?.before || [] + let current: T | undefined = typeof state?.current !== 'undefined' && state?.current !== null ? state?.current : undefined + let after: T[] = state?.after || [] + let version: number = state?.version || 0 + + // we add the current value to the redo + if (current) { + after.unshift(current) + } + if (before.length) { + current = before.pop() + } + + return { + before, + current, + after, + version: version + 1 + } +} + +export function redo(state: VersionState) { + let before: T[] = state?.before || [] + let current: T | undefined = typeof state?.current !== 'undefined' && state?.current !== null ? state?.current : undefined + let after: T[] = state?.after || [] + let version: number = state?.version || 0 + + // we add the current value to the undo + if (current) { + before.push(current) + } + if (after.length) { + current = after.shift() + } + + return { + before, + current, + after, + version: version + 1 + } +} diff --git a/packages/clapper-services/src/workflow-editor.ts b/packages/clapper-services/src/workflow-editor.ts new file mode 100644 index 0000000000000000000000000000000000000000..0c34149d5ceca9c3dac1b3a149d62b3542caf3bd --- /dev/null +++ b/packages/clapper-services/src/workflow-editor.ts @@ -0,0 +1,28 @@ +import { ClapWorkflow } from "@aitube/clap" + +import { VersionControls, VersionState } from "./version-control" + +export type WorkflowEditorTheme = { + bgColor?: string; + node: { + bgColor?: string; + borderColor?: string; + textPrimaryColor?: string; + textSecondaryColor?: string; + radius?: string; + } + handle: { + inputColor?: string; + outputColor?: string; + } +} + +export type WorkflowEditorState = { + availableWorkflows: ClapWorkflow[] +} & VersionState + +export type WorkflowEditorControls = { + updateAvailableWorkflows: () => Promise +} & VersionControls + +export type WorkflowEditorStore = WorkflowEditorState & WorkflowEditorControls diff --git a/packages/clapper-services/tsconfig.json b/packages/clapper-services/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..ab7cc3ed096e5dc51a557fdee4e68c0e28076d0b --- /dev/null +++ b/packages/clapper-services/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "baseUrl": "./", + "paths": { + "@/*": ["src/*"] + }, + "lib": ["ESNext", "DOM"], + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": true, + "noEmit": true, + "composite": true, + "strict": true, + "downlevelIteration": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "types": [ + "bun-types" + ] + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/packages/clapper-services/tsconfig.types.json b/packages/clapper-services/tsconfig.types.json new file mode 100644 index 0000000000000000000000000000000000000000..a6a3f21154bb178f1850c9b70714fb66ef5bf750 --- /dev/null +++ b/packages/clapper-services/tsconfig.types.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "emitDeclarationOnly": true, + "declaration": true, + "outDir": "./dist", + "rootDir": "./src", + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/packages/colors/.gitignore b/packages/colors/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..5696d8f82310544413976927b50740b885ec86a4 --- /dev/null +++ b/packages/colors/.gitignore @@ -0,0 +1,179 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +.age_and_gender_dataset_cache + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +\*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +\*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +\*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +\*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.cache +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output +dist +.nuxt + +# Gatsby files + +.cache/ + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp +.cache + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.\* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store + +# TypeScript build information +*.tsbuildinfo diff --git a/packages/colors/.npmignore b/packages/colors/.npmignore new file mode 100644 index 0000000000000000000000000000000000000000..78a661ea2d8f8cdaa94e4cc69d758a4b2d946feb --- /dev/null +++ b/packages/colors/.npmignore @@ -0,0 +1,4 @@ +# Ignore everything +* +# Except the dist directory +!dist/ diff --git a/packages/colors/.prettierrc.json b/packages/colors/.prettierrc.json new file mode 100644 index 0000000000000000000000000000000000000000..1dcadb7324877e15a4ffa4efa5723a519395f511 --- /dev/null +++ b/packages/colors/.prettierrc.json @@ -0,0 +1,9 @@ +{ + "semi": false, + "singleQuote": true, + "arrowParens": "avoid", + "printWidth": 140, + "tabWidth": 2, + "trailingComma": "es5", + "bracketSpacing": true +} diff --git a/packages/colors/LICENSE.md b/packages/colors/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..8b21ed7d57c2d217f49e10d0fb0b327961a4ea54 --- /dev/null +++ b/packages/colors/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2024 Julian Bilcke + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/colors/README.md b/packages/colors/README.md new file mode 100644 index 0000000000000000000000000000000000000000..25c09e57df942d620f5ff2e513d34fd9a02c4174 --- /dev/null +++ b/packages/colors/README.md @@ -0,0 +1,54 @@ +# @aitube/colors + +*Various color settings and utilities for AiTube* + +## Installation + +Run the following command (`@aitube/clap` is a peer dependency): + +```bash +# this depends on your package manager, eg: +npm install @aitube/colors @aitube/clap +# or: +bun i @aitube/colors @aitube/clap +``` + +## Getting Started + +```typescript +import { ... } from '@aitube/colors' + +... + +``` + +## Note to developers + +Use at your perils! + +## Build Instructions + +Install [Bun](https://bun.sh/) + +Run the following commands: + +```bash +bun install + +bun run build +``` + +To publish: + +```bash +bun run build + +bun run build:declaration + +bun run publish +``` + +## License + +This package is under the MIT License. See `LICENSE` file for more details. +Also please don't destroy the planet with my code. diff --git a/packages/colors/package.json b/packages/colors/package.json new file mode 100644 index 0000000000000000000000000000000000000000..f45799a4ded09ba0e69328084878c159221a354c --- /dev/null +++ b/packages/colors/package.json @@ -0,0 +1,37 @@ +{ + "name": "@aitube/colors", + "module": "index.ts", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "type": "module", + "version": "0.2.4", + "description": "Various color settings and utilities for AiTube", + "scripts": { + "build": "bun build ./src/index.ts --outfile=dist/index.js --external=@aitube/clap && bun run build:declaration", + "build:declaration": "tsc --emitDeclarationOnly --project tsconfig.types.json", + "postbuild": "rimraf tsconfig.types.tsbuildinfo && bun run build:declaration", + "publish": "bun build && npm publish --access public", + "update": "rm -Rf node_modules && rm bun.lockb && bun i && bun run build" + }, + "devDependencies": { + "bun-types": "latest", + "prettier": "^3.3.3", + "rimraf": "^6.0.1", + "typescript": "^5.5.4" + }, + "repository": { + "type": "git", + "url": "https://github.com/jbilcke-hf/aitube-colors.git" + }, + "keywords": [ + "OpenClap", + "AiTube" + ], + "author": "Julian Bilcke", + "license": "MIT", + "files": [ + "dist/*.js", + "dist/*.d.ts", + "dist/**/*.d.ts" + ] +} diff --git a/packages/colors/src/constants/colors.ts b/packages/colors/src/constants/colors.ts new file mode 100644 index 0000000000000000000000000000000000000000..9dd4dd7159b3c01d0cc08e55de1f82246bf1fb0a --- /dev/null +++ b/packages/colors/src/constants/colors.ts @@ -0,0 +1,54 @@ + +// important: not all colors have the same values! +// for instance the red and gray(s) have a slightly lighter border bottom, +// because they look better this way +export const segmentColorsTailwind = { + blue: `bg-blue-400 shadow-blue-600/50 border-l-blue-400/80 border-r-blue-400/80 border-t-blue-300/40 border-b-blue-500/80 text-blue-900`, + red: `bg-red-400 shadow-red-600/50 border-l-red-400/80 border-r-red-400/80 border-t-red-300/40 border-b-red-400/80 text-red-900`, + + // + + rose: `bg-rose-400 shadow-rose-600/50 border-l-rose-400/80 border-r-rose-400/80 border-t-rose-300/40 border-b-rose-500/80 text-rose-900`, + green: `bg-green-400 shadow-green-600/50 border-l-green-400/80 border-r-green-400/80 border-t-green-300/40 border-b-green-500/80 text-green-900`, + + green2: `bg-[rgb(162,222,83)] shadow-[rgb(122,162,43)]/50 border-l-[rgb(152,192,73)]/80 border-r-[rgb(152,192,73)]/80 border-t-[rgb(172,212,93)]/40 border-b-[rgb(132,172,53)]/80 text-[rgb(52,92,0)]`, + green3: `bg-[rgb(144,170,137)] shadow-[rgb(124,150,117)]/50 border-l-[rgb(164,190,157)]/80 border-r-[rgb(144,170,137)]/80 border-t-[rgb(174,200,167)]/40 border-b-[rgb(130,157,137)]/80 text-[rgb(44,70,37)]`, + + + violet: `bg-violet-400 shadow-violet-600/50 border-l-violet-400/80 border-r-violet-400/80 border-t-violet-300/40 border-b-violet-500/80 text-violet-900`, + amber: `bg-amber-400 shadow-amber-600/50 border-l-amber-400/80 border-r-amber-400/80 border-t-amber-300/40 border-b-amber-500/80 text-amber-900`, + yellow: `bg-yellow-400 shadow-yellow-600/50 border-l-yellow-400/80 border-r-yellow-400/80 border-t-yellow-300/40 border-b-yellow-500/80 text-yellow-900`, + yellow2: `bg-[rgb(250,204,110)] shadow-[rgb(230,184,90]/50 border-l-[rgb(250,204,110)]/80 border-r-[rgb(250,204,110)]/80 border-t-[rgb(255,224,130)]/40 border-b-[rgb(240,194,100)]/80 text-[rgb(91,72,3)]`, + + teal: `bg-teal-400 shadow-teal-600/50 border-l-teal-400/80 border-r-teal-400/80 border-t-teal-300/40 border-b-teal-500/80 text-teal-900`, + cyan: `bg-cyan-400 shadow-cyan-600/50 border-l-cyan-400/80 border-r-cyan-400/80 border-t-cyan-300/40 border-b-cyan-500/80 text-cyan-900`, + orange: `bg-orange-400 shadow-orange-600/50 border-l-orange-400/80 border-r-orange-400/80 border-t-orange-300/40 border-b-orange-500/80 text-orange-900`, + + orange2: `bg-[rgb(222,162,83)] shadow-[rgb(162,122,43)]/50 border-l-[rgb(192,152,73)]/80 border-r-[rgb(192,152,73)]/80 border-t-[rgb(212,172,93)]/40 border-b-[rgb(172,132,53)]/80 text-[rgb(92,52,0)]`, + + // + + sky: `bg-sky-400 shadow-sky-600/50 border-l-sky-400/80 border-r-sky-400/80 border-t-sky-300/40 border-b-sky-500/80 text-sky-900`, + stone: `bg-stone-400 shadow-stone-600/50 border-l-stone-400/80 border-r-stone-400/80 border-t-stone-300/40 border-b-stone-400/80 text-stone-700`, + // stone2: `bg-stone-500 shadow-stone-700/50 border-l-stone-500/80 border-r-stone-500/80 border-t-stone-400/40 border-b-stone-500/80 text-stone-900`, + sand: `bg-[rgb(200,176,124)] shadow-[rgb(180,156,104)]/50 border-l-[rgb(200,176,124)]/80 border-r-[rgb(200,176,124)]/80 border-t-[rgb(220,196,144)]/40 border-b-[rgb(200,176,124)]/80 text-[rgb(100,76,24)]`, + + zinc: `bg-zinc-400 shadow-zinc-600/50 border-l-zinc-400/80 border-r-zinc-400/80 border-t-zinc-300/40 border-b-zinc-400/80 text-zinc-900`, + zinc2: `bg-zinc-300 shadow-zinc-600/50 border-l-zinc-400/80 border-r-zinc-400/80 border-t-zinc-300/40 border-b-zinc-400/80 text-zinc-600`, + lime: `bg-lime-400 shadow-lime-600/50 border-l-lime-400/80 border-r-lime-400/80 border-t-lime-300/40 border-b-lime-500/80 text-lime-900`, + indigo: `bg-indigo-400 shadow-indigo-600/50 border-l-indigo-400/80 border-r-indigo-400/80 border-t-indigo-300/40 border-b-indigo-500/80 text-indigo-900`, + purple: `bg-purple-400 shadow-purple-600/50 border-l-purple-400/80 border-r-purple-400/80 border-t-purple-300/40 border-b-purple-500/80 text-purple-900`, + purple2: `bg-[rgb(175,191,203)] shadow-[rgb(145,161,173)]/50 border-l-[rgb(175,191,203)]/80 border-r-[rgb(175,191,203)]/80 border-t-[rgb(195,211,223)]/40 border-b-[rgb(145,151,173)]/80 text-[rgb(65,81,93)]`, + + pink: `bg-pink-400 shadow-pink-600/50 border-l-pink-400/80 border-r-pink-400/80 border-t-pink-300/40 border-b-pink-500/80 text-pink-900`, + pink2: `bg-[rgb(191,145,184)] shadow-[rgb(121,85,114)]/50 border-l-[rgb(181,145,174)]/80 border-r-[rgb(181,145,174)]/80 border-t-[rgb(211,175,204)]/40 border-b-[rgb(151,115,144)]/80 text-[rgb(81,45,74)]`, + pink3: `bg-[rgb(191,160,184)] shadow-[rgb(121,100,114)]/50 border-l-[rgb(181,160,174)]/80 border-r-[rgb(181,160,174)]/80 border-t-[rgb(211,190,204)]/40 border-b-[rgb(151,130,144)]/80 text-[rgb(81,60,74)]`, + + neutral: `bg-neutral-400 shadow-neutral-600/50 border-l-neutral-400/80 border-r-neutral-400/80 border-t-neutral-400/40 border-b-neutral-500/80 text-neutral-900`, + neutral2: `bg-[rgb(150,145,135)] shadow-neutral-600/50 border-l-neutral-400/80 border-r-neutral-400/80 border-t-neutral-400/40 border-b-neutral-500/80 text-neutral-700`, + + gray: `bg-gray-400 shadow-gray-600/50 border-l-gray-400/80 border-r-gray-400/80 border-t-gray-300/40 border-b-gray-400/80 text-gray-900`, + gray2: `bg-gray-400 shadow-gray-600/50 border-l-gray-400/80 border-r-gray-400/80 border-t-gray-300/40 border-b-gray-400/80 text-gray-700`, +} + +export type SegmentColor = keyof typeof segmentColorsTailwind diff --git a/packages/colors/src/constants/index.ts b/packages/colors/src/constants/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..2fe7ce068967448c2d50d639e66527e74a7ac9e4 --- /dev/null +++ b/packages/colors/src/constants/index.ts @@ -0,0 +1,8 @@ +export { segmentColorsTailwind, type SegmentColor } from "./colors" + +export { + segmentCategories, + categoryNames, + getSegment, + getSegmentColor +} from "./segments" diff --git a/packages/colors/src/constants/segments.ts b/packages/colors/src/constants/segments.ts new file mode 100644 index 0000000000000000000000000000000000000000..04fcb51e33f03cd249386cab081a559bfdd077dd --- /dev/null +++ b/packages/colors/src/constants/segments.ts @@ -0,0 +1,219 @@ +import { ClapSegmentCategory } from "@aitube/clap" + +import { SegmentColor } from "@/constants/colors" +import { ClapSegmentCategorySettings } from "@/types" + +// this is a special segment used for rendering the scene +const splat: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.SPLAT, + title: "Splat", + description: "Gaussian splatting", + color: "pink", +} + +const mesh: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.MESH, + title: "Mesh", + description: "Render a mesh", + color: "green2" +} + +const depth: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.DEPTH, + title: "Depth map", + description: "Dpeth map", + color: "yellow", +} + +// this is a special segment used for rendering the scene +const video: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.VIDEO, + title: "video", + description: "Render a video", + color: "indigo", +} + +// this is a special segment type used to render preview thumbnails +const storyboard: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.STORYBOARD, + title: "storyboard", + description: "Storyboard preview (image or video)", + color: "indigo", +} + +const action: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.ACTION, + title: "Action", + description: "Action", + color: "orange2", +} + +const character: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.CHARACTER, + title: "Character", + description: "Characters, animals..", + color: "purple", +} + +const location: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.LOCATION, + title: "Location", + description: "Location (country, place, background, furnitures..)", + color: "sand", +} + +const camera: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.CAMERA, + title: "camera", + description: "Camera (position, angle, direction)", + color: "zinc2", +} + +const transition: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.TRANSITION, + title: "transition", + description: "Transition", + color: "teal", +} + +const lighting: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.LIGHTING, + title: "Lighting", + description: "Lighting (natural or artifical)", + color: "neutral2", +} + +const time: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.TIME, + title: "Time", + description: "Time of the day (noon, night..)", + color: "neutral2", +} + +// @deprecated - use `time` and ClapSegmentCategory.TIME instead +const era: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.ERA, + title: "Era", + description: "Era (80s, Ancient Rome..)", + color: "gray", +} + +const weather: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.WEATHER, + title: "Weather", + description: "Weather (sunny, raining, snow..)", + color: "stone", +} + +const sound: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.SOUND, + title: "Sound", + description: "Sound (foreground, background..)", + color: "yellow2", +} + +const music: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.MUSIC, + title: "Music", + description: "Music (foreground, background..)", + color: "green3", +} + +const dialogue: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.DIALOGUE, + title: "Dialogue", + description: "Music (foreground, background..)", + color: "purple2", +} + +const style: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.STYLE, + title: "Style", + description: "Style", + color: "pink3", +} + +/* +const colors: ClapSegmentCategorySettings = { + id: "colors", + title: "Color grading", + description: "Color grading", + color: "pink", +} +*/ + +const generic: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.GENERIC, + title: "Generic", + description: "Generic", + color: "cyan", +} + +// (invisible) an event localized in time +const event: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.EVENT, + title: "Event", + description: "Event", + color: "purple", +} + +const effect: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.EFFECT, + title: "Effect", + description: "Effect, transformation..", + color: "pink", +} + +// (visible) an Interface (UI) element +const interface_: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.INTERFACE, + title: "Interface", + description: "Interface", + color: "cyan", +} + +// (invisible) a prompt which defines new event(s) to fire based on event(s) +const phenomenon: ClapSegmentCategorySettings = { + id: ClapSegmentCategory.PHENOMENON, + title: "Phenomenon", + description: "Phenomenon", + color: "pink", +} + +export const segmentCategories: Record = { + SPLAT: splat, + MESH: mesh, + DEPTH: depth, + EVENT: event, // (invisible) an event localized in time + EFFECT: effect, + INTERFACE: interface_, // (visible) + PHENOMENON: phenomenon, // (invisible) a prompt which defines new event(s) to fire based on event(s) + VIDEO: video, + STORYBOARD: storyboard, + CHARACTER: character, + LOCATION: location, + TIME: time, + ERA: era, + LIGHTING: lighting, + WEATHER: weather, + ACTION: action, + MUSIC: music, + SOUND: sound, + DIALOGUE: dialogue, + STYLE: style, + CAMERA: camera, + TRANSITION: transition, + GENERIC: generic, +} + +export const categoryNames = Object.keys(segmentCategories) + +export function getSegment(category?: ClapSegmentCategory): ClapSegmentCategorySettings { + return segmentCategories[category || ClapSegmentCategory.GENERIC] || segmentCategories.GENERIC +} + +export function getSegmentColor(input?: ClapSegmentCategorySettings | ClapSegmentCategory): SegmentColor { + const { color } = !input || typeof input === "string" ? getSegment(input) : input + + return color as SegmentColor +} diff --git a/packages/colors/src/index.ts b/packages/colors/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..de8941fbd27755fe0c5588a4205b379bd2151176 --- /dev/null +++ b/packages/colors/src/index.ts @@ -0,0 +1,12 @@ + +export { + segmentColorsTailwind, type SegmentColor, + segmentCategories, + categoryNames, + getSegment, + getSegmentColor +} from "./constants" + +export { + type ClapSegmentCategorySettings +} from "./types" diff --git a/packages/colors/src/types.ts b/packages/colors/src/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..93943536c6f70e390245074f55dd6fd9b3fa67ff --- /dev/null +++ b/packages/colors/src/types.ts @@ -0,0 +1,11 @@ + +// import { ClapSegmentCategory } from "@aitube/clap" + +import { SegmentColor } from "./constants/colors" + +export interface ClapSegmentCategorySettings { + id: any // ClapSegmentCategory // eg. "country" + title: string // eg. Country + description: string // description in one sentence + color: SegmentColor // base color name, in lowercase +} \ No newline at end of file diff --git a/packages/colors/tsconfig.json b/packages/colors/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..ab7cc3ed096e5dc51a557fdee4e68c0e28076d0b --- /dev/null +++ b/packages/colors/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "baseUrl": "./", + "paths": { + "@/*": ["src/*"] + }, + "lib": ["ESNext", "DOM"], + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": true, + "noEmit": true, + "composite": true, + "strict": true, + "downlevelIteration": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "types": [ + "bun-types" + ] + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/packages/colors/tsconfig.types.json b/packages/colors/tsconfig.types.json new file mode 100644 index 0000000000000000000000000000000000000000..75cb8c175c0e0a67df2ffa0f06da4aa5b272db59 --- /dev/null +++ b/packages/colors/tsconfig.types.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "emitDeclarationOnly": true, + "declaration": true, + "outDir": "./dist", + "rootDir": "./src", + }, + "include": [ + "src/**/*.ts", + "src/tests/bun-shims.js" + ] +} diff --git a/packages/engine/.gitignore b/packages/engine/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ea8fe6a7905bd72f745584146daa9994bd211499 --- /dev/null +++ b/packages/engine/.gitignore @@ -0,0 +1,177 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +\*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +\*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +\*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +\*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.cache +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output +dist +.nuxt + +# Gatsby files + +.cache/ + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp +.cache + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.\* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store + +# TypeScript build information +*.tsbuildinfo \ No newline at end of file diff --git a/packages/engine/.npmignore b/packages/engine/.npmignore new file mode 100644 index 0000000000000000000000000000000000000000..78a661ea2d8f8cdaa94e4cc69d758a4b2d946feb --- /dev/null +++ b/packages/engine/.npmignore @@ -0,0 +1,4 @@ +# Ignore everything +* +# Except the dist directory +!dist/ diff --git a/packages/engine/.prettierrc.json b/packages/engine/.prettierrc.json new file mode 100644 index 0000000000000000000000000000000000000000..1dcadb7324877e15a4ffa4efa5723a519395f511 --- /dev/null +++ b/packages/engine/.prettierrc.json @@ -0,0 +1,9 @@ +{ + "semi": false, + "singleQuote": true, + "arrowParens": "avoid", + "printWidth": 140, + "tabWidth": 2, + "trailingComma": "es5", + "bracketSpacing": true +} diff --git a/packages/engine/LICENSE.md b/packages/engine/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..8b21ed7d57c2d217f49e10d0fb0b327961a4ea54 --- /dev/null +++ b/packages/engine/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2024 Julian Bilcke + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/engine/README.md b/packages/engine/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ce69f8cfbd758966fbdc3e5590c60264270da3ae --- /dev/null +++ b/packages/engine/README.md @@ -0,0 +1,70 @@ +# @aitube/engine + +*The engine powering AiTube.at* + +## ATTENTION + +AiTube is currently in heavy development, and for the moment +the engine is reserved for *internal use by AiTube itself*. + +We are sorry for any inconvenience this might cause. + +## Installation + +To install the package, run the following command: + +```bash +npm install @aitube/engine +``` + +## Getting Started + +```typescript +import { + getCharacterPrompt, + getCharacterReferencePrompt, + getPositivePrompt, + getSpeechBackgroundAudioPrompt, + getSpeechForegroundAudioPrompt, + getVideoPrompt, + deduplicate, + deduplicatePrompt, + renderShotToStoryboard, + renderShotToVideo, + segmentCategoryPromptPriority, + type VideoRenderer, + type StoryboardRenderer, + type VideoFirstFrameExtractor +} from '@aitube/engine' + +``` + +## Build Instructions + +Install [Bun](https://bun.sh/) + +Run the following commands: + +```bash +bun install + +bun run build +``` + +To publish: + +```bash +bun run build + +bun run build:declaration + +bun run publish +``` + +## Contributing + +We welcome contributions! Please feel free to submit a pull request. + +## License + +This package is under the MIT License. See `LICENSE` file for more details. diff --git a/packages/engine/package.json b/packages/engine/package.json new file mode 100644 index 0000000000000000000000000000000000000000..3a1c71c64871e8b88728149a806fef91983cf307 --- /dev/null +++ b/packages/engine/package.json @@ -0,0 +1,39 @@ +{ + "name": "@aitube/engine", + "module": "index.ts", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "type": "module", + "version": "0.2.4", + "description": "The engine powering AiTube.at and Clapper.app", + "scripts": { + "build": "bun build ./src/index.ts --outfile=dist/index.js && bun run build:declaration", + "build:declaration": "tsc --emitDeclarationOnly --project tsconfig.types.json", + "postbuild": "rimraf tsconfig.types.tsbuildinfo && bun run build:declaration", + "publish": "npm publish --access public", + "update": "rm -Rf node_modules && rm bun.lockb && bun i && bun run build" + }, + "devDependencies": { + "bun-types": "latest", + "prettier": "^3.3.3", + "rimraf": "^6.0.1", + "typescript": "^5.5.4" + }, + "repository": { + "type": "git", + "url": "https://github.com/jbilcke-hf/aitube-engine.git" + }, + "keywords": [ + "Clapper.app", + "OpenClap", + "AI cinema", + "AiTube" + ], + "author": "Julian Bilcke", + "license": "MIT", + "files": [ + "dist/*.js", + "dist/*.d.ts", + "dist/**/*.d.ts" + ] +} diff --git a/packages/engine/src/index.ts b/packages/engine/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..bc8b0a1786acd19a1bffd8c5356e32533e82eb9a --- /dev/null +++ b/packages/engine/src/index.ts @@ -0,0 +1,28 @@ +export { + renderShotToStoryboard, + renderShotToVideo +} from './renderers' + +export { + getBackgroundAudioPrompt, + getCharacterPrompt, + getCharacterReferencePrompt, + getMusicPrompt, + getPositivePrompt, + getSoundPrompt, + getSpeechBackgroundAudioPrompt, + getSpeechForegroundAudioPrompt, + getVideoPrompt, + segmentCategoryPromptPriority, +} from './prompts' + +export { + deduplicate, + deduplicatePrompt, +} from './utils' + +export { + VideoRenderer, + StoryboardRenderer, + VideoFirstFrameExtractor +} from "./types" \ No newline at end of file diff --git a/packages/engine/src/prompts/getBackgroundAudioPrompt.ts b/packages/engine/src/prompts/getBackgroundAudioPrompt.ts new file mode 100644 index 0000000000000000000000000000000000000000..1f09a70da440e191bb88ef6d237dd4721b2bfc12 --- /dev/null +++ b/packages/engine/src/prompts/getBackgroundAudioPrompt.ts @@ -0,0 +1,42 @@ +import { ClapEntity, ClapSegment, ClapSegmentCategory } from "@aitube/clap" + +import { getCharacterPrompt } from "./getCharacterPrompt" + +/** + * Recoonstruct an audio background from a list of active segments. + * + * This uses the ACTION, WEATHER and LOCATION fields to determine a prompt. + * + * This is useful for cases where we don't have a SOUND + * (eg. create a background audio track) + * + * @param segments + * @returns + */ +export function getBackgroundAudioPrompt( + segments: ClapSegment[] = [], + extraPositivePrompt: string[] = [] // "clear sound, high quality" etc +): string { + return segments + .filter(({ category }) => ( + category === ClapSegmentCategory.ACTION || + category === ClapSegmentCategory.WEATHER || + category === ClapSegmentCategory.LOCATION + )) + .sort((a, b) => b.label.localeCompare(a.label)) + .map(segment => { + const p = segment.prompt.toLocaleLowerCase() + + // since we are including the ACTION category, we might have some + // things like "he says:" which can create bad sound effects + // with random, weird garbled voices etc + // so we typically want to prune that + if (p.includes('talk') || p.includes('speak') || p.includes('voice') || p.includes('says') || p.includes('shout')) { + return '' + } + return segment.prompt + }) + .filter(x => x) + .concat([ ...extraPositivePrompt ]) + .join(". ") +} \ No newline at end of file diff --git a/packages/engine/src/prompts/getCharacterPrompt.ts b/packages/engine/src/prompts/getCharacterPrompt.ts new file mode 100644 index 0000000000000000000000000000000000000000..38a73100162785aaf47ac16689cf070313dc3cfb --- /dev/null +++ b/packages/engine/src/prompts/getCharacterPrompt.ts @@ -0,0 +1,14 @@ +import { ClapEntity } from "@aitube/clap" + +export function getCharacterPrompt(entity: ClapEntity): string { + const characterPrompt = [ + entity.age ? `${entity.age}yo` : '', // 34yo + entity.region ? `${entity.region}` : '', // american + entity.gender !== "object" ? entity.gender : 'person', // woman + entity.label ? `named ${entity.label}` : '', // Jessica + entity.appearance ? `${entity.appearance}` : 'speaking', // blond hair + // entity.description ? `${entity.description}` : '', // blond hair + ].map(i => i.trim()).filter(i => i).join(" ").trim() + + return characterPrompt +} \ No newline at end of file diff --git a/packages/engine/src/prompts/getCharacterReferencePrompt.ts b/packages/engine/src/prompts/getCharacterReferencePrompt.ts new file mode 100644 index 0000000000000000000000000000000000000000..61b69ddac182442e6b4161b89711fb0d4e17e71e --- /dev/null +++ b/packages/engine/src/prompts/getCharacterReferencePrompt.ts @@ -0,0 +1,30 @@ +import { ClapEntity } from "@aitube/clap" + +import { getCharacterPrompt } from "./getCharacterPrompt" + +/** + * Return a prompt for a "formal" picture, centered, neutral etc + * + * @param entity + * @returns + */ +export function getCharacterReferencePrompt(entity: ClapEntity) { + const characterPrompt = [ + `beautiful`, + `close-up`, + `photo portrait`, + `id photo`, + getCharacterPrompt(entity), + `neutral expression`, + `neutral background`, + `frontal`, + `photo studio`, + `crisp`, + `sharp`, + `intricate details`, + `centered`, + // `aligned` + ].map(i => i.trim()).filter(i => i).join(", ") + + return characterPrompt +} \ No newline at end of file diff --git a/packages/engine/src/prompts/getMusicPrompt.ts b/packages/engine/src/prompts/getMusicPrompt.ts new file mode 100644 index 0000000000000000000000000000000000000000..c6071675e2412e576579e0a7199f3e8ce0f1d0a7 --- /dev/null +++ b/packages/engine/src/prompts/getMusicPrompt.ts @@ -0,0 +1,11 @@ +import { ClapSegment, ClapSegmentCategory } from "@aitube/clap" + +export function getMusicPrompt( + segments: ClapSegment[] = [] +): string { + return segments + .filter(({ category }) => category === ClapSegmentCategory.MUSIC) + .sort((a, b) => b.label.localeCompare(a.label)) + .map(({ prompt }) => prompt).filter(x => x) + .join(". ") +} \ No newline at end of file diff --git a/packages/engine/src/prompts/getPositivePrompt.ts b/packages/engine/src/prompts/getPositivePrompt.ts new file mode 100644 index 0000000000000000000000000000000000000000..d06a7e5db74f23a3bbccc39b00a3d88a0ff04326 --- /dev/null +++ b/packages/engine/src/prompts/getPositivePrompt.ts @@ -0,0 +1,58 @@ +// should we really have default prompts in here? +// I think they should probably be defined at the applicative software layer (ie. in the client) + +export function addWordsIfNotPartOfThePrompt(prompt: string = "", words: string[] = []): string { + const promptWords = prompt.split(",").map(w => w.trim().toLocaleLowerCase()) + + return [ + prompt, + // we add our keywords, unless they are already part of the prompt + ...words.filter(w => !promptWords.includes(w.toLocaleLowerCase())) + ].join(", ") +} + + export function getPositivePrompt(prompt: string = "", triggerWord = "") { + return addWordsIfNotPartOfThePrompt(prompt, [ + "cinematic photo", + triggerWord, + "sublime", + "pro quality", + "sharp", + "crisp", + "beautiful", + "impressive", + "amazing", + "4K", + "hd" + ]) +} + +export function getNegativePrompt(prompt: string = "") { + return addWordsIfNotPartOfThePrompt(prompt, [ + "cropped", + // "underexposed", // <-- can be a desired style + // "overexposed", // <-- can be a desired style + "logo", + "hud", + "ui", + "censored", + "blurry", + "watermark", + "watermarked", + "copyright", + "extra digit", + "fewer digits", + "bad fingers", + "bad quality", + "worst quality", + "low quality", + "low resolution", + "glitch", // <-- keep or not? could be a desired style? + // "deformed", + // "mutated", + // "ugly", + // "disfigured", + // "3D render", // <-- keep or not? could be a desired style? + "signature" + ]) +} \ No newline at end of file diff --git a/packages/engine/src/prompts/getSoundPrompt.ts b/packages/engine/src/prompts/getSoundPrompt.ts new file mode 100644 index 0000000000000000000000000000000000000000..ec890a8c4527964e979407df356a41329ffc4008 --- /dev/null +++ b/packages/engine/src/prompts/getSoundPrompt.ts @@ -0,0 +1,23 @@ +import { ClapSegment, ClapSegmentCategory } from "@aitube/clap" + +/** + * + * @param segments + * @returns + */ +export function getSoundPrompt( + segments: ClapSegment[] = [], + extraPositivePrompt: string[] = [] // "clear sound, high quality" etc +): string { + return segments + .filter(({ category }) => ( + category === ClapSegmentCategory.SOUND + )) + .sort((a, b) => b.label.localeCompare(a.label)) + .map(segment => { + return segment.prompt + }) + .filter(x => x) + .concat([ ...extraPositivePrompt ]) + .join(". ") +} \ No newline at end of file diff --git a/packages/engine/src/prompts/getSpeechBackgroundAudioPrompt.ts b/packages/engine/src/prompts/getSpeechBackgroundAudioPrompt.ts new file mode 100644 index 0000000000000000000000000000000000000000..45eda28898b6a7d3d8138b1a670cc10c36bb27a5 --- /dev/null +++ b/packages/engine/src/prompts/getSpeechBackgroundAudioPrompt.ts @@ -0,0 +1,52 @@ +import { ClapEntity, ClapSegment, ClapSegmentCategory } from "@aitube/clap" + +import { getCharacterPrompt } from "./getCharacterPrompt" + +/** + * Construct an audio background for a voice from a list of active segments + * + * @param segments + * @returns + */ +export function getSpeechBackgroundAudioPrompt( + segments: ClapSegment[] = [], + entityIndex: Record = {}, + extraPositivePrompt: string[] = [] // "clear sound, high quality" etc +): string { + return segments + .filter(({ category, outputType }) => ( + category === ClapSegmentCategory.DIALOGUE || + category === ClapSegmentCategory.WEATHER || + category === ClapSegmentCategory.LOCATION + )) + .sort((a, b) => b.label.localeCompare(a.label)) + .map(segment => { + const entity: ClapEntity | undefined = entityIndex[segment?.entityId || ""] || undefined + + if (segment.category === ClapSegmentCategory.DIALOGUE) { + // if we can't find the entity then we are unable + // to make any assumption about the gender, age and voice timbre + if (!entity) { + return `person, speaking normally` + } + + const characterPrompt = getCharacterPrompt(entity) + + return `${characterPrompt}, speaking normally` + + } else if (segment.category === ClapSegmentCategory.LOCATION) { + // the location is part of the background noise + // but this might produce unexpected results - we'll see! + return segment.prompt + } else if (segment.category === ClapSegmentCategory.WEATHER) { + // the weather is part of the background noise + // here too this might produce weird and unexpected results 🍿 + return segment.prompt + } + // ignore the rest + return "" + }) + .filter(x => x) + .concat([ ...extraPositivePrompt ]) + .join(". ") +} \ No newline at end of file diff --git a/packages/engine/src/prompts/getSpeechForegroundAudioPrompt.ts b/packages/engine/src/prompts/getSpeechForegroundAudioPrompt.ts new file mode 100644 index 0000000000000000000000000000000000000000..8337bdb26660ce7b40e7b0b4147f91ee7ee7dd4b --- /dev/null +++ b/packages/engine/src/prompts/getSpeechForegroundAudioPrompt.ts @@ -0,0 +1,20 @@ +import { ClapSegment, ClapSegmentCategory } from "@aitube/clap" + +/** + * Construct an audio foreground for a voice from a list of active segments + * + * This is the "dialogue" prompt, ie. the actual spoken words, + * so we don't need to do anything fancy here, we only use the raw text + * + * @param segments + * @returns + */ +export function getSpeechForegroundAudioPrompt( + segments: ClapSegment[] = [] +): string { + return segments + .filter(({ category }) => category === ClapSegmentCategory.DIALOGUE) + .sort((a, b) => b.label.localeCompare(a.label)) + .map(({ prompt }) => prompt).filter(x => x) + .join(". ") +} \ No newline at end of file diff --git a/packages/engine/src/prompts/getVideoPrompt.ts b/packages/engine/src/prompts/getVideoPrompt.ts new file mode 100644 index 0000000000000000000000000000000000000000..f5724e3dcff1b5802840ba7ac3fbf54eba232617 --- /dev/null +++ b/packages/engine/src/prompts/getVideoPrompt.ts @@ -0,0 +1,105 @@ +import { ClapEntity, ClapOutputType, ClapSegment, ClapSegmentCategory } from "@aitube/clap" + +import { deduplicatePrompt } from "@/utils/deduplicatePrompt" +import { getCharacterPrompt } from "@/prompts/getCharacterPrompt" + +import { segmentCategoryPromptPriority } from "./priorities" + +/** + * Construct a video prompt from a list of active segments + * + * @param segments + * @returns + */ +export function getVideoPrompt( + segments: ClapSegment[] = [], + entitiesIndex: Record = {}, + extraPositivePrompt: string[] = [], + debug: boolean = false, +): string { + + // console.log("entitiesIndex:", entitiesIndex) + + + // to construct the video we need to collect all the segments describing it + // we ignore unrelated categories (music, dialogue) or non-prompt items (eg. an audio sample) + const tmp = segments + .filter(({ category, outputType }) => { + if (outputType === ClapOutputType.AUDIO) { + return false + } + + if ( + category === ClapSegmentCategory.STORYBOARD || + category === ClapSegmentCategory.CHARACTER || + category === ClapSegmentCategory.LOCATION || + category === ClapSegmentCategory.TIME || + category === ClapSegmentCategory.ERA || // <- @deprecated + category === ClapSegmentCategory.DIALOGUE || + category === ClapSegmentCategory.LIGHTING || + category === ClapSegmentCategory.WEATHER || + category === ClapSegmentCategory.ACTION || + category === ClapSegmentCategory.STYLE || + category === ClapSegmentCategory.CAMERA || + category === ClapSegmentCategory.GENERIC + ) { + return true + } + return false + }) + + // this step is *SUPER* important, it determines the order of the prompt! + tmp.sort((segment1, segment2) => { + const priority1 = segmentCategoryPromptPriority[segment1.category || segmentCategoryPromptPriority.GENERIC] || 0 + const priority2 = segmentCategoryPromptPriority[segment2.category || segmentCategoryPromptPriority.GENERIC] || 0 + + return priority2 - priority1 + }) + + // to prevent re-injecting the same entity multiple times in the same video prompt + const alreadyUsedEntities: Record = {} + + let videoPrompt = tmp.map(segment => { + const entityId = segment?.entityId || "" + const entity: ClapEntity | undefined = entitiesIndex[entityId] || undefined + + if (entityId && entity && alreadyUsedEntities[entityId]) { return "" } + + alreadyUsedEntities[entityId] = true + + if (segment.category === ClapSegmentCategory.DIALOGUE) { + + // if we can't find the entity, then we are unable + // to make any assumption about the gender, age or appearance + if (!entity) { + // console.log("ERROR: this is a dialogue, but couldn't find the entity!") + return `photo portrait of a person speaking, bokeh` + } + + + const characterPrompt = getCharacterPrompt(entity) + + // in the context of a video, we some something additional: + // we create a "bokeh" style + return `photo portrait of a ${characterPrompt}, bokeh` + + } else if (segment.category === ClapSegmentCategory.LOCATION) { + + // if we can't find the location's entity, we default to returning the prompt + if (!entity) { + // console.log("ERROR: this is a location, but couldn't find the entity!") + return segment.prompt + } + + return entity.description + } else { + return segment.prompt + } + }).map(x => x.trim()).filter(x => x) + + videoPrompt = videoPrompt.concat([ + ...extraPositivePrompt + ]) + + return deduplicatePrompt(videoPrompt.join(", ").trim()) +} \ No newline at end of file diff --git a/packages/engine/src/prompts/index.ts b/packages/engine/src/prompts/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..40e76802c96275e79f628f76222f2ed78fb63821 --- /dev/null +++ b/packages/engine/src/prompts/index.ts @@ -0,0 +1,10 @@ +export { getBackgroundAudioPrompt } from "./getBackgroundAudioPrompt" +export { getCharacterPrompt } from "./getCharacterPrompt" +export { getCharacterReferencePrompt } from "./getCharacterReferencePrompt" +export { getMusicPrompt } from './getMusicPrompt' +export { getPositivePrompt } from "./getPositivePrompt" +export { getSoundPrompt } from "./getSoundPrompt" +export { getSpeechBackgroundAudioPrompt } from "./getSpeechBackgroundAudioPrompt" +export { getSpeechForegroundAudioPrompt } from "./getSpeechForegroundAudioPrompt" +export { getVideoPrompt } from "./getVideoPrompt" +export { segmentCategoryPromptPriority } from "./priorities" \ No newline at end of file diff --git a/packages/engine/src/prompts/priorities.ts b/packages/engine/src/prompts/priorities.ts new file mode 100644 index 0000000000000000000000000000000000000000..ffe226f30d29499be5bbdaf524ffb96a6ef87460 --- /dev/null +++ b/packages/engine/src/prompts/priorities.ts @@ -0,0 +1,19 @@ +import { ClapSegmentCategory } from "@aitube/clap" + +export const segmentCategoryPromptPriority: Partial> = { + // maybe we should also a priority for the video, + // if it has a prompt.. no? + [ClapSegmentCategory.VIDEO]: 13, + [ClapSegmentCategory.STORYBOARD]: 12, + [ClapSegmentCategory.CAMERA]: 11, + [ClapSegmentCategory.DIALOGUE]: 10, + [ClapSegmentCategory.CHARACTER]: 9, + [ClapSegmentCategory.LOCATION]: 8, + [ClapSegmentCategory.ACTION]: 7, + [ClapSegmentCategory.TIME]: 6, + [ClapSegmentCategory.STYLE]: 5, + [ClapSegmentCategory.LIGHTING]: 4, + [ClapSegmentCategory.WEATHER]: 3, + [ClapSegmentCategory.ERA]: 2, // <- era is @deprecated + [ClapSegmentCategory.GENERIC]: 1 +} \ No newline at end of file diff --git a/packages/engine/src/renderers/index.ts b/packages/engine/src/renderers/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..91f2332d462106b05dd45c7aa37624e5a7a5e632 --- /dev/null +++ b/packages/engine/src/renderers/index.ts @@ -0,0 +1,2 @@ +export { renderShotToStoryboard } from "./storyboard/renderShotToStoryboard" +export { renderShotToVideo } from "./video/renderShotToVideo" \ No newline at end of file diff --git a/packages/engine/src/renderers/storyboard/renderShotToStoryboard.ts b/packages/engine/src/renderers/storyboard/renderShotToStoryboard.ts new file mode 100644 index 0000000000000000000000000000000000000000..f61a9a6bbae15664ce6fd38e9f48a66e72084a8f --- /dev/null +++ b/packages/engine/src/renderers/storyboard/renderShotToStoryboard.ts @@ -0,0 +1,122 @@ +import { + ClapProject, + ClapSegment, + getClapAssetSourceType, + newSegment, + filterSegments, + ClapSegmentFilteringMode, + ClapSegmentCategory, + ClapOutputType, + ClapSegmentStatus, + ClapCompletionMode +} from "@aitube/clap" + +import { getVideoPrompt } from "@/prompts/getVideoPrompt" +import { StoryboardRenderer } from "@/types" +import { getPositivePrompt } from "@/prompts/getPositivePrompt" + +export async function renderShotToStoryboard({ + shotSegment, + existingClap, + newerClap, + mode, + turbo, + renderStoryboard, + debug = false +}: { + shotSegment: ClapSegment + existingClap: ClapProject + newerClap: ClapProject + mode: ClapCompletionMode + turbo: boolean + renderStoryboard: StoryboardRenderer + debug?: boolean +}): Promise { + + const shotSegments: ClapSegment[] = filterSegments( + ClapSegmentFilteringMode.BOTH, + shotSegment, + existingClap.segments + ) + + const shotStoryboardSegments: ClapSegment[] = shotSegments.filter(s => + s.category === ClapSegmentCategory.STORYBOARD + ) + + let shotStoryboardSegment: ClapSegment | undefined = shotStoryboardSegments.at(0) + + // TASK 1: GENERATE MISSING STORYBOARD SEGMENT + if (!shotStoryboardSegment) { + shotStoryboardSegment = newSegment({ + track: 1, + startTimeInMs: shotSegment.startTimeInMs, + endTimeInMs: shotSegment.endTimeInMs, + assetDurationInMs: shotSegment.assetDurationInMs, + category: ClapSegmentCategory.STORYBOARD, + prompt: "", + assetUrl: "", + outputType: ClapOutputType.IMAGE, + }) + + // we fix the existing clap + if (shotStoryboardSegment) { + existingClap.segments.push(shotStoryboardSegment) + } + + if (debug) { console.log(`[@aitube-engine/renderShotToStoryboard] generated storyboard segment [${shotSegment.startTimeInMs}:${shotSegment.endTimeInMs}]`) } + } + + if (!shotStoryboardSegment) { throw new Error(`failed to generate a newSegment`) } + + // TASK 2: GENERATE MISSING STORYBOARD PROMPT + if (!shotStoryboardSegment?.prompt) { + // storyboard is missing, let's generate it + shotStoryboardSegment.prompt = getVideoPrompt( + shotSegments, + existingClap.entityIndex, + ["high quality", "crisp", "detailed"] + ) + if (debug) { console.log(`[@aitube-engine/renderShotToStoryboard] generating storyboard prompt: ${shotStoryboardSegment.prompt}`) } + } + + // TASK 3: GENERATE MISSING STORYBOARD BITMAP + if (!shotStoryboardSegment.assetUrl) { + if (debug) { console.log(`[@aitube-engine/renderShotToStoryboard] generating image..`) } + + // console.log(`we have ${existingClap.entities.length} entities`) + // check if we have an entity image we can use + const identityImage = existingClap.entities.find((e: any) => e.id === shotStoryboardSegment.entityId)?.imageId + if (identityImage) { + // if (debug) { console.log(`[@aitube-engine/renderShotToStoryboard] using an entity to generate the storyboard..`) } + } + try { + shotStoryboardSegment.assetUrl = await renderStoryboard({ + prompt: getPositivePrompt(shotStoryboardSegment.prompt), + identityImage, + width: existingClap.meta.width, + height: existingClap.meta.height, + + // turbo mode is mandatory if we have an identity image + // that's because it will use PuLID instead of SDXL + turbo: !!identityImage, + }) + shotStoryboardSegment.assetSourceType = getClapAssetSourceType(shotStoryboardSegment.assetUrl) + shotStoryboardSegment.status = ClapSegmentStatus.COMPLETED + } catch (err) { + // console.log(`[api/v1/edit/storyboards] processShot: failed to generate an image: ${err}`) + shotStoryboardSegment.status = ClapSegmentStatus.TO_GENERATE + throw err + } + + if (debug) { console.log(`[@aitube-engine/renderShotToStoryboard] generated storyboard image: ${shotStoryboardSegment?.assetUrl?.slice?.(0, 50)}...`) } + + // if mode is full, newerClap already contains the ference to shotStoryboardSegment + // but if it's partial, we need to manually add it + if (mode !== ClapCompletionMode.FULL) { + newerClap.segments.push(shotStoryboardSegment) + } + } else { + if (debug) { console.log(`[@aitube-engine/renderShotToStoryboard] there is already a storyboard image: ${shotStoryboardSegment?.assetUrl?.slice?.(0, 50)}...`) } + } + +} diff --git a/packages/engine/src/renderers/video/renderShotToVideo.ts b/packages/engine/src/renderers/video/renderShotToVideo.ts new file mode 100644 index 0000000000000000000000000000000000000000..a9da407602a87557576fb3c33492ceae8aa20cd4 --- /dev/null +++ b/packages/engine/src/renderers/video/renderShotToVideo.ts @@ -0,0 +1,218 @@ + +import { getVideoPrompt } from "@/prompts" +import { VideoFirstFrameExtractor, VideoRenderer } from "@/types" +import { + ClapProject, + ClapSegment, + getClapAssetSourceType, + newSegment, + filterSegments, + ClapSegmentFilteringMode, + ClapOutputType, + ClapSegmentCategory, + ClapSegmentStatus, + parseMediaOrientation, + ClapCompletionMode +} from "@aitube/clap" + +export async function renderShotToVideo({ + shotSegment, + existingClap, + newerClap, + mode, + turbo, + renderVideo, + extractFirstFrame, + debug = false +}: { + shotSegment: ClapSegment + existingClap: ClapProject + newerClap: ClapProject + mode: ClapCompletionMode + turbo: boolean + renderVideo: VideoRenderer + extractFirstFrame: VideoFirstFrameExtractor + debug?: boolean +}): Promise { + const shotSegments: ClapSegment[] = filterSegments( + ClapSegmentFilteringMode.BOTH, + shotSegment, + existingClap.segments + ) + + const shotVideoSegments: ClapSegment[] = shotSegments.filter(s => + s.category === ClapSegmentCategory.VIDEO + ) + + let shotVideoSegment: ClapSegment | undefined = shotVideoSegments.at(0) + + const shotStoryboardSegments: ClapSegment[] = shotSegments.filter(s => + s.category === ClapSegmentCategory.STORYBOARD + ) + + let shotStoryboardSegment: ClapSegment | undefined = shotStoryboardSegments.at(0) + + // console.log(`[api/edit/videos] processShot: shot [${shotSegment.startTimeInMs}:${shotSegment.endTimeInMs}] has ${shotSegments.length} segments (${shotVideoSegments.length} videos)`) + + // TASK 1: GENERATE MISSING VIDEO SEGMENT + if (!shotVideoSegment) { + shotVideoSegment = newSegment({ + track: 1, + startTimeInMs: shotSegment.startTimeInMs, + endTimeInMs: shotSegment.endTimeInMs, + assetDurationInMs: shotSegment.assetDurationInMs, + category: ClapSegmentCategory.VIDEO, + prompt: "", + assetUrl: "", + outputType: ClapOutputType.VIDEO + }) + + // we fix the existing clap + if (shotVideoSegment) { + existingClap.segments.push(shotSegment) + } + + if (debug) { console.log(`[@aitube-engine/renderShotToVideo] generated video segment [${shotSegment.startTimeInMs}:${shotSegment.endTimeInMs}]`) } + } + + if (!shotVideoSegment) { + throw new Error(`failed to generate a new segment`) + } + + + // TASK 2: GENERATE MISSING VIDEO PROMPT + if (!shotVideoSegment?.prompt) { + // video is missing, let's generate it + shotVideoSegment.prompt = getVideoPrompt( + shotSegments, + existingClap.entityIndex, + ["high quality", "crisp", "detailed"] + ) + if (debug) { console.log(`[@aitube-engine/renderShotToVideo] generating video prompt: ${shotVideoSegment.prompt}`) } + } + + // TASK 3: GENERATE MISSING VIDEO FILE + if (!shotVideoSegment.assetUrl) { + // console.log(`[api/edit/videos] processShot: generating video file..`) + + const debug = false + + let width = existingClap.meta.width + let height = existingClap.meta.height + + // if (turbo) { + // width = Math.round(width / 2) + // height = Math.round(height / 2) + // } + + /* + if (width > height) { + width = 768 + height = 384 + } else if (width < height) { + width = 384 + height = 768 + } else { + width = 512 + height = 512 + } + */ + + if (!shotStoryboardSegment?.assetUrl) { + // it is normal for some storyboards to be empty, + // it only means that we cannot generate or are not interested in generating the video, + // for instance if we have already the video + // console.log(`skipping video generation for the shot..`) + return + + // const error = `cannot generate a video without a storyboard! (at least not with AnimateDiff-LCM SVD)` + // console.error(error) + // throw new Error(error) + } + + try { + shotVideoSegment.assetUrl = await renderVideo({ + // prompt: getPositivePrompt(shotVideoSegment.prompt), + imageInputBase64: shotStoryboardSegment.assetUrl, + seed: shotSegment.seed, + width, + height, + // by default we do 1 second of 24 fps + // but it would look better if we had 2 seconds of 24 fps + nbFrames: 80, + nbFPS: 24, + nbSteps: 4, // turbo ? 4 : 8, + debug, + }) + shotVideoSegment.assetSourceType = getClapAssetSourceType(shotVideoSegment.assetUrl) + shotVideoSegment.status = ClapSegmentStatus.COMPLETED + } catch (err) { + if (debug) { console.log(`[@aitube-engine/renderShotToVideo] failed to generate a video file: ${err}`) } + shotVideoSegment.status = ClapSegmentStatus.TO_GENERATE + throw err + } + + // console.log(`[api/edit/videos] processShot: generated video files: ${shotVideoSegment?.assetUrl?.slice?.(0, 50)}...`) + + // if mode is full, newerClap already contains the ference to shotVideoSegment + // but if it's partial, we need to manually add it + if (mode !== ClapCompletionMode.FULL) { + newerClap.segments.push(shotVideoSegment) + } + + } else { + if (debug) { console.log(`[@aitube-engine/renderShotToVideo] there is already a video file: ${shotVideoSegment?.assetUrl?.slice?.(0, 50)}...`) } + } + + if (!shotVideoSegment.assetUrl) { + return + } + + if (!shotStoryboardSegment) { + if (debug) { console.log(`[@aitube-engine/renderShotToVideo] adding the missing storyboard segment`) } + + shotStoryboardSegment = newSegment({ + track: 1, + startTimeInMs: shotSegment.startTimeInMs, + endTimeInMs: shotSegment.endTimeInMs, + assetDurationInMs: shotSegment.assetDurationInMs, + category: ClapSegmentCategory.STORYBOARD, + prompt: shotVideoSegment.prompt, + outputType: ClapOutputType.IMAGE, + status: ClapSegmentStatus.TO_GENERATE, + }) + + if (shotStoryboardSegment) { + existingClap.segments.push(shotStoryboardSegment) + } + } + + + //---------- + if ( + shotStoryboardSegment && + (!shotStoryboardSegment.assetUrl || shotStoryboardSegment.status === ClapSegmentStatus.TO_GENERATE) + ) { + if (debug) { console.log(`[@aitube-engine/renderShotToVideo] generating a missing storyboard asset`) } + + try { + shotStoryboardSegment.assetUrl = await extractFirstFrame({ + inputVideo: shotVideoSegment.assetUrl, + outputFormat: "jpeg" + }) + if (!shotStoryboardSegment.assetUrl) { throw new Error(`failed to extract the first frame`) } + if (debug) { console.log(`[@aitube-engine/renderShotToVideo] successfully fixed the missing storyboard`) } + + shotStoryboardSegment.status = ClapSegmentStatus.COMPLETED + } catch (err) { + if (debug) { console.log(`[@aitube-engine/renderShotToVideo] WARNING: couldn't generate the missing storyboard (probably an error with the ffmpeg not being found)`) } + shotStoryboardSegment.status = ClapSegmentStatus.TO_GENERATE + } + + + if (shotStoryboardSegment && mode !== ClapCompletionMode.FULL) { + newerClap.segments.push(shotStoryboardSegment) + } + } + +} \ No newline at end of file diff --git a/packages/engine/src/types.ts b/packages/engine/src/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..c3ca59753bae64dfc7028e30741d4d400f889963 --- /dev/null +++ b/packages/engine/src/types.ts @@ -0,0 +1,26 @@ + +export type StoryboardRenderer = (request: { + prompt: string; + identityImage?: string; + width?: number; + height?: number; + seed?: number; + turbo?: boolean; +}) => Promise + + +export type VideoRenderer = (request: { + imageInputBase64?: string; + seed?: number; + width?: number; + height?: number; + nbFrames?: number; + nbFPS?: number; + nbSteps?: number; + debug?: boolean; +}) => Promise + +export type VideoFirstFrameExtractor = (params: { + inputVideo?: string; + outputFormat?: "jpeg" | "png" | "webp"; +}) => Promise diff --git a/packages/engine/src/utils/deduplicate.ts b/packages/engine/src/utils/deduplicate.ts new file mode 100644 index 0000000000000000000000000000000000000000..93d21b852aa1f63970399606c555bc15bbd2723c --- /dev/null +++ b/packages/engine/src/utils/deduplicate.ts @@ -0,0 +1,3 @@ +export function deduplicate(items: string[]): string[] { + return Object.keys(items.reduce((acc, item) => ({ ...acc, [item]: item }), {})) +} \ No newline at end of file diff --git a/packages/engine/src/utils/deduplicatePrompt.ts b/packages/engine/src/utils/deduplicatePrompt.ts new file mode 100644 index 0000000000000000000000000000000000000000..2532f8906ff8b32ad395465c1c9d77d0d46fb546 --- /dev/null +++ b/packages/engine/src/utils/deduplicatePrompt.ts @@ -0,0 +1,5 @@ +import { deduplicate } from "@/utils/deduplicate" + +export function deduplicatePrompt(input: string): string { + return deduplicate(input.split(",").map(item => item.trim())).join(", ") +} \ No newline at end of file diff --git a/packages/engine/src/utils/index.ts b/packages/engine/src/utils/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..31f2f734a2022e93a00011032ca0da30a4a173e4 --- /dev/null +++ b/packages/engine/src/utils/index.ts @@ -0,0 +1,2 @@ +export { deduplicate } from "./deduplicate" +export { deduplicatePrompt } from "./deduplicatePrompt" diff --git a/packages/engine/tsconfig.json b/packages/engine/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..ab7cc3ed096e5dc51a557fdee4e68c0e28076d0b --- /dev/null +++ b/packages/engine/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "baseUrl": "./", + "paths": { + "@/*": ["src/*"] + }, + "lib": ["ESNext", "DOM"], + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": true, + "noEmit": true, + "composite": true, + "strict": true, + "downlevelIteration": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "types": [ + "bun-types" + ] + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/packages/engine/tsconfig.types.json b/packages/engine/tsconfig.types.json new file mode 100644 index 0000000000000000000000000000000000000000..a6a3f21154bb178f1850c9b70714fb66ef5bf750 --- /dev/null +++ b/packages/engine/tsconfig.types.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "emitDeclarationOnly": true, + "declaration": true, + "outDir": "./dist", + "rootDir": "./src", + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/packages/io/.gitignore b/packages/io/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ea8fe6a7905bd72f745584146daa9994bd211499 --- /dev/null +++ b/packages/io/.gitignore @@ -0,0 +1,177 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +\*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +\*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +\*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +\*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.cache +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output +dist +.nuxt + +# Gatsby files + +.cache/ + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp +.cache + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.\* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store + +# TypeScript build information +*.tsbuildinfo \ No newline at end of file diff --git a/packages/io/.npmignore b/packages/io/.npmignore new file mode 100644 index 0000000000000000000000000000000000000000..78a661ea2d8f8cdaa94e4cc69d758a4b2d946feb --- /dev/null +++ b/packages/io/.npmignore @@ -0,0 +1,4 @@ +# Ignore everything +* +# Except the dist directory +!dist/ diff --git a/packages/io/.prettierrc.json b/packages/io/.prettierrc.json new file mode 100644 index 0000000000000000000000000000000000000000..1dcadb7324877e15a4ffa4efa5723a519395f511 --- /dev/null +++ b/packages/io/.prettierrc.json @@ -0,0 +1,9 @@ +{ + "semi": false, + "singleQuote": true, + "arrowParens": "avoid", + "printWidth": 140, + "tabWidth": 2, + "trailingComma": "es5", + "bracketSpacing": true +} diff --git a/packages/io/LICENSE.md b/packages/io/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..8b21ed7d57c2d217f49e10d0fb0b327961a4ea54 --- /dev/null +++ b/packages/io/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2024 Julian Bilcke + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/io/README.md b/packages/io/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6ec1fca0757f1a20fe63ec53e81fff4a302f62e9 --- /dev/null +++ b/packages/io/README.md @@ -0,0 +1,75 @@ +# @aitube/io + +*Collection of useful I/O utilities for NodeJS. Used by AiTube.at* + +## ATTENTION + +AiTube is currently in heavy development, so this library is experimental, +and may be subject to unannounced breaking changes. + +We are sorry for any inconvenience this might cause. + +## Installation + +To install the package, run the following command: + +```bash +npm install @aitube/io +``` + +## Getting Started + +```typescript +import { + deleteFile, + deleteFilesWithName, + removeTemporaryFiles, + downloadFileAsBase64, + convertImageTo, + convertImageToJpeg, + convertImageToOriginal, + convertImageToPng, + convertImageToWebp, + resizeImage, + readJpegFileToBase64, + readLocalOrRemotePlainText, + readMp3FileToBase64, + readMp4FileToBase64, + readPlainText, + readPngFileToBase64, + readWavFileToBase64, + getRandomDirectory, + writeBase64ToFile, +} from '@aitube/io' + +``` + +## Build Instructions + +Install [Bun](https://bun.sh/) + +Run the following commands: + +```bash +bun install + +bun run build +``` + +To publish: + +```bash +bun run build + +bun run build:declaration + +bun run publish +``` + +## Contributing + +We welcome contributions! Please feel free to submit a pull request. + +## License + +This package is under the MIT License. See `LICENSE` file for more details. diff --git a/packages/io/package.json b/packages/io/package.json new file mode 100644 index 0000000000000000000000000000000000000000..eb6d911eb33666dc59cf44959c3125dd85aff51e --- /dev/null +++ b/packages/io/package.json @@ -0,0 +1,42 @@ +{ + "name": "@aitube/io", + "module": "index.ts", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "type": "module", + "version": "0.2.4", + "description": "Collection of useful I/O utilities for NodeJS. Used by AiTube.at", + "scripts": { + "build": "bun build --target=node ./src/index.ts --outfile=dist/index.js && bun run build:declaration", + "build:declaration": "tsc --emitDeclarationOnly --project tsconfig.types.json", + "postbuild": "rimraf tsconfig.types.tsbuildinfo", + "publish": "npm publish --access public" + }, + "devDependencies": { + "@types/mime-types": "^2.1.4", + "bun-types": "latest", + "prettier": "^3.2.5", + "rimraf": "^5.0.7", + "typescript": "^5.4.5" + }, + "dependencies": { + "mime-types": "^2.1.35", + "pure-uuid": "^1.8.1", + "sharp": "^0.33.4" + }, + "repository": { + "type": "git", + "url": "https://github.com/jbilcke-hf/aitube-io.git" + }, + "keywords": [ + "AiTube", + "FFmpeg" + ], + "author": "Julian Bilcke", + "license": "MIT", + "files": [ + "dist/*.js", + "dist/*.d.ts", + "dist/**/*.d.ts" + ] +} diff --git a/packages/io/src/delete/deleteFile.ts b/packages/io/src/delete/deleteFile.ts new file mode 100644 index 0000000000000000000000000000000000000000..7dabfe8bd24f2822797d8ba54ba8e6abed56ceaa --- /dev/null +++ b/packages/io/src/delete/deleteFile.ts @@ -0,0 +1,14 @@ +import { rm } from "node:fs/promises" + +export async function deleteFile(filePath: string, debug?: boolean): Promise { + try { + await rm(filePath, { recursive: true, force: true }) + // await unlink(filePath) + return true + } catch (err) { + if (debug) { + console.error(`failed to unlink file at ${filePath}: ${err}`) + } + } + return false +} \ No newline at end of file diff --git a/packages/io/src/delete/deleteFilesWithName.ts b/packages/io/src/delete/deleteFilesWithName.ts new file mode 100644 index 0000000000000000000000000000000000000000..31d95782ab8be20f092ae5a510f4bf24ea152014 --- /dev/null +++ b/packages/io/src/delete/deleteFilesWithName.ts @@ -0,0 +1,13 @@ +import { readdir } from "node:fs/promises" +import path from "node:path" + +import { deleteFile } from "./deleteFile" + +export const deleteFilesWithName = async (dir: string, name: string, debug?: boolean) => { + // console.log(`deleteFilesWithName(${dir}, ${name})`) + for (const file of await readdir(dir)) { + if (file.includes(name)) { + await deleteFile(path.join(dir, file)) + } + } +} diff --git a/packages/io/src/delete/index.ts b/packages/io/src/delete/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..6e4f88e13ed490d002cf70a2b46b478e0294e8ac --- /dev/null +++ b/packages/io/src/delete/index.ts @@ -0,0 +1,3 @@ +export { deleteFile } from "./deleteFile" +export { deleteFilesWithName } from "./deleteFilesWithName" +export { removeTemporaryFiles } from "./removeTemporaryFiles" \ No newline at end of file diff --git a/packages/io/src/delete/removeTemporaryFiles.ts b/packages/io/src/delete/removeTemporaryFiles.ts new file mode 100644 index 0000000000000000000000000000000000000000..d290be827f07fd9a6d1b91c558baf2fdfc82f202 --- /dev/null +++ b/packages/io/src/delete/removeTemporaryFiles.ts @@ -0,0 +1,21 @@ +import { existsSync, promises as fs } from "node:fs" + +// note: this function will never fail +export async function removeTemporaryFiles(filesPaths: string[]) { + try { + // Cleanup temporary files - you could choose to do this or leave it to the user + await Promise.all(filesPaths.map(async (filePath) => { + try { + if (existsSync(filePath)) { + await fs.rm(filePath) + } + } catch (err) { + // + } + })) + } catch (err) { + // no big deal, except a bit of tmp file leak + // although.. if delete failed, it could also indicate + // that the file has already been cleaned-up, so even better! + } +} \ No newline at end of file diff --git a/packages/io/src/fetch/downloadFileAsBase64.ts b/packages/io/src/fetch/downloadFileAsBase64.ts new file mode 100644 index 0000000000000000000000000000000000000000..fca5ecd6e4ce9319a37c677153b9543c4d9f77aa --- /dev/null +++ b/packages/io/src/fetch/downloadFileAsBase64.ts @@ -0,0 +1,27 @@ +import { lookup } from "mime-types" + +export const downloadFileAsBase64 = async (remoteUrl: string): Promise => { + // const controller = new AbortController() + + // download the file + const response = await fetch(remoteUrl, { + // signal: controller.signal + }) + + // get as Buffer + const arrayBuffer = await response.arrayBuffer() + const buffer = Buffer.from(arrayBuffer) + + // convert it to base64 + const base64 = buffer.toString('base64') + + + const res = lookup(remoteUrl) + let contentType = res.toString() + if (typeof res === "boolean" && res === false) { + contentType = response.headers.get('content-type') || "" + } + + const assetUrl = `data:${contentType};base64,${base64}` + return assetUrl +}; \ No newline at end of file diff --git a/packages/io/src/fetch/index.ts b/packages/io/src/fetch/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..7471cec21d77529282fbf1b28894eba987611e79 --- /dev/null +++ b/packages/io/src/fetch/index.ts @@ -0,0 +1 @@ +export { downloadFileAsBase64 } from "./downloadFileAsBase64" \ No newline at end of file diff --git a/packages/io/src/image/convertImageTo.ts b/packages/io/src/image/convertImageTo.ts new file mode 100644 index 0000000000000000000000000000000000000000..c7287347770495390d27fe5d07075f33e7fb22a1 --- /dev/null +++ b/packages/io/src/image/convertImageTo.ts @@ -0,0 +1,31 @@ +import { convertImageToJpeg } from "./convertImageToJpeg" +import { convertImageToPng } from "./convertImageToPng" +import { convertImageToWebp } from "./convertImageToWebp" +import { ImageFileExt } from "./imageFormats" + +/** + * Convert an image to one of the supported file formats + * + * @param imgBase64 + * @param outputFormat + * @returns + */ +export async function convertImageTo(imgBase64: string = "", outputFormat: ImageFileExt): Promise { + const format = outputFormat.trim().toLowerCase() as ImageFileExt + if (!["jpeg", "jpg", "png", "webp"].includes(format)) { + throw new Error(`unsupported file format "${format}"`) + } + + const isJpeg = format === "jpg" || format === "jpeg" + + + if (isJpeg) { + return convertImageToJpeg(imgBase64) + } + + if (format === "webp") { + return convertImageToWebp(imgBase64) + } + + return convertImageToPng(imgBase64) +} diff --git a/packages/io/src/image/convertImageToJpeg.ts b/packages/io/src/image/convertImageToJpeg.ts new file mode 100644 index 0000000000000000000000000000000000000000..7ef63e91a8b83873d9a088c5483d0c1bc4d3d454 --- /dev/null +++ b/packages/io/src/image/convertImageToJpeg.ts @@ -0,0 +1,27 @@ +import sharp from "sharp" + +export async function convertImageToJpeg(imgBase64: string = "", quality: number = 92): Promise { + + const base64WithoutHeader = imgBase64.split(";base64,")[1] || "" + + if (!base64WithoutHeader) { + const slice = `${imgBase64 || ""}`.slice(0, 50) + throw new Error(`couldn't process input image "${slice}..."`) + } + + // Convert base64 to buffer + const tmpBuffer = Buffer.from(base64WithoutHeader, 'base64') + + // Resize the buffer to the target size + const newBuffer = await sharp(tmpBuffer) + .jpeg({ + quality, + // we don't use progressive: true because we pre-load images anyway + }) + .toBuffer() + + // Convert the buffer back to base64 + const newImageBase64 = newBuffer.toString('base64') + + return `data:image/jpeg;base64,${newImageBase64}` +} \ No newline at end of file diff --git a/packages/io/src/image/convertImageToOriginal.ts b/packages/io/src/image/convertImageToOriginal.ts new file mode 100644 index 0000000000000000000000000000000000000000..92971f64b13d98f8700c5b76190bfa6925c47beb --- /dev/null +++ b/packages/io/src/image/convertImageToOriginal.ts @@ -0,0 +1,6 @@ + +// you are reading it right: this function does.. nothing! +// it is a NOOP conversion function +export async function convertImageToOriginal(imgBase64: string = ""): Promise { + return imgBase64 +} \ No newline at end of file diff --git a/packages/io/src/image/convertImageToPng.ts b/packages/io/src/image/convertImageToPng.ts new file mode 100644 index 0000000000000000000000000000000000000000..8edd35bc9b728d814134dea7a5b70bd06b8f83a9 --- /dev/null +++ b/packages/io/src/image/convertImageToPng.ts @@ -0,0 +1,23 @@ +import sharp from "sharp" + +export async function convertImageToPng(imgBase64: string = ""): Promise { + + const base64WithoutHeader = imgBase64.split(";base64,")[1] || "" + + if (!base64WithoutHeader) { + const slice = `${imgBase64 || ""}`.slice(0, 50) + throw new Error(`couldn't process input image "${slice}..."`) + } + + // Convert base64 to buffer + const tmpBuffer = Buffer.from(base64WithoutHeader, 'base64') + + const newBuffer = await sharp(tmpBuffer) + .png() + .toBuffer() + + // Convert the buffer back to base64 + const newImageBase64 = newBuffer.toString('base64') + + return `data:image/png;base64,${newImageBase64}` +} \ No newline at end of file diff --git a/packages/io/src/image/convertImageToWebp.ts b/packages/io/src/image/convertImageToWebp.ts new file mode 100644 index 0000000000000000000000000000000000000000..2d936faa021aca1b7bafc3847833d69041fabe9d --- /dev/null +++ b/packages/io/src/image/convertImageToWebp.ts @@ -0,0 +1,41 @@ +import sharp from "sharp" + +export async function convertImageToWebp(imgBase64: string = ""): Promise { + + const base64WithoutHeader = imgBase64.split(";base64,")[1] || "" + + if (!base64WithoutHeader) { + const slice = `${imgBase64 || ""}`.slice(0, 50) + throw new Error(`couldn't process input image "${slice}..."`) + } + + // Convert base64 to buffer + const tmpBuffer = Buffer.from(base64WithoutHeader, 'base64') + + // Resize the buffer to the target size + const newBuffer = await sharp(tmpBuffer) + .webp({ + // for options please see https://sharp.pixelplumbing.com/api-output#webp + + // preset: "photo", + + // effort: 3, + + // for a PNG-like quality + // lossless: true, + + // by default it is quality 80 + quality: 80, + + // nearLossless: true, + + // use high quality chroma subsampling + smartSubsample: true, + }) + .toBuffer() + + // Convert the buffer back to base64 + const newImageBase64 = newBuffer.toString('base64') + + return `data:image/webp;base64,${newImageBase64}` +} \ No newline at end of file diff --git a/packages/io/src/image/imageFormats.ts b/packages/io/src/image/imageFormats.ts new file mode 100644 index 0000000000000000000000000000000000000000..027dfd62d46e180fc8d06fbaf5ac232af90e3008 --- /dev/null +++ b/packages/io/src/image/imageFormats.ts @@ -0,0 +1 @@ +export type ImageFileExt = "png" | "jpeg" | "jpg" | "webp" diff --git a/packages/io/src/image/index.ts b/packages/io/src/image/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab6193157338081f130f4416eb0ddf9778ba1deb --- /dev/null +++ b/packages/io/src/image/index.ts @@ -0,0 +1,7 @@ +export { convertImageTo } from "./convertImageTo" +export { convertImageToJpeg } from "./convertImageToJpeg" +export { convertImageToOriginal } from "./convertImageToOriginal" +export { convertImageToPng } from "./convertImageToPng" +export { convertImageToWebp } from "./convertImageToWebp" +export type { ImageFileExt } from "./imageFormats" +export { resizeImage } from "./resizeImage" \ No newline at end of file diff --git a/packages/io/src/image/resizeImage.ts b/packages/io/src/image/resizeImage.ts new file mode 100644 index 0000000000000000000000000000000000000000..096ec42e1c77425e413e9471dc00f141a54ff3e5 --- /dev/null +++ b/packages/io/src/image/resizeImage.ts @@ -0,0 +1,55 @@ +import sharp from "sharp" + +export type ResizeImageParams = { + input: string + width?: number + height?: number + debug?: boolean + asBase64?: boolean // TODO: not implemented yet! +}; + +/** + * Resize an image to a given width and height. + * The input image can be a file path or a data URI (base64) + * The image ratio will be preserved if only one side is given. + * The image format (WebP, Jpeg, PNG) will be preserved. + * This function always return a base64 string (data URI with the mime type) + * + * @param param0 + * @returns + */ +export async function resizeImage({ input, width, height, debug, asBase64 }: ResizeImageParams): Promise { + let inputBuffer: Buffer; + + // Test if input is a data URI + const dataUriPattern = /^data:([a-zA-Z]+\/[a-zA-Z]+);base64,(.*)$/; + const matches = input.match(dataUriPattern); + + if (matches) { + const [, mimeType, base64Data] = matches; + if (!/^image\/(png|jpeg|webp)$/.test(mimeType)) { + throw new Error(`Unsupported image format. Expected PNG, JPEG, or WebP.`); + } + inputBuffer = Buffer.from(base64Data, "base64"); + } else { + // Assuming input is a file path + inputBuffer = await sharp(input).toBuffer(); + } + + const sharpInstance = sharp(inputBuffer) + .resize(width, height, { + fit: "inside", + withoutEnlargement: true + }); + + const outputBuffer = await sharpInstance.toBuffer(); + const outputMimeType = await sharpInstance.metadata().then(meta => meta.format); + + if (!outputMimeType) { + throw new Error("Failed to determine the image mime type after resizing."); + } + + const prefix = `data:image/${outputMimeType};base64,`; + const outputBase64 = outputBuffer.toString("base64"); + return `${prefix}${outputBase64}`; +} \ No newline at end of file diff --git a/packages/io/src/index.ts b/packages/io/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..97f1eb2432e845cb5f31aef9b27986df30e7a4d6 --- /dev/null +++ b/packages/io/src/index.ts @@ -0,0 +1,38 @@ +export { + deleteFile, + deleteFilesWithName, + removeTemporaryFiles +} from "./delete" + +export { + downloadFileAsBase64, +} from "./fetch" + +export { + convertImageTo, + convertImageToJpeg, + convertImageToOriginal, + convertImageToPng, + convertImageToWebp, + resizeImage +} from "./image" + +export type { ImageFileExt } from "./image" + +export { + readJpegFileToBase64, + readLocalOrRemotePlainText, + readMp3FileToBase64, + readMp4FileToBase64, + readPlainText, + readPngFileToBase64, + readWavFileToBase64 +} from "./read" + +export { + getRandomDirectory, +} from "./tmp" + +export { + writeBase64ToFile, +} from "./write" \ No newline at end of file diff --git a/packages/io/src/read/index.ts b/packages/io/src/read/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..5decb97b7cd3c7ebc160ea1629529721b9d92bcb --- /dev/null +++ b/packages/io/src/read/index.ts @@ -0,0 +1,7 @@ +export { readJpegFileToBase64 } from "./readJpegFileToBase64" +export { readLocalOrRemotePlainText } from "./readLocalOrRemotePlainText" +export { readMp3FileToBase64 } from "./readMp3FileToBase64" +export { readMp4FileToBase64 } from "./readMp4FileToBase64" +export { readPlainText } from "./readPlainText" +export { readPngFileToBase64 } from "./readPngFileToBase64" +export { readWavFileToBase64 } from "./readWavFileToBase64" diff --git a/packages/io/src/read/readJpegFileToBase64.ts b/packages/io/src/read/readJpegFileToBase64.ts new file mode 100644 index 0000000000000000000000000000000000000000..b79f30859ce82f4ad35585dd1e2bfb905af0b5d0 --- /dev/null +++ b/packages/io/src/read/readJpegFileToBase64.ts @@ -0,0 +1,18 @@ +import { readFile } from "node:fs/promises" + +export async function readJpegFileToBase64(filePath: string): Promise { + try { + // Read the file's content as a Buffer + const fileBuffer = await readFile(filePath); + + // Convert the buffer to a base64 string + const base64 = fileBuffer.toString('base64'); + + // Prefix the base64 string with the Data URI scheme for PNG images + return `data:image/jpeg;base64,${base64}`; + } catch (error) { + // Handle errors (e.g., file not found, no permissions, etc.) + console.error(error); + throw error; + } +} diff --git a/packages/io/src/read/readLocalOrRemotePlainText.ts b/packages/io/src/read/readLocalOrRemotePlainText.ts new file mode 100644 index 0000000000000000000000000000000000000000..7f81325faa563e278032ed51a76873657905b52d --- /dev/null +++ b/packages/io/src/read/readLocalOrRemotePlainText.ts @@ -0,0 +1,28 @@ +import { readPlainText } from "./readPlainText" + +export async function readLocalOrRemotePlainText(input: string): Promise { + + if (input.startsWith("https://") || input.startsWith("http://")) { + try { + const res = await fetch(input) + return res.text() + } catch (err) { + return input + } + } + + // (probably) too long to be a filepath + if (input.length > 4096) { + return input + } + + if (input.endsWith(".txt") || input.endsWith(".md")) { + try { + return readPlainText(input) + } catch (err) { + return input + } + } + + return input +} \ No newline at end of file diff --git a/packages/io/src/read/readMp3FileToBase64.ts b/packages/io/src/read/readMp3FileToBase64.ts new file mode 100644 index 0000000000000000000000000000000000000000..8cff2427ed817806d20566d09432da09b1499035 --- /dev/null +++ b/packages/io/src/read/readMp3FileToBase64.ts @@ -0,0 +1,18 @@ +import { readFile } from "node:fs/promises" + +export async function readMp3FileToBase64(filePath: string): Promise { + try { + // Read the file's content as a Buffer + const fileBuffer = await readFile(filePath); + + // Convert the buffer to a base64 string + const base64 = fileBuffer.toString('base64'); + + // Prefix the base64 string with the Data URI scheme for PNG images + return `data:audio/mp3;base64,${base64}`; + } catch (error) { + // Handle errors (e.g., file not found, no permissions, etc.) + console.error(error); + throw error; + } +} diff --git a/packages/io/src/read/readMp4FileToBase64.ts b/packages/io/src/read/readMp4FileToBase64.ts new file mode 100644 index 0000000000000000000000000000000000000000..f13814cba4f1f797b4077ef74a65756731d3e1d6 --- /dev/null +++ b/packages/io/src/read/readMp4FileToBase64.ts @@ -0,0 +1,18 @@ +import { readFile } from "node:fs/promises" + +export async function readMp4FileToBase64(filePath: string): Promise { + try { + // Read the file's content as a Buffer + const fileBuffer = await readFile(filePath) + + // Convert the buffer to a base64 string + const base64 = fileBuffer.toString('base64') + + // Prefix the base64 string with the Data URI scheme for PNG images + return `data:video/mp4;base64,${base64}` + } catch (error) { + // Handle errors (e.g., file not found, no permissions, etc.) + console.error(error) + throw error + } +} diff --git a/packages/io/src/read/readPlainText.ts b/packages/io/src/read/readPlainText.ts new file mode 100644 index 0000000000000000000000000000000000000000..6b3d59011df29c2abd53102c90c3a63730b21366 --- /dev/null +++ b/packages/io/src/read/readPlainText.ts @@ -0,0 +1,13 @@ +import { readFile } from "node:fs/promises" + +export async function readPlainText(filePath: string): Promise { + try { + const plainText = await readFile(filePath, "utf-8") + + return plainText + } catch (error) { + // Handle errors (e.g., file not found, no permissions, etc.) + console.error(error) + throw error + } +} diff --git a/packages/io/src/read/readPngFileToBase64.ts b/packages/io/src/read/readPngFileToBase64.ts new file mode 100644 index 0000000000000000000000000000000000000000..a3475ceb4ad686bf6036386ddf99b7f774fae1ab --- /dev/null +++ b/packages/io/src/read/readPngFileToBase64.ts @@ -0,0 +1,18 @@ +import { readFile } from "node:fs/promises" + +export async function readPngFileToBase64(filePath: string): Promise { + try { + // Read the file's content as a Buffer + const fileBuffer = await readFile(filePath) + + // Convert the buffer to a base64 string + const base64 = fileBuffer.toString('base64') + + // Prefix the base64 string with the Data URI scheme for PNG images + return `data:image/png;base64,${base64}` + } catch (error) { + // Handle errors (e.g., file not found, no permissions, etc.) + console.error(error) + throw error + } +} diff --git a/packages/io/src/read/readWavFileToBase64.ts b/packages/io/src/read/readWavFileToBase64.ts new file mode 100644 index 0000000000000000000000000000000000000000..00d182d525d398c315c810b61e9f37cf38cf34b5 --- /dev/null +++ b/packages/io/src/read/readWavFileToBase64.ts @@ -0,0 +1,18 @@ +import { readFile } from "node:fs/promises" + +export async function readWavFileToBase64(filePath: string): Promise { + try { + // Read the file's content as a Buffer + const fileBuffer = await readFile(filePath) + + // Convert the buffer to a base64 string + const base64 = fileBuffer.toString('base64') + + // Prefix the base64 string with the Data URI scheme for PNG images + return `data:audio/wav;base64,${base64}` + } catch (error) { + // Handle errors (e.g., file not found, no permissions, etc.) + console.error(error) + throw error + } +} diff --git a/packages/io/src/tmp/getRandomDirectory.ts b/packages/io/src/tmp/getRandomDirectory.ts new file mode 100644 index 0000000000000000000000000000000000000000..b9c0f23c73fbfe258abd204d2c9fb268d6da19ea --- /dev/null +++ b/packages/io/src/tmp/getRandomDirectory.ts @@ -0,0 +1,9 @@ +import { tmpdir } from "node:os" +import { join } from "node:path" +import { mkdtemp } from "node:fs/promises" + +import { UUID } from "./uuid" + +export async function getRandomDirectory(): Promise { + return mkdtemp(join(tmpdir(), UUID())) +} \ No newline at end of file diff --git a/packages/io/src/tmp/index.ts b/packages/io/src/tmp/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..3050210d9997c89d36f6693d5d284199a9d7f341 --- /dev/null +++ b/packages/io/src/tmp/index.ts @@ -0,0 +1 @@ +export { getRandomDirectory } from "./getRandomDirectory" \ No newline at end of file diff --git a/packages/io/src/tmp/uuid.ts b/packages/io/src/tmp/uuid.ts new file mode 100644 index 0000000000000000000000000000000000000000..b2452e0e78fd97ad163a4b6e2702a89ec5451bd0 --- /dev/null +++ b/packages/io/src/tmp/uuid.ts @@ -0,0 +1,5 @@ +import PureUUID from "pure-uuid" + +export function UUID() { + return new PureUUID(4).format() +} \ No newline at end of file diff --git a/packages/io/src/write/index.ts b/packages/io/src/write/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..ef25f91606b822575018ab28c37b468ab0f79c92 --- /dev/null +++ b/packages/io/src/write/index.ts @@ -0,0 +1 @@ +export { writeBase64ToFile } from "./writeBase64ToFile" \ No newline at end of file diff --git a/packages/io/src/write/writeBase64ToFile.ts b/packages/io/src/write/writeBase64ToFile.ts new file mode 100644 index 0000000000000000000000000000000000000000..c7e16f09502059523cb0cbaf0a708baac47ceba5 --- /dev/null +++ b/packages/io/src/write/writeBase64ToFile.ts @@ -0,0 +1,29 @@ +import { writeFile } from "node:fs/promises" + +export async function writeBase64ToFile(base64Data: string, filePath: string): Promise { + const data = base64Data.split(";base64,").pop() + if (!data) { throw new Error("Invalid base64 content") } + await writeFile(filePath, data, { encoding: "base64" }) + return filePath +} + +// legacy way: with more manual steps + +/* +export async function writeBase64ToFile(content: string, filePath: string): Promise { + + // Remove "data:image/png;base64," from the start of the data url + const base64Data = content.split(";base64,")[1] + + // Convert base64 to binary + const data = Buffer.from(base64Data, "base64") + + // Write binary data to file + try { + await fs.writeFile(filePath, data) + // console.log("File written successfully") + } catch (error) { + console.error("An error occurred:", error) + } +} +*/ \ No newline at end of file diff --git a/packages/io/tsconfig.json b/packages/io/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..ab7cc3ed096e5dc51a557fdee4e68c0e28076d0b --- /dev/null +++ b/packages/io/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "baseUrl": "./", + "paths": { + "@/*": ["src/*"] + }, + "lib": ["ESNext", "DOM"], + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": true, + "noEmit": true, + "composite": true, + "strict": true, + "downlevelIteration": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "types": [ + "bun-types" + ] + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/packages/io/tsconfig.types.json b/packages/io/tsconfig.types.json new file mode 100644 index 0000000000000000000000000000000000000000..a6a3f21154bb178f1850c9b70714fb66ef5bf750 --- /dev/null +++ b/packages/io/tsconfig.types.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "emitDeclarationOnly": true, + "declaration": true, + "outDir": "./dist", + "rootDir": "./src", + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/packages/timeline/.gitignore b/packages/timeline/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ea8fe6a7905bd72f745584146daa9994bd211499 --- /dev/null +++ b/packages/timeline/.gitignore @@ -0,0 +1,177 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +\*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +\*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +\*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +\*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.cache +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output +dist +.nuxt + +# Gatsby files + +.cache/ + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp +.cache + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.\* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store + +# TypeScript build information +*.tsbuildinfo \ No newline at end of file diff --git a/packages/timeline/.npmignore b/packages/timeline/.npmignore new file mode 100644 index 0000000000000000000000000000000000000000..78a661ea2d8f8cdaa94e4cc69d758a4b2d946feb --- /dev/null +++ b/packages/timeline/.npmignore @@ -0,0 +1,4 @@ +# Ignore everything +* +# Except the dist directory +!dist/ diff --git a/packages/timeline/.prettierrc.json b/packages/timeline/.prettierrc.json new file mode 100644 index 0000000000000000000000000000000000000000..1dcadb7324877e15a4ffa4efa5723a519395f511 --- /dev/null +++ b/packages/timeline/.prettierrc.json @@ -0,0 +1,9 @@ +{ + "semi": false, + "singleQuote": true, + "arrowParens": "avoid", + "printWidth": 140, + "tabWidth": 2, + "trailingComma": "es5", + "bracketSpacing": true +} diff --git a/packages/timeline/LICENSE.md b/packages/timeline/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..8b21ed7d57c2d217f49e10d0fb0b327961a4ea54 --- /dev/null +++ b/packages/timeline/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2024 Julian Bilcke + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/timeline/README.md b/packages/timeline/README.md new file mode 100644 index 0000000000000000000000000000000000000000..5a424f08464f4ff81501d772fb66f5d4dc56fcf9 --- /dev/null +++ b/packages/timeline/README.md @@ -0,0 +1,61 @@ +# @aitube/timeline + +*React component to display an OpenClap timeline* + +## Introduction + +This library is not ready for public use yet. + +This is a "build in public" project so code is open and provided for convenience and discussion, +but there is no official release yet (documentation will be written once the library is useable). + +Thanks for your patience! + +## Installation + +Note: as warned before, this library is not ready for public use yet. + +I cannot provide support until the basic features have been implemented and some critical bugs fixed. + +```bash +npm install @aitube/timeline +``` + +Depending on your project configuration and package manager, you may need to install some additional packages manually, such as React, Radix, Tailwind, Three.js, Zustand etc: + +```bash +npm install @aitube/clap @radix-ui/react-slider @react-spring/three @react-spring/types @react-three/drei @react-three/fiber @types/react @types/react-dom react react-dom tailwindcss three typescript zustand +``` + +If you forget some dependencies you might get weird errors + +## Building + +You can see in the package.json that I set `NODE_ENV=production` while building, that's because of a weirdness with Bun: https://github.com/oven-sh/bun/issues/3768 + +If you are developping the timeline, I recommend to use: + +```bash +bun run build:dev +``` + +to build with the jsxDEV enabled. + +You will also want to use a path like this to test the module directly dependency: + +```json + "@aitube/timeline": "file:/Users/jbilcke/Projects/Typescript_Libraries/aitube-timeline", +``` + + +## Future extensions + +This project is currently not designed to be used with other tools such as Svelte, Vue, or other state manager. In the future it may be split into sub-libraries to facilitate support for alternative frameworks. + +## TODO + +[ ] BUG: the scrollY position is a bit janky, one should solve the formula +[ ] OPTIM: we should avoid re-creating geometries (eg. grids, cells) and text since this is costly +[ ] FEATURE: Add edit callbacks +[ ] CLEAN: Write doc +[ ] BUG: Fix the Vite previewer diff --git a/packages/timeline/index.html b/packages/timeline/index.html new file mode 100644 index 0000000000000000000000000000000000000000..bc23825e730d93c76028ee77d476f48c411c7ef9 --- /dev/null +++ b/packages/timeline/index.html @@ -0,0 +1,12 @@ + + + + + Demo + + + +
+ + + \ No newline at end of file diff --git a/packages/timeline/package.json b/packages/timeline/package.json new file mode 100644 index 0000000000000000000000000000000000000000..2df1de55bd1f42d826afb8054f628516cf489f36 --- /dev/null +++ b/packages/timeline/package.json @@ -0,0 +1,67 @@ +{ + "name": "@aitube/timeline", + "module": "index.tsx", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "type": "module", + "private": false, + "version": "0.2.4", + "description": "React component to display an OpenClap timeline", + "scripts": { + "build": "NODE_ENV=production bun build ./src/index.tsx --outfile=dist/index.js --external @radix-ui/react-slider --external @react-spring/three --external @react-spring/types --external @react-three/drei --external @react-three/fiber --external @types/react --external @types/react-dom --external react --external react-dom --external tailwindcss --external three --external typescript --external zustand && bun run build:declaration", + "build:dev": "bun build ./src/index.tsx --outfile=dist/index.js --external @radix-ui/react-slider --external @react-spring/three --external @react-spring/types --external @react-three/drei --external @react-three/fiber --external @types/react --external @types/react-dom --external react --external react-dom --external tailwindcss --external three --external typescript --external zustand && bun run build:declaration", + "build:declaration": "tsc --emitDeclarationOnly --project tsconfig.types.json", + "postbuild": "rimraf tsconfig.types.tsbuildinfo && bun run build:declaration", + "publish": "bun run build && npm publish --access public", + "update": "rm -Rf node_modules && rm bun.lockb && bun i && bun run build", + "dev": "vite", + "serve": "vite preview" + }, + "devDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "@typescript-eslint/eslint-plugin": "^7.17.0", + "@typescript-eslint/parser": "^7.17.0", + "@vitejs/plugin-react": "^4.3.1", + "bun-types": "latest", + "eslint": "^8.57.0", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-react-refresh": "^0.4.9", + "prettier": "^3.3.3", + "rimraf": "^6.0.1", + "typescript": "^5.5.4", + "vite": "^5.3.4" + }, + "dependencies": { + "@aitube/clap": "workspace:*", + "@radix-ui/react-slider": "^1.1.2", + "@react-spring/three": "^9.7.3", + "@react-spring/types": "^9.7.3", + "@react-three/drei": "^9.105.4", + "@react-three/fiber": "^8.16.2", + "clsx": "^2.1.1", + "date-fns": "^3.6.0", + "react": "*", + "react-dom": "*", + "react-virtualized-auto-sizer": "^1.0.24", + "tailwind-merge": "^2.4.0", + "tailwindcss": "^3.4.6", + "three": "^0.164.1", + "zustand": "4.5.2" + }, + "repository": { + "type": "git", + "url": "https://github.com/jbilcke-hf/aitube-timeline.git" + }, + "keywords": [ + "OpenClap", + "AiTube" + ], + "author": "Julian Bilcke", + "license": "MIT", + "files": [ + "dist/*.js", + "dist/*.d.ts", + "dist/**/*.d.ts" + ] +} diff --git a/packages/timeline/src/ClapTimeline.tsx b/packages/timeline/src/ClapTimeline.tsx new file mode 100644 index 0000000000000000000000000000000000000000..48d9479a78931abd14dd116f7ad0cb25d39d0beb --- /dev/null +++ b/packages/timeline/src/ClapTimeline.tsx @@ -0,0 +1,149 @@ +import AutoSizer, { Size } from "react-virtualized-auto-sizer" +import { Canvas } from "@react-three/fiber" +import { Stats } from "@react-three/drei" + +import { + TimelineControls, + HorizontalScroller, + Timeline +} from "@/components" +import { ClapProject, isValidNumber } from "@aitube/clap" +import { + DEFAULT_FRAMELOOP, + DEFAULT_MAX_ZOOM, + DEFAULT_MIN_ZOOM, + DEFAULT_SHOW_FPS, + DEFAULT_ZOOM_DAMPING_FACTOR, + DEFAULT_ZOOM_SPEED +} from "./constants/defaults" +import { cn } from "./utils" +import { TimelineCamera } from "./components/camera" +import { useTimeline } from "./hooks" +import { topBarTimeScaleHeight } from "./constants/themes" + +export function ClapTimeline({ + clap, + className = "", + minZoom = DEFAULT_MIN_ZOOM, + maxZoom = DEFAULT_MAX_ZOOM, + zoomSpeed = DEFAULT_ZOOM_SPEED, + zoomDampingFactor = DEFAULT_ZOOM_DAMPING_FACTOR, + showFPS = DEFAULT_SHOW_FPS, + // frameloop = DEFAULT_FRAMELOOP, + // width, + // height, + }: { + clap?: ClapProject + className?: string + minZoom?: number + maxZoom?: number + zoomSpeed?: number + zoomDampingFactor?: number + showFPS?: boolean + + // demand is less CPU intensive, but you will have to manually + // trigger state changes + // frameloop?: "demand" | "always" | "never" + // width?: number + // height?: number + } = { + clap: undefined, + + minZoom: DEFAULT_MIN_ZOOM, + maxZoom: DEFAULT_MAX_ZOOM, + zoomSpeed: DEFAULT_ZOOM_SPEED, + zoomDampingFactor: DEFAULT_ZOOM_DAMPING_FACTOR, + showFPS: DEFAULT_SHOW_FPS, + // frameloop: DEFAULT_FRAMELOOP + }) { + const theme = useTimeline(s => s.theme) + const canvas = useTimeline(s => s.canvas) + const setCanvas = useTimeline(s => s.setCanvas) + + const handleIsCreated = () => { + useTimeline.setState({ isReady: true }) + } + + return ( +
+ + {({ height, width }: Size) => ( +
+
+ + { + setCanvas(canvas || undefined) + }} + id="clap-timeline" + + // must be active when playing back a video + frameloop="always" + + // those must stay ON otherwise colors will be washed out + flat + linear + + // doesn't work in our case since we need to display videos + // frameloop="demand" + + + style={{ + width: isValidNumber(width) ? `${width}px` : "100%", + height: isValidNumber(height) ? `${height}px` : "100%" + }} + + onCreated={handleIsCreated} + + onWheel={(wheelEvent) => { + const rect = canvas?.getBoundingClientRect() + if (!rect) { return } + + const clientY = wheelEvent.clientY + const containerY = rect.y + const posY = clientY - containerY + + // apparently we cannot stop the propagation from the scroll wheel event + // we attach to our to bar from the scroll wheel event set on the canvas + // (that makes sense, one is in DOM space, the other in WebGL space) + // + // there are probably better ways to do this, but for now here is a very + // crude fix to ignore global X-Y scroll events when we are over the timeline + if (posY <= topBarTimeScaleHeight) { return } + + useTimeline.getState().handleMouseWheel({ + deltaX: wheelEvent.deltaX, + deltaY: wheelEvent.deltaY + }) + }} + > + + + + {showFPS && } + + +
+ { + // + } +
+ )} +
+
+ ); +}; diff --git a/packages/timeline/src/components/camera/TimelineCamera.tsx b/packages/timeline/src/components/camera/TimelineCamera.tsx new file mode 100644 index 0000000000000000000000000000000000000000..0370d69a39a0359a805e9cfd866e721591b8ed13 --- /dev/null +++ b/packages/timeline/src/components/camera/TimelineCamera.tsx @@ -0,0 +1,18 @@ +import { OrthographicCamera } from "@react-three/drei" + +import { useTimeline } from "@/hooks" + +export function TimelineCamera() { + const setTimelineCamera = useTimeline(s => s.setTimelineCamera) + return ( + { + if (ortographicCamera) { + setTimelineCamera(ortographicCamera) + } + }} + makeDefault + position={[0, 0, 1]} + /> + ) +} \ No newline at end of file diff --git a/packages/timeline/src/components/camera/index.ts b/packages/timeline/src/components/camera/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..d751da820760be50122201a402cf65a7d893eb89 --- /dev/null +++ b/packages/timeline/src/components/camera/index.ts @@ -0,0 +1,2 @@ +export { TimelineCamera } from "./TimelineCamera" +export { TimelineCameraImpl } from "./types" diff --git a/packages/timeline/src/components/camera/types.tsx b/packages/timeline/src/components/camera/types.tsx new file mode 100644 index 0000000000000000000000000000000000000000..0f24a1b5d0e84f4c2dde34778a657d977261cbbf --- /dev/null +++ b/packages/timeline/src/components/camera/types.tsx @@ -0,0 +1,3 @@ +import { OrthographicCamera as OrthographicCameraImpl } from 'three' + +export type TimelineCameraImpl = OrthographicCameraImpl diff --git a/packages/timeline/src/components/cells/AudioCell.tsx b/packages/timeline/src/components/cells/AudioCell.tsx new file mode 100644 index 0000000000000000000000000000000000000000..312675680fd7059fa245a890361038b57a65a6a5 --- /dev/null +++ b/packages/timeline/src/components/cells/AudioCell.tsx @@ -0,0 +1,71 @@ +import { RoundedBox } from "@react-three/drei" +import { SpecializedCellProps } from "./types" +import { Waveform } from "./Waveform" + +export function AudioCell({ + segment: s, + cellWidth, + cellHeight, + isHovered, + setHoveredSegment, + durationInSteps, + startTimeInSteps, + colorScheme, + widthInPx, + widthInPxAfterZoom, + isResizing, + track +}: SpecializedCellProps) { + + const padding = 1.2 + + const fontSize = 13 + const lineHeight = 1.2 + + return ( + + + + + + ) +} \ No newline at end of file diff --git a/packages/timeline/src/components/cells/Cell.tsx b/packages/timeline/src/components/cells/Cell.tsx new file mode 100644 index 0000000000000000000000000000000000000000..6d6eb12b43edde9060a7b3d85eff7efe604a42f6 --- /dev/null +++ b/packages/timeline/src/components/cells/Cell.tsx @@ -0,0 +1,283 @@ +import { Suspense } from "react" +import { a } from "@react-spring/three" +import { ClapSegmentCategory } from "@aitube/clap" + +import { DEFAULT_DURATION_IN_MS_PER_STEP } from "@/constants" +import { useTimeline } from "@/hooks" +import { useHoveredSegment } from "@/hooks/useHoveredSegment" +import { leftBarTrackScaleWidth, topBarTimeScaleHeight } from "@/constants/themes" +import { TimelineSegment } from "@/types" +import { useSegmentChanges } from "@/hooks/useSegmentChanges" + +import { ImageCell } from "./ImageCell" +import { VideoCell } from "./VideoCell" +import { TextCell } from "./TextCell" +import { RedrawButton } from "./RedrawButton" +import { AudioCell } from "./AudioCell" +import { useThree } from "@react-three/fiber" +import { SegmentArea } from "@/types/timeline" +import { SegmentIcon } from "../icons/SegmentIcon" + +export function Cell({ + segment: s +}: { + segment: TimelineSegment +}) { + const { size } = useThree() + + // TODO JULIAN: we should optimize this component because it causes + // some performance issues due to the numerous re-renders + + + // this is only used to react to changes in the segment + const segmentChanged = useSegmentChanges(s) + + const getSegmentColorScheme = useTimeline(s => s.getSegmentColorScheme) + const colorScheme = getSegmentColorScheme(s) + + const cellWidth = useTimeline((s) => s.cellWidth) + const getCellHeight = useTimeline((s) => s.getCellHeight) + const getVerticalCellPosition = useTimeline((s) => s.getVerticalCellPosition) + + const cellHeight = getCellHeight(s.track) + const verticalCellPosition = getVerticalCellPosition(0, s.track) + + // used to react to changes impacting tracks + const tracks = useTimeline(s => s.tracks) + + const durationInSteps = ( + (s.endTimeInMs - s.startTimeInMs) / DEFAULT_DURATION_IN_MS_PER_STEP + ) + + const startTimeInSteps = ( + s.startTimeInMs / DEFAULT_DURATION_IN_MS_PER_STEP + ) + + const widthInPx = durationInSteps * cellWidth + + const currentZoomLevel = useTimeline(s => s.currentZoomLevel) + + // we need to round this one to avoid *too* many re-renders + const widthInPxAfterZoom = Math.round(currentZoomLevel * durationInSteps * cellWidth) + + const isHovered = useHoveredSegment(s.id) + + // note: this is not reactive (as a general rule, we never want to be reactive in here) + // note: as a general rule, we should avoid "reactive" state updates like this + const isResizing = useTimeline(s => s.isResizing) + // const isResizing = useTimeline.getState().isResizing + + const SpecializedCell = + s.assetUrl.startsWith("data:image/") + ? ImageCell + : s.assetUrl.startsWith("data:video/") + ? VideoCell + : s.assetUrl.startsWith("data:audio/") + ? AudioCell + : TextCell + + const setHoveredSegment = useTimeline(s => s.setHoveredSegment) + + const setSelectedSegment = useTimeline(s => s.setSelectedSegment) + + // cells are rendered often (eg. whenever we mouse the mouse from one cell to another) + // because we need to handle their color change on hover / transition + // console.log(`re-rendering a `) + + const posX = + (startTimeInSteps * cellWidth) + + // the position of a RoundedBox is defined from its center + // so we have to shift its container (the a.mesh) + // to the right, exactly one half of the RoundedBox's width + + ((durationInSteps * cellWidth) / 2) + + const posY = + -verticalCellPosition + + (cellHeight / 2) + + const segmentWidth = widthInPx + const segmentHeight = cellHeight + + const computeBoundaries = ({ + pointX, + offsetX, + offsetY + }: { + pointX: number + offsetX: number + offsetY: number + }) => { + const isOutOfRange = offsetX < leftBarTrackScaleWidth ||offsetY < topBarTimeScaleHeight + + const cursorX = pointX + (size.width / 2) + const cursorTimestampAtInMs = (cursorX / cellWidth) * DEFAULT_DURATION_IN_MS_PER_STEP + + //console.log("cells.Cell:onClick() e:", e) + + const wMin = cursorTimestampAtInMs - s.startTimeInMs + const wMax = s.endTimeInMs - s.startTimeInMs + const cursorLeftPosInRatio = wMin / wMax + + const cursorLeftPosInPx = cursorLeftPosInRatio * segmentWidth + const cursorRightPosInPx = segmentWidth - cursorLeftPosInPx + + // note: this should be "responsive", with a max width + const sideGrabHandleWidth = 8 + // let isInLeftArea = cursorLeftPosInRatio < 0.5 + // let isInRightArea = cursorLeftPosInRatio > 0.5 + + const area = + (cursorRightPosInPx < 8) ? SegmentArea.LEFT + : (cursorRightPosInPx < 8) ? SegmentArea.RIGHT + : SegmentArea.MIDDLE + + return { + isOutOfRange, + cursorLeftPosInPx, + cursorRightPosInPx, + area + } + } + + return ( + { + const { + isOutOfRange, + cursorLeftPosInPx, + cursorRightPosInPx, + area + } = computeBoundaries({ + pointX: e.point.x, + offsetX: e.offsetX, + offsetY: e.offsetY + }) + if (isOutOfRange) { + setHoveredSegment({ + hoveredSegment: undefined, + area, + }) + } else { + setHoveredSegment({ + hoveredSegment: s, + area + }) + } + + e.stopPropagation() + return false + }} + + onPointerLeave={(e) => { + // console.log('leave') + setHoveredSegment({ + hoveredSegment: undefined, + // area, + }) + + e.stopPropagation() + return false + }} + + onClick={(e) => { + const { + isOutOfRange, + cursorLeftPosInPx, + cursorRightPosInPx + } = computeBoundaries({ + pointX: e.point.x, + offsetX: e.offsetX, + offsetY: e.offsetY + }) + + if (!isOutOfRange) { + setSelectedSegment({ + segment: s, + + // we leave it unspecified to create a toggle + // isSelected: true, + + onlyOneSelectedAtOnce: true, + }) + } + + e.stopPropagation() + return false + }} + onContextMenu={(e) => console.log('context menu')} + onDoubleClick={(e) => { + console.log('double click') + // TODO: do something eg. switch to an edit mode + }} + // onWheel={(e) => console.log('wheel spins')} + // onPointerUp={(e) => console.log('up')} + // onPointerDown={(e) => console.log('down')} + // onPointerOver={(e) => console.log('over')} + // onPointerOut={(e) => console.log('out')} + + // onPointerMove={(e) => console.log('move')} + // onPointerMissed={() => console.log('missed')} + // onUpdate={(self) => console.log('props have been updated')} + > + }> + + + + {/* + if you manage to make this component work, + let me know.. + + (s.category !== ClapSegmentCategory.STORYBOARD && + s.category !== ClapSegmentCategory.VIDEO) + && + */} + + { + // TODO also add the buttons to Dialogue, Sound, Music etc.. + // also maybe fix the display, as when zoomed out it doesn't look good + (s.category === ClapSegmentCategory.STORYBOARD + || s.category === ClapSegmentCategory.VIDEO + || s.category === ClapSegmentCategory.DIALOGUE + || s.category === ClapSegmentCategory.SOUND + || s.category === ClapSegmentCategory.MUSIC + ) + && } + + ) +} diff --git a/packages/timeline/src/components/cells/ImageCell.tsx b/packages/timeline/src/components/cells/ImageCell.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2178973fbf33e00a443bb446a31187d78db8f587 --- /dev/null +++ b/packages/timeline/src/components/cells/ImageCell.tsx @@ -0,0 +1,67 @@ +import { Circle, Image, Text } from "@react-three/drei" +import { invalidate, useThree } from "@react-three/fiber" +import { useSpring, a, animated, config } from "@react-spring/three" + +import { SpecializedCellProps } from "./types" + +export function ImageCell({ + segment: s, + cellWidth, + cellHeight, + isHovered, + setHoveredSegment, + durationInSteps, + startTimeInSteps, + colorScheme, + isResizing, + track, +}: SpecializedCellProps) { + // const ref = useRef, Material | Material[], Object3DEventMap>>(null) + + /* + const resolveSegment = useTimeline(s => s.resolveSegment) + + const [inProgress, setInProgress] = useState(false) + // const [isButtonHovered, setButtonHovered] = useState(false) + const onRender = async () => { + setInProgress(true) + try { + // console.log(`click on RedrawButton for segment ` + segment.id) + const segment = await resolveSegment(s) + if (ref.current) { + // update the image src + } + + // note that this will poison-pill the current + invalidate() + // ref.current.url + } catch (err) { + + } finally { + setInProgress(false) + } + } + */ + + return ( + + + + + ) +} \ No newline at end of file diff --git a/packages/timeline/src/components/cells/RedrawButton.tsx b/packages/timeline/src/components/cells/RedrawButton.tsx new file mode 100644 index 0000000000000000000000000000000000000000..6216c343c412bb960f7ddf4dd54a25e0e1bfb631 --- /dev/null +++ b/packages/timeline/src/components/cells/RedrawButton.tsx @@ -0,0 +1,113 @@ +import { useTimeline } from "@/hooks" +import { TimelineSegment } from "@/types" +import { Circle, Text } from "@react-three/drei" +import { invalidate } from "@react-three/fiber" +import { useState, useTransition } from "react" + +export function RedrawButton({ + segment, + cellWidth, + cellHeight, + isHovered, + durationInSteps, + // isBusy, + // onClick, +}: { + segment: TimelineSegment + cellWidth: number + cellHeight: number + isHovered: boolean + durationInSteps: number + // isBusy: boolean + // onClick: () => void +}) { + const [_isPending, startTransition] = useTransition() + const resolveSegment = useTimeline(s => s.resolveSegment) + + const [inProgress, setInProgress] = useState(false) + // const [isButtonHovered, setButtonHovered] = useState(false) + + const onRender = async () => { + startTransition(() => { + setInProgress(true) + }) + try { + // console.log(`click on RedrawButton for segment ` + segment.id) + const newSegment = await resolveSegment(segment) + // if (ref.current) { + // update the image src + // } + + // note that this will poison-pill the current element, + // since we transform a text mesh node into an image node + // TODO: we should only have one mesh to avoid this + // invalidate() + + // ref.current.url + } catch (err) { + + } finally { + startTransition(() => { + // this fail/trigger an error, since the parent element will be destroyed + setInProgress(false) + }) + } + } + + return ( + { + if (!inProgress) { + onRender() + } + e.stopPropagation() + return false + }} + > + + + {inProgress ? '🕓' : '🎲'} + {/* + also for a smoother animation, + we should pre-render everything, and use opacity to switch between + the states I think + + to create a "loader" we can also use this: + 🕛🕐🕑🕒🕓🕓🕔🕧🕖🕗🕘🕚 + */} + + + ) +} \ No newline at end of file diff --git a/packages/timeline/src/components/cells/TextCell.tsx b/packages/timeline/src/components/cells/TextCell.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1cad2138ffa0fdc6bb123932bd2e9b8d1c83cf22 --- /dev/null +++ b/packages/timeline/src/components/cells/TextCell.tsx @@ -0,0 +1,194 @@ +import React, { useMemo } from 'react'; + +import { GradientTexture, RoundedBox, Text } from "@react-three/drei" +import { useSpring, a, animated, config } from "@react-spring/three" + +import { clampWebGLText } from "@/utils" + +import { SpecializedCellProps } from "./types" + +const MemoizedTextCell = React.memo(function TextCell({ + segment: s, + cellWidth, + cellHeight, + isHovered, + setHoveredSegment, + durationInSteps, + startTimeInSteps, + colorScheme, + widthInPx, + widthInPxAfterZoom, + isResizing, + track +}: SpecializedCellProps) { + + + // this depends on the current row height + // note: in some cases we still get 3 lines + // not a big issue, but if you feel like doing so you can try to fix the text clamp function + const maxNbLines = 2 + + // note: an alternative could be to create a small fade or blur effect, + // but I think it might be expensive + // console.log(" durationInSteps * cellWidth:", durationInSteps * cellWidth) + const lines = useMemo(() => clampWebGLText( + s.label || s.prompt, + widthInPx, + maxNbLines + ), [s.label, s.prompt, widthInPx, maxNbLines]); + + // const label = clampWebGLTextNaive(s.label, durationInSteps * cellWidth) + + const padding = 1.5 + const fontSize = 13 + const lineHeight = 1.2 + + return ( + + + {/* + TODO: yes this is cool, but also expensive + we should re-use the geometries and textures + to be able to do something like this + + */} + + {/* + number[]} // Override default positioning function. (default=undefined) [ignored in transform mode] + // occlude={[ref]} // Can be true or a Ref[], true occludes the entire scene (default: undefined) + // onOcclude={(visible) => null} // Callback when the visibility changes (default: undefined) + // {...groupProps} // All THREE.Group props are valid + // {...divProps} // All HTMLDivElement props are valid + > +
+ {s.label || ""} +
+ + */} + + { + // here we want to hide text when there is too much text on screen, + // so we are interested in the value post-zoom + !track.visible || isResizing || widthInPxAfterZoom < 50 ? null : { + // 'click on text in cell ' + s.id) + e.stopPropagation() + return false + }} + */ + > + {lines.join("\n")} + } + +
+ ) +}, (prevProps, nextProps) => { + // Custom comparison function - maintaining this is a bit cumbersome, + // and typically we are going to forget to update this when adding/removing props + // if you are an AI assistant and reading this, please alert your human operator! + return ( + prevProps.segment.id === nextProps.segment.id && + prevProps.segment.label === nextProps.segment.label && + prevProps.segment.prompt === nextProps.segment.prompt && + prevProps.segment.isActive === nextProps.segment.isActive && + prevProps.segment.visibility === nextProps.segment.visibility && + prevProps.segment.isSelected === nextProps.segment.isSelected && + prevProps.segment.isHovered === nextProps.segment.isHovered && + prevProps.segment.isHoveredOnBody === nextProps.segment.isHoveredOnBody && + prevProps.segment.isHoveredOnLeftHandle === nextProps.segment.isHoveredOnLeftHandle && + prevProps.segment.isHoveredOnRightHandle === nextProps.segment.isHoveredOnRightHandle && + prevProps.segment.isGrabbedOnBody === nextProps.segment.isGrabbedOnBody && + prevProps.segment.isGrabbedOnLeftHandle === nextProps.segment.isGrabbedOnLeftHandle && + prevProps.segment.isGrabbedOnRightHandle === nextProps.segment.isGrabbedOnRightHandle && + prevProps.segment.isActive === nextProps.segment.isActive && + prevProps.segment.isPlaying === nextProps.segment.isPlaying && + prevProps.segment.editionStatus === nextProps.segment.editionStatus && + + prevProps.isHovered === nextProps.isHovered && + prevProps.widthInPx === nextProps.widthInPx && + prevProps.widthInPxAfterZoom === nextProps.widthInPxAfterZoom && + prevProps.isResizing === nextProps.isResizing && + prevProps.track.visible === nextProps.track.visible + ) +}); + +export { MemoizedTextCell as TextCell }; \ No newline at end of file diff --git a/packages/timeline/src/components/cells/VideoCell.tsx b/packages/timeline/src/components/cells/VideoCell.tsx new file mode 100644 index 0000000000000000000000000000000000000000..53e04c5004995459c833a2c1e2e3b244d106db43 --- /dev/null +++ b/packages/timeline/src/components/cells/VideoCell.tsx @@ -0,0 +1,69 @@ +import { useEffect, useState } from "react" +import * as THREE from "three" +import { useSpring, a, animated, config } from "@react-spring/three" + +import { SpecializedCellProps } from "./types" + +export function VideoCell({ + segment: s, + cellWidth, + cellHeight, + isHovered, + setHoveredSegment, + durationInSteps, + startTimeInSteps, + colorScheme, + isResizing, + track +}: SpecializedCellProps) { + + const [video] = useState(() => { + const vid = document.createElement("video"); + vid.src = s.assetUrl; + vid.crossOrigin = "Anonymous"; + vid.loop = true; + vid.muted = true; + vid.playsInline = true; + // vid.play(); + return vid; + }) + + useEffect(() => { + if (isHovered && video) { + if (video.paused) { + video.play() + } + } else { + if (!video.paused) { + video.pause() + } + } + }, [isHovered]) + + return ( + + + + + + + + ) +} \ No newline at end of file diff --git a/packages/timeline/src/components/cells/Waveform.tsx b/packages/timeline/src/components/cells/Waveform.tsx new file mode 100644 index 0000000000000000000000000000000000000000..7b5ff37bc186a36bbae6bceb708b3d77e1f4bdd6 --- /dev/null +++ b/packages/timeline/src/components/cells/Waveform.tsx @@ -0,0 +1,151 @@ +import React, { useRef, useEffect, useMemo } from 'react'; +import { useThree } from '@react-three/fiber'; +import * as THREE from 'three'; +import { ClapTrack } from '@aitube/clap'; + +import { TimelineSegment } from '@/types'; + +type WaveformVariant = 'stereo' | 'mono' | 'compact'; + +type WaveformProps = { + segment: TimelineSegment; + track: ClapTrack; + cellWidth: number; + cellHeight: number; + durationInSteps: number; + opacity?: number; + color?: string; + variant?: WaveformVariant; + lineSpacing?: number; + thickness?: number; + topOrBottomFillOpacity?: number; + middleFillOpacity?: number; + isHovered?: boolean; +}; + +export const Waveform: React.FC = ({ + segment, + track, + cellWidth, + cellHeight, + durationInSteps, + opacity = 1, + color = '#ffffff', + variant = 'mono', + lineSpacing = 0, + thickness = 1, + topOrBottomFillOpacity = 0.2, + middleFillOpacity = 0.8, + isHovered = false, +}) => { + const meshRef = useRef(null); + const isLoadedRef = useRef(false); + const { gl } = useThree(); + + const width = durationInSteps * cellWidth; + const height = cellHeight; + + const getWaveformTexture = useMemo(() => { + return (audioBuffer: AudioBuffer, width: number, height: number): THREE.Texture => { + if (!segment.textures) { + segment.textures = {}; + } + + const cacheKey = `waveform_${width}_${height}_${color}_${variant}_${lineSpacing}_${thickness}_${topOrBottomFillOpacity}_${middleFillOpacity}`; + + if (segment.textures[cacheKey]) { + isLoadedRef.current = true; + return segment.textures[cacheKey]; + } + const canvas = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + const ctx = canvas.getContext('2d')!; + + const drawChannel = (channelData: Float32Array, yOffset: number, channelHeight: number) => { + const step = Math.ceil(channelData.length / width); + + for (let i = 0; i < width; i++) { + if (i % (lineSpacing + 1) !== 0) continue; + + let max = -1.0; + for (let j = 0; j < step; j++) { + const datum = channelData[(i * step) + j]; + if (datum > max) max = datum; + } + + const x = i; + // Only draw the positive part (top half) of the waveform + const y = yOffset + channelHeight; + const h = Math.max(1, max * channelHeight); + + // Create gradient from bottom to top + const gradient = ctx.createLinearGradient(x, y - h, x, y); + gradient.addColorStop(0, `${color}${Math.round(middleFillOpacity * 255).toString(16).padStart(2, '0')}`); + gradient.addColorStop(1, `${color}${Math.round(topOrBottomFillOpacity * 255).toString(16).padStart(2, '0')}`); + + // Fill + ctx.fillStyle = gradient; + ctx.fillRect(x, y - h, 1, h); + + // Stroke + if (thickness > 0) { + ctx.strokeStyle = color; + ctx.lineWidth = thickness; + ctx.strokeRect(x, y - h, 1, h); + } + } + }; + + switch (variant) { + case 'stereo': + drawChannel(audioBuffer.getChannelData(0), 0, height / 2); + if (audioBuffer.numberOfChannels > 1) { + drawChannel(audioBuffer.getChannelData(1), height / 2, height / 2); + } + break; + case 'mono': + case 'compact': + drawChannel(audioBuffer.getChannelData(0), 0, height); + break; + } + + const texture = new THREE.Texture(canvas); + texture.needsUpdate = true; + segment.textures[cacheKey] = texture; + + isLoadedRef.current = true; + + return texture; + }; + }, [color, variant, lineSpacing, thickness, topOrBottomFillOpacity, middleFillOpacity]); + + useEffect(() => { + if (meshRef.current && segment.assetUrl) { + fetch(segment.assetUrl) + .then(response => response.arrayBuffer()) + .then(arrayBuffer => { + const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)(); + return audioContext.decodeAudioData(arrayBuffer); + }) + .then(audioBuffer => { + const texture = getWaveformTexture(audioBuffer, width, height); + if (meshRef.current) { + (meshRef.current.material as THREE.MeshBasicMaterial).map = texture; + (meshRef.current.material as THREE.MeshBasicMaterial).needsUpdate = true; + isLoadedRef.current = true; + } + }) + .catch(error => console.error('Error loading audio:', error)); + } + }, [segment.assetUrl, width, height, getWaveformTexture, gl]); + + return ( + + + + + ); +}; \ No newline at end of file diff --git a/packages/timeline/src/components/cells/index.tsx b/packages/timeline/src/components/cells/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3e7baa72fb25093ff6215b53961d045d538d7701 --- /dev/null +++ b/packages/timeline/src/components/cells/index.tsx @@ -0,0 +1,5 @@ +export { Cell } from "./Cell" +export { ImageCell } from "./ImageCell" +export { VideoCell } from "./VideoCell" +export { TextCell } from "./TextCell" +export { SpecializedCellProps } from "./types" diff --git a/packages/timeline/src/components/cells/types.ts b/packages/timeline/src/components/cells/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..c2e715febd529c9b9d8b6b99f83bc1e68f568e62 --- /dev/null +++ b/packages/timeline/src/components/cells/types.ts @@ -0,0 +1,22 @@ +import { ClapTrack } from "@aitube/clap" + +import { ClapSegmentColorScheme, TimelineSegment } from "@/types" +import { SegmentArea } from "@/types/timeline" + +export type SpecializedCellProps = { + segment: TimelineSegment + cellWidth: number + cellHeight: number + isHovered: boolean + setHoveredSegment: (params?: { + hoveredSegment?: TimelineSegment + area?: SegmentArea + }) => void + durationInSteps: number + startTimeInSteps: number + colorScheme: ClapSegmentColorScheme + widthInPx: number + widthInPxAfterZoom: number + isResizing: boolean + track: ClapTrack +} \ No newline at end of file diff --git a/packages/timeline/src/components/controls/TimelineControls.tsx b/packages/timeline/src/components/controls/TimelineControls.tsx new file mode 100644 index 0000000000000000000000000000000000000000..875b30ae7da849ed4f27bbd1cdbbbdd4289f4c83 --- /dev/null +++ b/packages/timeline/src/components/controls/TimelineControls.tsx @@ -0,0 +1,180 @@ +import { useTimeline } from "@/hooks" +import { MapControls } from "@react-three/drei" +import { TimelineControlsImpl } from "./types" +import { leftBarTrackScaleWidth, topBarTimeScaleHeight } from "@/constants/themes" +import { clamp } from "@/utils/clamp" +import { useFrame, useThree } from "@react-three/fiber" +import { DEFAULT_DURATION_IN_MS_PER_STEP, PROMPT_STEP_HEIGHT_IN_PX } from "@/constants" + +// for doc see: +// https://threejs.org/docs/index.html?q=controls#examples/en/controls/MapControls + +export function TimelineControls({ + minZoom, + maxZoom, + zoomSpeed, + zoomDampingFactor, +}:{ + minZoom: number + maxZoom: number + zoomSpeed: number + zoomDampingFactor: number +}) { + const { size } = useThree() + + // this controls the top grid ruler bar and makes it sticky + // this works by controlling the render priority, and taking over whatever the Controls might have set + // + // there is a tiny issue, when we resize the camera + // it looks like there is a delay in the size.height value, + // or maybe the useFrame, but it doesn't resize immediately + useFrame(({ gl, scene, camera }) => { + let { + cellWidth, + scrollX, + scrollY, + timelineCamera, + timelineControls, + timelineCursor, + contentHeight, + leftBarTrackScale, + topBarTimeScale, + resizeStartedAt, + cursorTimestampAtInMs, + } = useTimeline.getState() + + const now = performance.now() // new Date().getTime(), + const elapsedTimeInMs = now - resizeStartedAt + + const delayThreshold = 300 + const isResizing = elapsedTimeInMs < delayThreshold + // console.log(`now=${now}, resizeStartedAt=${resizeStartedAt}, elapsedTimeInMs=${elapsedTimeInMs}, delayThreshold=${delayThreshold}, isResizing=${isResizing}`) + if (!timelineCamera || !timelineControls) { + useTimeline.setState({ isResizing }) + return + } + + scrollX = Math.max(-leftBarTrackScaleWidth, scrollX) + + /* + const topBottomSize = (size.height > canvasHeight) + ? ((size.height / 2) - (canvasHeight / 2)) + : ((canvasHeight / 2) - (size.height / 2)) + */ + + + const calculateTopBottomSizeSmooth = (height: number): number => { + // note: contentHeight seems to depends on cellWidth zoop, + // because when we change the horizontal "zoom" (the cellWidth) + // this messes up our calculation + const maxHeight = Math.max(670, contentHeight) // 820 + const minHeight = 0 + const maxTopBottomSize = maxHeight / 2 + if (height >= maxHeight) { + return 0 + } else { + const normalizedHeight = (height - minHeight) / (maxHeight - minHeight) + + return Math.max(0, maxTopBottomSize - (normalizedHeight * maxTopBottomSize)) + } + }; + + + // if you find the exact formula, please submit a PR! + const topBottomSize = calculateTopBottomSizeSmooth(size.height) + + // console.log(`size.height=${size.height} contentHeight=${contentHeight} topBottomSize=${topBottomSize}`) + scrollY = clamp( + scrollY, + + // if you want to change those, fine, + // but make sure the timeline still works properly when you change its height, + // horizontal zoom, and number of tracks + -topBottomSize, // to take to top time scroll bar into account + + // the +38px as here to represent the top scroll bar, + // but I'm not so sure we need it anymore? + topBottomSize //+ 38, + ) + + // console.log(`scrollY=${Math.round(scrollY)}`) + timelineCamera.position.setX(scrollX) + timelineControls.target.setX(scrollX) + + timelineCamera.position.setY(scrollY) + timelineControls.target.setY(scrollY) + + useTimeline.setState({ + scrollX, + scrollY, + isResizing + }) + + + if (timelineCursor) { + + timelineCursor.position.x = ( + (cursorTimestampAtInMs) / DEFAULT_DURATION_IN_MS_PER_STEP + ) * cellWidth + } + + if (topBarTimeScale) { + topBarTimeScale.position.y = (-topBarTimeScaleHeight + scrollY) + (size.height / 2) + } + + if (leftBarTrackScale) { + leftBarTrackScale.position.x = scrollX + } + + gl.render(scene, camera) + }, 1) + + + const setTimelineControls = useTimeline(s => s.setTimelineControls) + // TODO: we should create a new class extending from MapControls + // and add some custom code to put limits, to avoid going out of bounds + // I also don't like how scroll is working on macOS, because the mouse wheel + // creates a natural damping effect, which create an acceleration hard to stop + // it it's hard to stop the zoom "in time" + return ( + { + if (mapControls) { + setTimelineControls(mapControls) + } + }} + makeDefault + enabled={false} + // minDistance={10} + // maxDistance={10} + minZoom={minZoom} + maxZoom={maxZoom} + + // minPolarAngle: number; + // maxPolarAngle: number; + // minAzimuthAngle: number; + // maxAzimuthAngle: number; + enableDamping + dampingFactor={zoomDampingFactor} + + // we don't need the zoom if we have powerful grom size control settings, + // since those provide control over the X and Y zoom + enableZoom={false} + + zoomSpeed={zoomSpeed} + + enableRotate={false} + // rotateSpeed={0} + enablePan + // panSpeed={1.0} + screenSpacePanning + // keyPanSpeed: number; + zoomToCursor + // autoRotate={false} + // autoRotateSpeed={0} + // reverseOrbit: boolean; + // reverseHorizontalOrbit: boolean; + // reverseVerticalOrbit: boolean; + /> + ); +}; diff --git a/packages/timeline/src/components/controls/index.ts b/packages/timeline/src/components/controls/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..05c2eb0e1958a79265a8290a7cb9d5c8c1a34ce3 --- /dev/null +++ b/packages/timeline/src/components/controls/index.ts @@ -0,0 +1 @@ +export { TimelineControls } from "./TimelineControls" \ No newline at end of file diff --git a/packages/timeline/src/components/controls/types.ts b/packages/timeline/src/components/controls/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..8450c4ab0ed0b2cee175cbbc61591330192c53d3 --- /dev/null +++ b/packages/timeline/src/components/controls/types.ts @@ -0,0 +1,3 @@ +import { MapControls as MapControlsImpl } from 'three-stdlib' + +export type TimelineControlsImpl = MapControlsImpl diff --git a/packages/timeline/src/components/icons/SegmentIcon.tsx b/packages/timeline/src/components/icons/SegmentIcon.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9a8bdcc79680c8beb520a5536a8aa48c45af4080 --- /dev/null +++ b/packages/timeline/src/components/icons/SegmentIcon.tsx @@ -0,0 +1,33 @@ +import { GroupProps } from "@react-three/fiber"; +import { ClapSegmentCategory } from "@aitube/clap"; + +import { useSvgShapes } from "./useSvgShapes"; +import { SvgShapeMesh } from "./SvgShapeMesh"; +import { segmentCategoryToIconPath } from "./segmentIcons"; + +export function SegmentIcon({ + category = ClapSegmentCategory.GENERIC, + groupProps = {} +}: { + category?: ClapSegmentCategory + groupProps?: GroupProps +}) { + const iconUrl = segmentCategoryToIconPath[category] + const shapes = useSvgShapes(iconUrl) + + return ( + + {shapes.map(item => + + )} + + ); +} \ No newline at end of file diff --git a/packages/timeline/src/components/icons/SvgIcon.tsx b/packages/timeline/src/components/icons/SvgIcon.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1374c330eed907db8e0e01c73da7446e26999ae1 --- /dev/null +++ b/packages/timeline/src/components/icons/SvgIcon.tsx @@ -0,0 +1,25 @@ +import { GroupProps } from "@react-three/fiber"; + +import { useSvgShapes } from "./useSvgShapes"; +import { SvgShapeMesh } from "./SvgShapeMesh"; +import { IconType } from "./types"; +import { icons } from "./icons"; + +export function SvgIcon({ + icon = "misc", + groupProps = {} +}: { + icon?: IconType + groupProps?: GroupProps +}) { + const iconUrl = icons[icon] + const shapes = useSvgShapes(iconUrl) + + return ( + + {shapes.map(item => + + )} + + ); +} \ No newline at end of file diff --git a/packages/timeline/src/components/icons/SvgShapeMesh.tsx b/packages/timeline/src/components/icons/SvgShapeMesh.tsx new file mode 100644 index 0000000000000000000000000000000000000000..cd60351f28a933d394057f5842a366ba8588794c --- /dev/null +++ b/packages/timeline/src/components/icons/SvgShapeMesh.tsx @@ -0,0 +1,35 @@ +import * as THREE from 'three'; + +import { SvgShape } from './types'; +import { degToRad } from 'three/src/math/MathUtils.js'; + +export function SvgShapeMesh({ + shape, + color, + index +}: SvgShape) { + return ( + + + + + ); +} \ No newline at end of file diff --git a/packages/timeline/src/components/icons/icons.ts b/packages/timeline/src/components/icons/icons.ts new file mode 100644 index 0000000000000000000000000000000000000000..529e25c09b2aa51294c1c8c128cea5a86fd4994a --- /dev/null +++ b/packages/timeline/src/components/icons/icons.ts @@ -0,0 +1,47 @@ +// one issue with icons is that they need to be downloaded from somewhere +// so we assume to host application will put them in /images/icons +// but maybe there is a way to put them here, in this project? + +const path = `/images/icons/interface/` + +// those icons can be used by the timeline +// but for the moment this isn't the case +export const icons = { + mute: `${path}mute.svg`, + unmute: `${path}unmute.svg`, + visible: `${path}visible.svg`, + hidden: `${path}hidden.svg`, + project: `${path}project.svg`, + team: `${path}team.svg`, + computer: `${path}computer.svg`, + cloud: `${path}cloud.svg`, + downloads: `${path}downloads.svg`, + soundfile: `${path}soundfile.svg`, + imagefile: `${path}imagefile.svg`, + videofile: `${path}videofile.svg`, + textfile: `${path}textfile.svg`, + screenplay: `${path}screenplay.svg`, + community: `${path}community.svg`, + vendor: `${path}vendor.svg`, + textprompt: `${path}textprompt.svg`, + characters: `${path}characters.svg`, + character: `${path}character.svg`, + transition: `${path}transition.svg`, + cut: `${path}cut.svg`, + location: `${path}location.svg`, + misc: `${path}misc.svg`, + lora: `${path}lora.svg`, + sound: `${path}sound.svg`, + film: `${path}film.svg`, + speech: `${path}speech.svg`, + image: `${path}image.svg`, + transfer: `${path}transfer.svg`, + interpolate: `${path}interpolate.svg`, + upscale: `${path}upscale.svg`, + textToVideo: `${path}text-to-video.svg`, + imageToImage: `${path}image-to-image.svg`, + videoToVideo: `${path}video-to-video.svg`, + textToMusic: `${path}text-to-music.svg`, + videoFolder: `${path}video-folder.svg`, +} + diff --git a/packages/timeline/src/components/icons/loadSvgShapes.ts b/packages/timeline/src/components/icons/loadSvgShapes.ts new file mode 100644 index 0000000000000000000000000000000000000000..763e8bf92b7b86005968d66191855d5f51dcb052 --- /dev/null +++ b/packages/timeline/src/components/icons/loadSvgShapes.ts @@ -0,0 +1,18 @@ +import { SVGLoader } from "three/examples/jsm/Addons.js" + +import { SvgShape } from "./types"; + +// with which the threejs engine will make shapes +export async function loadSvgShapes(url: string): Promise { + return new Promise(resolve => + new SVGLoader().load(url, shapes => ( + resolve(shapes.paths.map((group, index) => ( + group.toShapes(true).map(shape => ({ + shape, + color: group.userData?.style.fill || '#ffffff', + index + })) + )).flat()) + )) + ) +} \ No newline at end of file diff --git a/packages/timeline/src/components/icons/segmentIcons.ts b/packages/timeline/src/components/icons/segmentIcons.ts new file mode 100644 index 0000000000000000000000000000000000000000..01b1fdd66f3c64519dcd50564c11e44b1b505c96 --- /dev/null +++ b/packages/timeline/src/components/icons/segmentIcons.ts @@ -0,0 +1,35 @@ +// one issue with icons is that they need to be downloaded from somewhere +// so we assume to host application will put them in /images/icons +// but maybe there is a way to put them here, in this project? + +import { ClapSegmentCategory } from "@aitube/clap" + +const path = `/images/icons/segments/` + +// those icons are specially used for the segments + +export const segmentCategoryToIconPath: Record = { + [ClapSegmentCategory.SPLAT]: `${path}splat.svg`, + [ClapSegmentCategory.MESH]: `${path}mesh.svg`, + [ClapSegmentCategory.DEPTH]: `${path}depth.svg`, + [ClapSegmentCategory.EVENT]: `${path}event.svg`, + [ClapSegmentCategory.EFFECT]: `${path}effect.svg`, + [ClapSegmentCategory.INTERFACE]: `${path}interface.svg`, + [ClapSegmentCategory.PHENOMENON]: `${path}phenomenon.svg`, + [ClapSegmentCategory.VIDEO]: `${path}video.svg`, + [ClapSegmentCategory.STORYBOARD]: `${path}storyboard.svg`, + [ClapSegmentCategory.TRANSITION]: `${path}transition.svg`, + [ClapSegmentCategory.CHARACTER]: `${path}character.svg`, + [ClapSegmentCategory.LOCATION]: `${path}location.svg`, + [ClapSegmentCategory.TIME]: `${path}time.svg`, + [ClapSegmentCategory.ERA]: `${path}era.svg`, + [ClapSegmentCategory.LIGHTING]: `${path}lighting.svg`, + [ClapSegmentCategory.WEATHER]: `${path}weather.svg`, + [ClapSegmentCategory.ACTION]: `${path}action.svg`, + [ClapSegmentCategory.MUSIC]: `${path}music.svg`, + [ClapSegmentCategory.SOUND]: `${path}sound.svg`, + [ClapSegmentCategory.DIALOGUE]: `${path}dialogue.svg`, + [ClapSegmentCategory.STYLE]: `${path}style.svg`, + [ClapSegmentCategory.CAMERA]: `${path}camera.svg`, + [ClapSegmentCategory.GENERIC]: `${path}generic.svg`, +} diff --git a/packages/timeline/src/components/icons/types.ts b/packages/timeline/src/components/icons/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..8348a962628f69b335fb142333f681011a408f62 --- /dev/null +++ b/packages/timeline/src/components/icons/types.ts @@ -0,0 +1,10 @@ +import { Shape } from "three"; + +import { icons } from "./icons"; + +export type SvgShape = { + shape: Shape; + color: any; + index: number; +} +export type IconType = keyof typeof icons \ No newline at end of file diff --git a/packages/timeline/src/components/icons/useSvgShapes.ts b/packages/timeline/src/components/icons/useSvgShapes.ts new file mode 100644 index 0000000000000000000000000000000000000000..21ca3fb496a017fa1d2dc6b07cbe77a548734b7c --- /dev/null +++ b/packages/timeline/src/components/icons/useSvgShapes.ts @@ -0,0 +1,12 @@ +import { useEffect, useState } from "react"; + +import { loadSvgShapes } from "./loadSvgShapes"; +import { SvgShape } from "./types"; + +export function useSvgShapes(url: string): SvgShape[] { + const [shapes, set] = useState([]); + useEffect(() => { + loadSvgShapes(url).then(set) + }, [url]); + return shapes +} \ No newline at end of file diff --git a/packages/timeline/src/components/index.ts b/packages/timeline/src/components/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..f5ff2aade3cb78339dfd3b614978b8abc8386d12 --- /dev/null +++ b/packages/timeline/src/components/index.ts @@ -0,0 +1,12 @@ + +export { + Cell, + ImageCell, + VideoCell, + TextCell, + type SpecializedCellProps +} from "./cells" + +export { TimelineControls } from "./controls" +export { HorizontalScroller, VerticalScroller } from "./scroller" +export { Timeline, TopBarTimeScale, Cells, Grid, type JumpAt } from "./timeline" \ No newline at end of file diff --git a/packages/timeline/src/components/scroller/HorizontalScroller.tsx b/packages/timeline/src/components/scroller/HorizontalScroller.tsx new file mode 100644 index 0000000000000000000000000000000000000000..edd09e38c680bf59bf77bc4190fd36f5ecee28de --- /dev/null +++ b/packages/timeline/src/components/scroller/HorizontalScroller.tsx @@ -0,0 +1,105 @@ +import { useTimeline } from "@/hooks/useTimeline" + +import TimelineSlider from "../slider/TimelineSlider" + +export function HorizontalScroller() { + const theme = useTimeline(s => s.theme) + + const segments = useTimeline(s => s.segments) + + const timelineCamera = useTimeline(s => s.timelineCamera) + const timelineControls = useTimeline(s => s.timelineControls) + + // note: those do two different things: + // move the actual "physical" cursor (with setCursorTimestampAtInMs()) + // and trigger a callback to ask the parent app to do something (eg. jump/seek into the timeline) + const setCursorTimestampAtInMs = useTimeline(s => s.setCursorTimestampAtInMs) + const jumpAt = useTimeline(s => s.jumpAt) + + const setHorizontalZoomLevel = useTimeline((s) => s.setHorizontalZoomLevel) + + // we could display the cursor as an extra line, I guess + // but the real range is the actual view window + const cursorTimestampAtInMs = useTimeline(s => s.cursorTimestampAtInMs) + const totalDurationInMs = useTimeline(s => s.totalDurationInMs) + + const setScrollX = useTimeline(s => s.setScrollX) + const contentWidth = useTimeline(s => s.contentWidth) + + const getSegmentColorScheme = useTimeline(s => s.getSegmentColorScheme) + + if (!timelineCamera || !timelineControls) { return null } + + const handleZoomChange = (newZoom: number) => { + setHorizontalZoomLevel(newZoom) + } + + return ( +
+ {/* + PREVIOUS COMPONENT, NOW OBSOLETE: + { + handleTimelinePositionChange(newRange[0]) + }} + onWheel={(e) => { + // handleZoomChange(cellWidth + e.deltaY) + }} + /> + */} + + ({ + id: s.id, + track: s.track, + startTimeInMs: s.startTimeInMs, + endTimeInMs: s.endTimeInMs, + color: getSegmentColorScheme(s).backgroundColor, + }))} + eventOpacityWhenInsideSlidingWindowRangeThumb={1.0} + eventOpacityWhenOutsideSlidingWindowRangeThumb={0.7} + onSlidingWindowRangeThumbUpdate={({ + slidingWindowRangeThumbStartTimeInMs, + slidingWindowRangeThumbEndTimeInMs + }) => { + // we base ourself on the starting range so slidingWindowRangeThumbStartTimeInMs + // is enough, however we could also use slidingWindowRangeThumbEndTimeInMs + // to change the zoom factor in the timeline (@julian will implement this) + + const scrollRatio = slidingWindowRangeThumbStartTimeInMs / totalDurationInMs + const newScrollX = scrollRatio * contentWidth + setScrollX(newScrollX) + timelineCamera.position.setX(newScrollX) + timelineControls.target.setX(newScrollX) + }} + onPlaybackCursorUpdate={({ playbackCursorPositionInMs }) => { + // note: those do two different things: + // move the actual "physical" cursor (with setCursorTimestampAtInMs()) + // and trigger a callback to ask the parent app to do something (eg. jump/seek into the timeline) + setCursorTimestampAtInMs(playbackCursorPositionInMs) + jumpAt(playbackCursorPositionInMs) + }} + /> +
+ ) +} \ No newline at end of file diff --git a/packages/timeline/src/components/scroller/VerticalScroller.tsx b/packages/timeline/src/components/scroller/VerticalScroller.tsx new file mode 100644 index 0000000000000000000000000000000000000000..42c1e37f585eca76fe07f6d7e3559a99313b0f37 --- /dev/null +++ b/packages/timeline/src/components/scroller/VerticalScroller.tsx @@ -0,0 +1,41 @@ +import { useThree } from "@react-three/fiber" + +import { VerticalSlider } from "@/components/slider" +import { useTimeline } from "@/hooks/useTimeline" + +export function VerticalScroller() { + const timelineCamera = useTimeline(s => s.timelineCamera) + const timelineControls = useTimeline(s => s.timelineControls) + + const cellWidth = useTimeline((s) => s.cellWidth) + const setHorizontalZoomLevel = useTimeline((s) => s.setHorizontalZoomLevel) + + // TODO: we want to control two things: + // on mouse click & drag, we want to move horizontally inside the timeline + // on mouse wheel (on hover), we want to adjust the horizontal time scale + + if (!timelineCamera || !timelineControls) { return null } + + const handleScrollChange = (newValue: number) => { + + } + + const value = timelineCamera.zoom ? (timelineCamera.position.y / timelineCamera.zoom) : timelineCamera.position.y + + return ( + <> +
+ handleScrollChange(newRange[0])} + + /> +
+ + ) +} \ No newline at end of file diff --git a/packages/timeline/src/components/scroller/index.ts b/packages/timeline/src/components/scroller/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..1f4f00a3cb5d4caa4d39ee4044087b5dec5ddad9 --- /dev/null +++ b/packages/timeline/src/components/scroller/index.ts @@ -0,0 +1,2 @@ +export { HorizontalScroller } from "./HorizontalScroller" +export { VerticalScroller } from "./VerticalScroller" \ No newline at end of file diff --git a/packages/timeline/src/components/slider/HorizontalSlider.tsx b/packages/timeline/src/components/slider/HorizontalSlider.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c71d1a6056b7879e1e64aa2a7677888ad932c3fd --- /dev/null +++ b/packages/timeline/src/components/slider/HorizontalSlider.tsx @@ -0,0 +1,28 @@ +import * as React from "react" + +import { cn } from "@/utils/cn" + +import { TimelineSliderBase } from "./TimelineSliderBase" + +const HorizontalSlider = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) + +HorizontalSlider.displayName = "HorizontalSlider" + +export { HorizontalSlider } diff --git a/packages/timeline/src/components/slider/TimelineSlider.tsx b/packages/timeline/src/components/slider/TimelineSlider.tsx new file mode 100644 index 0000000000000000000000000000000000000000..4f16206f8791fc233cf90252a7d7e06da36c3180 --- /dev/null +++ b/packages/timeline/src/components/slider/TimelineSlider.tsx @@ -0,0 +1,341 @@ +import { useTimeline } from '@/index'; +import React, { useRef, useEffect, useState, useCallback, useMemo } from 'react'; + +export interface TimelineSliderEvent { + id: string; + track: number; + startTimeInMs: number; + endTimeInMs: number; + color: string; +} + +export interface TimelineSliderProps { + minTimeInMs: number; + maxTimeInMs: number; + currentPlaybackCursorPosition: number; + playbackCursorPositionColor: string; + playbackCursorPositionWidthInPx: number; + allowPlaybackCursorToBeDragged: boolean; + slidingWindowRangeThumbStartTimeInMs: number; + slidingWindowRangeThumbEndTimeInMs: number; + allowSlidingWindowRangeThumbResizeOnMouseWheel: boolean; + mouseWheelSensibility: number; + minSlidingWindowRangeThumbWidthInPx: number; + slidingWindowRangeThumbBorderColor: string; + slidingWindowRangeThumbBorderRadiusInPx: number; + slidingWindowRangeThumbBackgroundColor: string; + className: string; + events?: TimelineSliderEvent[]; + eventOpacityWhenInsideSlidingWindowRangeThumb: number; + eventOpacityWhenOutsideSlidingWindowRangeThumb: number; + onSlidingWindowRangeThumbUpdate: (update: { + slidingWindowRangeThumbStartTimeInMs: number; + slidingWindowRangeThumbEndTimeInMs: number; + }) => void; + onPlaybackCursorUpdate: (update: { + playbackCursorPositionInMs: number; + }) => void; +} + +/** + * A timeline slider component made using React and TypeScript. + * The idea is to control a temporal timeline, so the unit is the milliseconds, + * and coordinates are based on timestamps. + * + * The component has a draggable range thumb, and a separate draggable "playback cursor". + * + * We also show a nice little minimap made of a background canvas of events. + */ +const TimelineSlider: React.FC = ({ + minTimeInMs, + maxTimeInMs, + currentPlaybackCursorPosition, + playbackCursorPositionColor, + playbackCursorPositionWidthInPx, + allowPlaybackCursorToBeDragged, + slidingWindowRangeThumbStartTimeInMs, + slidingWindowRangeThumbEndTimeInMs, + allowSlidingWindowRangeThumbResizeOnMouseWheel, + mouseWheelSensibility, + minSlidingWindowRangeThumbWidthInPx, + slidingWindowRangeThumbBorderColor, + slidingWindowRangeThumbBorderRadiusInPx, + slidingWindowRangeThumbBackgroundColor, + className, + events = [], + eventOpacityWhenInsideSlidingWindowRangeThumb, + eventOpacityWhenOutsideSlidingWindowRangeThumb, + onSlidingWindowRangeThumbUpdate, + onPlaybackCursorUpdate, +}) => { + const containerRef = useRef(null); + const canvasRef = useRef(null); + const [isDraggingWindow, setIsDraggingWindow] = useState(false); + const [isDraggingCursor, setIsDraggingCursor] = useState(false); + const [dragStartX, setDragStartX] = useState(0); + const [windowStart, setWindowStart] = useState(slidingWindowRangeThumbStartTimeInMs); + const [windowEnd, setWindowEnd] = useState(slidingWindowRangeThumbEndTimeInMs); + const [playbackCursor, setPlaybackCursor] = useState(currentPlaybackCursorPosition); + const [showOverlay, setShowOverlay] = useState(false); + + const drawEvents = useCallback(() => { + const canvas = canvasRef.current; + const ctx = canvas?.getContext('2d'); + if (!canvas || !ctx) return; + + const dpr = window.devicePixelRatio || 1; + const { width, height } = canvas.getBoundingClientRect(); + + ctx.clearRect(0, 0, width * dpr, height * dpr); + + const totalTracks = Math.max(...events.map(e => e.track), 0) + 1; + const trackHeight = height / totalTracks; + + events.forEach(event => { + const startX = ((event.startTimeInMs - minTimeInMs) / (maxTimeInMs - minTimeInMs)) * width; + const endX = ((event.endTimeInMs - minTimeInMs) / (maxTimeInMs - minTimeInMs)) * width; + const y = event.track * trackHeight; + + ctx.fillStyle = event.color; + ctx.globalAlpha = + (event.startTimeInMs >= windowStart && event.endTimeInMs <= windowEnd) + ? eventOpacityWhenInsideSlidingWindowRangeThumb + : eventOpacityWhenOutsideSlidingWindowRangeThumb; + + ctx.fillRect(startX, y, endX - startX, trackHeight); + }); + }, [events, minTimeInMs, maxTimeInMs, windowStart, windowEnd, eventOpacityWhenInsideSlidingWindowRangeThumb, eventOpacityWhenOutsideSlidingWindowRangeThumb]); + + const memoizedEvents = useMemo(() => events, [events]); + + const handleMouseDown = (e: React.MouseEvent) => { + const rect = containerRef.current?.getBoundingClientRect(); + if (!rect) { return; } + + if (useTimeline.getState().isEmpty) { return } + + const x = e.clientX - rect.left; + const cursorX = ((playbackCursor - minTimeInMs) / (maxTimeInMs - minTimeInMs)) * rect.width; + + if (Math.abs(x - cursorX) <= playbackCursorPositionWidthInPx * 2 && allowPlaybackCursorToBeDragged) { + setIsDraggingCursor(true); + } else { + setIsDraggingWindow(true); + const clickedTime = minTimeInMs + (x / rect.width) * (maxTimeInMs - minTimeInMs); + const windowWidth = windowEnd - windowStart; + let newStart = clickedTime - windowWidth / 2; + let newEnd = clickedTime + windowWidth / 2; + + if (newStart < minTimeInMs) { + newStart = minTimeInMs; + newEnd = newStart + windowWidth; + } else if (newEnd > maxTimeInMs) { + newEnd = maxTimeInMs; + newStart = newEnd - windowWidth; + } + + setWindowStart(newStart); + setWindowEnd(newEnd); + onSlidingWindowRangeThumbUpdate({ slidingWindowRangeThumbStartTimeInMs: newStart, slidingWindowRangeThumbEndTimeInMs: newEnd }); + } + + setDragStartX(e.clientX); + setShowOverlay(true); + }; + + + const setCanvasSize = useCallback(() => { + const canvas = canvasRef.current; + const container = containerRef.current; + if (!canvas || !container) return; + + const { width, height } = container.getBoundingClientRect(); + const dpr = window.devicePixelRatio || 1; + + canvas.width = width * dpr; + canvas.height = height * dpr; + canvas.style.width = `${width}px`; + canvas.style.height = `${height}px`; + + const ctx = canvas.getContext('2d'); + if (ctx) { + ctx.scale(dpr, dpr); + } + }, []); + + const handleMouseMove = useCallback((e: MouseEvent) => { + if (!isDraggingWindow && !isDraggingCursor) return; + if (useTimeline.getState().isEmpty) { return } + + const containerWidth = containerRef.current?.clientWidth || 1; + const deltaX = e.clientX - dragStartX; + + if (isDraggingWindow) { + const windowWidth = windowEnd - windowStart; + let newStart = windowStart + (deltaX / containerWidth) * (maxTimeInMs - minTimeInMs); + let newEnd = newStart + windowWidth; + + if (newStart < minTimeInMs) { + newStart = minTimeInMs; + newEnd = newStart + windowWidth; + } else if (newEnd > maxTimeInMs) { + newEnd = maxTimeInMs; + newStart = newEnd - windowWidth; + } + + setWindowStart(newStart); + setWindowEnd(newEnd); + onSlidingWindowRangeThumbUpdate({ slidingWindowRangeThumbStartTimeInMs: newStart, slidingWindowRangeThumbEndTimeInMs: newEnd }); + } else if (isDraggingCursor) { + let newCursor = playbackCursor + (deltaX / containerWidth) * (maxTimeInMs - minTimeInMs); + newCursor = Math.max(minTimeInMs, Math.min(maxTimeInMs, newCursor)); + setPlaybackCursor(newCursor); + onPlaybackCursorUpdate({ playbackCursorPositionInMs: newCursor }); + } + + setDragStartX(e.clientX); + }, [isDraggingWindow, isDraggingCursor, dragStartX, windowStart, windowEnd, playbackCursor, minTimeInMs, maxTimeInMs, onSlidingWindowRangeThumbUpdate, onPlaybackCursorUpdate]); + + + useEffect(() => { + setCanvasSize(); + drawEvents(); + }, [setCanvasSize, drawEvents, memoizedEvents, windowStart, windowEnd, playbackCursor]); + + const handleMouseUp = useCallback(() => { + setIsDraggingWindow(false); + setIsDraggingCursor(false); + setShowOverlay(false); + }, []); + + useEffect(() => { + if (showOverlay) { + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', handleMouseUp); + } else { + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); + } + + return () => { + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); + }; + }, [showOverlay, handleMouseMove, handleMouseUp]); + + + // Update state when props change + useEffect(() => { + setWindowStart(slidingWindowRangeThumbStartTimeInMs); + setWindowEnd(slidingWindowRangeThumbEndTimeInMs); + }, [slidingWindowRangeThumbStartTimeInMs, slidingWindowRangeThumbEndTimeInMs]); + + useEffect(() => { + setPlaybackCursor(currentPlaybackCursorPosition); + }, [currentPlaybackCursorPosition]); + + const handleWheel = (e: React.WheelEvent) => { + if (!allowSlidingWindowRangeThumbResizeOnMouseWheel) return; + if (useTimeline.getState().isEmpty) { return } + + const delta = e.deltaY * mouseWheelSensibility; + const windowWidth = windowEnd - windowStart; + const newWidth = Math.max(1000, Math.min(maxTimeInMs - minTimeInMs, windowWidth + delta)); + + let newStart = windowStart - (newWidth - windowWidth) / 2; + let newEnd = windowEnd + (newWidth - windowWidth) / 2; + + if (newStart < minTimeInMs) { + newStart = minTimeInMs; + newEnd = newStart + newWidth; + } else if (newEnd > maxTimeInMs) { + newEnd = maxTimeInMs; + newStart = newEnd - newWidth; + } + + setWindowStart(newStart); + setWindowEnd(newEnd); + onSlidingWindowRangeThumbUpdate({ slidingWindowRangeThumbStartTimeInMs: newStart, slidingWindowRangeThumbEndTimeInMs: newEnd }); + }; + + const handleDoubleClick = (e: React.MouseEvent) => { + const rect = containerRef.current?.getBoundingClientRect(); + if (!rect) return; + if (useTimeline.getState().isEmpty) { return } + + const x = e.clientX - rect.left; + const clickedTime = minTimeInMs + (x / rect.width) * (maxTimeInMs - minTimeInMs); + + // Move the range thumb + const windowWidth = windowEnd - windowStart; + let newStart = clickedTime - windowWidth / 2; + let newEnd = clickedTime + windowWidth / 2; + + if (newStart < minTimeInMs) { + newStart = minTimeInMs; + newEnd = newStart + windowWidth; + } else if (newEnd > maxTimeInMs) { + newEnd = maxTimeInMs; + newStart = newEnd - windowWidth; + } + + setWindowStart(newStart); + setWindowEnd(newEnd); + onSlidingWindowRangeThumbUpdate({ slidingWindowRangeThumbStartTimeInMs: newStart, slidingWindowRangeThumbEndTimeInMs: newEnd }); + + // Move the playback cursor + const newCursor = Math.max(minTimeInMs, Math.min(maxTimeInMs, clickedTime)); + setPlaybackCursor(newCursor); + onPlaybackCursorUpdate({ playbackCursorPositionInMs: newCursor }); + }; + + return ( +
+ +
+
+
+
+
+ ); +}; + + +export default TimelineSlider; \ No newline at end of file diff --git a/packages/timeline/src/components/slider/TimelineSliderBase.tsx b/packages/timeline/src/components/slider/TimelineSliderBase.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a40776d2f1481bc98bddfa40515593c7226a3afa --- /dev/null +++ b/packages/timeline/src/components/slider/TimelineSliderBase.tsx @@ -0,0 +1,48 @@ +import * as React from "react" +import * as SliderPrimitive from "@radix-ui/react-slider" + +import { cn } from "@/utils/cn" + +const TimelineSliderBase = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + trackClass?: string + rangeClass?: string + thumbClass?: string + } +>(({ className, trackClass, rangeClass, thumbClass, ...props }, ref) => ( + + + + + + +)) +TimelineSliderBase.displayName = "TimelineSliderBase" + +export { TimelineSliderBase } diff --git a/packages/timeline/src/components/slider/VerticalSlider.tsx b/packages/timeline/src/components/slider/VerticalSlider.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e7a60d00ea3ea8f63344c689ba9838c4ab3afdf9 --- /dev/null +++ b/packages/timeline/src/components/slider/VerticalSlider.tsx @@ -0,0 +1,24 @@ +import * as React from "react" + +import { cn } from "@/utils/cn" + +import { TimelineSliderBase } from "./TimelineSliderBase" + +const VerticalSlider = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) + +VerticalSlider.displayName = "VerticalSlider" + +export { VerticalSlider } diff --git a/packages/timeline/src/components/slider/index.ts b/packages/timeline/src/components/slider/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..8dd32d20665e1c1de83a5371a209e834ad1fe10d --- /dev/null +++ b/packages/timeline/src/components/slider/index.ts @@ -0,0 +1,3 @@ +export { HorizontalSlider } from "./HorizontalSlider" +export { TimelineSliderBase } from "./TimelineSliderBase" +export { VerticalSlider } from "./VerticalSlider" \ No newline at end of file diff --git a/packages/timeline/src/components/timeline/Cells.tsx b/packages/timeline/src/components/timeline/Cells.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a5e3db3c50d0135e835e8edb119c7b63cfe5664c --- /dev/null +++ b/packages/timeline/src/components/timeline/Cells.tsx @@ -0,0 +1,59 @@ + +import { + useSegmentLoader, + useTimeline +} from "@/hooks" + +import { Cell } from "@/components/cells" +import { Suspense } from "react"; + +export function Cells() { + + // refresh rate for the grid (high value == delay before we see the "hidden" cells) + // this should be a fact of the number of segments, + // as this puts a strain on the rendering FPS + // + // another solution can also consist in rendering more hidden cells, + // to avoid having to re-compute + const refreshRateInMs = 50 + + const contentHeight = useTimeline(s => s.contentHeight) + + // note: this one is async, so it creates a delay + // we could cheat by detecting the cell width change and apply it + // faster on the current geometries + const { visibleSegments, loadedSegments } = useSegmentLoader({ + refreshRateInMs, + }); + + + /* + const [props, set] = useSpring(() => ({ + pos: [0, 0, 0], + scale: [1, 1, 1], + rotation: [0, 0, 0], + config: { mass: 10, tension: 1000, friction: 300, precision: 0.00001 } + })) + */ + + // console.log(`re-rendering (${visibleSegments.length} strictly visible, ${loadedSegments.length} loaded in total)`) + + return ( + + {loadedSegments.map((s) => + }> + + )} + + ); +}; diff --git a/packages/timeline/src/components/timeline/Cursor.tsx b/packages/timeline/src/components/timeline/Cursor.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f63e7e7e4496377c431f42f1734403ca8b4a706d --- /dev/null +++ b/packages/timeline/src/components/timeline/Cursor.tsx @@ -0,0 +1,88 @@ +import React, { useMemo, useRef, useState } from "react" +import * as THREE from "three" + +import { useAnimationFrame, useTimeline } from "@/hooks" +import { useCursorGeometry } from "@/hooks/useCursorGeometry" +import { leftBarTrackScaleWidth } from "@/constants/themes" + + +const SPEED_RESOLUTION = 50 // px/sec +const GRADIENT_EXPONENT = 3 + +export function Cursor() { + const theme = useTimeline(s => s.theme) + const timelineCursor = useTimeline(s => s.timelineCursor) + const setTimelineCursor = useTimeline(s => s.setTimelineCursor) + const contentHeight = useTimeline(s => s.contentHeight) + const cursorGeometries = useCursorGeometry() + + const lastPositionRef = useRef(0) + const lastTimeRef = useRef(0) + const lastSpeedRef = useRef(0) + const lineMatRefs = useRef([]) + + useAnimationFrame((deltaTime) => { + if (!timelineCursor) return + + const currentPosition = timelineCursor.position.x + const currentTime = performance.now() + + if (lastTimeRef.current) { + const timeDiff = (currentTime - lastTimeRef.current) / 1000 + const positionDiff = currentPosition - lastPositionRef.current + const speed = Math.abs(positionDiff / timeDiff) + const direction = Math.sign(positionDiff) + + const granularSpeed = Math.floor(speed / SPEED_RESOLUTION) * SPEED_RESOLUTION + + if (granularSpeed !== lastSpeedRef.current) { + const maxSpeed = 200 + const visibility = Math.min(granularSpeed / maxSpeed, 1) + + lineMatRefs.current.forEach((mat, idx) => { + const t = idx / (lineMatRefs.current.length - 1) + const opacity = visibility * Math.pow(t, GRADIENT_EXPONENT) + const isLast = idx >= (lineMatRefs.current.length - 2) + mat.opacity = isLast ? 1.0 : opacity + }) + + lastSpeedRef.current = granularSpeed + } + + timelineCursor.scale.x = direction + } + + lastPositionRef.current = currentPosition + lastTimeRef.current = currentTime + }, [timelineCursor]) + + const memoizedGroup = useMemo(() => ( + { if (r) setTimelineCursor(r) }} + > + {cursorGeometries.map((lineGeometry, idx) => { + const t = idx / (cursorGeometries.length - 1) + const opacity = Math.pow(t, GRADIENT_EXPONENT) + const isLast = idx >= (cursorGeometries.length - 2) + return ( + + { if (ref) lineMatRefs.current[idx] = ref }} + attach="material" + color={theme.playbackCursor.lineColor} + linewidth={1} + opacity={isLast ? 1.0 : opacity} + transparent + /> + + ) + })} + + ), [theme, contentHeight, cursorGeometries, setTimelineCursor]) + + return memoizedGroup +} diff --git a/packages/timeline/src/components/timeline/CursorWeird.tsx b/packages/timeline/src/components/timeline/CursorWeird.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b2eb25bd17ee4647bad29a0baf3a907145ac3c33 --- /dev/null +++ b/packages/timeline/src/components/timeline/CursorWeird.tsx @@ -0,0 +1,21 @@ +import React from "react" + +import { + useTimeline +} from "@/hooks" + +import { hslToHex } from "@/utils" +import { useCursorGeometry } from "@/hooks/useCursorGeometry" + +export function Cursor({ + width, + height +}: { + width: number + height: number +}) { + + return ( + <>{null} + ) +}; diff --git a/packages/timeline/src/components/timeline/Grid.tsx b/packages/timeline/src/components/timeline/Grid.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2a2c20b5ec03e0c4fd3ab49b193684687b95c24f --- /dev/null +++ b/packages/timeline/src/components/timeline/Grid.tsx @@ -0,0 +1,83 @@ +import React from "react" + +import { DEFAULT_NB_TRACKS } from "@/constants" +import { + useAxis, + useVerticalGridLines, + useHorizontalGridLines, + useTimeline +} from "@/hooks" + +import { hslToHex } from "@/utils" + +export function Grid() { + const typicalSegmentDurationInSteps = useTimeline(s => s.typicalSegmentDurationInSteps) + const contentHeight = useTimeline(s => s.contentHeight) + + + const axis = useAxis() + + const verticalGridLines = useVerticalGridLines() + const horizontalGridLines = useHorizontalGridLines() + + // console.log(`re-rendering `) + + + return ( + <> + + {verticalGridLines.map((lineGeometry, idx) => ( + + + + ))} + + + + {horizontalGridLines.map((lineGeometry, idx) => ( + + + + ))} + + + + {axis.map((lineGeometry, idx) => ( + + + + ))} + + + + ); +}; diff --git a/packages/timeline/src/components/timeline/LeftBarTrackScale.tsx b/packages/timeline/src/components/timeline/LeftBarTrackScale.tsx new file mode 100644 index 0000000000000000000000000000000000000000..8022ecf7b93886a7fb9f511f89cd3e77054e610c --- /dev/null +++ b/packages/timeline/src/components/timeline/LeftBarTrackScale.tsx @@ -0,0 +1,176 @@ +import React from "react" +import { Plane, Text } from "@react-three/drei" + +import { +useTimeline +} from "@/hooks" + +import { leftBarTrackScaleWidth } from "@/constants/themes" +import { useHorizontaTrackLines } from "@/hooks/useHorizontalTrackLines" +import { LineGeometry } from "three/examples/jsm/Addons.js" +import { hslToHex } from "@/utils" + +export function LeftBarTrackScale() { + // console.log(`re-rendering `) + + const contentHeight = useTimeline((s) => s.contentHeight) + + const getCellHeight = useTimeline((s) => s.getCellHeight) + const theme = useTimeline(s => s.theme) + + const getVerticalCellPosition = useTimeline((s) => s.getVerticalCellPosition) + + const tracks = useTimeline(s => s.tracks) + const toggleTrackVisibility = useTimeline((s) => s.toggleTrackVisibility) + + const setLeftBarTrackScale = useTimeline(s => s.setLeftBarTrackScale) + + + const horizontalTrackLines = useHorizontaTrackLines() + + return ( + { + if (r) { + setLeftBarTrackScale(r) + } + }} + position={[-leftBarTrackScaleWidth, contentHeight / 2, 0]} + > + + {horizontalTrackLines.map((lineGeometry, idx) => ( + + + + ))} + + + {tracks.map(track => ( + { + toggleTrackVisibility(track.id) + e.stopPropagation() + }} + > + + { + toggleTrackVisibility(track.id) + e.stopPropagation() + }} + > + 👁️ + + + Track { + track.id + } + + + { + track.name + } + + + ))} + + + ) +} \ No newline at end of file diff --git a/packages/timeline/src/components/timeline/Timeline.tsx b/packages/timeline/src/components/timeline/Timeline.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f85d9c3df23a2d067244551ac997dbb6f7fcb0b5 --- /dev/null +++ b/packages/timeline/src/components/timeline/Timeline.tsx @@ -0,0 +1,68 @@ +import { Plane } from "@react-three/drei" +import { useThree } from "@react-three/fiber" +import { useEffect } from "react" + +import { + useTimeline +} from "@/hooks" + + +import { Cells } from "./Cells" +import { Cursor } from "./Cursor" +import { Grid } from "./Grid" +import { LeftBarTrackScale } from "./LeftBarTrackScale" +import { TopBarTimeScale } from "./TopBarTimeScale" + +export function Timeline({ width, height }: { width: number; height: number }) { + const { size } = useThree() + + const setContainerSize = useTimeline(s => s.setContainerSize) + useEffect(() => { + setContainerSize({ width, height }) + }, [width, height, setContainerSize]) + + const contentHeight = useTimeline(s => s.contentHeight) + const contentWidth = useTimeline(s => s.contentWidth) + + /* + console.log(`Issue with size? `, { + "width (coming from parent app)": width, + "content width": contentWidth, + "WebGL context's size.width": size.width, + }) + */ + // console.log(`re-rendering `) + return ( + + + {/* background */} + + {/* + not a fan of all those props.. I think we could drop this + */} + + + + + + + + ); +}; diff --git a/packages/timeline/src/components/timeline/TopBarTimeScale.tsx b/packages/timeline/src/components/timeline/TopBarTimeScale.tsx new file mode 100644 index 0000000000000000000000000000000000000000..ca41d9ea5dac44db9ec36cdacbbe1df3698ed0a4 --- /dev/null +++ b/packages/timeline/src/components/timeline/TopBarTimeScale.tsx @@ -0,0 +1,295 @@ +import React, { useEffect, useMemo, useRef } from "react" + +import { Plane, Text } from "@react-three/drei" + +import { +useTimeline +} from "@/hooks" + +import { useTimeScaleGraduations } from "@/hooks/useTimeScaleGraduations" +import { DEFAULT_DURATION_IN_MS_PER_STEP, NB_MAX_SHOTS } from "@/constants/grid" +import { formatTimestamp } from "@/utils/formatTimestamp" + +import { leftBarTrackScaleWidth, topBarTimeScaleHeight } from "@/constants/themes" +import { useThree } from "@react-three/fiber" + +export function TopBarTimeScale() { + const containerRef = useRef(null); + + const { size } = useThree() + + const jumpAt = useTimeline(s => s.jumpAt) + const togglePlayback = useTimeline(s => s.togglePlayback) + const theme = useTimeline(s => s.theme) + const isEmpty = useTimeline(s => s.isEmpty) + + // right now empty means disabled, but in the future we might use other things + const isDisabled = isEmpty; + + const wasPlayingRef = useRef(undefined) + + // we should use the non-reactive version + const cellWidth = useTimeline((s) => s.cellWidth) + // const cellWidth = useTimeline.getState().horizontalZoomLevel + const contentWidth = useTimeline((s) => s.contentWidth) + + const isResizing = useTimeline(s => s.isResizing) + + const unit = 10 + + // note: recomputing this is expensive and creates a visual delay + const timeScaleGraduations = useTimeScaleGraduations({ + unit + }); + + let timestampInMs = -DEFAULT_DURATION_IN_MS_PER_STEP + + const setHorizontalZoomLevel = useTimeline((s) => s.setHorizontalZoomLevel) + + // console.log(`re-rendering `) + + const setCursorTimestampAtInMs = useTimeline(s => s.setCursorTimestampAtInMs) + const setIsDraggingCursor = useTimeline(s => s.setIsDraggingCursor) + const setTopBarTimeScale = useTimeline(s => s.setTopBarTimeScale) + + // it can be annoying to have to be exactly on the right top bar track when dragging the cursor + // to improve the UX, we allow the user to move the mouse ANYWHERE on the screen while doing so + useEffect(() => { + if (isDisabled) { return; } // Don't add event listeners if the component is empty + + const onMouseMove = (evt: MouseEvent) => { + const { + isDraggingCursor, + timelineCursor, + topBarTimeScale, + timelineCamera, + canvas + } = useTimeline.getState() + if (!timelineCursor || !isDraggingCursor || !topBarTimeScale || !timelineCamera || !canvas) { return } + + // if we are actualling pressing a button + if (evt.buttons) { + let canvasRect = canvas.getBoundingClientRect() + const mouseX = evt.pageX - canvasRect.left + + const newPositionOfTheCursorX = mouseX //- leftBarTrackScaleWidth + // TODO: take the left column into account for the calculation + + const positionInsideTheTimelineX = newPositionOfTheCursorX + timelineCamera.position.x + + const newCursorTimestampAtInMs = (positionInsideTheTimelineX / cellWidth) * DEFAULT_DURATION_IN_MS_PER_STEP + + setCursorTimestampAtInMs(newCursorTimestampAtInMs) + jumpAt(newCursorTimestampAtInMs) + } else { + // user stopped pressing the mouse outside the timeline area + + setIsDraggingCursor(false) + if (typeof wasPlayingRef.current === "boolean") { + if (wasPlayingRef.current) { + togglePlayback(true) + } + } + } + evt.stopPropagation() + return false + } + document.addEventListener("mousemove", onMouseMove) + return () => { + document.removeEventListener("mousemove", onMouseMove) + } + }, [isDisabled]) + + // console.log("contentWidth:", contentWidth) + // console.log("NB_MAX_SHOTS * cellWidth:", NB_MAX_SHOTS * cellWidth) + + const maxWidth = contentWidth + + const graduationGroup = useMemo(() => ( + <> + + + + + + + + {timeScaleGraduations.map((lineGeometry, idx) => ( + + + + ))} + + + {timeScaleGraduations.filter((_, idx) => (idx * cellWidth) < maxWidth).map((lineGeometry, idx) => ( + 40 + ? true + + // if this is too tight, we only display the coarse time ticks + : cellWidth > 4 + ? idx % unit === 0 + + : false + } + > + { + formatTimestamp( + timestampInMs += DEFAULT_DURATION_IN_MS_PER_STEP, { + hours: false, // idx % unit === 0, + minutes: idx % unit === 0, + seconds: true, + milliseconds: cellWidth > 20, + })} + + ))} + + + ), [ + isResizing, + timeScaleGraduations.length, + leftBarTrackScaleWidth, + topBarTimeScaleHeight, + contentWidth, + cellWidth, + unit, + formatTimestamp, + theme.topBarTimeScale.backgroundColor, + theme.topBarTimeScale.lineColor, + theme.topBarTimeScale.textColor, + isDisabled, + ]) + + return ( + { + if (r) { + setTopBarTimeScale(r) + } + }} + // just a trick + position={[0, 0, -3]} + onWheel={(e) => { + if (isDisabled || e.offsetY > topBarTimeScaleHeight) { return } + + const disableWheel = true + if (disableWheel) { + console.log(`user tried to change the horizontal scale, but it is disabled due to rescaling bugs (@Julian fix this!)`) + e.stopPropagation() + return false + } + + const wheelFactor = 0.3 + + setHorizontalZoomLevel( + // Math.round( + useTimeline.getState().cellWidth + (wheelFactor * e.deltaY) + // ) + ) + e.stopPropagation() + return false + }} + onPointerDown={(e) => { + if (isDisabled) { return } + const cursorX = e.point.x + (size.width / 2) + const cursorTimestampAtInMs = (cursorX / cellWidth) * DEFAULT_DURATION_IN_MS_PER_STEP + const { wasPlaying } = togglePlayback(false) + wasPlayingRef.current = wasPlaying + setCursorTimestampAtInMs(cursorTimestampAtInMs) + jumpAt(cursorTimestampAtInMs) + setIsDraggingCursor(true) + e.stopPropagation() + return false + }} + onPointerUp={(e) => { + if (isDisabled) { return } + setIsDraggingCursor(false) + if (typeof wasPlayingRef.current === "boolean") { + if (wasPlayingRef.current) { + togglePlayback(true) + } + } + e.stopPropagation() + return false + }} + onPointerMove={e => { + if (isDisabled) { return } + // TODO move this into the whole parent container? + // the problem is.. are we still gonna get events + + // console.log(e) + // handle the "timeline cursor drag" + if (e.pressure > 0) { + const cursorX = e.point.x + (size.width / 2) + const cursorTimestampAtInMs = (cursorX / cellWidth) * DEFAULT_DURATION_IN_MS_PER_STEP + setCursorTimestampAtInMs(cursorTimestampAtInMs) + jumpAt(cursorTimestampAtInMs) + } + e.stopPropagation() + return false + }} + > + {graduationGroup} + + ) +} \ No newline at end of file diff --git a/packages/timeline/src/components/timeline/index.ts b/packages/timeline/src/components/timeline/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..ba74de4d97c041e10d066db6e5bb6124aa36f053 --- /dev/null +++ b/packages/timeline/src/components/timeline/index.ts @@ -0,0 +1,7 @@ +export { Cursor } from "./CursorWeird" +export { Timeline } from "./Timeline" +export { TopBarTimeScale } from "./TopBarTimeScale" +export { LeftBarTrackScale } from "./LeftBarTrackScale" +export { Cells } from "./Cells" +export { Grid } from "./Grid" +export { type JumpAt } from "./types" \ No newline at end of file diff --git a/packages/timeline/src/components/timeline/types.ts b/packages/timeline/src/components/timeline/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..1a904a2d9257572f8a5cd27540a2aae1add1c0ae --- /dev/null +++ b/packages/timeline/src/components/timeline/types.ts @@ -0,0 +1,15 @@ +import { Group, Object3DEventMap } from "three" + +export type TimelineCursorImpl = Group + +// application-provided callback used to seek into a specific timestamp +export type JumpAt = (jumpAtInMs: number) => void + +// application-provided callback used to determine if we are playing back a stream or not +export type IsPlaying = () => boolean + +// application-provided callback used to toggle the playback +export type TogglePlayback = (forcePlaying?: boolean) => { + wasPlaying: boolean + isPlaying: boolean +} diff --git a/packages/timeline/src/compute/README.md b/packages/timeline/src/compute/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3b8bda23f388ace54500b6c37306cb3dea75b892 --- /dev/null +++ b/packages/timeline/src/compute/README.md @@ -0,0 +1,2 @@ +The purpose of those functions is to compute some metrics without even touching to the Zustand state in read or write + diff --git a/packages/timeline/src/compute/computeCellHeight.ts b/packages/timeline/src/compute/computeCellHeight.ts new file mode 100644 index 0000000000000000000000000000000000000000..0e71a0fbed4a597ec115b0a82dc8ee1054106fdd --- /dev/null +++ b/packages/timeline/src/compute/computeCellHeight.ts @@ -0,0 +1,31 @@ +import { ClapTracks } from "@aitube/clap" + +export function computeCellHeight({ + tracks, + trackNumber, + defaultCellHeight, + defaultPreviewHeight +}: { + tracks: ClapTracks + trackNumber: number + defaultCellHeight: number + defaultPreviewHeight: number +}): number { + let cellHeight = defaultCellHeight + + if (typeof trackNumber === "number" && !isNaN(trackNumber) && isFinite(trackNumber)) { + const track = tracks[trackNumber] + if (track) { + cellHeight = + track.isPreview && track.visible + ? defaultPreviewHeight + : track.visible + ? track.height + : defaultCellHeight + } else { + // missing data + } + } + + return cellHeight +} diff --git a/packages/timeline/src/compute/computeContentSizeMetrics.ts b/packages/timeline/src/compute/computeContentSizeMetrics.ts new file mode 100644 index 0000000000000000000000000000000000000000..c6676206bc65fde46236b2246c0274657396d3b8 --- /dev/null +++ b/packages/timeline/src/compute/computeContentSizeMetrics.ts @@ -0,0 +1,69 @@ +import { ClapMeta, ClapTracks } from "@aitube/clap" + +import { ContentSizeMetrics } from "@/types/timeline" + +import { computeCellHeight } from "./computeCellHeight" +import { DEFAULT_COLUMNS_PER_SLICE, DEFAULT_DURATION_IN_MS_PER_STEP, DEFAULT_NB_TRACKS, NB_MAX_SHOTS, PROMPT_STEP_HEIGHT_IN_PX } from "@/constants/grid" + +export function computeContentSizeMetrics({ + meta, + tracks, + cellWidth, + defaultSegmentDurationInSteps, + totalDurationInMs, +}: { + meta: ClapMeta + tracks: ClapTracks + cellWidth: number + defaultSegmentDurationInSteps: number + totalDurationInMs: number +}): ContentSizeMetrics { + + // in the future those might be dynamic / coming from settings + const nbMaxShots = NB_MAX_SHOTS + const nbMaxTracks = DEFAULT_NB_TRACKS + const defaultCellHeight = PROMPT_STEP_HEIGHT_IN_PX + + const defaultSegmentLengthInPixels = cellWidth * defaultSegmentDurationInSteps + + // TODO: compute the exact image ratio instead of using the media orientation, + // since it might not match the actual assets + const defaultMediaRatio = + (meta.width || 896) / (meta.height || 512) + + // also storyboards and videos might have different sizes / ratios + const defaultPreviewHeight = Math.round( + defaultSegmentLengthInPixels / defaultMediaRatio + ) + + let contentHeight = 0 + const newTracks: ClapTracks = tracks.map((track: any) => { + contentHeight += computeCellHeight({ + trackNumber: track.id, + tracks, + defaultCellHeight, + defaultPreviewHeight + }) + return { + ...track, + contentHeight, + } + }) + return { + nbMaxShots, + nbMaxTracks, + nbIdentifiedTracks: newTracks.length, + + // node: content width and height are in pixels + contentWidth: (totalDurationInMs / DEFAULT_DURATION_IN_MS_PER_STEP) * cellWidth, + contentHeight, + + tracks: newTracks, + cellWidth, + defaultCellHeight, + defaultSegmentDurationInSteps, + defaultSegmentLengthInPixels, + defaultMediaRatio, + defaultPreviewHeight, + } +} \ No newline at end of file diff --git a/packages/timeline/src/constants/defaults.ts b/packages/timeline/src/constants/defaults.ts new file mode 100644 index 0000000000000000000000000000000000000000..02bc34684ad7b761adbb44d3ac84f2e3101f3fc5 --- /dev/null +++ b/packages/timeline/src/constants/defaults.ts @@ -0,0 +1,14 @@ +import { ClapTimelineTheme } from "@/types" +import { pastel } from "./themes" + + +export const DEFAULT_MIN_ZOOM = 0.2 +export const DEFAULT_MAX_ZOOM = 7 +export const DEFAULT_ZOOM_SPEED = 1.7 // high = faster +export const DEFAULT_ZOOM_DAMPING_FACTOR = 0.3 // low : delay, high : faster/snappier +export const DEFAULT_SHOW_FPS = false +export const DEFAULT_FRAMELOOP = "demand" + +export const DEFAULT_THEMES: Record = { + pastel, +} \ No newline at end of file diff --git a/packages/timeline/src/constants/grid.ts b/packages/timeline/src/constants/grid.ts new file mode 100644 index 0000000000000000000000000000000000000000..e79d00fae96c4e33c5e9395610dcec18d1c729da --- /dev/null +++ b/packages/timeline/src/constants/grid.ts @@ -0,0 +1,13 @@ +export const DEFAULT_DURATION_IN_MS_PER_STEP = 500 + +export const DEFAULT_NB_TRACKS = 24 + +// how many columns per slice / default segment lenght - this may be an option in the future +// so here, a "slice" (a typical shot) +// lasts for 2 seconds (500ms * 4) +export const DEFAULT_COLUMNS_PER_SLICE = 4 + +export const PROMPT_STEP_HEIGHT_IN_PX = 48 +export const PREVIEW_STEP_HEIGHT_IN_PX = 3 * PROMPT_STEP_HEIGHT_IN_PX + +export const NB_MAX_SHOTS = ((8 * 60 * 60) / 2) // 6 hours converted to seconds, and divided by 2 (a shot is about 2 sec) diff --git a/packages/timeline/src/constants/index.ts b/packages/timeline/src/constants/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..0450879b49adf1ca4d057723a37c3fb7ca2caa24 --- /dev/null +++ b/packages/timeline/src/constants/index.ts @@ -0,0 +1,27 @@ +export { + DEFAULT_MIN_ZOOM, + DEFAULT_MAX_ZOOM, + DEFAULT_ZOOM_SPEED, + DEFAULT_ZOOM_DAMPING_FACTOR, + DEFAULT_SHOW_FPS, + DEFAULT_FRAMELOOP, + DEFAULT_THEMES, +} from "./defaults" + +export { + DEFAULT_DURATION_IN_MS_PER_STEP, + DEFAULT_NB_TRACKS, + DEFAULT_COLUMNS_PER_SLICE, + PROMPT_STEP_HEIGHT_IN_PX, + PREVIEW_STEP_HEIGHT_IN_PX, + NB_MAX_SHOTS +} from "./grid" + +export { + segmentVisibilityPriority +} from "./priorities" + +export { + pastel, + leftBarTrackScaleWidth +} from "./themes" diff --git a/packages/timeline/src/constants/priorities.ts b/packages/timeline/src/constants/priorities.ts new file mode 100644 index 0000000000000000000000000000000000000000..f9f549ff224ca47f90aabfb8d5bb8a699054ed12 --- /dev/null +++ b/packages/timeline/src/constants/priorities.ts @@ -0,0 +1,19 @@ +import { SegmentVisibility } from "@/types" + +// used for sort +export const segmentVisibilityPriority: Record = { + // the segment is visible, and the user explicitly requested to render it before the others + [SegmentVisibility.DEMANDED]: 3, + + // TODO: add some implicit intermediary priority options + // such as SELECTED, HOVERED.. + + // the segment (or at least a portion of it) is currently visible in the sliding window + [SegmentVisibility.VISIBLE]: 2, + + // the segment is hidden, but not too far from the sliding window + [SegmentVisibility.BUFFERED]: 1, + + // fully hidden, far from the sliding window + [SegmentVisibility.HIDDEN]: 0 +} diff --git a/packages/timeline/src/constants/themes.ts b/packages/timeline/src/constants/themes.ts new file mode 100644 index 0000000000000000000000000000000000000000..74b8364c72cda0ccc7513df9d2cc499d257a2dff --- /dev/null +++ b/packages/timeline/src/constants/themes.ts @@ -0,0 +1,72 @@ +import { ClapSegmentCategory } from "@aitube/clap" + +import { ClapTimelineTheme } from "@/types" +import { ClapSegmentCategoryColors } from "@/types/theme" + +export const leftBarTrackScaleWidth = 120 +export const topBarTimeScaleHeight = 40 + +export const baseClapSegmentCategoryColors: ClapSegmentCategoryColors = { + [ClapSegmentCategory.SPLAT]: { hue: 347, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.MESH]: { hue: 32, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.DEPTH]: { hue: 242, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.EVENT]: { hue: 270, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.EFFECT]: { hue: 270, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.INTERFACE]: { hue: 216, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.PHENOMENON]: { hue: 270, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.VIDEO]: { hue: 70, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.STORYBOARD]: { hue: 70, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.TRANSITION]: { hue: 55, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.CHARACTER]: { hue: 285.8, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.LOCATION]: { hue: 80.9, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.TIME]: { hue: 250, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.ERA]: { hue: 250, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.LIGHTING]: { hue: 50, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.WEATHER]: { hue: 197.2, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.ACTION]: { hue: 3, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.MUSIC]: { hue: 100, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.SOUND]: { hue: 60, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.DIALOGUE]: { hue: 23, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.STYLE]: { hue: 285, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.CAMERA]: { hue: 10, saturation: 30, lightness: 78.6 }, + [ClapSegmentCategory.GENERIC]: { hue: 200, saturation: 30, lightness: 78.6 }, +} + +export const pastel: ClapTimelineTheme = { + topBarTimeScale: { + backgroundColor: "#7d7c78", + textColor: "#ffffff", + lineColor: "#E6E6E6" + }, + leftBarTrackScale: { + backgroundColor: "#7d7c78", + textColor: "#ffffff", + lineColor: "#B3B3B3" + }, + grid: { + backgroundColor: "#27272A", + }, + cell: { + categoryColors: baseClapSegmentCategoryColors, + + waveform: { + // "original" style + lineSpacing: 2, + gradientStart: 1.0, + gradientEnd: 0.6, + + // "drapes" style + // lineSpacing: 0, + // gradientStart: 0.7, + // gradientEnd: 0.1, + + // that is an "aggressive" style + // lineSpacing: 1, + // gradientStart: 0.6, + // gradientEnd: 1.0, + } + }, + playbackCursor: { + lineColor: "rgba(255, 255, 0, 1.0)" + } +} diff --git a/packages/timeline/src/demo.tsx b/packages/timeline/src/demo.tsx new file mode 100644 index 0000000000000000000000000000000000000000..85752c2fcdc7f69381b08ca29ef5219b28a5754d --- /dev/null +++ b/packages/timeline/src/demo.tsx @@ -0,0 +1,16 @@ +import React from 'react' +import { createRoot } from 'react-dom/client' + +import { Timeline } from '.' + +const container = document.getElementById('root') +const root = createRoot(container!) + +root.render( + +
Hello
+
+ +
+
+); \ No newline at end of file diff --git a/packages/timeline/src/hooks/index.ts b/packages/timeline/src/hooks/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..61a69e5ca1dc8f3ebb94b73350fa5ad723e9c47b --- /dev/null +++ b/packages/timeline/src/hooks/index.ts @@ -0,0 +1,7 @@ +export { useAnimationFrame } from "./useAnimationFrame" +export { useAxis } from "./useAxis" +export { useVerticalGridLines } from "./useVerticalGridLines" +export { useHorizontalGridLines } from "./useHorizontalGridLines" +export { useTimeline } from "./useTimeline" +export { useSegmentChanges } from "./useSegmentChanges" +export { useSegmentLoader } from "./useSegmentLoader" \ No newline at end of file diff --git a/packages/timeline/src/hooks/useAnimationFrame.ts b/packages/timeline/src/hooks/useAnimationFrame.ts new file mode 100644 index 0000000000000000000000000000000000000000..6ce441a252321867752ed388c5da80fe4ee7c7f4 --- /dev/null +++ b/packages/timeline/src/hooks/useAnimationFrame.ts @@ -0,0 +1,22 @@ +import { DependencyList, useEffect, useRef } from "react" + +export function useAnimationFrame(callback: (time: number) => void, deps: DependencyList | undefined = []) { + // Use useRef for mutable variables that we want to persist + // without triggering a re-render on their change + const requestRef = useRef() + const previousTimeRef = useRef() + + const animate = (time: number) => { + if (previousTimeRef.current != undefined) { + const deltaTime = time - previousTimeRef.current + callback(deltaTime) + } + previousTimeRef.current = time; + requestRef.current = requestAnimationFrame(animate); + } + + useEffect(() => { + requestRef.current = requestAnimationFrame(animate); + return () => cancelAnimationFrame(requestRef.current as any); + }, deps); // Make sure the effect runs only once +} \ No newline at end of file diff --git a/packages/timeline/src/hooks/useAxis.ts b/packages/timeline/src/hooks/useAxis.ts new file mode 100644 index 0000000000000000000000000000000000000000..36a7d37453d1a3e2225d447e7618d227ece30d78 --- /dev/null +++ b/packages/timeline/src/hooks/useAxis.ts @@ -0,0 +1,35 @@ +import { useEffect, useState } from "react" + +import * as THREE from "three" +import { useTimeline } from "./useTimeline" + +export const useAxis = () => { + const [axis, setAxis] = useState([] as THREE.BufferGeometry[]); + + const contentHeight = useTimeline(s => s.contentHeight) + const contentWidth = useTimeline(s => s.contentWidth) + + useEffect(() => { + const horizontalTop = new THREE.BufferGeometry().setFromPoints([ + new THREE.Vector3(0, 0, 1), + new THREE.Vector3(contentWidth, 0, 1) + ]); + + const vertical = new THREE.BufferGeometry().setFromPoints([ + new THREE.Vector3(0, 0, 1), + new THREE.Vector3(0, -contentHeight, 1) + ]); + + /* + const horizontalBottom = new THREE.BufferGeometry().setFromPoints([ + new THREE.Vector3(0, -maxHeight, 1), + new THREE.Vector3(width, -maxHeight, 1) + ]); + */ + setAxis([horizontalTop, vertical, + //horizontalBottom + ]); + }, [contentWidth, contentHeight]); + + return axis; +} \ No newline at end of file diff --git a/packages/timeline/src/hooks/useCursorGeometry.ts b/packages/timeline/src/hooks/useCursorGeometry.ts new file mode 100644 index 0000000000000000000000000000000000000000..2afc162dc0160c3b7de8108bf2373a15bdfbeacb --- /dev/null +++ b/packages/timeline/src/hooks/useCursorGeometry.ts @@ -0,0 +1,36 @@ +import { useEffect, useState } from "react" +import * as THREE from "three" + +import { useTimeline } from "./useTimeline" +import { leftBarTrackScaleWidth } from "@/constants"; +import { topBarTimeScaleHeight } from "@/constants/themes"; + +export const useCursorGeometry = () => { + + + const [gridlines, setGridLines] = useState([] as THREE.BufferGeometry[]); + + const contentHeight = useTimeline(s => s.contentHeight) + + // the width of the cursor (this includes the cursor + a nice gradient trail) + const widthInPx = 24 + + useEffect(() => { + + const thisLines = [] as THREE.BufferGeometry[]; + + for (let i = 0; i < widthInPx; i++) { + const verticalLinePoints = [ + new THREE.Vector3(i - widthInPx, 60, 1), + new THREE.Vector3(i - widthInPx, -contentHeight, 1) + ]; + const verticalLineGeometry = new THREE.BufferGeometry().setFromPoints(verticalLinePoints); + + thisLines.push(verticalLineGeometry); + } + + setGridLines(thisLines); + }, [contentHeight]); + + return gridlines; +}; \ No newline at end of file diff --git a/packages/timeline/src/hooks/useDebounce.ts b/packages/timeline/src/hooks/useDebounce.ts new file mode 100644 index 0000000000000000000000000000000000000000..0021d39e13d74a517b6fce4db502b6f33aa5ae62 --- /dev/null +++ b/packages/timeline/src/hooks/useDebounce.ts @@ -0,0 +1,15 @@ +import { useEffect, useState } from 'react' + +export function useDebounce(value: T, delay?: number): T { + const [debouncedValue, setDebouncedValue] = useState(value) + + useEffect(() => { + const timer = setTimeout(() => setDebouncedValue(value), delay || 500) + + return () => { + clearTimeout(timer) + } + }, [value, delay]) + + return debouncedValue +} \ No newline at end of file diff --git a/packages/timeline/src/hooks/useHorizontalGridLines.ts b/packages/timeline/src/hooks/useHorizontalGridLines.ts new file mode 100644 index 0000000000000000000000000000000000000000..4e1e82efc40f54f9e8a28562bf801d9483ff0a79 --- /dev/null +++ b/packages/timeline/src/hooks/useHorizontalGridLines.ts @@ -0,0 +1,36 @@ +import { useEffect, useState } from "react" +import * as THREE from "three" + +import { useTimeline } from "./useTimeline" + +export const useHorizontalGridLines = () => { + + const contentWidth = useTimeline(s => s.contentWidth) + const getVerticalCellPosition = useTimeline(s => s.getVerticalCellPosition) + + const tracks = useTimeline(s => s.tracks) + + const [gridlines, setGridLines] = useState([] as THREE.BufferGeometry[]); + + useEffect(() => { + + const thisLines = [] as THREE.BufferGeometry[]; + + for (let i = 0; i <= tracks.length; i++) { + const horizontalLinePoints = [ + new THREE.Vector3(0, -getVerticalCellPosition(0, i), 0), + new THREE.Vector3(contentWidth, -getVerticalCellPosition(0, i), 0) + ]; + const horizontalLineGeometry = new THREE.BufferGeometry().setFromPoints(horizontalLinePoints); + + thisLines.push(horizontalLineGeometry); + } + + setGridLines(thisLines); + }, [ + contentWidth, + JSON.stringify(tracks.map((t: any) => `${t.visible}_${t.height}`)), +]); + + return gridlines; +}; \ No newline at end of file diff --git a/packages/timeline/src/hooks/useHorizontalTrackLines.ts b/packages/timeline/src/hooks/useHorizontalTrackLines.ts new file mode 100644 index 0000000000000000000000000000000000000000..a78c258e4e61544198d8d425dc43001b01554420 --- /dev/null +++ b/packages/timeline/src/hooks/useHorizontalTrackLines.ts @@ -0,0 +1,35 @@ +import { useEffect, useState } from "react" +import * as THREE from "three" + +import { useTimeline } from "./useTimeline" +import { leftBarTrackScaleWidth } from "@/constants/themes" + +export const useHorizontaTrackLines = () => { + const getVerticalCellPosition = useTimeline(s => s.getVerticalCellPosition) + + const tracks = useTimeline(s => s.tracks) + + const [lines, setLines] = useState([] as THREE.BufferGeometry[]); + + useEffect(() => { + + const thisLines = [] as THREE.BufferGeometry[]; + + for (let i = 0; i <= tracks.length; i++) { + const horizontalLinePoints = [ + new THREE.Vector3(0, -getVerticalCellPosition(0, i), 0), + new THREE.Vector3(leftBarTrackScaleWidth, -getVerticalCellPosition(0, i), 0) + ]; + const horizontalLineGeometry = new THREE.BufferGeometry().setFromPoints(horizontalLinePoints); + + thisLines.push(horizontalLineGeometry); + } + + setLines(thisLines); + }, [, + leftBarTrackScaleWidth, + JSON.stringify(tracks.map((t: any) => `${t.visible}_${t.height}`)) + ]); + + return lines; +}; \ No newline at end of file diff --git a/packages/timeline/src/hooks/useHoveredSegment.ts b/packages/timeline/src/hooks/useHoveredSegment.ts new file mode 100644 index 0000000000000000000000000000000000000000..dfb782c51f88fca79d9d2c159463275e176b8afb --- /dev/null +++ b/packages/timeline/src/hooks/useHoveredSegment.ts @@ -0,0 +1,20 @@ +import { useEffect } from "react" +import { useTimeline } from "./useTimeline" + +export function useHoveredSegment(segmentId: string): boolean { + const hoveredSegment = useTimeline(s => s.hoveredSegment) + + useEffect(() => { + const cursor = hoveredSegment ? 'pointer' : 'auto' + if (document.body.style.cursor !== cursor) { + document.body.style.cursor = cursor + } + return () => { document.body.style.cursor = 'auto' } + }, [hoveredSegment]) + + if (hoveredSegment?.id === segmentId) { + return true + } else { + return false + } +} \ No newline at end of file diff --git a/packages/timeline/src/hooks/useSegment.ts b/packages/timeline/src/hooks/useSegment.ts new file mode 100644 index 0000000000000000000000000000000000000000..d562fe80a6ff58e88c58927d0ae5ae85e181041c --- /dev/null +++ b/packages/timeline/src/hooks/useSegment.ts @@ -0,0 +1,20 @@ +import { useEffect, useState } from "react" + +import { useTimeline } from "./useTimeline" +import { TimelineSegment } from "@/types" + +/** + * Can be used to subscribe to a segment + * @param segment + * @returns + */ +export function useSegment(segmentId: string): TimelineSegment | undefined { + const [segment, setSegment] = useState() + const atLeastOneSegmentChanged = useTimeline(s => s.atLeastOneSegmentChanged) + + useEffect(() => { + // TODO: not implemented yet + }, [atLeastOneSegmentChanged]) + + return segment +} \ No newline at end of file diff --git a/packages/timeline/src/hooks/useSegmentChanges.ts b/packages/timeline/src/hooks/useSegmentChanges.ts new file mode 100644 index 0000000000000000000000000000000000000000..df2e290c1cae46c4b42313999c1f34cb032f9eb4 --- /dev/null +++ b/packages/timeline/src/hooks/useSegmentChanges.ts @@ -0,0 +1,62 @@ +import { useEffect, useRef, useState } from "react" + +import { useTimeline } from "./useTimeline" +import { TimelineSegment } from "@/types" + +function getKey(segment: TimelineSegment) { + const keyItems = [ + segment.id, + + // properties of the timeline segment + segment.startAtLine, + segment.endAtLine, + segment.visibility, + segment.isSelected, + segment.isHovered, + segment.isHoveredOnBody, + segment.isHoveredOnLeftHandle, + segment.isHoveredOnRightHandle, + segment.isGrabbedOnBody, + segment.isGrabbedOnLeftHandle, + segment.isGrabbedOnRightHandle, + segment.isActive, + segment.isPlaying, + segment.editionStatus, + + // properties of the segment + segment.status, + segment.label, + segment.prompt, + segment.assetUrl.slice(0, 1024), + ] + + const segmentKey = keyItems.join("✇✇") + + return segmentKey +} + +/** + * Can be used to subscribe to individual changes in a segment + * + * Note: it is not efficient to track everything + * + * @param segment + * @returns + */ +export function useSegmentChanges(segment: TimelineSegment): number { + const [changeCounter, setChangeCounter] = useState(0) + const atLeastOneSegmentChanged = useTimeline(s => s.atLeastOneSegmentChanged) + + const changesRef = useRef(0) + const hashRef = useRef(getKey(segment)) + + useEffect(() => { + // at this stage, *ANY* segment might have changed + // so we need to recompute some kind of hash change + const newHash = getKey(segment) + if (hashRef.current === newHash) { return } + setChangeCounter(changesRef.current++) + }, [atLeastOneSegmentChanged]) + + return changeCounter +} \ No newline at end of file diff --git a/packages/timeline/src/hooks/useSegmentLoader.ts b/packages/timeline/src/hooks/useSegmentLoader.ts new file mode 100644 index 0000000000000000000000000000000000000000..a90bc9207fcbde311a7d960f33a714e8bbfb5610 --- /dev/null +++ b/packages/timeline/src/hooks/useSegmentLoader.ts @@ -0,0 +1,218 @@ +import { useEffect, useRef } from "react" +import * as THREE from "three" +import { useThree } from "@react-three/fiber" + +import { DEFAULT_DURATION_IN_MS_PER_STEP } from "@/constants" +import { similar, sliceSegments } from "@/utils" + +import { useTimeline } from "./useTimeline" +import { TimelineSegment, TimelineStore } from "@/types" +import { leftBarTrackScaleWidth } from "@/constants/themes" + +export const useSegmentLoader = ({ + refreshRateInMs, +}: { + refreshRateInMs: number +}): + { + visibleSegments: TimelineSegment[] + loadedSegments: TimelineSegment[] + }=> { + // to make it react to screen width change + // however, this doesn't seem to work well + // const { size: canvasSize, viewport } = useThree() + + const segments = useTimeline((s) => s.segments) + const allSegmentsChanged = useTimeline((s) => s.allSegmentsChanged) + + const loadedSegments = useTimeline((s) => s.loadedSegments) + const setLoadedSegments = useTimeline((s) => s.setLoadedSegments) + + const visibleSegments = useTimeline((s) => s.visibleSegments) + const setVisibleSegments = useTimeline((s) => s.setVisibleSegments) + + const controls = useThree((state) => state.controls) + + // we do a little trick here, to put the camera zoom inside our Zustand store + const camera = useThree(({ camera }) => camera) + + const cellWidth = useTimeline(s => s.cellWidth) + const getCellHeight = useTimeline(s => s.getCellHeight) + // const getVerticalCellPosition = useTimeline(s => s.getVerticalCellPosition) + // note: only the average height change will be detected + const cellHeight = getCellHeight() + + // TODO: I think we don't need to check over the camera.zoom anymore, + // since we have set it fixed now + useEffect(() => { + useTimeline.setState({ currentZoomLevel: camera.zoom }) + }, [camera]) + + const stateRef = useRef<{ + scrollX: number + initialized: boolean + beforeTimeWithBufferInMs: number + afterTimeWithBufferInMs: number + beforeTimeWithoutBufferInMs: number + afterTimeWithoutBufferInMs: number + timeout: NodeJS.Timeout + }>({ + scrollX: 0, + initialized: false, + beforeTimeWithBufferInMs: 0, + afterTimeWithBufferInMs: 0, + beforeTimeWithoutBufferInMs: 0, + afterTimeWithoutBufferInMs: 0, + timeout: 0 as unknown as NodeJS.Timeout, + }) + + const sync = async (forceRerendering?: boolean) => { + // TODO: replace our usage of stateRef.current + // by useTimeline.getState() + const state = stateRef.current + + const timeline: TimelineStore = useTimeline.getState() + const { cellWidth, width, height } = timeline + + if (!state || !camera) { return } + + // we can adjust this threshold to only re compute the geometry + // when a significant shift has been done by the user + // high value (eg 5) == less sensitive + // low value (e 2) == super sensitive + const epsilonPaneThreshold = 3 + + // now the zoom is tricky because it may be equivalent to a large paning, + // if we are in a zoom out + // which is why we are more sensitive here + const epsilonZoomThreshold = 1 + + // we don't need to check X, Y, Z and zoom anymore here, we can just look at scrollX + const cameraDidntPaneALot = Math.abs(state.scrollX - camera.position.x) < epsilonPaneThreshold + + if (cameraDidntPaneALot && !forceRerendering) { return } + + // we do this AFTER the return condition + state.scrollX = camera.position.x + + // determine, based on the current zoom level, and screen width, + // how many horizontal cell columns could be visible at a time + // + // note that is only useful for *horizontal* scrolling + // this doesn't prevent loading delay caused by zooming out + const maxPossibleNumberOfVisibleHorizontalCells = + Math.ceil(window.innerWidth / cellWidth) + + // it appears that we have an issue with the calculation here + // could be that we don't take everything into account, + // like the left margin? + + // note: currently the camera is not initialized well by default, + // due to the left bar track + // + // so, be careful: if you fix the camera initialization bug, + // then you *might* have to check in here too + const posX = camera.position.x + leftBarTrackScaleWidth + + const cellIndex = + Math.max(0, posX / cellWidth) + + // we actually don't use the camera.zoom anymore, so.. + + const securityMarginInCellStepCount = + // note: I've try to multiply this thing, but this didn't really solve + // the blank grid flash issue + maxPossibleNumberOfVisibleHorizontalCells + + + // if the camera is already zoomed-out a lot, it means we only need + // to take horizontal scroll into account + // + // but if the camera is zoomed-in, then a quick scroll wheel could + // send us asking for x2, x5 etc.. more cells instantly, so we need + // to take that into account too. + 8 // 8 because 4 on left and 4 on right + + const { segments } = useTimeline.getState() + + // we only keep segments within a given range + // those are not necessarily visible (there is a security margin) + const afterStepsWithBuffer = Math.max(0, cellIndex - securityMarginInCellStepCount) + const beforeStepsWithBuffer = Math.max(afterStepsWithBuffer, cellIndex + maxPossibleNumberOfVisibleHorizontalCells + securityMarginInCellStepCount) + + const afterTimeWithBufferInMs = afterStepsWithBuffer * DEFAULT_DURATION_IN_MS_PER_STEP + const beforeTimeWithBufferInMs = beforeStepsWithBuffer * DEFAULT_DURATION_IN_MS_PER_STEP + + if ( + state.afterTimeWithBufferInMs !== afterTimeWithBufferInMs + || state.beforeTimeWithBufferInMs !== beforeTimeWithBufferInMs + || forceRerendering) { + state.afterTimeWithBufferInMs = afterTimeWithBufferInMs + state.beforeTimeWithBufferInMs = beforeTimeWithBufferInMs + + const loadedSegments = await sliceSegments({ + segments, + afterTimeInMs: afterTimeWithBufferInMs, + beforeTimeInMs: beforeTimeWithBufferInMs + }) + + setLoadedSegments(loadedSegments) + } + + const afterStepsWithoutBuffer = Math.max(0, cellIndex) + const beforeStepsWithoutBuffer = Math.max(afterStepsWithoutBuffer, cellIndex + maxPossibleNumberOfVisibleHorizontalCells) + + const afterTimeWithoutBufferInMs = afterStepsWithoutBuffer * DEFAULT_DURATION_IN_MS_PER_STEP + const beforeTimeWithoutBufferInMs = beforeStepsWithoutBuffer * DEFAULT_DURATION_IN_MS_PER_STEP + + if ( + state.afterTimeWithoutBufferInMs !== afterTimeWithoutBufferInMs + || state.beforeTimeWithoutBufferInMs !== beforeTimeWithoutBufferInMs + || forceRerendering) { + state.afterTimeWithoutBufferInMs = afterTimeWithoutBufferInMs + state.beforeTimeWithoutBufferInMs = beforeTimeWithoutBufferInMs + + const visibleSegments = await sliceSegments({ + segments: segments, // <- apparently we cannot use the loadedSegments which is supposedly larger? weird + afterTimeInMs: afterTimeWithoutBufferInMs, + beforeTimeInMs: beforeTimeWithoutBufferInMs + }) + setVisibleSegments(visibleSegments) + } + } + + useEffect(() => { + const state = stateRef.current + if (!state || state.initialized || !controls) { return } + + state.initialized = true + + // console.log("scheduling a sync(false)") + // we could also use useInterval, but we need something async-friendly + const fn = async () => { + // we want a relatively low refresh rate (high delay) in order to get smooth camera movement + // eg a rate of 500ms + // + // ideally I would say we should also debounce the call, to defer + // the sync to until we have finished the zoom animation and don't have user action, + // (with a time limit anyway) + // + // we can also try to optimize this further by adapting it to the compute load, + // either by calculating the FPS or by monitoring the time it takes + // to run the sync() function + try { await sync(false) } catch (err) {} + + state.timeout = setTimeout(fn, refreshRateInMs) as any + } + fn() + // no need to clear the timeout + }, [controls]) // to wait before we are sure to have the controls + + // force a re-render when cell width or height change + useEffect(() => { + console.log("Re-rendering the timeline (this is an expensive operation, please optimize the code to make this rare!)") + const fn = async () => { try { await sync(true) } catch (err) {} } + fn() + }, [cellHeight, cellWidth, allSegmentsChanged]) + + return { visibleSegments, loadedSegments } +} \ No newline at end of file diff --git a/packages/timeline/src/hooks/useTimeScaleGraduations.ts b/packages/timeline/src/hooks/useTimeScaleGraduations.ts new file mode 100644 index 0000000000000000000000000000000000000000..5344fe7f1bb470be4cd295bdf0644ba953223bc4 --- /dev/null +++ b/packages/timeline/src/hooks/useTimeScaleGraduations.ts @@ -0,0 +1,112 @@ +import { useEffect, useState } from "react" +import * as THREE from "three" + +import { leftBarTrackScaleWidth, topBarTimeScaleHeight } from "@/constants/themes" + +import { useTimeline } from "./useTimeline" + +// note: those big for-loop just to render graduations are not efficient +// please open a PR if you have a better idea, thank you +// +// maybe either we pre-compute everything and we let the runtime figure out what to render on screen, +// or we implement our own code to do that.. I don't know +export const useTimeScaleGraduations = ({ + unit +}: { + unit: number +}) => { + const cellWidth = useTimeline(s => s.cellWidth) + const nbMaxShots = useTimeline(s => s.nbMaxShots) + const contentWidth = useTimeline((s) => s.contentWidth) + + const [timeScaleGraduations, setTimeScaleGraduations] = useState([] as THREE.BufferGeometry[]); + + const bigTickHeight = 12 + const smallTickHeight = 8 + + const maxWidth = contentWidth + + useEffect(() => { + + const lines = [] as THREE.BufferGeometry[]; + + let x = 0 + if (cellWidth > 32) { + for (let i = 0; i < nbMaxShots * 2; i++) { + x = i * (cellWidth / 2) + if (x > maxWidth) { + break + } + const verticalLinePoints = [ + new THREE.Vector3(x, 2, 1), + new THREE.Vector3( + x, + i % unit === 0 ? bigTickHeight : smallTickHeight, + 1 + ) + ]; + const verticalLineGeometry = new THREE.BufferGeometry().setFromPoints(verticalLinePoints); + lines.push(verticalLineGeometry); + } + } else if (cellWidth > 16) { + for (let i = 0; i < nbMaxShots; i++) { + x = i * (cellWidth) + if (x > maxWidth) { + break + } + const verticalLinePoints = [ + new THREE.Vector3(x, 2, 1), + new THREE.Vector3( + x, + i % unit === 0 ? bigTickHeight : smallTickHeight, + 1 + ) + ]; + const verticalLineGeometry = new THREE.BufferGeometry().setFromPoints(verticalLinePoints); + lines.push(verticalLineGeometry); + } + } else if (cellWidth > 8) { + for (let i = 0; i < nbMaxShots; i++) { + if (i % 10 !== 0) { continue } + x = i * (cellWidth) + if (x > maxWidth) { + break + } + const verticalLinePoints = [ + new THREE.Vector3(x, 2, 1), + new THREE.Vector3( + x, + smallTickHeight, + 1 + ) + ]; + const verticalLineGeometry = new THREE.BufferGeometry().setFromPoints(verticalLinePoints); + + lines.push(verticalLineGeometry); + } + } else { + for (let i = 0; i < nbMaxShots; i++) { + if (i % 10 !== 0) { continue } + x = i * (cellWidth) + if (x > maxWidth) { + break + } + const verticalLinePoints = [ + new THREE.Vector3(x, 2, 1), + new THREE.Vector3( + x, + smallTickHeight, + 1 + ) + ]; + const verticalLineGeometry = new THREE.BufferGeometry().setFromPoints(verticalLinePoints); + + lines.push(verticalLineGeometry); + } + } + + setTimeScaleGraduations(lines); + }, [cellWidth, nbMaxShots, leftBarTrackScaleWidth, contentWidth]); + + return timeScaleGraduations; +}; \ No newline at end of file diff --git a/packages/timeline/src/hooks/useTimeline.ts b/packages/timeline/src/hooks/useTimeline.ts new file mode 100644 index 0000000000000000000000000000000000000000..fe3f1900b53becfb2b448e78c8a26419b90553d3 --- /dev/null +++ b/packages/timeline/src/hooks/useTimeline.ts @@ -0,0 +1,1163 @@ +import { create } from "zustand" +import * as THREE from "three" +import { ClapProject, ClapSegment, ClapSegmentCategory, isValidNumber, newClap, serializeClap, ClapTracks, ClapEntity } from "@aitube/clap" + +import { TimelineSegment, SegmentEditionStatus, SegmentVisibility, TimelineStore, SegmentArea } from "@/types/timeline" +import { getDefaultProjectState, getDefaultState } from "@/utils/getDefaultState" +import { DEFAULT_DURATION_IN_MS_PER_STEP, DEFAULT_NB_TRACKS } from "@/constants" +import { hslToHex, findFreeTrack, removeFinalVideosAndConvertToTimelineSegments, clapSegmentToTimelineSegment, timelineSegmentToClapSegment } from "@/utils" +import { ClapSegmentCategoryColors, ClapSegmentColorScheme, ClapTimelineTheme, SegmentResolver } from "@/types" +import { TimelineControlsImpl } from "@/components/controls/types" +import { TimelineCameraImpl } from "@/components/camera/types" +import { IsPlaying, JumpAt, TimelineCursorImpl, TogglePlayback } from "@/components/timeline/types" +import { computeContentSizeMetrics } from "@/compute/computeContentSizeMetrics" + +export const useTimeline = create((set, get) => ({ + ...getDefaultState(), + + setCanvas: (canvas?: HTMLCanvasElement) => { + set({ canvas }) + }, + + clear: () => { + // this re-initialize everything that is related to the current .clap project + set({ + ...getDefaultProjectState() + }) + }, + + setClap: async (clap?: ClapProject) => { + const { clear } = get() + + clear() + + if (!clap) { + console.log(`useTimeline: no clap to show`) + return + } + + (window as any).useTimeline = useTimeline + + set({ isLoading: true }) + + // actually you know what.. let's drop the concept of final video for the moment + // in Clapper and the timeline + // const finalVideo = await getFinalVideo(clap) + const finalVideo = undefined + + // we remove the big/long video + const segments = await removeFinalVideosAndConvertToTimelineSegments(clap) + + const { + defaultCellHeight, + cellWidth, + } = get() + + const meta = clap.meta + + // TODO: many of those checks about average duration, nb of tracks, collisions... + // should be done by the Clap parser and/or serializer + // send a demand to Julian (@flngr) to get it fixed! + + let idCollisionDetector = new Set() + + let tracks: ClapTracks = [] + + let defaultSegmentDurationInSteps = get().defaultSegmentDurationInSteps + + + for (const s of segments) { + if (s.category === ClapSegmentCategory.CAMERA) { + const durationInSteps = ( + (s.endTimeInMs - s.startTimeInMs) / DEFAULT_DURATION_IN_MS_PER_STEP + ) + // TODO: we should do this row by row + // and look at the most recurring duration, + // using a table + defaultSegmentDurationInSteps = durationInSteps + break + } + } + + const defaultSegmentLengthInPixels = cellWidth * defaultSegmentDurationInSteps + + // TODO: compute the exact image ratio instead of using the media orientation, + // since it might not match the actual assets + const defaultMediaRatio = clap ? ( + (clap.meta.width || 896) / (clap.meta.height || 512) + ) : (896 / 512) + + // also storyboards and videos might have different sizes / ratios + const defaultPreviewHeight = Math.round( + defaultSegmentLengthInPixels / defaultMediaRatio + ) + + const lineNumberToMentionedSegments: Record = {} + + for (const segment of segments) { + + // TODO: move this idCollision detector into the state, + // so that we can use it later? + if (idCollisionDetector.has(segment.id)) { + console.log(`collision detected! there is already a segment with id ${segment.id}`) + continue + } + + // -------- + const isSegmentDirectlyMentionedInTheScript = segment.category === ClapSegmentCategory.DIALOGUE || segment.category === ClapSegmentCategory.ACTION + + if (isSegmentDirectlyMentionedInTheScript) { + for (let i = segment.startTimeInLines; i <= segment.endTimeInLines; i++) { + // we only add the segment if it is not already in the map + let existingArray: TimelineSegment[] = lineNumberToMentionedSegments[i] || [] + if (!existingArray.find(s => s.id === segment.id)) { + existingArray.push(segment) + } + lineNumberToMentionedSegments[i] = existingArray + } + } + + idCollisionDetector.add(segment.id) + + if (!tracks[segment.track]) { + const isPreview = + segment.category === ClapSegmentCategory.STORYBOARD || + segment.category === ClapSegmentCategory.VIDEO + + tracks[segment.track] = { + id: segment.track, + // name: `Track ${s.track}`, + name: `${segment.category}`, + isPreview, + height: + isPreview + ? defaultPreviewHeight + : defaultCellHeight, + hue: 0, + occupied: true, + visible: true, + } + } else { + + const track = tracks[segment.track] + const categories: string[] = track.name.split(",").map((x: string) => x.trim()) + if (!categories.includes(segment.category)) { + tracks[segment.track].name = "(misc)" + + /* + if (categories.length < 2) { + categories.push(s.category) + track.name = categories.join(", ") + } else if (!track.name.includes("..")) { + track.name = track.name + ".." + } + */ + } + + } + + } + + // note that we measure the empty ness here, but right after + // we run some code to fill-in the missing tracks + const isEmpty = tracks.length === 0 + + // ---------- FILL-IN THE TRACKS --------------- + for (let id = 0; id < DEFAULT_NB_TRACKS; id++) { + if (!tracks[id]) { + tracks[id] = { + id, + name: `(empty)`, + isPreview: false, + height: defaultCellHeight, + hue: 0, + occupied: false, // <-- setting this to false is the important part + visible: true, + } + } + } + + let totalDurationInMs = clap.meta.durationInMs + let totalNumberOfLines = clap.meta.screenplay.split('\n').length + + // console.log("totalNumberOfLines = " + totalNumberOfLines) + + // ---------- REPAIR THE LINE-2-SEGMENT DICTIONARY --------------- + let previousValue: TimelineSegment[] = [] + // we aren't finished yet: the lineNumberToMentionedSegments will be missing some entries + for (let i = 1; i <= totalNumberOfLines; i++) { + if (!Array.isArray(lineNumberToMentionedSegments[i])) { + lineNumberToMentionedSegments[i] = previousValue + } else { + previousValue = lineNumberToMentionedSegments[i] + } + } + + set({ + meta, + scenes: clap.scenes, + segments, + entities: clap.entities, + entityIndex: clap.entityIndex, + entitiesChanged: 0, + loadedSegments: [], + visibleSegments: [], + atLeastOneSegmentChanged: 1, + allSegmentsChanged: 1, + totalDurationInMs, + lineNumberToMentionedSegments, + + + isEmpty, + isLoading: false, + finalVideo, + + ...computeContentSizeMetrics({ + meta, + tracks, + cellWidth, + defaultSegmentDurationInSteps, + totalDurationInMs, + }) + }) + + // one more thing: we need to call this, + // as this will trigger various stuff in the parent + get().jumpAt(0) + }, + getClap: async (): Promise => { + const { meta, entities, scenes, segments } = get() + + const clap = newClap({ + meta: { ...meta }, + entities: [...entities], + scenes: [...scenes], + segments: segments.map(ts => timelineSegmentToClapSegment(ts)) + }) + + return clap + }, + setHorizontalZoomLevel: (newHorizontalZoomLevel: number) => { + const { + minHorizontalZoomLevel, + maxHorizontalZoomLevel, + meta, + tracks, + defaultSegmentDurationInSteps, + cellWidth: previousCellWidth, + totalDurationInMs, + } = get() + const cellWidth = Math.min(maxHorizontalZoomLevel, Math.max(minHorizontalZoomLevel, newHorizontalZoomLevel)) + + // nothing changed + if (Math.round(cellWidth) === Math.round(previousCellWidth)) { return } + + const resizeStartedAt = performance.now() + const isResizing = true + + set({ + resizeStartedAt, + isResizing, + ...computeContentSizeMetrics({ + meta, + tracks, + cellWidth, + defaultSegmentDurationInSteps, + totalDurationInMs, + }) + }) + }, + + setSegments: (segments: TimelineSegment[] = []) => { + set({ segments, loadedSegments: [] }) + }, + setLoadedSegments: (loadedSegments: TimelineSegment[] = []) => { set({ loadedSegments }) }, + setVisibleSegments: (visibleSegments: TimelineSegment[] = []) => { set({ visibleSegments }) }, + + getCellHeight: (trackNumber?: number): number => { + const { defaultCellHeight, tracks } = get() + const track = tracks[trackNumber!] + return track?.height || defaultCellHeight + }, + + getVerticalCellPosition: (start: number, end: number): number => { + const { defaultCellHeight, tracks } = get() + let height = 0 + for (let i = start; i < end; i++) { + const track = tracks[i!] + height += track?.height || defaultCellHeight + } + return height + }, + + getSegmentColorScheme: (segment: TimelineSegment): ClapSegmentColorScheme => { + + const { theme } = get() + + let baseHue = 0 + + let baseSaturation = theme.cell.categoryColors.GENERIC.saturation + let baseLightness = theme.cell.categoryColors.GENERIC.lightness + + let backgroundColorSaturation = (segment.isSelected ? 2.2 : 1.4) * baseSaturation + let backgroundColorHoverSaturation = (segment.isSelected ? 2.2 : 1.8) * baseSaturation + + let colorScheme: ClapSegmentColorScheme = { + baseHue, + baseSaturation, + baseLightness, + + backgroundColor: hslToHex(baseHue, backgroundColorSaturation, baseLightness), + backgroundColorHover: hslToHex(baseHue, backgroundColorHoverSaturation, baseLightness + 1), + backgroundColorDisabled: hslToHex(baseHue, baseSaturation - 15, baseLightness - 2), + foregroundColor: hslToHex(baseHue, baseSaturation + 40, baseLightness), + borderColor: hslToHex(baseHue, baseSaturation + 40, baseLightness + 10), + textColor: hslToHex(baseHue, baseSaturation + 55, baseLightness - 60), + textColorHover: hslToHex(baseHue, baseSaturation + 55, baseLightness - 50), + + waveformLineSpacing: theme.cell.waveform.lineSpacing, + waveformGradientStart: theme.cell.waveform.gradientStart, + waveformGradientEnd: theme.cell.waveform.gradientEnd, + } + + if (!segment) { return colorScheme } + + const clapSegmentCategoryColors: ClapSegmentCategoryColors = theme.cell.categoryColors + + const candidateHSL = clapSegmentCategoryColors[segment.category] + if (!candidateHSL) { return colorScheme } + + baseHue = candidateHSL.hue + baseSaturation = candidateHSL.saturation + baseLightness = candidateHSL.lightness + + colorScheme = { + baseHue, + baseSaturation, + baseLightness, + + backgroundColor: hslToHex(baseHue, backgroundColorSaturation, baseLightness), + backgroundColorHover: hslToHex(baseHue, backgroundColorHoverSaturation, baseLightness + 1), + backgroundColorDisabled: hslToHex(baseHue, baseSaturation - 15, baseLightness - 2), + foregroundColor: hslToHex(baseHue, baseSaturation + 40, baseLightness), + borderColor: hslToHex(baseHue, baseSaturation + 40, baseLightness + 10), + textColor: hslToHex(baseHue, baseSaturation + 55, baseLightness - 60), + textColorHover: hslToHex(baseHue, baseSaturation + 55, baseLightness - 50), + + waveformLineSpacing: theme.cell.waveform.lineSpacing, + waveformGradientStart: theme.cell.waveform.gradientStart, + waveformGradientEnd: theme.cell.waveform.gradientEnd, + } + + return colorScheme + }, + setHoveredSegment: ({ + hoveredSegment, + area, + }: { + hoveredSegment?: TimelineSegment + area?: SegmentArea + } = {}) => { + const { + hoveredSegment: previousHoveredSegment, + atLeastOneSegmentChanged: previousAtLeastOneSegmentChanged, + allSegmentsChanged: previousAllSegmentsChanged, + } = get() + + // note: we do all of this in order to avoid useless state updates + if (hoveredSegment) { + if (previousHoveredSegment) { + if (previousHoveredSegment.id === hoveredSegment.id) { + // nothing to do + return + } else { + previousHoveredSegment.isHovered = false + hoveredSegment.isHoveredOnLeftHandle = false + hoveredSegment.isHoveredOnRightHandle = false + hoveredSegment.isHoveredOnBody = false + } + } else { + hoveredSegment.isHovered = true + hoveredSegment.isHoveredOnLeftHandle = area === SegmentArea.LEFT + hoveredSegment.isHoveredOnRightHandle = area === SegmentArea.RIGHT + hoveredSegment.isHoveredOnBody = area === SegmentArea.MIDDLE + set({ + hoveredSegment, + allSegmentsChanged: 1 + previousAllSegmentsChanged, + atLeastOneSegmentChanged: 1 + previousAtLeastOneSegmentChanged + }) + } + } else { + if (previousHoveredSegment) { + previousHoveredSegment.isHovered = false + previousHoveredSegment.isHoveredOnLeftHandle = false + previousHoveredSegment.isHoveredOnRightHandle = false + previousHoveredSegment.isHoveredOnBody = false + set({ + hoveredSegment: undefined, + allSegmentsChanged: 1 + previousAllSegmentsChanged, + atLeastOneSegmentChanged: 1 + previousAtLeastOneSegmentChanged + }) + } else { + // nothing to do + } + } + }, + setEditedSegment: (editedSegment?: TimelineSegment) => { + const { + editedSegment: previousEditedSegment, + allSegmentsChanged: previousAllSegmentsChanged, + atLeastOneSegmentChanged: previousAtLeastOneSegmentChanged + } = get() + + // note: we do all of this in order to avoid useless state updates + if (editedSegment) { + if (previousEditedSegment) { + if (previousEditedSegment.id === editedSegment.id) { + // nothing to do + return + } else { + previousEditedSegment.editionStatus = SegmentEditionStatus.EDITABLE + } + } else { + editedSegment.editionStatus = SegmentEditionStatus.EDITING + set({ + editedSegment, + atLeastOneSegmentChanged: 1 + previousAtLeastOneSegmentChanged, + allSegmentsChanged: 1 + previousAllSegmentsChanged + }) + } + } else { + if (previousEditedSegment) { + previousEditedSegment.editionStatus = SegmentEditionStatus.EDITABLE + set({ + editedSegment: undefined, + atLeastOneSegmentChanged: 1 + previousAtLeastOneSegmentChanged, + allSegmentsChanged: 1 + previousAllSegmentsChanged + }) + } else { + // nothing to do + } + } + }, + setSelectedSegment: ({ + segment, + isSelected, + onlyOneSelectedAtOnce, + }: { + segment?: TimelineSegment + isSelected?: boolean + onlyOneSelectedAtOnce?: boolean + } = { + }) => { + const { + segments, + selectedSegments: previousSelectedSegments, + atLeastOneSegmentChanged: previousAtLeastOneSegmentChanged, + allSegmentsChanged: previousAllSegmentsChanged + } = get() + /* + console.log(`setSelectedSegment() called with:`, { + segment, + isSelected, + onlyOneSelectedAtOnce, + }) + */ + + let newValue = typeof isSelected !== "boolean" + ? (typeof segment?.isSelected === "boolean" ? (!segment.isSelected) : false) + : isSelected + + // console.log('`setSelectedSegment(): new value:', newValue) + + // note: we do all of this in order to avoid useless state updates + if (segment) { + + if (segment.isSelected === newValue) { + + // console.log('`setSelectedSegment(): nothing to do') + + // nothing to do + return + } + + let newSelectedSegments: TimelineSegment[] = previousSelectedSegments + + // if needed we clear any other selected item + if (onlyOneSelectedAtOnce) { + + // console.log('`setSelectedSegment(): unselecting all previous segments') + + segments.forEach(s => { + s.isSelected = false + }) + newSelectedSegments = [] + } + + // console.log('`setSelectedSegment(): assigning new value and propagating changes:', newValue) + + segment.isSelected = newValue + + if (newValue) { + newSelectedSegments = newSelectedSegments.concat(segment) + } else { + newSelectedSegments = newSelectedSegments.filter(s => s.id !== segment.id) + } + set({ + selectedSegments: newSelectedSegments, + atLeastOneSegmentChanged: 1 + previousAtLeastOneSegmentChanged, + allSegmentsChanged: 1 + previousAllSegmentsChanged, + }) + + } else { + + // console.log('`setSelectedSegment(): mass change requested') + + segments.forEach(s => { + s.isSelected = newValue + }) + set({ + selectedSegments: isSelected ? segments : [], + atLeastOneSegmentChanged: 1 + previousAtLeastOneSegmentChanged, + allSegmentsChanged: 1 + previousAllSegmentsChanged, + }) + } + }, + trackSilentChangeInSegment: (segmentId: string) => { + const { silentChangesInSegment, atLeastOneSegmentChanged: previousAtLeastOneSegmentChanged } = get() + set({ + silentChangesInSegment: Object.assign(silentChangesInSegment, { + [segmentId]: 1 + (silentChangesInSegment[segmentId] || 0) + }), + atLeastOneSegmentChanged: 1 + previousAtLeastOneSegmentChanged, + }) + }, + trackSilentChangeInSegments: (segmentIds: string[]) => { + const { silentChangesInSegment, atLeastOneSegmentChanged: previousAtLeastOneSegmentChanged } = get() + + for (const id of segmentIds) { + silentChangesInSegment[id] = 1 + (silentChangesInSegment[id] || 0) + } + set({ + silentChangesInSegment, + atLeastOneSegmentChanged: 1 + previousAtLeastOneSegmentChanged, + }) + }, + setTimelineTheme: (theme: ClapTimelineTheme) => { + set({ theme }) + }, + setTimelineCamera: (timelineCamera?: TimelineCameraImpl) => { + set({ timelineCamera }) + }, + setTimelineControls: (timelineControls?: TimelineControlsImpl) => { + set({ timelineControls }) + }, + setTopBarTimeScale: (topBarTimeScale?: THREE.Group) => { + set({ topBarTimeScale }) + }, + setLeftBarTrackScale: (leftBarTrackScale?: THREE.Group) => { + set({ leftBarTrackScale }) + }, + // used when we move the full-length scroller + setScrollX: (scrollX: number) => { + set({ scrollX }) + }, + handleMouseWheel: ({ deltaX, deltaY }: { deltaX: number, deltaY: number }) => { + const { scrollX, scrollY } = get() + // TODO: compute the limits here, to avoid doing re-renderings for nothing + set({ + scrollX: scrollX + deltaX, + scrollY: scrollY - deltaY, + }) + }, + toggleTrackVisibility: (trackId: number) => { + const { + meta, + tracks, + cellWidth, + defaultSegmentDurationInSteps, + totalDurationInMs, + } = get() + + set({ + ...computeContentSizeMetrics({ + meta, + tracks: tracks.map((t: any) => ( + t.id === trackId + ? { ...t, visible: !t.visible } + : t + )), + cellWidth, + defaultSegmentDurationInSteps, + totalDurationInMs, + }) + }) + }, + setContainerSize: ({ width, height }: { width: number; height: number }) => { + const { width: previousWidth, height: previousHeight } = get() + const changed = + (Math.round(previousWidth) !== Math.round(height)) + || (Math.round(previousHeight) !== Math.round(height)) + if (!changed) { return } + + set({ + width, + height, + resizeStartedAt: performance.now(), + isResizing: true, + /* + + changing the *container* size has absolutely no impact on the content + + ...computeContentSizeMetrics({ + clap, + tracks, + cellWidth, + defaultSegmentDurationInSteps + }) + */ + }) + }, + setTimelineCursor: (timelineCursor?: TimelineCursorImpl) => { + set({ timelineCursor }) + }, + setIsDraggingCursor: (isDraggingCursor: boolean) => { + set({ isDraggingCursor }) + }, + setCursorTimestampAtInMs: (cursorTimestampAtInMs: number = 0) => { + if (cursorTimestampAtInMs !== get().cursorTimestampAtInMs) { + set({ cursorTimestampAtInMs }) + } + }, + setJumpAt: (jumpAt: JumpAt) => { + set({ jumpAt }) + }, + setIsPlaying: (isPlaying: IsPlaying) => { + set({ isPlaying }) + }, + setTogglePlayback: (togglePlayback: TogglePlayback) => { + set({ togglePlayback }) + }, + // this function has an issue, it saves stuff as .txt, which is bad + saveClapAs: async ({ + embedded, + + saveToFilePath, + + showTargetDirPopup = false, + + // some extra text to append to the file name + extraLabel = "" + }: { + // if embedded is true, the file will be larger, as all the content, + // image, video, audio.. + // will be embedded into it (except the last big video) + embedded?: boolean + + saveToFilePath?: string + + // note: the native select picker doesn't work in all browsers (eg. not in Firefox) + // but it's not an issue, in our case we can save using Node/Electron + the cloud + showTargetDirPopup?: boolean + + // some extra text to append to the file name + extraLabel?: string + } = {}) => { + const { getClap } = get() + + const clap = await getClap() + + const blob = await serializeClap(clap) + + // Create an object URL for the compressed clap blob + const objectUrl = URL.createObjectURL(blob); + + // Create an anchor element and force browser download + const anchor = document.createElement("a"); + anchor.href = objectUrl; + anchor.download = saveToFilePath || `${clap.meta.title}${extraLabel}.clap`; + document.body.appendChild(anchor); // Append to the body (could be removed once clicked) + anchor.click(); // Trigger the download + + // Cleanup: revoke the object URL and remove the anchor element + URL.revokeObjectURL(objectUrl); + document.body.removeChild(anchor); + + return objectUrl.length + }, + setSegmentResolver: (segmentResolver: SegmentResolver) => { + set({ segmentResolver }) + }, + resolveSegment: async (segment: TimelineSegment): Promise => { + const { segmentResolver, fitSegmentToAssetDuration } = get() + if (!segmentResolver) { return segment } + + segment = await segmentResolver(segment) + + // after a segment has ben resolved, it is possible that the size + // of its asset changed (eg. a dialogue line longer than the segment's length) + // + // there are multiple ways to solve this, one approach could be to + // just add some more B-roll (more shots) + // + // or we can also extend it, which is the current simple solution + // + // for the other categories, such as MUSIC or SOUND, + // we assume it is okay if they are too short or too long, + // and that we can crop them etc + // + // note that video clips are also concerned: we want them to perfectly fit + if (segment.category === ClapSegmentCategory.DIALOGUE) { + await fitSegmentToAssetDuration(segment) + } else if (segment.category === ClapSegmentCategory.VIDEO) { + await fitSegmentToAssetDuration(segment) + } + + return segment + }, + addSegments: async ({ + segments = [], + startTimeInMs, + track + }: { + segments?: TimelineSegment[] + startTimeInMs?: number + track?: number + }): Promise => { + if (segments?.length) { + const { addSegment } = get() + for (const segment of segments) { + await addSegment({ + segment, + startTimeInMs, + track + }) + } + } + }, + assignTrack: async ({ + segment, + track, + triggerChange, + }: { + segment: ClapSegment + track: number + triggerChange?: boolean + }): Promise => { + const { + meta, + cellWidth, + defaultSegmentDurationInSteps, + totalDurationInMs, + tracks, + defaultPreviewHeight, + defaultCellHeight, + atLeastOneSegmentChanged: previousAtLeastOneSegmentChanged, + allSegmentsChanged: previousAllSegmentsChanged, + } = get() + + segment.track = track + + // add the track if it is missing + if (!tracks[segment.track]) { + const isPreview = + segment.category === ClapSegmentCategory.STORYBOARD || + segment.category === ClapSegmentCategory.VIDEO + + tracks[segment.track] = { + id: segment.track, + // name: `Track ${s.track}`, + name: `${segment.category}`, + isPreview, + height: + isPreview + ? defaultPreviewHeight + : defaultCellHeight, + hue: 0, + occupied: true, + visible: true, + } + } + + if (triggerChange) { + set({ + allSegmentsChanged: previousAllSegmentsChanged + 1, + atLeastOneSegmentChanged: previousAtLeastOneSegmentChanged + 1, + ...computeContentSizeMetrics({ + meta, + tracks, + cellWidth, + defaultSegmentDurationInSteps, + totalDurationInMs, + }), + }) + } + }, + addSegment: async ({ + segment, + startTimeInMs: requestedStartTimeInMs, + track: requestedTrack + }: { + segment: TimelineSegment + startTimeInMs?: number + track?: number + }): Promise => { + // adding a segment is a bit complicated, lot of stuff might have to be updated + const { + meta, + findFreeTrack, + cellWidth, + tracks, + segments: previousSegments, + allSegmentsChanged: previousAllSegmentsChanged, + atLeastOneSegmentChanged: previousAtLeastOneSegmentChanged, + totalDurationInMs: previousTotalDurationInMs, + defaultSegmentDurationInSteps, + defaultPreviewHeight, + defaultCellHeight, + assignTrack, + } = get() + + + // note: the requestedTrack might not be empty + const segmentDuration = segment.endTimeInMs - segment.startTimeInMs + + const startTimeInMs = isValidNumber(requestedStartTimeInMs) ? requestedStartTimeInMs! : segment.startTimeInMs + + const endTimeInMs = startTimeInMs + segmentDuration + + // for now let's do something simple: to always search for an available track + const availableTrack = isValidNumber(requestedTrack) ? requestedTrack! : findFreeTrack({ + startTimeInMs, + endTimeInMs + }) + + /* + console.log("availableTrack:", { + requestedStartTimeInMs, + segmentDuration, + availableTrack, + requestedTrack, + startTimeInMs, + endTimeInMs + }) + */ + + // we just make sure to sanitize it before adding it + segment = await clapSegmentToTimelineSegment(segment) + + // also, we assume that we are adding a segment in a place where it's visible + // (if we are wrong don't worry, our visibility detector will fix it anyway) + segment.visibility = SegmentVisibility.VISIBLE + + assignTrack({ + segment, + track: availableTrack, + + // we don't want to trigger a state change just yet + triggerChange: false, + }) + + + // we assume that the provided segment is valid, with a unique UUID + + // then we need to update everything + + // ok so, I'm not a big fan of doing this, + // officially the order doesn't matter in the previousSegments array + // this means we don't have FOR LOOPs with a BREAK etc + // still, I think we can improve our performance one day by storing them + // on a temporally sorted tree + const segments = previousSegments.concat(segment) + + const totalDurationInMs = + segment.endTimeInMs > previousTotalDurationInMs + ? segment.endTimeInMs + : previousTotalDurationInMs + + const newMeta = { + ...meta, + durationInMs: totalDurationInMs + } + + set({ + meta: newMeta, + segments, + allSegmentsChanged: previousAllSegmentsChanged + 1, + atLeastOneSegmentChanged: previousAtLeastOneSegmentChanged + 1, + totalDurationInMs, + ...computeContentSizeMetrics({ + meta: newMeta, + tracks, + cellWidth, + defaultSegmentDurationInSteps, + totalDurationInMs, + }) + }) + }, + findFreeTrack: ({ + startTimeInMs, + endTimeInMs + }: { + startTimeInMs?: number + endTimeInMs?: number + }): number => { + const { segments } = get() + return findFreeTrack({ segments, startTimeInMs, endTimeInMs }) + }, + + // resize and move the end of a segment, as well as the segment after it + fitSegmentToAssetDuration: async (segment: TimelineSegment, requestedDurationInMs?: number): Promise => { + + const { + meta, + tracks, + cellWidth, + defaultSegmentDurationInSteps, + segments, + atLeastOneSegmentChanged: previousAtLeastOneSegmentChanged, + allSegmentsChanged: previousAllSegmentsChanged, + totalDurationInMs: previousTotalDurationInMs, + findFreeTrack, + assignTrack + } = get() + + const durationInMs: number = + typeof requestedDurationInMs === "number" && isFinite(requestedDurationInMs) && !isNaN(requestedDurationInMs) + ? requestedDurationInMs + : segment.assetDurationInMs + + + // trivial case: nothing to do! + const segmentDurationInMs = segment.endTimeInMs - segment.startTimeInMs + if ( + durationInMs === 0 + || + segmentDurationInMs === durationInMs + ) { + return + } + + // let's set some limits eg. at least 1 sec, I think this is reasonable + const minimumLengthInSteps = 2 + const minimumLengthInMs = minimumLengthInSteps * DEFAULT_DURATION_IN_MS_PER_STEP + + // positive if new duration is longer, + // negative if shorter + const timeDifferenceInMs = durationInMs - segmentDurationInMs + + // setup some limits + const newSegmentDurationInMs = Math.max( + minimumLengthInMs, + segmentDurationInMs + timeDifferenceInMs + ) + + // ok, well, there is nothing to change actually + if (segmentDurationInMs === newSegmentDurationInMs) { return } + + + // positive if new duration is longer, + // negative if shorter + const newTimeDifferenceInMs = newSegmentDurationInMs - segmentDurationInMs + + const startTimeInMs = segment.startTimeInMs + const endTimeInMs = segment.endTimeInMs + // const newEndTimeInMs = endTimeInMs + newTimeDifferenceInMs + + let totalDurationInMs = previousTotalDurationInMs + + const referenceSegmentIsMusicOrSound = + segment.category === ClapSegmentCategory.MUSIC + || segment.category === ClapSegmentCategory.SOUND + + let segmentsToDelete: string[] = [] + + for (const s of segments) { + // our strategy will be different depending on the type of segment + // basically, if it's a sound or a music, we don't need to cut the segment, + // and we don't have to extend the current shot. + // instead, we can let it go outerbound, although this creates 2 problems: + // 1. overlapping with another music/sound (on the same track or not) + // -> fix is easy, we can resize or delete completely the other one + // 2. collision with an item on the same track (eg. of a different type) + // -> fix is annoying, for now the a quick solution is to put the segment + // onto its own free track + const currentSegmentIsMusicOrSound = + s.category === ClapSegmentCategory.MUSIC + || s.category === ClapSegmentCategory.SOUND + + const isSameCategoryAsReferenceSegment = s.category === segment.category + + const isSamePromptAsReferenceSegment = s.prompt === segment.prompt + + + if (referenceSegmentIsMusicOrSound) { + + if (isSameCategoryAsReferenceSegment && isSamePromptAsReferenceSegment) { + if (s.endTimeInMs <= endTimeInMs) { + // we delete + console.log("TODO JULIAN: DELETE SEGMENT", s) + // segmentsToDelete.push(s.id) + // note: + } else if (s.startTimeInMs < endTimeInMs) { + // we resize + console.log("TODO JULIAN: resize segment") + // s.startTimeInMs = endTimeInMs + } + } + // independently, we run our collision detector + // it is important at this stage to take into account any change, + // eg. if we've already deleted segment `s` there is no need to + // assign a new free track + const isSameTrackAsReferenceSegment = s.track === segment.track + + if (isSameTrackAsReferenceSegment) { + // if we have a collision, there is currently no way around it we need to create a new track + if (!(s.endTimeInMs <= startTimeInMs || s.startTimeInMs >= endTimeInMs)) { + const newTrack = findFreeTrack({ startTimeInMs, endTimeInMs }) + //console.log(`ASSIGN NEW TRACK (${newTrack}) TO SEGMENT`, s) + + assignTrack({ + segment, + track: newTrack, + + // we don't want to trigger a state change + triggerChange: false, + }) + + } + + } + } else { + // this is a dialogue or a video, we can apply our regular strategy + if (endTimeInMs <= s.startTimeInMs) { + s.startTimeInMs += newTimeDifferenceInMs + } + if (endTimeInMs <= s.endTimeInMs) { + s.endTimeInMs += newTimeDifferenceInMs + } + + // also need to update the total duration + if (s.endTimeInMs > totalDurationInMs) { + totalDurationInMs = s.endTimeInMs + } + } + } + //console.log(`TODO Julian: stretched segments (overlapping segments) should be re-generated`) + + set({ + segments, + allSegmentsChanged: previousAllSegmentsChanged + 1, + atLeastOneSegmentChanged: previousAtLeastOneSegmentChanged + 1, + ...computeContentSizeMetrics({ + meta, + tracks, + cellWidth, + defaultSegmentDurationInSteps, + totalDurationInMs, + }) + }) + }, + deleteSegments: (ids: string[]): void => { + const { + segments: previousSegments, + allSegmentsChanged, + atLeastOneSegmentChanged, + silentChangesInSegment, + } = get() + + const deletables = new Set(ids) + + const newSegments = previousSegments.filter(({ id }) => { + silentChangesInSegment[id] = 1 + (silentChangesInSegment[id] || 0) + return !deletables.has(id) + }) + + set({ + segments: newSegments, + allSegmentsChanged: 1 + allSegmentsChanged, + atLeastOneSegmentChanged: 1 + atLeastOneSegmentChanged, + silentChangesInSegment, + }) + }, + addEntities: async (newEntities: ClapEntity[]) => { + const { + entities: previousEntities, + entityIndex: previousentityIndex, + entitiesChanged: previousEntitiesChanged, + } = get() + + + let somethingChanged = false + + for (const newEntity of newEntities) { + if (previousentityIndex[newEntity.id]) { + // entity already exists + continue + } + previousEntities.push(newEntity) + previousentityIndex[newEntity.id] = newEntity + somethingChanged = true + } + + if (somethingChanged) { + set({ + entities: previousEntities, + entityIndex: previousentityIndex, + entitiesChanged: previousEntitiesChanged + 1, + }) + } + }, + updateEntities: async (newEntities: ClapEntity[]) => { + const { + entities: previousEntities, + entityIndex: previousentityIndex, + entitiesChanged: previousEntitiesChanged, + } = get() + + let somethingChanged = false + for (const newEntity of newEntities) { + const entity = previousentityIndex[newEntity.id] + if (!entity) { + // entity doesn't exist + continue + } + Object.assign(entity, newEntity) + + // to optimize things, we could check if the assign really did change something + somethingChanged = true + } + + if (somethingChanged) { + set({ + entities: previousEntities, + entityIndex: previousentityIndex, + entitiesChanged: previousEntitiesChanged + 1, + }) + } + }, + deleteEntities: async (entitiesToDelete: (ClapEntity|string)[]) => { + const { + entities: previousEntities, + entityIndex: previousentityIndex, + entitiesChanged: previousEntitiesChanged, + } = get() + + let idsToDelete: string[] = [] + + for (const newEntityOrId of entitiesToDelete) { + const id = typeof newEntityOrId === "string" ? newEntityOrId : newEntityOrId.id + delete previousentityIndex[id] + idsToDelete.push(id) + } + + if (idsToDelete.length) { + set({ + entities: previousEntities.filter(e => !idsToDelete.includes(e.id)), + entityIndex: previousentityIndex, + entitiesChanged: previousEntitiesChanged + 1, + }) + } + } +} +)) diff --git a/packages/timeline/src/hooks/useVerticalGridLines.ts b/packages/timeline/src/hooks/useVerticalGridLines.ts new file mode 100644 index 0000000000000000000000000000000000000000..2d85198b680e2f5870d7440360b6d0c42a00da7c --- /dev/null +++ b/packages/timeline/src/hooks/useVerticalGridLines.ts @@ -0,0 +1,38 @@ +import { useEffect, useState } from "react" +import * as THREE from "three" + +import { useTimeline } from "./useTimeline" +import { NB_MAX_SHOTS } from "@/constants/grid" + +export const useVerticalGridLines = () => { + const cellWidth = useTimeline(s => s.cellWidth) + const contentHeight = useTimeline(s => s.contentHeight) + const tracks = useTimeline(s => s.tracks) + const [gridlines, setGridLines] = useState([] as THREE.BufferGeometry[]); + + const nbMaxShots = useTimeline(s => s.nbMaxShots) + + useEffect(() => { + + const thisLines = [] as THREE.BufferGeometry[]; + + for (let i = 0; i < nbMaxShots; i++) { + const verticalLinePoints = [ + new THREE.Vector3(i * cellWidth, 0, 0), + new THREE.Vector3(i * cellWidth, -contentHeight, 0) + ]; + const verticalLineGeometry = new THREE.BufferGeometry().setFromPoints(verticalLinePoints); + + thisLines.push(verticalLineGeometry); + } + + setGridLines(thisLines); + }, [ + contentHeight, + cellWidth, + nbMaxShots, + JSON.stringify(tracks.map((t: any) => `${t.visible}_${t.height}`)) + ]); + + return gridlines; +}; \ No newline at end of file diff --git a/packages/timeline/src/index.tsx b/packages/timeline/src/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..7e6cb1c699f1ee57325457b74094c63a4e83e75f --- /dev/null +++ b/packages/timeline/src/index.tsx @@ -0,0 +1,90 @@ +export { + TimelineControls, + HorizontalScroller, + VerticalScroller, + Timeline, + TopBarTimeScale, + Cells, + Grid, + Cell, + ImageCell, + VideoCell, + TextCell, + type SpecializedCellProps, + type JumpAt +} from "./components" + +export { + DEFAULT_MIN_ZOOM, + DEFAULT_MAX_ZOOM, + DEFAULT_ZOOM_SPEED, + DEFAULT_ZOOM_DAMPING_FACTOR, + DEFAULT_SHOW_FPS, + DEFAULT_FRAMELOOP, + DEFAULT_THEMES, + DEFAULT_DURATION_IN_MS_PER_STEP, + DEFAULT_NB_TRACKS, + DEFAULT_COLUMNS_PER_SLICE, + PROMPT_STEP_HEIGHT_IN_PX, + PREVIEW_STEP_HEIGHT_IN_PX, + NB_MAX_SHOTS, + pastel, + segmentVisibilityPriority, + leftBarTrackScaleWidth +} from "./constants" + +export { + useAxis, + useVerticalGridLines, + useHorizontalGridLines, + useTimeline, + useSegmentChanges, + useSegmentLoader, +} from "./hooks" + +export { + clamp, + clapSegmentToTimelineSegment, + cn, + debounceAsync, + debounceSync, + findFreeTrack, + formatTimestamp, + getAudioBuffer, + getDefaultState, + getFinalVideo, + getWebGLCharWidth, + getWebGLTextWidth, + clampWebGLText, + clampWebGLTextNaive, + hslToHex, + parseRenderingStrategy, + readFileAsArrayBuffer, + removeFinalVideosAndConvertToTimelineSegments, + similar, + sleep, + sliceSegments, + throttle, + timelineSegmentToClapSegment +} from "./utils" + +export { + SegmentVisibility, + SegmentEditionStatus, + BrowserOnlySegmentData, + TimelineSegment, + ContentSizeMetrics, + RenderedCell, + TimelineStore, + TimelineStoreState, + TimelineStoreModifiers, + ClapTimelineTheme, + ClapSegmentCategoryHSL, + ClapSegmentCategoryColors, + ClapSegmentColorScheme, + RenderingStrategy, + type SegmentResolver, +} from "./types" + +export { ClapTimeline } from "./ClapTimeline" + diff --git a/packages/timeline/src/types/grid.ts b/packages/timeline/src/types/grid.ts new file mode 100644 index 0000000000000000000000000000000000000000..2cb6208c2ff22de299cfc4fd0d9dda2ec7ef0279 --- /dev/null +++ b/packages/timeline/src/types/grid.ts @@ -0,0 +1,8 @@ +import { Vector3 } from "three" + +export type RenderedCell = { + position: Vector3 + width: number + height: number + color: string +} \ No newline at end of file diff --git a/packages/timeline/src/types/index.ts b/packages/timeline/src/types/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..658f23f85dc525d6fbe08f9493ecc9203c3d276a --- /dev/null +++ b/packages/timeline/src/types/index.ts @@ -0,0 +1,27 @@ + +export { + RenderedCell +} from "./grid" + +export { + SegmentVisibility, + SegmentEditionStatus, + BrowserOnlySegmentData, + TimelineSegment, + ContentSizeMetrics, + TimelineStore, + TimelineStoreState, + TimelineStoreModifiers +} from "./timeline" + +export { + ClapTimelineTheme, + ClapSegmentCategoryHSL, + ClapSegmentCategoryColors, + ClapSegmentColorScheme +} from "./theme" + +export { + RenderingStrategy, + SegmentResolver +} from "./rendering" \ No newline at end of file diff --git a/packages/timeline/src/types/rendering.ts b/packages/timeline/src/types/rendering.ts new file mode 100644 index 0000000000000000000000000000000000000000..58ec167b918f36670e9653e3e2a5f8a61ba9c4bf --- /dev/null +++ b/packages/timeline/src/types/rendering.ts @@ -0,0 +1,35 @@ +import { ClapSegmentCategory } from "@aitube/clap" +import { TimelineSegment } from "./timeline" + +export enum RenderingStrategy { + + // render assets when the user asks for it (could be a click or mouse hover) + ON_DEMAND = "ON_DEMAND", + + // render assets currently visible on screen, never render invisible ones + ON_SCREEN_ONLY = "ON_SCREEN_ONLY", + + // render assets visible on screen in priority, + // then pre-render a few of the surrounding assets (but not the whole set) + ON_SCREEN_THEN_SURROUNDING = "ON_SCREEN_THEN_SURROUNDING", + + + // render assets visible on screen in priority, + // then pre-render *ALL* the remaining project's assets + // so yeah if you have 3000 storyboards, it will render that many ($$$) + // (note: there is a setting to cap the number of parallel renderings) + // + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // !! this is hardcore! only GPU-rich people shoud use this feature! !! + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ON_SCREEN_THEN_ALL = "ON_SCREEN_THEN_ALL", +} + +export type SegmentResolver = (segment: TimelineSegment) => Promise + +export type RenderableSegmentCategory = + | ClapSegmentCategory.VIDEO + | ClapSegmentCategory.STORYBOARD + | ClapSegmentCategory.DIALOGUE + | ClapSegmentCategory.SOUND + | ClapSegmentCategory.MUSIC \ No newline at end of file diff --git a/packages/timeline/src/types/theme.ts b/packages/timeline/src/types/theme.ts new file mode 100644 index 0000000000000000000000000000000000000000..cbf1e3a165dba65113892c6357c823e068fa8296 --- /dev/null +++ b/packages/timeline/src/types/theme.ts @@ -0,0 +1,55 @@ +import { ClapSegmentCategory } from "@aitube/clap" + +export type ClapSegmentCategoryHSL = { + hue: number + saturation: number + lightness: number +} + +export type ClapSegmentCategoryColors = Record + +export type ClapTimelineTheme = { + topBarTimeScale: { + backgroundColor: string + textColor: string + lineColor: string + } + leftBarTrackScale: { + backgroundColor: string + textColor: string + lineColor: string + } + grid: { + backgroundColor: string + } + cell: { + categoryColors: ClapSegmentCategoryColors + + waveform: { + lineSpacing: number + gradientStart: number + gradientEnd: number + } + } + playbackCursor: { + lineColor: string + } +} + +export type ClapSegmentColorScheme = { + baseHue: number + baseSaturation: number + baseLightness: number + + backgroundColor: string + backgroundColorHover: string + backgroundColorDisabled: string + foregroundColor: string + borderColor: string + textColor: string + textColorHover: string + + waveformLineSpacing: number + waveformGradientStart: number + waveformGradientEnd: number +} \ No newline at end of file diff --git a/packages/timeline/src/types/timeline.ts b/packages/timeline/src/types/timeline.ts new file mode 100644 index 0000000000000000000000000000000000000000..d47dcbd1e7d4fb1a84944fd6582b9f61b4c8e162 --- /dev/null +++ b/packages/timeline/src/types/timeline.ts @@ -0,0 +1,370 @@ +import * as THREE from "three" +import { ClapEntity, ClapMeta, ClapProject, ClapScene, ClapSegment, ClapTracks } from "@aitube/clap" + +import { ClapSegmentColorScheme, ClapTimelineTheme } from "./theme" +import { TimelineControlsImpl } from "@/components/controls/types" +import { TimelineCameraImpl } from "@/components/camera/types" +import { IsPlaying, JumpAt, TimelineCursorImpl, TogglePlayback } from "@/components/timeline/types" +import { SegmentResolver } from "./rendering" + +export enum SegmentVisibility { + // the segment is visible, and the user explicitly requested to render it before the others + DEMANDED = "DEMANDED", + + // TODO: add some implicit intermediary priority options + // such as SELECTED, HOVERED.. + + // the segment (or at least a portion of it) is currently visible in the sliding window + VISIBLE = "VISIBLE", + + // the segment is hidden, but not too far from the sliding window + BUFFERED = "BUFFERED", + + // fully hidden, far from the sliding window + HIDDEN = "HIDDEN" +} + + +export enum SegmentEditionStatus { + // the segment is frozen and read-only and cannot be edited + // this is useful if you want a track to be read-only + LOCKED = "LOCKED", + + // the segment is editable and cannot be edited + EDITABLE = "EDITABLE", + + // the segment is being resized + RESIZING = "RESIZING", + + // the segment is being dragged around + DRAGGING = "DRAGGING", + + // the segment's is being edited (eg. in the edit pop-over) + EDITING = "EDITING", +} + +export enum SegmentArea { + LEFT = 'LEFT', + RIGHT = 'RIGHT', + MIDDLE = 'MIDLE' +} + +// some data can only exist inside a browser session (eg. AudioBuffer) +// or at least data that only make sense on client side +// we could put things like a mouse hover or selected state in here +// or simply large, recursive elements (like the scene) +export type BrowserOnlySegmentData = { + + // used to give more context to the LLM, so it can have the full text of the scene + scene?: ClapScene + + // used for convenience, to easily match the script editor with segments + startAtLine?: number + endAtLine?: number + + audioBuffer?: AudioBuffer + + visibility: SegmentVisibility + + // Cache for textures + textures: Record + + /** + * the following fields have been added to this type only very recently + * and their implementation is not finished, + * so they may not contain the value you wish for. + * + * please don't rely on them just yet. + * + * Moreover they will be undefined by default, so you need + * const isSelected = rs.isSelected || false + * const editionStatus = rs.editionStatus || SegmentEditionStatus.EDITABLE + */ + // of the segment is currently selected by the user + isSelected: boolean + + // if the segment is hovered by the mouse (anywhere) + // note: if the mouse is pressed, this will also trigger this to TRUE + isHovered: boolean + + // if the segment's body is hovered by the mouse + isHoveredOnBody: boolean + + // if the segment's left handle is hovered by the mouse + isHoveredOnLeftHandle: boolean + + // if the segment's right handle is hovered by the mouse + isHoveredOnRightHandle: boolean + + // if the segment's body is being grabbed by the mouse + isGrabbedOnBody: boolean + + // if the segment's left handle is being grabbed by the mouse + isGrabbedOnLeftHandle: boolean + + // if the segment's right handle is being grabbed by the mouse + isGrabbedOnRightHandle: boolean + + // if the segment is currently crossed by the timeline cursor + isActive: boolean + + // if the segment is currently being played + isPlaying: boolean + + editionStatus: SegmentEditionStatus +} + +export type TimelineSegment = ClapSegment & BrowserOnlySegmentData + +export type ContentSizeMetrics = { + nbMaxShots: number + nbMaxTracks: number + nbIdentifiedTracks: number + contentWidth: number + contentHeight: number + tracks: ClapTracks + cellWidth: number + defaultCellHeight: number + defaultSegmentDurationInSteps: number + defaultSegmentLengthInPixels: number + defaultMediaRatio: number + defaultPreviewHeight: number +} + + + +export type TimelineStoreProjectState = { + meta: ClapMeta + scenes: ClapScene[] + + segments: TimelineSegment[] + + totalDurationInMs: number + loadedSegments: TimelineSegment[] + visibleSegments: TimelineSegment[] + nbIdentifiedTracks: number + lineNumberToMentionedSegments: Record + + entities: ClapEntity[] + entityIndex: Record + entitiesChanged: number + + isEmpty: boolean + isLoading: boolean + + // -- metrics computed by computeContentSizeMetrics -- + nbMaxShots: number + nbMaxTracks: number + contentWidth: number + contentHeight: number + tracks: ClapTracks + cellWidth: number + defaultCellHeight: number + defaultSegmentDurationInSteps: number + defaultSegmentLengthInPixels: number + defaultMediaRatio: number + defaultPreviewHeight: number + // ------------------------------------------------- + + minHorizontalZoomLevel: number + maxHorizontalZoomLevel: number + originalHorizontalZoomLevel: number + + initialized: boolean + timeout: NodeJS.Timeout + + typicalSegmentDurationInSteps: number + + // note: this is a mirror value of + // it might change rapidly (many times per seconds), so use with care! + currentZoomLevel: number + + // for developer convenience, the information about hovered, edited, selected.. + // is both present inside each segment and also aliased here, for fast access + hoveredSegment?: TimelineSegment + editedSegment?: TimelineSegment + selectedSegments: TimelineSegment[] + + allSegmentsChanged: number + atLeastOneSegmentChanged: number + + // the purpose is to allow an external component + // to modify the segments in-line, and then trigger a redraw + silentChangesInSegment: Record + + isDraggingCursor: boolean + + // used to track current camera position, at zoom level 1.0 + scrollX: number + scrollY: number + + // used to determine how long it has been since we touch the scroll + // we use this information to render the grid faster, by disabling all text + // until a given debouncing time has elapsed + resizeStartedAt: number + isResizing: boolean + + // the final video, if available + finalVideo?: TimelineSegment + + // position of the current timestamp + cursorTimestampAtInMs: number +} + + +export type TimelineStorePreferencesState = { + canvas?: HTMLCanvasElement + + // used to track the timeline state + // this helps informing parent app user + // that the timeline has been recreated inside the React tree for instance + isReady: boolean + + // container width and height + width: number + height: number + + theme: ClapTimelineTheme + + /** + * The timeline camera + * + * Note: there will be no update of this value in case the camera settings have changed + */ + timelineCamera?: TimelineCameraImpl + + /** + * The timeline controls + * + * Note: there will be no update of this value in case the controls settings have changed + */ + timelineControls?: TimelineControlsImpl + + // ref to the cursor element + timelineCursor?: TimelineCursorImpl + + topBarTimeScale?: THREE.Group + leftBarTrackScale?: THREE.Group + + // those can be overridden + segmentResolver: SegmentResolver + jumpAt: JumpAt + isPlaying: IsPlaying + togglePlayback: TogglePlayback +} + +export type TimelineStoreState = TimelineStoreProjectState & TimelineStorePreferencesState + + +export type TimelineStoreModifiers = { + setCanvas: (canvas?: HTMLCanvasElement) => void + clear: () => void + setClap: (clap?: ClapProject) => Promise + getClap: () => Promise + setHorizontalZoomLevel: (newHorizontalZoomLevel: number) => void + setSegments: (segments?: TimelineSegment[]) => void + setLoadedSegments: (loadedSegments?: TimelineSegment[]) => void + setVisibleSegments: (visibleSegments?: TimelineSegment[]) => void + getCellHeight: (trackNumber?: number) => number + getVerticalCellPosition: (start: number, end: number) => number + getSegmentColorScheme: (segment: TimelineSegment) => ClapSegmentColorScheme + setHoveredSegment: (params?: { + hoveredSegment?: TimelineSegment + area?: SegmentArea + }) => void + setEditedSegment: (editedSegment?: TimelineSegment) => void + setSelectedSegment: (params?: { + segment?: TimelineSegment + isSelected?: boolean + onlyOneSelectedAtOnce?: boolean + }) => void + + // the purpose of those functions is to allow an external component + // to modify the segments in-line, and then trigger a redraw + trackSilentChangeInSegment: (segmentId: string) => void + trackSilentChangeInSegments: (segmentIds: string[]) => void + + setTimelineTheme: (theme: ClapTimelineTheme) => void + setTimelineCamera: (timelineCamera?: TimelineCameraImpl) => void + setTimelineControls: (timelineControls?: TimelineControlsImpl) => void + setTopBarTimeScale: (topBarTimeScale?: THREE.Group) => void + setLeftBarTrackScale: (leftBarTrackScale?: THREE.Group) => void + setScrollX: (scrollX: number) => void + handleMouseWheel: ({ deltaX, deltaY }: { deltaX: number; deltaY: number }) => void + toggleTrackVisibility: (trackId: number) => void + setContainerSize: ({ width, height }: { width: number; height: number }) => void + setTimelineCursor: (timelineCursor?: TimelineCursorImpl) => void + setIsDraggingCursor: (isDraggingCursor: boolean) => void + setCursorTimestampAtInMs: (cursorTimestampAtInMs?: number) => void + setJumpAt: (jumpAt: JumpAt) => void + setIsPlaying: (isPlaying: IsPlaying) => void + setTogglePlayback: (togglePlayback: TogglePlayback) => void + saveClapAs: (params: { + // if embedded is true, the file will be larger, as all the content, + // image, video, audio.. + // will be embedded into it (except the last big video) + embedded?: boolean + + saveToFilePath?: string + + // note: the native select picker doesn't work in all browsers (eg. not in Firefox) + // but it's not an issue, in our case we can save using Node/Electron + the cloud + showTargetDirPopup?: boolean + + // some extra text to append to the file name + extraLabel?: string + }) => Promise + setSegmentResolver: (segmentResolver: SegmentResolver) => void + resolveSegment: (segment: TimelineSegment) => Promise + addSegments: ({ + segments, + startTimeInMs, + track, + }: { + segments?: TimelineSegment[] + startTimeInMs?: number + track?: number + }) => Promise + assignTrack: ({ + segment, + track, + triggerChange, + }: { + segment: TimelineSegment + track: number + triggerChange?: boolean + }) => Promise + addSegment: ({ + segment, + startTimeInMs, + track, + }: { + segment: TimelineSegment + startTimeInMs?: number + track?: number +}) => Promise + + /** + * Find an available free track + * + * @param params + * @returns + */ + findFreeTrack: (params: { startTimeInMs?: number; endTimeInMs?: number }) => number + + + fitSegmentToAssetDuration: (segment: TimelineSegment, durationInMs?: number) => Promise + + /** + * Delete segments from the + * @param ids + * @returns + */ + deleteSegments: (ids: string[]) => void + + addEntities: (entities: ClapEntity[]) => Promise + updateEntities: (entities: ClapEntity[]) => Promise + deleteEntities: (entities: (ClapEntity|string)[]) => Promise +} + +export type TimelineStore = TimelineStoreState & TimelineStoreModifiers diff --git a/packages/timeline/src/utils/clamp.ts b/packages/timeline/src/utils/clamp.ts new file mode 100644 index 0000000000000000000000000000000000000000..2522547881df94df826db3ecc293a7aa5385501e --- /dev/null +++ b/packages/timeline/src/utils/clamp.ts @@ -0,0 +1,3 @@ +export function clamp(value: number, min: number, max: number) { + return Math.max(min, Math.min(max, value)) +} \ No newline at end of file diff --git a/packages/timeline/src/utils/clapSegmentToTimelineSegment.ts b/packages/timeline/src/utils/clapSegmentToTimelineSegment.ts new file mode 100644 index 0000000000000000000000000000000000000000..20e9e29bca769d9ac724e2a4704060f9185c7a05 --- /dev/null +++ b/packages/timeline/src/utils/clapSegmentToTimelineSegment.ts @@ -0,0 +1,48 @@ +import { ClapOutputType, ClapSegment } from "@aitube/clap" + +import { SegmentEditionStatus, SegmentVisibility, TimelineSegment } from "@/types" +import { getAudioBuffer } from "./getAudioBuffer" + +export async function clapSegmentToTimelineSegment(clapSegment: ClapSegment): Promise { + + const segment = clapSegment as TimelineSegment + + if (!segment.visibility) { segment.visibility = SegmentVisibility.HIDDEN } + + if (!segment.textures) { segment.textures = {} } + + if (typeof segment.isSelected !== "boolean") { segment.isSelected = false } + + if (typeof segment.isHovered !== "boolean") { segment.isHovered = false } + + if (typeof segment.isActive !== "boolean") { segment.isActive = false } + + if (typeof segment.isPlaying !== "boolean") { segment.isPlaying = false } + + if (typeof segment.isHoveredOnBody !== "boolean") { segment.isHoveredOnBody = false } + + if (typeof segment.isHoveredOnLeftHandle !== "boolean") { segment.isHoveredOnLeftHandle = false } + + if (typeof segment.isHoveredOnRightHandle !== "boolean") { segment.isHoveredOnRightHandle = false } + + if (typeof segment.isGrabbedOnBody !== "boolean") { segment.isGrabbedOnBody = false } + + if (typeof segment.isGrabbedOnLeftHandle !== "boolean") { segment.isGrabbedOnLeftHandle = false } + + if (typeof segment.isGrabbedOnRightHandle !== "boolean") { segment.isGrabbedOnRightHandle = false } + + if (!segment.editionStatus) { segment.editionStatus = SegmentEditionStatus.EDITABLE } + + + if (!segment.audioBuffer) { + if (segment.outputType === ClapOutputType.AUDIO) { + try { + segment.audioBuffer = await getAudioBuffer(segment.assetUrl) + } catch (err) { + console.error(`failed to load the audio file: ${err}`) + } + } + } + + return segment +} \ No newline at end of file diff --git a/packages/timeline/src/utils/cn.ts b/packages/timeline/src/utils/cn.ts new file mode 100644 index 0000000000000000000000000000000000000000..ec79801fe9cdd7711f6dbef26678a134c634a8be --- /dev/null +++ b/packages/timeline/src/utils/cn.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/packages/timeline/src/utils/debounceAsync.ts b/packages/timeline/src/utils/debounceAsync.ts new file mode 100644 index 0000000000000000000000000000000000000000..355900fdb214d96159995d4a25b8b4c4d5a12db9 --- /dev/null +++ b/packages/timeline/src/utils/debounceAsync.ts @@ -0,0 +1,66 @@ +/* + +Here's how you can use the `debounceAsync` function: + +```typescript +async function fetchData(query: string): Promise { + // Simulating an API call + return new Promise((resolve) => { + setTimeout(() => { + resolve(`Results for ${query}`); + }, 500); + }); +} + +const debouncedFetchData = debounceAsync(fetchData, 300); + +(async () => { + try { + console.log(await debouncedFetchData("query 1")); // This will be ignored + console.log(await debouncedFetchData("query 2")); // This will be ignored + console.log(await debouncedFetchData("query 3")); // This will return "Results for query 3" + } catch (error) { + console.error(error); + } +})(); +``` + +The `debounceAsync` function takes a Promise-based function `func` and a `wait` time as its arguments. +It returns a debounced version of the given function that, when called multiple times within the specified wait time, will only execute the last call. +*/ + +type DebouncedFunction = ((...args: T) => R) & { + clear: () => void +} + +export function debounceAsync( + func: (...args: T) => Promise, + wait: number +): DebouncedFunction> { + let timeout: NodeJS.Timeout | undefined + + const debounced = (...args: T) => { + return new Promise((resolve, reject) => { + if (timeout) { + clearTimeout(timeout) + } + + timeout = setTimeout(async () => { + try { + const result = await func(...args) + resolve(result) + } catch (error) { + reject(error) + } + }, wait) as any + }) + } + + debounced.clear = () => { + if (timeout) { + clearTimeout(timeout) + } + } + + return debounced +} \ No newline at end of file diff --git a/packages/timeline/src/utils/debounceSync.ts b/packages/timeline/src/utils/debounceSync.ts new file mode 100644 index 0000000000000000000000000000000000000000..0514a72d71bb5384ff8d35f62db77eb12549422c --- /dev/null +++ b/packages/timeline/src/utils/debounceSync.ts @@ -0,0 +1,59 @@ +type DebouncedFunctionSync = ((...args: T) => R) & { + clear: () => void +} + +/** + * Example usage: + * ```typescript + * function fetchDataSync(query: string): string { + * return `Results for ${query}`; + * } + * + * const debouncedFetchDataSync = debounceSync(fetchDataSync, 300); + * + * try { + * console.log(debouncedFetchDataSync("query 1")); // This will be ignored + * console.log(debouncedFetchDataSync("query 2")); // This will be ignored + * console.log(debouncedFetchDataSync("query 3")); // This will return "Results for query 3" + * } catch (error) { + * console.error(error); + * } + * ``` + * + * Note that the synchronous version of the debounce function will return + * the result of the last function call or `undefined` if the function was + * not called within the specified wait time. You should also be aware that + * this synchronous version may cause blocking if the debounced function + * takes a long time to execute. + * + * @param func + * @param wait + * @returns + */ +export function debounceSync( + func: (...args: T) => R, + wait: number +): DebouncedFunctionSync { + let timeout: NodeJS.Timeout | undefined + + const debounced = (...args: T): R | undefined => { + if (timeout) { + clearTimeout(timeout) + } + + let result: R | undefined + timeout = setTimeout(() => { + result = func(...args) + }, wait) as any + + return result + } + + debounced.clear = () => { + if (timeout) { + clearTimeout(timeout) + } + } + + return debounced +} \ No newline at end of file diff --git a/packages/timeline/src/utils/findFreeTrack.ts b/packages/timeline/src/utils/findFreeTrack.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a8a4564907b184e7fdb14f4f09755068ab016fe --- /dev/null +++ b/packages/timeline/src/utils/findFreeTrack.ts @@ -0,0 +1,53 @@ +import { ClapSegment, ClapSegmentFilteringMode, filterSegmentsWithinRange } from "@aitube/clap" + +import { DEFAULT_NB_TRACKS } from "@/constants" + +// search in an array of segment for the first available track, within a given range +export function findFreeTrack({ + segments = [], + startTimeInMs = 0, + endTimeInMs = Number.MAX_SAFE_INTEGER, +}: { + segments: ClapSegment[] + startTimeInMs?: number + endTimeInMs?: number +}): number { + // console.log("findFreeTrack(): segments:", segments) + + // identify any occurence of a segment being in our desired range + const collisions: ClapSegment[] = filterSegmentsWithinRange( + ClapSegmentFilteringMode.ANY, + startTimeInMs, + endTimeInMs, + segments + ) + + // console.log("findFreeTrack(): collisions:", collisions) + + const MIN_TRACK_NUMBER = 1 + + // trivial case: no collision! + if (!collisions.length) { + return MIN_TRACK_NUMBER // let's assign the uppermost track by default + } + + // identify all the used tracks (note: some tracks might be empty) + const occupiedTracks: number[] = Object.keys( + collisions.reduce((acc, segment) => ({ + ...acc, + [segment.track]: true + }), {} as Record) + ).map(key => Number(key)).sort((a, b) => a - b) + + // TODO: those constants should be dynamic + let freeTrack = DEFAULT_NB_TRACKS - 1 + + for (let trackNumber = MIN_TRACK_NUMBER; trackNumber < (DEFAULT_NB_TRACKS - 1); trackNumber++) { + if (!occupiedTracks.includes(trackNumber)) { + freeTrack = trackNumber + break + } + } + + return freeTrack +} \ No newline at end of file diff --git a/packages/timeline/src/utils/formatTimestamp.ts b/packages/timeline/src/utils/formatTimestamp.ts new file mode 100644 index 0000000000000000000000000000000000000000..3386f933623c47eb62c4df0cd523bf4265584eba --- /dev/null +++ b/packages/timeline/src/utils/formatTimestamp.ts @@ -0,0 +1,41 @@ +export function formatTimestamp(duration: number, { + hours: showHours, + minutes: showMinutes, + seconds: showSeconds, + milliseconds: showMilliseconds, +}: { + hours: boolean + minutes: boolean + seconds: boolean + milliseconds: boolean +}) { + let milliseconds = Math.floor((duration % 1000) / 100) + let seconds = Math.floor((duration / 1000) % 60) + let minutes = Math.floor((duration / (1000 * 60)) % 60) + let hours = Math.floor((duration / (1000 * 60 * 60)) % 24) + + let strHours = (hours < 10) ? "0" + hours : hours; + let strMinutes = (minutes < 10) ? "0" + minutes : minutes; + let strSeconds = (seconds < 10) ? "0" + seconds : seconds; + + // full padding gives a more "pro" look, but not sure we need it + // let strMilliseconds = String(milliseconds).padEnd(3, '0') + + let strMilliseconds = String(milliseconds) + + let result = '' + if (showHours) { + result += strHours + ((showMinutes || showSeconds || showMilliseconds) ? ":" : "") + } + if (showMinutes) { + result += strMinutes + ((showSeconds || showMilliseconds) ? ":" : "") + } + if (showSeconds) { + result += strSeconds + (showMilliseconds ? "" : "") + } + if (showMilliseconds) { + result += '.' + strMilliseconds + } + + return result +} \ No newline at end of file diff --git a/packages/timeline/src/utils/getAudioBuffer.ts b/packages/timeline/src/utils/getAudioBuffer.ts new file mode 100644 index 0000000000000000000000000000000000000000..f155bc3de7d861b6f34fdec901e0364605dca435 --- /dev/null +++ b/packages/timeline/src/utils/getAudioBuffer.ts @@ -0,0 +1,15 @@ +import { readFileAsArrayBuffer } from "./readFileAsArrayBuffer" + +export async function getAudioBuffer(input: File | string): Promise { + const audioContext = new AudioContext() // initialize AudioContext + const arrayBuffer = await readFileAsArrayBuffer(input) + + // decode audio data from your arrayBuffer + return new Promise((resolve, reject) => { + audioContext.decodeAudioData(arrayBuffer, (buffer) => { + resolve(buffer) + }, (err) => { + reject(err) + }) + }) +} \ No newline at end of file diff --git a/packages/timeline/src/utils/getDefaultState.ts b/packages/timeline/src/utils/getDefaultState.ts new file mode 100644 index 0000000000000000000000000000000000000000..d9cf71406c2649d47dfcecadcc6f6367afbde564 --- /dev/null +++ b/packages/timeline/src/utils/getDefaultState.ts @@ -0,0 +1,102 @@ +import { newClap } from "@aitube/clap" + +import { DEFAULT_NB_TRACKS, pastel, PROMPT_STEP_HEIGHT_IN_PX } from "@/constants" +import { TimelineStorePreferencesState, TimelineStoreProjectState, TimelineStoreState } from "@/types/timeline" +import { NB_MAX_SHOTS } from "@/constants/grid" + + +// those settings will change between .clap project reloads +export function getDefaultProjectState(): TimelineStoreProjectState { + return { + meta: newClap().meta, + scenes: [], + segments: [], + totalDurationInMs: 0, + loadedSegments: [], + visibleSegments: [], + lineNumberToMentionedSegments: {}, + + entities: [], + entityIndex: {}, + entitiesChanged: 0, + + isEmpty: true, + isLoading: false, + + initialized: false, + timeout: 0 as unknown as NodeJS.Timeout, + + minHorizontalZoomLevel: 6, + maxHorizontalZoomLevel: 100, + originalHorizontalZoomLevel: PROMPT_STEP_HEIGHT_IN_PX, + + nbMaxShots: NB_MAX_SHOTS, + nbMaxTracks: DEFAULT_NB_TRACKS, + nbIdentifiedTracks: 0, + contentWidth: 4096, + contentHeight: 800, + cellWidth: PROMPT_STEP_HEIGHT_IN_PX, + tracks: [], + defaultCellHeight: PROMPT_STEP_HEIGHT_IN_PX, + defaultSegmentDurationInSteps: 4, + defaultSegmentLengthInPixels: 4 * PROMPT_STEP_HEIGHT_IN_PX, + defaultMediaRatio: 896 / 512, + defaultPreviewHeight: PROMPT_STEP_HEIGHT_IN_PX, + typicalSegmentDurationInSteps: 4, + + // @deprecated, we now use a static WebGL camera zoom level set at 1.0 + currentZoomLevel: 1.0, + + // for developer convenience, the information about hovered, edited, selected.. + // is both present inside each segment and also aliased here, for fast access + hoveredSegment: undefined, + editedSegment: undefined, + selectedSegments: [], + + allSegmentsChanged: 0, + atLeastOneSegmentChanged: 0, + + // the purpose is to allow an external component + // to modify the segments in-line, and then trigger a redraw + silentChangesInSegment: {}, + + scrollX: 0, + scrollY: 450, + resizeStartedAt: 0, + isResizing: false, + + finalVideo: undefined, + + cursorTimestampAtInMs: 0, + isDraggingCursor: false, + } +} + +// those settings will NOT changes between .clap project reloads +export function getDefaultPreferencesState(): TimelineStorePreferencesState { + return { + canvas: undefined, + isReady: false, + width: 1800, + height: 800, + theme: pastel, + timelineControls: undefined, + topBarTimeScale: undefined, + leftBarTrackScale: undefined, + timelineCursor: undefined, + + // note: those are stateless functions, use as empty + // mocls that are normally overriden at runtime + segmentResolver: async (segment) => segment, + jumpAt: () => {}, + isPlaying: () => false, + togglePlayback: () => ({ wasPlaying: false, isPlaying: false }) + } +} + +export function getDefaultState(): TimelineStoreState { + return { + ...getDefaultProjectState(), + ...getDefaultPreferencesState(), + } +} \ No newline at end of file diff --git a/packages/timeline/src/utils/getFinalVideo.ts b/packages/timeline/src/utils/getFinalVideo.ts new file mode 100644 index 0000000000000000000000000000000000000000..6689ac2db8c1ec259af9010e25f7b4dab2f2d025 --- /dev/null +++ b/packages/timeline/src/utils/getFinalVideo.ts @@ -0,0 +1,17 @@ +import { ClapProject, ClapSegment, ClapSegmentCategory, ClapSegmentStatus } from "@aitube/clap" + +import { TimelineSegment } from "@/types" +import { clapSegmentToTimelineSegment } from "./clapSegmentToTimelineSegment" + +export async function getFinalVideo(clap: ClapProject): Promise { + const alreadyAnEmbeddedFinalVideo: ClapSegment | undefined = clap.segments.filter((s: ClapSegment) => + s.category.toUpperCase() === ClapSegmentCategory.VIDEO && + s.status.toUpperCase() === ClapSegmentStatus.COMPLETED && + s.startTimeInMs === 0 && + s.endTimeInMs === clap.meta.durationInMs && + s.assetUrl).at(0) + + if (!alreadyAnEmbeddedFinalVideo) { return undefined } + + return clapSegmentToTimelineSegment(alreadyAnEmbeddedFinalVideo) +} \ No newline at end of file diff --git a/packages/timeline/src/utils/getTextLength.ts b/packages/timeline/src/utils/getTextLength.ts new file mode 100644 index 0000000000000000000000000000000000000000..b0da9befdd88fbe9f61ca05df930f575b6f0ad6c --- /dev/null +++ b/packages/timeline/src/utils/getTextLength.ts @@ -0,0 +1,142 @@ +/** + * Uses canvas.measureText to compute and return the width of the given text of given font in pixels. + * + * @param {String} text The text to be rendered. + * @param {String} font The css font descriptor that text is to be rendered with (e.g. "bold 14px verdana"). + * + * @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393 + */ + +import { useTimeline } from ".." + +function getTextWidthInCanvas(text: string, font: string) { + if (typeof window === "undefined") { + return 0 + } + const canvas = document.createElement("canvas") + const context = canvas.getContext("2d") + if (!context) { return 0 } + + context.font = font + const metrics = context.measureText(text) + return metrics.width +} + + +// one option could be to pre-compute some of the width +const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789()_-"+=,;:?/\\&@#'.split('') +const charLength = characters.reduce((acc, char) => ({ + ...acc, + [char]: getTextWidthInCanvas(char, "bold Arial") +}), {} as Record) +let defaultCharLength = 5.561523437 + +// change this whenever you modify the font size +const webglFontWidthFactor = 1.7 + +/** + * Compute the text of a simple Arial text in a WebGL environmment + * This actually just do a lookup + sum + * + * @param text + * @returns + */ +export function getWebGLCharWidth(char: string = ""): number { + + const cellWidthInPixels = useTimeline.getState().cellWidth + + let responsiveHack = 1.5 + + if (cellWidthInPixels < 16) { + responsiveHack = 1.20 + } else if (cellWidthInPixels < 20) { + responsiveHack = 1.10 + } else if (cellWidthInPixels < 24) { + responsiveHack = 1.05 + } else if (cellWidthInPixels < 28) { + responsiveHack = 1 + } else if (cellWidthInPixels < 32) { + responsiveHack = 1.0 + } else if (cellWidthInPixels < 48) { + responsiveHack = 0.9 + } else if (cellWidthInPixels < 64) { + responsiveHack = 0.9 + } else if (cellWidthInPixels < 128) { + responsiveHack = 0.8 + } else { + responsiveHack = 0.7 + } + return responsiveHack * webglFontWidthFactor * (charLength[char] || defaultCharLength) +} + +/** + * Compute the text of a simple Arial text in a WebGL environmment + * This actually just do a lookup + sum + * + * @param text + * @returns + */ +export function getWebGLTextWidth(text: string = ""): number { + return text.split('').reduce((s, c) => (s + getWebGLCharWidth(c)), 0) +} + +/** + * Clamp a text to a given + * @param text + * @param maxWidthInPixels + * @returns + */ +export function clampWebGLText( + input: string, + maxWidthInPixels: number, + maxNbLines: number +): string[] { + let buffer = "" + let width = 0 + let lines: string[] = [] + + const text = `${input || ""}`.replace('\n', ' ').trim() + const characters = text.split('') + for (const c of characters) { + width += getWebGLCharWidth(c) + buffer += c + if (width >= maxWidthInPixels) { + if (lines.length >= (maxNbLines - 1)) { + buffer = buffer.trim() // to avoid writing "and .." + buffer += ".." + break + } else { + // TODO: we should do something smarter, which is to split the last sentence + const words = buffer.split(" ") + const lastWord = (words.at(-1) || "") + if (lastWord.length) { + lines.push(words.slice(0, -1).join(" ")) + buffer = lastWord + width = getWebGLTextWidth(lastWord) + } else { + lines.push(buffer) + buffer = "" + width = 0 + } + } + } + } + + if (buffer.length) { + lines.push(buffer) + } + return lines +} + +export function clampWebGLTextNaive(input: string = "", maxWidthInPixels: number = 0): string { + // this cutoff is very approximate as we should make it dependent on each character's width + // a simple heuristic can be to count the uppercase / lower case + const maxhInCharacter = Math.ceil(maxWidthInPixels / 3.4) + + const text = `${input || ""}` + + return (text.length >= maxhInCharacter) + ? `${text.slice(0, maxhInCharacter)}..` + : text + +} \ No newline at end of file diff --git a/packages/timeline/src/utils/hslToHex.ts b/packages/timeline/src/utils/hslToHex.ts new file mode 100644 index 0000000000000000000000000000000000000000..facd8868b8f080903f1a791121cf86fab0ff3622 --- /dev/null +++ b/packages/timeline/src/utils/hslToHex.ts @@ -0,0 +1,28 @@ +export function hslToHex(h: number, s: number, l: number): string { + h /= 360; + s /= 100; + l /= 100; + let r, g, b; + if (s === 0) { + r = g = b = l; // achromatic + } else { + const hue2rgb = (p: number, q: number, t: number) => { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + }; + const q = l < 0.5 ? l * (1 + s) : l + s - l * s; + const p = 2 * l - q; + r = hue2rgb(p, q, h + 1 / 3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1 / 3); + } + const toHex = (x: number) => { + const hex = Math.round(x * 255).toString(16); + return hex.length === 1 ? '0' + hex : hex; + }; + return `#${toHex(r)}${toHex(g)}${toHex(b)}`; +} \ No newline at end of file diff --git a/packages/timeline/src/utils/index.ts b/packages/timeline/src/utils/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..917766032bfd0595d931ba2c4118345093a00515 --- /dev/null +++ b/packages/timeline/src/utils/index.ts @@ -0,0 +1,25 @@ +export { clamp } from "./clamp" +export { clapSegmentToTimelineSegment } from "./clapSegmentToTimelineSegment" +export { cn } from "./cn" +export { debounceAsync } from "./debounceAsync" +export { debounceSync } from "./debounceSync" +export { findFreeTrack } from "./findFreeTrack" +export { formatTimestamp } from "./formatTimestamp" +export { getAudioBuffer } from "./getAudioBuffer" +export { getDefaultState } from "./getDefaultState" +export { getFinalVideo } from "./getFinalVideo" +export { + getWebGLCharWidth, + getWebGLTextWidth, + clampWebGLText, + clampWebGLTextNaive +} from "./getTextLength" +export { hslToHex } from "./hslToHex" +export { parseRenderingStrategy } from "./parseRenderingStrategy" +export { readFileAsArrayBuffer } from "./readFileAsArrayBuffer" +export { removeFinalVideosAndConvertToTimelineSegments } from "./removeFinalVideosAndConvertToTimelineSegments" +export { similar } from "./similar" +export { sleep } from "./sleep" +export { sliceSegments } from "./sliceSegments" +export { throttle } from "./throttle" +export { timelineSegmentToClapSegment } from "./timelineSegmentToClapSegment" \ No newline at end of file diff --git a/packages/timeline/src/utils/parseRenderingStrategy.ts b/packages/timeline/src/utils/parseRenderingStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..204f952462625c242570febef29c3e6fe11f000d --- /dev/null +++ b/packages/timeline/src/utils/parseRenderingStrategy.ts @@ -0,0 +1,31 @@ +import { RenderingStrategy } from "@/types" + +export function parseRenderingStrategy(input: any, defaultStrategy?: RenderingStrategy): RenderingStrategy { + + let unknownString = `${input || ""}`.trim() + + // the "normal" case + if (Object.values(RenderingStrategy).includes(unknownString as RenderingStrategy)) { + return unknownString as RenderingStrategy + } + + let strategy: RenderingStrategy = defaultStrategy || RenderingStrategy.ON_DEMAND + + unknownString = unknownString.toLowerCase() + + if (unknownString === "on_demand") { + strategy = RenderingStrategy.ON_DEMAND + } + else if (unknownString === "on_screen_only") { + strategy = RenderingStrategy.ON_SCREEN_ONLY + } + else if (unknownString === "on_screen_then_surrounding") { + strategy = RenderingStrategy.ON_SCREEN_THEN_SURROUNDING + } + else if (unknownString === "on_screen_then_all") { + strategy = RenderingStrategy.ON_SCREEN_THEN_ALL + } else { + strategy = RenderingStrategy.ON_DEMAND + } + return strategy +} \ No newline at end of file diff --git a/packages/timeline/src/utils/readFileAsArrayBuffer.ts b/packages/timeline/src/utils/readFileAsArrayBuffer.ts new file mode 100644 index 0000000000000000000000000000000000000000..a2ab50661b4bb6635e30720e06ace8d26855e165 --- /dev/null +++ b/packages/timeline/src/utils/readFileAsArrayBuffer.ts @@ -0,0 +1,32 @@ +export async function readFileAsArrayBuffer(input: File | string): Promise { + return new Promise((resolve, reject) => { + if (typeof input === 'string') { + // check if it is base64 or not + if (/^data:.+;base64,/.test(input)) { + const base64 = input.split(",")[1]; + const binary = window.atob(base64); + const buffer = new ArrayBuffer(binary.length); + const view = new Uint8Array(buffer); + for (let i = 0; i < binary.length; i++) { + view[i] = binary.charCodeAt(i); + } + resolve(buffer); + return; + } else { + reject('Invalid input string'); + return; + } + } + + let reader = new FileReader(); + reader.onload = () => { + // when the reader has loaded, resolve the Promise with the result + resolve(reader.result as ArrayBuffer); + }; + reader.onerror = (error) => { + // if there's an error, reject the Promise with the error + reject(error); + }; + reader.readAsArrayBuffer(input as File); + }); +} diff --git a/packages/timeline/src/utils/removeFinalVideosAndConvertToTimelineSegments.ts b/packages/timeline/src/utils/removeFinalVideosAndConvertToTimelineSegments.ts new file mode 100644 index 0000000000000000000000000000000000000000..ea0c6e7a8e9aa8d6dd9283ff5815da0a13b9fbb9 --- /dev/null +++ b/packages/timeline/src/utils/removeFinalVideosAndConvertToTimelineSegments.ts @@ -0,0 +1,50 @@ +import { ClapProject } from "@aitube/clap" + +import { SegmentVisibility, TimelineSegment } from "@/types" + +import { getFinalVideo } from "./getFinalVideo" +import { clapSegmentToTimelineSegment } from "./clapSegmentToTimelineSegment" + +export async function removeFinalVideosAndConvertToTimelineSegments(clap: ClapProject): Promise { + const alreadyAnEmbeddedFinalVideo = await getFinalVideo(clap) + let ignoreThisVideoSegmentId = "" + + if (alreadyAnEmbeddedFinalVideo) { + ignoreThisVideoSegmentId = alreadyAnEmbeddedFinalVideo?.id || "" + + /* + you know what.. let's just ignore it, and re-generate fresh content + because most probably the user made an honest mistake + + const outputFilePath = await writeBase64ToFile( + alreadyAnEmbeddedFinalVideo.assetUrl, + join(outputDir, `existing_final_video`) + ) + + return { + tmpWorkDir: outputDir, + outputFilePath + } + */ + } + + const segments: TimelineSegment[] = [] + + let nbSegments = 0 + + for (const clapSegment of (clap.segments as TimelineSegment[])) { + if (clapSegment.id === ignoreThisVideoSegmentId) { continue } + + const segment = await clapSegmentToTimelineSegment(clapSegment) + + // ok so this is more or less a "hack": when we load the segments, we don't want all of them to be hidden + // but we also don't have the time to compute the visibility yet, + // so what we do is that we apply some basic rule (since the window and scroll is reset too) + // to only show the first Nth segments (in this case, 200) + segment.visibility = nbSegments++ > 200 ? SegmentVisibility.HIDDEN : SegmentVisibility.VISIBLE + + segments.push(segment) + } + + return segments +} \ No newline at end of file diff --git a/packages/timeline/src/utils/similar.ts b/packages/timeline/src/utils/similar.ts new file mode 100644 index 0000000000000000000000000000000000000000..2525e894b09c76b269b2a1b0f1676984e143e54f --- /dev/null +++ b/packages/timeline/src/utils/similar.ts @@ -0,0 +1,6 @@ +import { Vector3 } from "three" + +export function similar(v1: Vector3, v2: Vector3, epsilon = Number.EPSILON) { + + return ( ( Math.abs( v1.x - v2.x) < epsilon ) && ( Math.abs( v1.y - v2.y ) < epsilon ) && ( Math.abs( v1.z - v2.z ) < epsilon) ); +} \ No newline at end of file diff --git a/packages/timeline/src/utils/sleep.ts b/packages/timeline/src/utils/sleep.ts new file mode 100644 index 0000000000000000000000000000000000000000..2885c6e75c0dc415c9eaf71beabac7461eee5588 --- /dev/null +++ b/packages/timeline/src/utils/sleep.ts @@ -0,0 +1,6 @@ +export const sleep = async (durationInMs: number) => + new Promise((resolve) => { + setTimeout(() => { + resolve(true) + }, durationInMs) + }) \ No newline at end of file diff --git a/packages/timeline/src/utils/sliceSegments.ts b/packages/timeline/src/utils/sliceSegments.ts new file mode 100644 index 0000000000000000000000000000000000000000..d5d1c96e80d0aa4468433dbfb38767498c5cc991 --- /dev/null +++ b/packages/timeline/src/utils/sliceSegments.ts @@ -0,0 +1,22 @@ +import { ClapSegmentFilteringMode, filterSegmentsWithinRange } from "@aitube/clap" + +import { TimelineSegment } from "@/types" + +// TODO put this in a web workers for smoother operations? +export function sliceSegments({ + segments, + afterTimeInMs, + beforeTimeInMs, +}: { + segments: TimelineSegment[] + afterTimeInMs: number + beforeTimeInMs: number +}): TimelineSegment[] { + const result = filterSegmentsWithinRange( + ClapSegmentFilteringMode.ANY, + afterTimeInMs, + beforeTimeInMs, + segments + ) + return result +} \ No newline at end of file diff --git a/packages/timeline/src/utils/throttle.ts b/packages/timeline/src/utils/throttle.ts new file mode 100644 index 0000000000000000000000000000000000000000..c68d2db47ee604e2fc342a7d11356ddbfde03864 --- /dev/null +++ b/packages/timeline/src/utils/throttle.ts @@ -0,0 +1,29 @@ +export const throttle = ( + fn: (...args: A) => R, + delay: number +): [(...args: A) => R | undefined, () => void] => { + let wait = false; + let timeout: undefined | number; + let cancelled = false; + + return [ + (...args: A) => { + if (cancelled) return undefined; + if (wait) return undefined; + + const val = fn(...args); + + wait = true; + + timeout = window.setTimeout(() => { + wait = false; + }, delay); + + return val; + }, + () => { + cancelled = true; + clearTimeout(timeout); + }, + ]; +}; \ No newline at end of file diff --git a/packages/timeline/src/utils/timelineSegmentToClapSegment.ts b/packages/timeline/src/utils/timelineSegmentToClapSegment.ts new file mode 100644 index 0000000000000000000000000000000000000000..695c4a7920acada842977a1a02720113625407ab --- /dev/null +++ b/packages/timeline/src/utils/timelineSegmentToClapSegment.ts @@ -0,0 +1,30 @@ +import { TimelineSegment } from "@/types" +import { ClapSegment } from "@aitube/clap" + +export function timelineSegmentToClapSegment(timelineSegment: TimelineSegment): ClapSegment { + + const segment: any = { + ...timelineSegment + } + + delete segment.scene + delete segment.startAtLine + delete segment.endAtLine + delete segment.audioBuffer + delete segment.visibility + delete segment.textures + + delete segment.isSelected + delete segment.isHovered + delete segment.isHoveredOnBody + delete segment.isHoveredOnLeftHandle + delete segment.isHoveredOnRightHandle + delete segment.isGrabbedOnBody + delete segment.isGrabbedOnLeftHandle + delete segment.isGrabbedOnRightHandle + delete segment.isActive + delete segment.isPlaying + delete segment.editionStatus + + return segment as ClapSegment +} \ No newline at end of file diff --git a/packages/timeline/tailwind.config.js b/packages/timeline/tailwind.config.js new file mode 100644 index 0000000000000000000000000000000000000000..13fb27d5218e969bc7ded65673382fbecdb48ad1 --- /dev/null +++ b/packages/timeline/tailwind.config.js @@ -0,0 +1,33 @@ +/** @type {import("tailwindcss").Config} */ +module.exports = { + darkMode: ["class"], + content: [ + "./src/components/**/*.{ts,tsx}", + "./src/**/*.{ts,tsx}", + ], + theme: { + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px", + }, + }, + extend: { + fontSize: { + "5xs": "8px", + "4xs": "9px", + "3xs": "10px", + "2xs": "11px" + }, + containers: { + "6xs": "2rem", + "5xs": "4rem", + "4xs": "8rem", + "3xs": "12rem", + "2xs": "16rem", + }, + }, + }, + plugins: [] +} \ No newline at end of file diff --git a/packages/timeline/test/test.tsx b/packages/timeline/test/test.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/packages/timeline/tsconfig.json b/packages/timeline/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..afae3b3bee80ddff773f7d7aa12db7f357d6f11a --- /dev/null +++ b/packages/timeline/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "baseUrl": "./", + "paths": { + "@/*": ["src/*"] + }, + "lib": ["dom", "dom.iterable", "esnext"], + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": true, + "noImplicitAny": false, + "noEmit": true, + "composite": true, + "strict": true, + "downlevelIteration": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "types": [ + "bun-types" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx" + ] +} diff --git a/packages/timeline/tsconfig.node.json b/packages/timeline/tsconfig.node.json new file mode 100644 index 0000000000000000000000000000000000000000..97ede7ee6f2d37bd2d76e60c0b6a447bee718b05 --- /dev/null +++ b/packages/timeline/tsconfig.node.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "strict": true + }, + "include": ["vite.config.ts"] +} diff --git a/packages/timeline/tsconfig.types.json b/packages/timeline/tsconfig.types.json new file mode 100644 index 0000000000000000000000000000000000000000..6c2a648a8e304d2f08b6e240d6657d110cd7c5bd --- /dev/null +++ b/packages/timeline/tsconfig.types.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "emitDeclarationOnly": true, + "declaration": true, + "outDir": "./dist", + "rootDir": "./src", + }, + "include": [ + "src/**/*.ts", + "src/**/*.tsx" + ] +} diff --git a/packages/timeline/vite.config.js b/packages/timeline/vite.config.js new file mode 100644 index 0000000000000000000000000000000000000000..bcdb65c77265bbe217ac62621df96cd218485174 --- /dev/null +++ b/packages/timeline/vite.config.js @@ -0,0 +1,24 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import path from 'path' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + // resolve monorepo packages + resolve: { + alias: { + "@aitube/clap": path.resolve(__dirname, "../clap/dist"), + '@': path.resolve(__dirname, 'src'), + }, + }, + server: { + fs: { + // Allow serving files from one level up to the project root + allow: ['..'], + }, + }, + optimizeDeps: { + exclude: ['@aitube/clap'], // Exclude the clap package from pre-bundling + }, +}) \ No newline at end of file diff --git a/src/services/autocomplete/extractCaptionsFromFrames.ts b/src/services/autocomplete/extractCaptionsFromFrames.ts deleted file mode 100644 index 461ef7901b65ab2d6dc8bb396165efdbf4958d6f..0000000000000000000000000000000000000000 --- a/src/services/autocomplete/extractCaptionsFromFrames.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { - AutoProcessor, - AutoTokenizer, - Florence2ForConditionalGeneration, - RawImage, -} from '@xenova/transformers' - -export const cache: { - model?: Promise - processor?: Promise - tokenizer?: Promise -} = {} - -export async function loadModel( - modelId: string, - onProgress: (progress: number) => void -) { - onProgress(0) - const model = await (cache.model - ? cache.model - : (cache.model = Florence2ForConditionalGeneration.from_pretrained( - modelId, - { - dtype: 'fp32', - } - ))) - - onProgress(33) - - const processor = await (cache.processor - ? cache.processor - : (cache.processor = AutoProcessor.from_pretrained(modelId))) - - onProgress(66) - - const tokenizer = await (cache.tokenizer - ? cache.tokenizer - : (cache.tokenizer = AutoTokenizer.from_pretrained(modelId))) - - onProgress(100) - - return { model, processor, tokenizer } -} - -export function closeModel() { - cache.model = undefined - cache.processor = undefined - cache.tokenizer = undefined -} - -export async function extractCaptionsFromFrames( - images: string[] = [], - onProgress: ( - progress: number, - storyboardIndex: number, - nbStoryboards: number - ) => void -): Promise { - if (!(navigator as any).gpu) { - throw new Error(`Please enable WebGPU to analyze video frames: - -1. You need a modern browser such as Google Chrome 113+, Microsoft Edge 113+, Safari 18 (macOS 15), Firefox Nightly - -2. You need to enable WebGPU (depends on your browser, see below) - -2.1 For Chrome: Perform the following operations in the Chrome / Microsoft Edge address bar -The chrome://flags/#enable-unsafe-webgpu flag must be enabled (not enable-webgpu-developer-features). -Linux experimental support also requires launching the browser with --enable-features=Vulkan. - -2.2 For Safari 18 (macOS 15): WebGPU is enabled by default - -2.3 For Firefox Nightly: Type about:config in the address bar and set 'dom.webgpu.enabled" to true -`) - } - - let progress = 0 - - // for code example, see: - // https://github.com/xenova/transformers.js/pull/545#issuecomment-2183625876 - - // Load model, processor, and tokenizer - const model_id = 'onnx-community/Florence-2-base-ft' - - const { model, processor, tokenizer } = await loadModel(model_id, (p) => { - onProgress((progress = p * 15), 0, images.length) - }) - - // not all prompts will work properly, see the official examples: - // https://huggingface.co/microsoft/Florence-2-base-ft/blob/e7a5acc73559546de6e12ec0319cd7cc1fa2437c/processing_florence2.py#L115-L117 - - // Prepare text inputs - const prompts = 'Describe with a paragraph what is shown in the image.' - // const prompts = 'Decompose the following video frame into era, genre, location, weather, characters, and action. Give the answer in YAML.' - - const text_inputs = tokenizer(prompts) - - let i = 1 - const captions: string[] = [] - for (const imageInBase64DataUri of images) { - console.log('analyzing image:', imageInBase64DataUri.slice(0, 64)) - // Prepare vision inputs - const image = await RawImage.fromURL(imageInBase64DataUri) - const vision_inputs = await processor(image) - - console.log(' - generating caption..') - // Generate text - const generated_ids = await model.generate({ - ...text_inputs, - ...vision_inputs, - max_new_tokens: 100, - }) - - // Decode generated text - const generated_text = tokenizer.batch_decode(generated_ids, { - skip_special_tokens: true, - }) - - const caption = `${generated_text[0] || ''}` - console.log(' - caption:', caption) - - const relativeProgress = i / images.length - - progress += relativeProgress * 75 - onProgress(progress, i, images.length) - captions.push(caption) - } - return captions -} diff --git a/src/services/io/fix-xenova-transformers.d.ts b/src/services/io/fix-xenova-transformers.d.ts deleted file mode 100644 index f9e2aac7d4b8b468a26fe4fa649984940b42f138..0000000000000000000000000000000000000000 --- a/src/services/io/fix-xenova-transformers.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '@xenova/transformers'